用 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 画一个球体的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ 中的 OpenGL 中将坐标从 3D 透视投影映射到 2D 正交投影