用 Opengl 画一个球体

Posted

技术标签:

【中文标题】用 Opengl 画一个球体【英文标题】:Draw A Sphere With Opengl 【发布时间】:2012-01-22 05:59:23 【问题描述】:

我通过 OpenGL 绘制球体。 该程序可以在“SLIED = STACK”时绘制球体。 但是当“SLIED not equal STACK”时它不起作用。 我可能弄错了“索引数组”。

我想使用 VBO 和 DMA(动态内存分配。使用平面数组)。 但如果你有其他好主意,请教我。

            //#pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
            #pragma comment(lib,"glew32.lib")

            #include <gl/glew.h>
            #include <math.h>
            #include <GL/freeglut/freeglut.h>
            #define WIDTH 640
            #define HEIGHT 480
            #define M_PI 3.14159265358979323846

            float angle=0.0f;

            //functions----------------------------------------------//
            void Shere_dma(double radius, int nSlice, int nStack);
            void setSphereData(double radius, int nSlice, int nStack);
            void DrawSphereVBO(void);
            //-------------------------------------------------------//

            //variabless---------------------------------------------//
            int SLICE=0;
            int STACK=0;

            GLuint SVboId[3];
            GLfloat* Svertex;//Vertex
            GLfloat* Snormal;//Normal
            GLfloat* Scolor; //Color

            GLuint* indices_top;    //TOP indices
            GLuint* indices_bottom; //BOTTOM indies
            GLuint* indices_side;   //SIDE indices
            //-------------------------------------------------------//

            //Memory Allocate
            void Shere_dma(double radius, int nSlice, int nStack)
                Svertex = new GLfloat[(nSlice+1)*(nStack+1)*3];
                Snormal = new GLfloat[(nSlice+1)*(nStack+1)*3];
                Scolor = new GLfloat[(nSlice+1)*(nStack+1)*3];

                indices_top = new GLuint[(nSlice+1)*(nStack+1)*3];
                indices_bottom = new GLuint[(nSlice+1)*(nStack+1)*3];
                indices_side = new GLuint[(nSlice+1)*(nStack+1)*4];
            
            //inputData
            void setSphereData(double radius, int nSlice, int nStack)
                double phi; //Azimuth
                double theta; //long

                int coordinates=0;
                int Slice_current_point_no=0;
                int Slice_next_point_no=0;

                const int x = 0;
                const int y = 1;
                const int z = 2;

                const int p1 = 0;
                const int p2 = 1;
                const int p3 = 2;
                const int p4 = 3;

                //Vertex
                for(int i = 0;i <= nSlice;i++)
                   
                    phi = 2.0 * M_PI * (double)i / (double)nSlice;
                    for(int j = 0;j <= nStack;j++)
                       
                        theta = M_PI * (double)j / (double)nStack;
                        Svertex[coordinates+x] = (float)(radius * sin(theta) * cos(phi));   //x
                        Svertex[coordinates+y] = (float)(radius * sin(theta) * sin(phi));   //y
                        Svertex[coordinates+z] = (float)(radius * cos(theta));              //z

                        Snormal[coordinates+x] = (float)(radius * sin(theta) * cos(phi));   //x
                        Snormal[coordinates+y] = (float)(radius * sin(theta) * sin(phi));   //y
                        Snormal[coordinates+z] = (float)(radius * cos(theta));              //z

                        Scolor[coordinates+x] = 1.0;                                            //x
                        Scolor[coordinates+y] = 0.0;                                            //y
                        Scolor[coordinates+z] = 0.0;                                            //z

                        coordinates += 3;           
                    
                

                //TOP
                coordinates = 0;
                Slice_current_point_no = 0;
                Slice_next_point_no    = nSlice;

                for(int i = 0; i < nSlice; i++)

                    indices_top[coordinates+p1] = Slice_current_point_no;
                    indices_top[coordinates+p2] = indices_top[coordinates]+1;
                    indices_top[coordinates+p3] = Slice_next_point_no+2;

                    coordinates+=3;
                    Slice_current_point_no += nSlice+1;
                    Slice_next_point_no    += nSlice+1;
                

                //BOTTOM
                coordinates =0;
                Slice_current_point_no  = 0;
                Slice_next_point_no     = nSlice;

                for(int i = 0; i < nSlice; i++)

                    indices_bottom[coordinates+p1] = Slice_current_point_no+(nStack-1);
                    indices_bottom[coordinates+p2] = indices_bottom[coordinates]+1;
                    indices_bottom[coordinates+p3] = Slice_next_point_no+(nStack);

                    coordinates+=3;
                    Slice_current_point_no += nSlice+1;
                    Slice_next_point_no    += nSlice+1;
                
                //↓May be wrong ********************************************************************************//
                //SIDE
                coordinates=0;
                Slice_current_point_no = 0;
                Slice_next_point_no    = nSlice+1;

                for(int i=0; i < nSlice;i++)
                    for(int j=1; j < nStack-1; j++)
                        indices_side[coordinates+p1]    = Slice_current_point_no+j;
                        indices_side[coordinates+p2] = indices_side[coordinates]+1;
                        indices_side[coordinates+p3] = Slice_next_point_no+(j+1);
                        indices_side[coordinates+p4] = Slice_next_point_no+j;
                        coordinates+=4;
                    
                       Slice_current_point_no += nSlice+1;
                       Slice_next_point_no    += nSlice+1;
                
                //↑May be wrong ********************************************************************************//
                 glGenBuffers(3,&SVboId[0]);

                 //Vertex
                 glBindBuffer(GL_ARRAY_BUFFER,SVboId[0]);
                 glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*(nSlice+1)*(nStack+1)*3,
                    Svertex,GL_DYNAMIC_DRAW);

                 //Normal
                 glBindBuffer(GL_ARRAY_BUFFER,SVboId[1]);
                 glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*(nSlice+1)*(nStack+1)*3,
                    Snormal,GL_DYNAMIC_DRAW);

                 //Color
                 glBindBuffer(GL_ARRAY_BUFFER,SVboId[2]);
                 glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*(nSlice+1)*(nStack+1)*3,
                     Scolor,GL_STREAM_DRAW);

            

            //Draw
            void DrawSphereVBO(void)
            
                int point=0;

                //Enable
                glEnableClientState(GL_VERTEX_ARRAY);
                glEnableClientState(GL_NORMAL_ARRAY);
                glEnableClientState(GL_COLOR_ARRAY);

                //Vertex
                glBindBuffer(GL_ARRAY_BUFFER,SVboId[0]);
                glVertexPointer(3, GL_FLOAT, 0, 0);

                //Normal
                glBindBuffer(GL_ARRAY_BUFFER,SVboId[1]);
                glNormalPointer(GL_FLOAT, 0, 0);

                //Color
                glBindBuffer(GL_ARRAY_BUFFER,SVboId[2]);
                glColorPointer(3,GL_FLOAT, 0, 0);

                //---------------------------------Draw---------------------------------------------------//

                //TOP
                for(int i=0; i<SLICE;i++)
                    glDrawRangeElements(GL_TRIANGLES, point, point+2, 3, GL_UNSIGNED_INT, indices_top+i*3);
                    point+=3;
                

                //BOTTOM
                point=0;
                for(int i=0; i<SLICE;i++)
                    glDrawRangeElements(GL_TRIANGLES, point, point+2, 3, GL_UNSIGNED_INT, indices_bottom+i*3);
                    point+=3;
                


                //↓May be wrong ********************************************************************************//
                //SIDE  
                point=0;
                for(int i=0; i< (SLICE*(STACK-2));i++)
                    glDrawRangeElements(GL_QUADS, point, point+3, 4, GL_UNSIGNED_INT, indices_side+i*4);
                    point+=4;
                
                //↑May be wrong ********************************************************************************//

                //---------------------------------Draw---------------------------------------------------//

                //Disable
                glDisableClientState(GL_COLOR_ARRAY);
                glDisableClientState(GL_NORMAL_ARRAY);
                glDisableClientState(GL_VERTEX_ARRAY);

            

            void display(void)
            
             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
             glViewport(0,0,WIDTH,HEIGHT);
             glMatrixMode(GL_PROJECTION);
             glLoadIdentity();
             gluPerspective(30.0, (double)WIDTH / (double)HEIGHT, 1.0, 1000.0);
             glMatrixMode(GL_MODELVIEW);
             glLoadIdentity();
             gluLookAt(5.0, 5.0,5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

             glRotatef(angle,0.0f,1.0f,0.0f);

             DrawSphereVBO();

             glutSwapBuffers();
            
            void idle(void)
            
             glutPostRedisplay();
             angle+=0.2f;
            
            void Init()
             glewInit();
             glClearColor(1.0, 1.0, 1.0, 1.0);
             glEnable(GL_DEPTH_TEST);
             glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
             glEnable(GL_COLOR_MATERIAL);
             glEnable(GL_LIGHT0);
             glEnable(GL_LIGHTING);
             glEnable(GL_NORMALIZE);


             SLICE = 5;
             STACK = 5;
             Shere_dma(1,SLICE,STACK);      //MemoryAllocate
             setSphereData(1,SLICE,STACK);  //InputData

            

            int main(int argc, char *argv[])
            
             glutInitWindowPosition(100, 100);
             glutInitWindowSize(WIDTH, HEIGHT);
             glutInit(&argc, argv);
             glutCreateWindow("VBO");
             glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
             glutDisplayFunc(display);
             glutIdleFunc(idle);
             Init();
             glutMainLoop();
             return 0;
            

我参考了这段代码。

        void drawSphere(double radius, int nSlice, int nStack)
        
            int i, j;
            double phi; //
            double theta; //long
            float p[31][31][3]; //Vertex
            float *p1,*p2,*p3,*p4;

            if(nSlice > 30) nSlice = 30;
            if(nStack > 30) nStack = 30;

            //Vertex
            for(i = 0;i <= nSlice;i++)
               
                phi = 2.0 * M_PI * (double)i / (double)nSlice;
                for(j = 0;j <= nStack;j++)
                   
                    theta = M_PI * (double)j / (double)nStack;
                    p[i][j][0] = (float)(radius * sin(theta) * cos(phi));//x
                    p[i][j][1] = (float)(radius * sin(theta) * sin(phi));//y
                    p[i][j][2] = (float)(radius * cos(theta));           //z
                
            

            //Top(j=0)
            for(i = 0;i < nSlice; i++)
            
                p1 = p[i][0];     p2 = p[i][1];
                p3 = p[i+1][1]; 
                glBegin(GL_TRIANGLES);
                    glNormal3fv(p1); glVertex3fv(p1);
                    glNormal3fv(p2); glVertex3fv(p2);
                    glNormal3fv(p3); glVertex3fv(p3);
                glEnd();
            
            //Bottom
            j=nStack-1;
            for(i = 0;i < nSlice; i++)
            
                p1 = p[i][j];     p2 = p[i][j+1];
                p3 = p[i+1][j]; 
                glBegin(GL_TRIANGLES);
                    glNormal3fv(p1); glVertex3fv(p1);
                    glNormal3fv(p2); glVertex3fv(p2);
                    glNormal3fv(p3); glVertex3fv(p3);
                glEnd();
            

            for(i = 0;i < nSlice;i++)
                for(j = 1;j < nStack-1; j++)
                
                    p1 = p[i][j];     p2 = p[i][j+1];
                    p3 = p[i+1][j+1]; p4 = p[i+1][j];
                    glBegin(GL_QUADS);
                        glNormal3fv(p1); glVertex3fv(p1);
                        glNormal3fv(p2); glVertex3fv(p2);
                        glNormal3fv(p3); glVertex3fv(p3);
                        glNormal3fv(p4); glVertex3fv(p4);
                    glEnd();
                
            
        

【问题讨论】:

【参考方案1】:

我写了一个关于生成球体网格的教程——它没有附带源代码,但描述了这个过程并引导您解决您将遇到的问题。您可以在以下位置找到教程:http://sol.gfxile.net/sphere/index.html

【讨论】:

【参考方案2】:

我建议使用两个角度 phi(高度)和 theta(周围)或使用球体方程来使用球坐标:

x2 + y2 + z2 = r2
您是否将其中一个值保持不变并在稍后替换第二个值以找到第三个值时递增。

【讨论】:

以上是关于用 Opengl 画一个球体的主要内容,如果未能解决你的问题,请参考以下文章

在OpenGL中绘制一个相机对齐的圆

OpenGL:球体减慢帧速率

在 C++ 中的 OpenGL 中将坐标从 3D 透视投影映射到 2D 正交投影

PyQtGraph & OpenGL:如何在两个坐标之间创建一个球体?

OpenGL/C++ 3D 球体

如何使用 OpenGL 创建一个或多个球体?