OpenGL中八面体的递归细分

时间:2014-11-06 22:14:54

标签: opengl recursion division

我一直在提到这篇帖子Drawing Sphere in OpenGL without using gluSphere()?,这对我帮助很大,但我现在很难过。

我的场景中有一个八面体,我现在想要递归细分三角形来创建一个球体。我发现这段代码应该为我执行细分,但我完全不理解

void subdivide(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3], int depth)
{
    GLfloat v12[3], v23[3], v31[3]; int i;
    if (depth == 0) {
    drawTriangle(v1, v2, v3);
    return;
}
for (i = 0; i < 3; i++) 
{
    v12[i] = (v1[i]+v2[i])/2.0;
    v23[i] = (v2[i]+v3[i])/2.0;
    v31[i] = (v3[i]+v1[i])/2.0;
}

我设置了一个结构来保持位置,法线和颜色

// simple vertex container
struct SimpleVertex
{
    vec3        pos;    // Position
    vec3        normal  // Normal
    vec4        colour; // Colour
};

这就是我设置顶点的地方

 /*
    *
    * This is just one triangle form my octahedron
    *
    */
     static void createVertexBuffer()
        {
            // Create some vertices to put in our VBO.
            // Create vertex buffer
            SimpleVertex vertices[] =

            {
                // Side 1 Front
                { vec3(0.0f, 1.0f, 1.0f), vec3(0.0f, 0.0f, 1.0f), vec4(1.0f, 0.0f, 0.0f, 1.0f) },
                { vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec4(0.0f, 1.0f, 0.0f, 1.0f) },
                { vec3(1.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f), vec4(0.0f, 0.0f, 1.0f, 1.0f) },
            }
        }

如果有人能解释我如何使用上述方法来细分我的三角形,我会很感激。

2 个答案:

答案 0 :(得分:7)

递归细分本身相当简单,你已经拥有它的一部分。取八面体的一个三角形,我们通过将完整三角形的坐标传递给递归函数以及所需的细分级别(3到5范围内的某些内容将给出合理的范围)来播种递归调用:

subdivide(1.0f, 0.0f, 0.0f,
          0.0f, 1.0f, 0.0f,
          0.0f, 0.0f, 1.0f,
          LEVEL_COUNT);

然后,在递归函数中,我们首先检查是否达到了0级,在这种情况下我们有一个最终的三角形。否则,我们将三角形拆分为4,并为每个三角形进行递归调用。根据您已经找到的图表,4个子三角形的顶点由原始三角形顶点和边缘中间构成:

      v3
     /  \
    /    \
  v13----v23
  /  \  /  \
 /    \/    \
v1----v12---v2

递归函数如下所示:

void subdivide(float v1x, float v1y, float v1z,
               float v2x, float v2y, float v2z,
               float v3x, float v3y, float v3z,
               int level) {
    if (level == 0) {
        // Reached desired tessellation level, emit triangle.
        drawTriangle(v1x, v1y, v1z,
                     v2x, v2y, v2z,
                     v3x, v3y, v3z);
    } else {
        // Calculate middle of first edge...
        float v12x = 0.5f * (v1x + v2x);
        float v12y = 0.5f * (v1y + v2y);
        float v12z = 0.5f * (v1z + v2z);
        // ... and renormalize it to get a point on the sphere.
        float s = 1.0f / sqrt(v12x * v12x + v12y * v12y + v12z * v12z);
        v12x *= s;
        v12y *= s;
        v12z *= s;

        // Same thing for the middle of the other two edges.
        float v13x = 0.5f * (v1x + v3x);
        float v13y = 0.5f * (v1y + v3y);
        float v13z = 0.5f * (v1z + v3z);
        float s = 1.0f / sqrt(v13x * v13x + v13y * v13y + v13z * v13z);
        v13x *= s;
        v13y *= s;
        v13z *= s;

        float v23x = 0.5f * (v2x + v3x);
        float v23y = 0.5f * (v2y + v3y);
        float v23z = 0.5f * (v2z + v3z);
        float s = 1.0f / sqrt(v23x * v23x + v23y * v23y + v23z * v23z);
        v23x *= s;
        v23y *= s;
        v23z *= s;

        // Make the recursive calls.
        subdivide(v1x, v1y, v1z,
                  v12x, v12y, v12z,
                  v13x, v13y, v13z,
                  level - 1);
        subdivide(v12x, v12y, v12z,
                  v2x, v2y, v2z,
                  v23x, v23y, v23z,
                  level - 1);
        subdivide(v13x, v13y, v13z,
                  v23x, v23y, v23z,
                  v3x, v3y, v3z,
                  level - 1);
        subdivide(v12x, v12y, v12z,
                  v23x, v23y, v23z,
                  v13x, v13y, v13z,
                  level - 1);
    }
}

这为您提供了所需的所有顶点。但它会多次计算曲面细分的每个顶点。如果您只想计算每个顶点一次,并将它们存储在顶点缓冲区中,那么它会变得有点痛苦。为此,您还必须将索引传递给递归函数,并对这些索引进行一些数学运算,以便您可以将每个结果顶点放在唯一索引处。如果你想从所有产生的独特顶点得到漂亮的三角形条带,它会变得更加麻烦。

不幸的是,所有这些细节都有些超出了答案的范围。但我希望上述内容至少能清楚地解释进行实际细分所需的基础数学和逻辑。

答案 1 :(得分:1)

我也跟着你提到的文章,但我生成了我自己的递归函数,如下所示

Drawtriangle(vecta, vectb, vectb, int max, depth)
{
If(Depth <= max)
Add a
add b
add c

vecd = midlepoint(veca,vecb)
vece = middlepoint(vecb,vecc)
Vecf = midlepoint(vecc,veca)

depth++

Drawtriangle(veca,vecb,vecc,max,depth);
drawtriangle(veca,vecd,vecf...
drawtrianfle(vecd,vecb,vece...
drawtriangle(vecf,vecc,vece...
dratriangle(vecf,vecd,vece..

}