如何使用opengl, c++,而不是过剩/Glu来渲染球体[复制]

时间:2022-09-10 19:05:54

This question already has an answer here:

这个问题已经有了答案:

I am relatively new to OpenGL and C++ in general and I've been working on a custom framework in which I am asked to render spheres. I ve done research and managed to generate a somewhat-sphere made from points. I would like if possible to reform it so I can have an actual sphere made from triangles having properties such as radius. The code I used to generate sphere made from points is as follows:

总的来说,我对OpenGL和c++比较陌生,我一直在研究一个定制框架,在这个框架中,我被要求渲染球体。我已经做了一些研究,并设法产生了一个由点组成的球体。如果可能的话,我想要对它进行改造,这样我就能得到一个由三角形构成的球体,它具有半径等性质。我用来生成球面的代码如下:

Mesh* Mesh::GenerateSphere()
{

    const int Y_SEGMENT= 10;
    const int X_SEGMENT = 20;
    //const float count;


    Mesh*m = new Mesh();
    m->numVertices = (X_SEGMENT+1)*(Y_SEGMENT+1);
    m->type = GL_POINTS;
    m->vertices = new Vector3[m->numVertices];

    //s->GenerateTriangle();
    for (int i = 0; i < Y_SEGMENT+1;i++)
    {
        float angleY = PI*i / Y_SEGMENT;
        float y = cos(angleY);
        float xz = sin(angleY);

        for (int j = 0; j < X_SEGMENT+1; j++)
        {

            float angleX = 2*PI*j / X_SEGMENT;
            float x = xz*cos(angleX);
            float z = xz*sin(angleX);
            Vector3 v(x,y,z);
            m->vertices[i * (X_SEGMENT+1)+j] = v;
        }
    }
    m->BufferData();
    return m;
}

2 个解决方案

#1


0  

Here's some code I wrote a long, long time ago. I've drawn the areas immediately surrounding the poles with a triangle-fan and the remainder of the sphere with quad-strips. You could of course, use triangles instead of the quads, but since the pairs of triangles would still be planar, it wont look any different, unless I'm mistaken - it's been a long times since I touched anything GL.

这是我很久很久以前写的一些代码。我已经画出了周围的区域,用一个三角形扇子和其他的带四根的球体。当然,你可以用三角形代替四边形,但是因为三角形的对仍然是平面的,所以它看起来不会有任何不同,除非我弄错了——自从我接触了任何东西以来已经有很长一段时间了。

As molbdnilo points out, you'll get a better sphere by calculating your points in a different manner. If the intention is to texture-map the sphere, you'll get better results again if you subdivide and smooth a cube, since this avoids 'pinching' around the poles. Here's a good article that discusses this: http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm

正如molbdnilo所指出的,通过不同的方式计算你的点,你会得到一个更好的球体。如果你的意图是给球贴图,如果你细分和平滑一个立方体,你会得到更好的结果,因为这避免了在极点附近的“挤压”。这里有一篇很好的文章讨论了这个问题:http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm。

I should also point-out that there's a problem with the way that I either calculate the normals, or transform then when rotating - I used to get funky lighting results when looking at the sphere when it was rotated. (I think it's with the normals) Also, looking at the just code now, I'm not sure that I've computed the number of vertices required correctly - you'll have to double-check that.It appears as though I don't store verts for either of the poles in the array.

我还应该指出,我计算法线的方法有问题,或者当旋转时变换——当我看到旋转的球时,我经常会得到一些古怪的照明效果。(我认为是法线),看看现在的代码,我不确定我是否已经计算了所需的顶点数——你必须仔细检查一下。看起来好像我没有为数组中的任何一个极点存储一个。

EDIT: Here's a pic of the output:

编辑:这是输出的图片:

如何使用opengl, c++,而不是过剩/Glu来渲染球体[复制]

typedef struct {
    GLfloat x, y, z;
}vec3;

