跳轉到內容

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);

< OpenGL 程式設計

瀏覽並下載 完整程式碼
華夏公益教科書