OpenGL中八面体的递归细分 [英] Recursive subdivision on octahedron in OpenGL

查看:363
本文介绍了OpenGL中八面体的递归细分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在指这篇帖子在OpenGL中绘制Sphere而不使用gluSphere( )?这对我有很大帮助,但现在我很沮丧.

I have been referring to this post Drawing Sphere in OpenGL without using gluSphere()? which has helped me quite a lot but i'm stumped now.

我的场景中有一个八面体,我现在想递归地细分三角形以创建一个球体.我找到了应该为我进行细分的这段代码,但我不太了解

I have an octahedron in my scene and I would now like to recursively subdivide the triangles to create a sphere. I found this block of code which is supposed to carry out the subdivision for me but I don't understand it fully

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

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

I set up a struct to hold a position, normal and a color

// 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) },
            }
        }

如果有人能解释我如何使用上述方法细分三角形,我将不胜感激.

If anyone could explain how I could use the method above to subdivide my triangles, i'd appreciate it.

推荐答案

递归细分本身非常简单,您已经拥有了一部分.以八面体的一个三角形为例,我们通过将整个三角形的坐标传递给递归函数以及所需的细分级别来播种递归调用(在3到5之间的范围将给出合理的球体):

The recursive subdivision itself is fairly straightforward, and you have parts of it already. Taking one triangle of the octahedron, we seed the recursive calls by passing the coordinates of the full triangle to the recursive function, together with the desired subdivision level (something in the range of 3 to 5 will give reasonable spheres):

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

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

Then, in the recursive function, we first check if we reached level 0, in which case we have a final triangle. Otherwise we split the triangle into 4, and make the recursive call for each of them. The vertices of the 4 sub-triangles are formed from the original triangle vertices and the middle of their edges, based on the diagrams you already found:

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

这将为您提供所需的所有顶点.但是它会多次计算镶嵌的每个顶点.如果只想一次计算每个顶点,然后将它们存储在顶点缓冲区中,就会感到有些痛苦.为此,您还必须将索引传递给递归函数,并对这些索引进行一些数学运算,以便可以将每个结果顶点放置在唯一的索引处.如果要从所有生成的唯一顶点上绘制漂亮的三角形条纹,则变得更加麻烦.

This gives you all the vertices you need. But it calculates each vertex of the tessellation multiple times. Where it gets slightly painful is if you want to calculate each vertex only once, and store them in a vertex buffer. To do that, you'll have to also pass indices to the recursive function, and do some math on those indices so that you can place each resulting vertex at a unique index. It gets even more cumbersome if you want nice triangle strips from all the resulting unique vertices.

不幸的是,所有这些细节都超出了此处的答案范围.但我希望以上内容至少可以清楚地说明进行实际细分所需的基本数学和逻辑.

Unfortunately all those details are somewhat beyond the scope of an answer here. But I hope that the above will at least clearly explain the underlying math and logic needed to do the actual subdivision.

这篇关于OpenGL中八面体的递归细分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