void myGlutBall(float radius, int numStacks, int numSides)
{
//    vec3 points[sides * (sides-1)];
    GLfloat curRadius, curTheta, curRho, deltaTheta, deltaRho, curX,curY,curZ;
    int curStack, curSlice, numVerts = (numStacks-1)*numSides;
    vec3 points[numVerts];
    int curVert = 0;
    int t;

    deltaTheta = (2*M_PI) / numSides;
    deltaRho = M_PI / numStacks;

        for (curStack=1; curStack<numStacks; curStack++)
        {
            curRho = (3.141/2.0) - curStack*deltaRho;
            curY = sin(curRho) * radius;
            curRadius = cos(curRho) * radius;
            for (curSlice=0; curSlice<numSides; curSlice++)
            {
                curTheta = curSlice * deltaTheta;
                curX = curRadius * cos(curTheta);
                curZ = -curRadius * sin(curTheta);
                points[curVert++] = vec3{curX,curY,curZ};
            }
        }

    // option 1 - points only
    /*
    glBegin(GL_POINTS);
    glNormal3d(0,1,0);
    glVertex3d(0,radius,0);
    for (t=0; t<numVerts; t++)
    {
        curX = points[t].x;
        curY = points[t].y;
        curZ = points[t].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    }
    glNormal3d(0,-1,0);
    glVertex3d(0,-radius,0);
    glEnd();
    */

    ///////////////////////////////
    // option 2 - solid
    ///////////////////////////////
    // part A - draw the top 'lid' (tris)
    glBegin(GL_TRIANGLE_FAN);
        glNormal3d(0,1,0);
        glVertex3d(0,radius,0);
        for (t=0; t<numSides; t++)
        {
            curX = points[t].x;
            curY = points[t].y;
            curZ = points[t].z;
            glNormal3d(curX, curY, curZ);
            glVertex3d(curX, curY, curZ);
        }
            curX = points[0].x;
            curY = points[0].y;
            curZ = points[0].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    glEnd();

    // part B - draw the 'sides' (quads)
    int vertIndex;
    for (curStack=0; curStack<numStacks-2; curStack++)
    {
        vertIndex = curStack * numSides;
        glBegin(GL_QUAD_STRIP);
            for (curSlice=0; curSlice<numSides; curSlice++)
            {
                glNormal3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);
                glVertex3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);

                glNormal3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
                glVertex3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
            }
            glNormal3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
            glVertex3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
            glNormal3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
            glVertex3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
        glEnd();
    }

    // part C - draw the bottom 'lid' (tris)
    glBegin(GL_TRIANGLE_FAN);
        glNormal3d(0,-1,0);
        glVertex3d(0,-radius,0);
        for (t=0; t<numSides-1; t++)
        {
            curX = points[numVerts-1-t].x;
            curY = points[numVerts-1-t].y;
            curZ = points[numVerts-1-t].z;
            glNormal3d(curX, curY, curZ);
            glVertex3d(curX, curY, curZ);
        }
            curX = points[numVerts-1].x;
            curY = points[numVerts-1].y;
            curZ = points[numVerts-1].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    glEnd();

}

#2


0  

In my rendering class I was taught to imagine a Sphere as a rounded grid. So first you take the implementation of a grid with dimension 1 in x and y, centered in the position (0,0,0) that will be subdivided by n-rows (rowMax) and m-columns (colMax):

在我的渲染类中,我被教导将球体想象成一个圆形网格。首先,你要在x和y中,以x和y为中心的一个网格的实现,它的中心位置(0,0,0)将被n行(rowMax)和m列(colMax)细分:

// Aux function
inline int index (int i, int j)
{
    return i + j*(m_colMax + 1);
}

float numCoords = 3*rowMax*colMax; // Array size

float *coordData = new float[numCoords]; // Array with coordinate positions

// Fill coordinate positions [to change]
for (int j = 0; j <= rowMax; j++) {
    for (int i = 0; i <= colMax; i++) {
        int k = index(i, j);
        coordData[k] = (float)i / m_colMax - (0.5f);
        coordData[k + 1] = (float)j / m_rowMax - (0.5f);
        coordData[k + 2] = 0;
    }
}

