OpenGL 编程/边界框
外观
我们分析物体
- X、Y 和 Z 的最小坐标
- X、Y 和 Z 的最大坐标
- 我们计算物体所需的尺寸:X、Y 和 Z 中的
max-min
- 我们计算物体的中心:X、Y 和 Z 中的
(min+max)/2
我们计算围绕物体的立方体
- 我们准备一个大小为 1(1x1x1)的立方体,以原点为中心
- 我们根据物体的尺寸对其进行缩放
- 我们将其以物体为中心
要绘制立方体
- 我们使用 1 个循环线绘制正面
- 我们使用 1 个循环线绘制背面
- 我们绘制 4 条正交线以连接两个面
void draw_bbox(struct mesh* mesh) {
if (mesh->vertices.size() == 0)
return;
// Cube 1x1x1, centered on origin
GLfloat vertices[] = {
-0.5, -0.5, -0.5, 1.0,
0.5, -0.5, -0.5, 1.0,
0.5, 0.5, -0.5, 1.0,
-0.5, 0.5, -0.5, 1.0,
-0.5, -0.5, 0.5, 1.0,
0.5, -0.5, 0.5, 1.0,
0.5, 0.5, 0.5, 1.0,
-0.5, 0.5, 0.5, 1.0,
};
GLuint vbo_vertices;
glGenBuffers(1, &vbo_vertices);
glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
GLushort elements[] = {
0, 1, 2, 3,
4, 5, 6, 7,
0, 4, 1, 5, 2, 6, 3, 7
};
GLuint ibo_elements;
glGenBuffers(1, &ibo_elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
GLfloat
min_x, max_x,
min_y, max_y,
min_z, max_z;
min_x = max_x = mesh->vertices[0].x;
min_y = max_y = mesh->vertices[0].y;
min_z = max_z = mesh->vertices[0].z;
for (int i = 0; i < mesh->vertices.size(); i++) {
if (mesh->vertices[i].x < min_x) min_x = mesh->vertices[i].x;
if (mesh->vertices[i].x > max_x) max_x = mesh->vertices[i].x;
if (mesh->vertices[i].y < min_y) min_y = mesh->vertices[i].y;
if (mesh->vertices[i].y > max_y) max_y = mesh->vertices[i].y;
if (mesh->vertices[i].z < min_z) min_z = mesh->vertices[i].z;
if (mesh->vertices[i].z > max_z) max_z = mesh->vertices[i].z;
}
glm::vec3 size = glm::vec3(max_x-min_x, max_y-min_y, max_z-min_z);
glm::vec3 center = glm::vec3((min_x+max_x)/2, (min_y+max_y)/2, (min_z+max_z)/2);
glm::mat4 transform = glm::translate(glm::mat4(1), center) * glm::scale(glm::mat4(1), size);
/* Apply object's transformation matrix */
glm::mat4 m = mesh->object2world * transform;
glUniformMatrix4fv(uniform_m, 1, GL_FALSE, glm::value_ptr(m));
glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices);
glEnableVertexAttribArray(attribute_v_coord);
glVertexAttribPointer(
attribute_v_coord, // attribute
4, // number of elements per vertex, here (x,y,z,w)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
0, // no extra data between each position
0 // offset of first element
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_elements);
glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, (GLvoid*)(4*sizeof(GLushort)));
glDrawElements(GL_LINES, 8, GL_UNSIGNED_SHORT, (GLvoid*)(8*sizeof(GLushort)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(attribute_v_coord);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &vbo_vertices);
glDeleteBuffers(1, &ibo_elements);
}
如在 科学教程 05 中看到的那样,您可以通过使用以下方法来改善线和表面混合的情况
/* main */
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1, 0);
即使在绘制线之后,也要保持 GL_POLYGON_OFFSET_FILL
启用,在绘制表面时也需要启用它。
如果需要,您还可以增加线宽
glLineWidth(2);
浏览并下载 完整代码