// Fill index
int k = 0;
GLuint *indexData = new GLuint[numCoords]; // Array with indexing data 
for (int j = 0; j < rowMax; j++) {
    for (int i = 0; i < colMax; i++) {
        indexData[k++] = index (i, j);
        indexData[k++] = index (i + 1, j + 1);
        indexData[k++] = index (i, j + 1);
        indexData[k++] = index (i, j);
        indexData[k++] = index (i + 1, j);
        indexData[k++] = index (i + 1, j + 1);          
    }
}

And with this data, remember to use DrawElements() and GL_TRIANGLES to take indexing into account (the second link has a clear image of this approach). Since you are new to OpenGL, this two links can summarize what you need to learn:

有了这些数据,请记住使用DrawElements()和gl_三角形来考虑索引(第二个链接对这个方法有一个清晰的图像)。由于你是OpenGL的新成员,这两个链接可以总结你需要学习的内容:

[1] Using OGL 2.1 without shaders: http://www.songho.ca/opengl/gl_vertexarray.html

[1]使用ogl2.1没有着色:http://www.songho.ca/opengl/gl_vertexarray.html。

[2] Using more advanced techniques (aka, OGL 3.3+ with Core/Compatibility Profile) http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/

[2]使用更先进的技术(aka, OGL 3.3+与核心/兼容性配置文件)http://www.opengl- tutories.org/mediatals/tutorial -9-vbo-indexing/。

Now, to do what you need, just change the code in the first for loop:

现在,为了满足您的需要,只需在第一个for循环中更改代码:

// Fill coordinate positions 
// Pi variable can be a define or declared somewhere in your code
float radius = 1.0f;
for (int j = 0; j <= rowMax; j++) {
    for (int i = 0; i <= colMax; i++) {
        int k = index(i, j);
        float teta = ((float)i / m_colMax) * 2 * (float)Pi;
        float fi = ((float)j / m_rowMax)*(float)Pi;
        coordData[k] = radius*(cos (teta))*(sin (fi));
        coordData[k + 1] = radius*(cos (fi));
        coordData[k + 2] = 1.0f*(sin (teta))*(sin (fi));
    }
}

And you will have your sphere coordinates with indexes. Use a for loop to draw it on the old pipeline of OpenGL (2.1 or Compatibility Profile) or setup your buffers (VAO, VBO) on the new pipeline of OpenGL (Core Profile).

你会得到你的球坐标和指数。使用for循环将其绘制在OpenGL(2.1或兼容性配置文件)的旧管道上,或者在OpenGL(核心配置文件)的新管道上设置缓冲(VAO, VBO)。

#1


0  

Here's some code I wrote a long, long time ago. I've drawn the areas immediately surrounding the poles with a triangle-fan and the remainder of the sphere with quad-strips. You could of course, use triangles instead of the quads, but since the pairs of triangles would still be planar, it wont look any different, unless I'm mistaken - it's been a long times since I touched anything GL.

这是我很久很久以前写的一些代码。我已经画出了周围的区域,用一个三角形扇子和其他的带四根的球体。当然,你可以用三角形代替四边形,但是因为三角形的对仍然是平面的,所以它看起来不会有任何不同,除非我弄错了——自从我接触了任何东西以来已经有很长一段时间了。

As molbdnilo points out, you'll get a better sphere by calculating your points in a different manner. If the intention is to texture-map the sphere, you'll get better results again if you subdivide and smooth a cube, since this avoids 'pinching' around the poles. Here's a good article that discusses this: http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm

正如molbdnilo所指出的,通过不同的方式计算你的点,你会得到一个更好的球体。如果你的意图是给球贴图,如果你细分和平滑一个立方体,你会得到更好的结果,因为这避免了在极点附近的“挤压”。这里有一篇很好的文章讨论了这个问题:http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm。

I should also point-out that there's a problem with the way that I either calculate the normals, or transform then when rotating - I used to get funky lighting results when looking at the sphere when it was rotated. (I think it's with the normals) Also, looking at the just code now, I'm not sure that I've computed the number of vertices required correctly - you'll have to double-check that.It appears as though I don't store verts for either of the poles in the array.

我还应该指出,我计算法线的方法有问题,或者当旋转时变换——当我看到旋转的球时,我经常会得到一些古怪的照明效果。(我认为是法线),看看现在的代码,我不确定我是否已经计算了所需的顶点数——你必须仔细检查一下。看起来好像我没有为数组中的任何一个极点存储一个。

EDIT: Here's a pic of the output:

编辑:这是输出的图片:

如何使用opengl, c++,而不是过剩/Glu来渲染球体[复制]

typedef struct {
    GLfloat x, y, z;
}vec3;

void myGlutBall(float radius, int numStacks, int numSides)
{
//    vec3 points[sides * (sides-1)];
    GLfloat curRadius, curTheta, curRho, deltaTheta, deltaRho, curX,curY,curZ;
    int curStack, curSlice, numVerts = (numStacks-1)*numSides;
    vec3 points[numVerts];
    int curVert = 0;
    int t;

    deltaTheta = (2*M_PI) / numSides;
    deltaRho = M_PI / numStacks;

        for (curStack=1; curStack<numStacks; curStack++)
        {
            curRho = (3.141/2.0) - curStack*deltaRho;
            curY = sin(curRho) * radius;
            curRadius = cos(curRho) * radius;
            for (curSlice=0; curSlice<numSides; curSlice++)
            {
                curTheta = curSlice * deltaTheta;
                curX = curRadius * cos(curTheta);
                curZ = -curRadius * sin(curTheta);
                points[curVert++] = vec3{curX,curY,curZ};
            }
        }

    // option 1 - points only
    /*
    glBegin(GL_POINTS);
    glNormal3d(0,1,0);
    glVertex3d(0,radius,0);
    for (t=0; t<numVerts; t++)
    {
        curX = points[t].x;
        curY = points[t].y;
        curZ = points[t].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    }
    glNormal3d(0,-1,0);
    glVertex3d(0,-radius,0);
    glEnd();
    */

    ///////////////////////////////
    // option 2 - solid
    ///////////////////////////////
    // part A - draw the top 'lid' (tris)
    glBegin(GL_TRIANGLE_FAN);
        glNormal3d(0,1,0);
        glVertex3d(0,radius,0);
        for (t=0; t<numSides; t++)
        {
            curX = points[t].x;
            curY = points[t].y;
            curZ = points[t].z;
            glNormal3d(curX, curY, curZ);
            glVertex3d(curX, curY, curZ);
        }
            curX = points[0].x;
            curY = points[0].y;
            curZ = points[0].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    glEnd();

    // part B - draw the 'sides' (quads)
    int vertIndex;
    for (curStack=0; curStack<numStacks-2; curStack++)
    {
        vertIndex = curStack * numSides;
        glBegin(GL_QUAD_STRIP);
            for (curSlice=0; curSlice<numSides; curSlice++)
            {
                glNormal3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);
                glVertex3d(points[vertIndex+curSlice].x, points[vertIndex+curSlice].y, points[vertIndex+curSlice].z);

                glNormal3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
                glVertex3d(points[vertIndex+numSides+curSlice].x, points[vertIndex+numSides+curSlice].y, points[vertIndex+numSides+curSlice].z);
            }
            glNormal3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
            glVertex3d(points[vertIndex].x, points[vertIndex].y, points[vertIndex].z);
            glNormal3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
            glVertex3d(points[vertIndex+numSides].x, points[vertIndex+numSides].y, points[vertIndex+numSides].z);
        glEnd();
    }

    // part C - draw the bottom 'lid' (tris)
    glBegin(GL_TRIANGLE_FAN);
        glNormal3d(0,-1,0);
        glVertex3d(0,-radius,0);
        for (t=0; t<numSides-1; t++)
        {
            curX = points[numVerts-1-t].x;
            curY = points[numVerts-1-t].y;
            curZ = points[numVerts-1-t].z;
            glNormal3d(curX, curY, curZ);
            glVertex3d(curX, curY, curZ);
        }
            curX = points[numVerts-1].x;
            curY = points[numVerts-1].y;
            curZ = points[numVerts-1].z;
        glNormal3d(curX, curY, curZ);
        glVertex3d(curX, curY, curZ);
    glEnd();

}

#2


0  

In my rendering class I was taught to imagine a Sphere as a rounded grid. So first you take the implementation of a grid with dimension 1 in x and y, centered in the position (0,0,0) that will be subdivided by n-rows (rowMax) and m-columns (colMax):

在我的渲染类中,我被教导将球体想象成一个圆形网格。首先,你要在x和y中,以x和y为中心的一个网格的实现,它的中心位置(0,0,0)将被n行(rowMax)和m列(colMax)细分:

// Aux function
inline int index (int i, int j)
{
    return i + j*(m_colMax + 1);
}

float numCoords = 3*rowMax*colMax; // Array size

float *coordData = new float[numCoords]; // Array with coordinate positions

// Fill coordinate positions [to change]
for (int j = 0; j <= rowMax; j++) {
    for (int i = 0; i <= colMax; i++) {
        int k = index(i, j);
        coordData[k] = (float)i / m_colMax - (0.5f);
        coordData[k + 1] = (float)j / m_rowMax - (0.5f);
        coordData[k + 2] = 0;
    }
}

// Fill index
int k = 0;
GLuint *indexData = new GLuint[numCoords]; // Array with indexing data 
for (int j = 0; j < rowMax; j++) {
    for (int i = 0; i < colMax; i++) {
        indexData[k++] = index (i, j);
        indexData[k++] = index (i + 1, j + 1);
        indexData[k++] = index (i, j + 1);
        indexData[k++] = index (i, j);
        indexData[k++] = index (i + 1, j);
        indexData[k++] = index (i + 1, j + 1);          
    }
}

And with this data, remember to use DrawElements() and GL_TRIANGLES to take indexing into account (the second link has a clear image of this approach). Since you are new to OpenGL, this two links can summarize what you need to learn:

有了这些数据,请记住使用DrawElements()和gl_三角形来考虑索引(第二个链接对这个方法有一个清晰的图像)。由于你是OpenGL的新成员,这两个链接可以总结你需要学习的内容:

[1] Using OGL 2.1 without shaders: http://www.songho.ca/opengl/gl_vertexarray.html

[1]使用ogl2.1没有着色:http://www.songho.ca/opengl/gl_vertexarray.html。

[2] Using more advanced techniques (aka, OGL 3.3+ with Core/Compatibility Profile) http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-9-vbo-indexing/

[2]使用更先进的技术(aka, OGL 3.3+与核心/兼容性配置文件)http://www.opengl- tutories.org/mediatals/tutorial -9-vbo-indexing/。

Now, to do what you need, just change the code in the first for loop:

现在,为了满足您的需要,只需在第一个for循环中更改代码:

// Fill coordinate positions 
// Pi variable can be a define or declared somewhere in your code
float radius = 1.0f;
for (int j = 0; j <= rowMax; j++) {
    for (int i = 0; i <= colMax; i++) {
        int k = index(i, j);
        float teta = ((float)i / m_colMax) * 2 * (float)Pi;
        float fi = ((float)j / m_rowMax)*(float)Pi;
        coordData[k] = radius*(cos (teta))*(sin (fi));
        coordData[k + 1] = radius*(cos (fi));
        coordData[k + 2] = 1.0f*(sin (teta))*(sin (fi));
    }
}

And you will have your sphere coordinates with indexes. Use a for loop to draw it on the old pipeline of OpenGL (2.1 or Compatibility Profile) or setup your buffers (VAO, VBO) on the new pipeline of OpenGL (Core Profile).

你会得到你的球坐标和指数。使用for循环将其绘制在OpenGL(2.1或兼容性配置文件)的旧管道上,或者在OpenGL(核心配置文件)的新管道上设置缓冲(VAO, VBO)。