Creating a 3D sphere in Opengl using Visual C++
我无法使用C ++中的OpenGL库函数glutSolidSphere()创建简单的3D球体。
这是我尝试过的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include<GL/glu.h> void display() { glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,0.0,0.0); glLoadIdentity(); glutSolidSphere( 5.0, 20.0, 20.0); glFlush(); } void myInit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); glMatrixMode(GL_MODELVIEW); } void main(int argc,char **argv) { qobj = gluNewQuadric(); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutCreateWindow("pendulum"); glutDisplayFunc(display); myInit(); glutMainLoop(); } |
在OpenGL中,您无需创建对象,只需绘制它们即可。 绘制之后,OpenGL将不再关心您发送的几何图形。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #define _USE_MATH_DEFINES #include <GL/gl.h> #include <GL/glu.h> #include <vector> #include <cmath> // your framework of choice here class SolidSphere { protected: std::vector<GLfloat> vertices; std::vector<GLfloat> normals; std::vector<GLfloat> texcoords; std::vector<GLushort> indices; public: SolidSphere(float radius, unsigned int rings, unsigned int sectors) { float const R = 1./(float)(rings-1); float const S = 1./(float)(sectors-1); int r, s; vertices.resize(rings * sectors * 3); normals.resize(rings * sectors * 3); texcoords.resize(rings * sectors * 2); std::vector<GLfloat>::iterator v = vertices.begin(); std::vector<GLfloat>::iterator n = normals.begin(); std::vector<GLfloat>::iterator t = texcoords.begin(); for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { float const y = sin( -M_PI_2 + M_PI * r * R ); float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R ); float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R ); *t++ = s*S; *t++ = r*R; *v++ = x * radius; *v++ = y * radius; *v++ = z * radius; *n++ = x; *n++ = y; *n++ = z; } indices.resize(rings * sectors * 4); std::vector<GLushort>::iterator i = indices.begin(); for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { *i++ = r * sectors + s; *i++ = r * sectors + (s+1); *i++ = (r+1) * sectors + (s+1); *i++ = (r+1) * sectors + s; } } void draw(GLfloat x, GLfloat y, GLfloat z) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(x,y,z); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 0, &vertices[0]); glNormalPointer(GL_FLOAT, 0, &normals[0]); glTexCoordPointer(2, GL_FLOAT, 0, &texcoords[0]); glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, &indices[0]); glPopMatrix(); } }; SolidSphere sphere(1, 12, 24); void display() { int const win_width = …; // retrieve window dimensions from int const win_height = …; // framework of choice here float const win_aspect = (float)win_width / (float)win_height; glViewport(0, 0, win_width, win_height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, win_aspect, 1, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); #ifdef DRAW_WIREFRAME glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif sphere.draw(0, 0, -5); swapBuffers(); } int main(int argc, char *argv[]) { // initialize and register your framework of choice here return 0; } |
到目前为止,似乎还没有人解决您的原始代码中的实际问题,所以即使现在这个问题已经很久了,我也想这样做。
该问题最初与与球体的半径和位置有关的投影有关。我认为您会发现问题并不太复杂。该程序实际上可以正常运行,只是所绘制的内容很难看到。
首先,使用调用创建了正交投影
1 | gluOrtho2D(0.0, 499.0, 0.0, 499.0); |
这"相当于用近= -1和远= 1调用glOrtho"。这意味着观察视锥的深度为2。因此,半径大于1(直径= 2)的球体将无法完全容纳在视锥中。
然后打电话
1 2 | glLoadIdentity(); glutSolidSphere(5.0, 20.0, 20.0); |
使用加载模型视图矩阵的单位矩阵,然后"渲染以指定半径的建模坐标原点为中心的球"。意思是,球体是在原点(x,y,z)=(0,0,0)处渲染的,半径为5。
现在,问题是三个方面:
解决方案只是更改视角的视锥和球体的半径。例如,
1 2 | gluOrtho2D(-5.0, 5.0, -5.0, 5.0); glutSolidSphere(5.0, 20, 20); |
呈现以下图像。
如您所见,半径为5的球的"赤道"周围只有一小部分可见。(我更改了投影以将球填充到窗口中。)另一个示例,
1 2 | gluOrtho2D(-1.1, 1.1, -1.1, 1.1); glutSolidSphere(1.1, 20, 20); |
呈现以下图像。
上图显示了视锥内部的更多球体,但该球仍比视锥中大0.2个深度单位。如您所见,球体的"冰盖"不见了,无论是北部还是南部。因此,如果我们希望整个球体都适合于深度为2的视锥中,则必须使半径小于或等于1。
1 2 | gluOrtho2D(-1.0, 1.0, -1.0, 1.0); glutSolidSphere(1.0, 20, 20); |
呈现以下图像。
我希望这对某人有所帮助。照顾自己!
我不知道datenwolf的索引生成如何正确。 但我仍然发现他的解决方案相当明确。 这是我经过一番思考后得到的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) { int curRow = r * sectors; int nextRow = (r+1) * sectors; indices.push_back(curRow + s); indices.push_back(nextRow + s); indices.push_back(nextRow + (s+1)); indices.push_back(curRow + s); indices.push_back(nextRow + (s+1)); indices.push_back(curRow + (s+1)); } void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords, float radius, unsigned int rings, unsigned int sectors) { float const R = 1./(float)(rings-1); float const S = 1./(float)(sectors-1); for(int r = 0; r < rings; ++r) { for(int s = 0; s < sectors; ++s) { float const y = sin( -M_PI_2 + M_PI * r * R ); float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R ); float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R ); texcoords.push_back(vec2(s*S, r*R)); vertices.push_back(vec3(x,y,z) * radius); push_indices(indices, sectors, r, s); } } } |
我喜欢硬币的答案。 这很容易理解,并且可以使用三角形。 但是,他的程序的索引有时会超出范围。 因此,我在这里发布了他的代码,做了两个小小的更正:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | inline void push_indices(vector<GLushort>& indices, int sectors, int r, int s) { int curRow = r * sectors; int nextRow = (r+1) * sectors; int nextS = (s+1) % sectors; indices.push_back(curRow + s); indices.push_back(nextRow + s); indices.push_back(nextRow + nextS); indices.push_back(curRow + s); indices.push_back(nextRow + nextS); indices.push_back(curRow + nextS); } void createSphere(vector<vec3>& vertices, vector<GLushort>& indices, vector<vec2>& texcoords, float radius, unsigned int rings, unsigned int sectors) { float const R = 1./(float)(rings-1); float const S = 1./(float)(sectors-1); for(int r = 0; r < rings; ++r) { for(int s = 0; s < sectors; ++s) { float const y = sin( -M_PI_2 + M_PI * r * R ); float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R ); float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R ); texcoords.push_back(vec2(s*S, r*R)); vertices.push_back(vec3(x,y,z) * radius); if(r < rings-1) push_indices(indices, sectors, r, s); } } } |
Datanewolf的代码几乎是正确的。 我必须扭转绕组和法线,以使其在固定管道上正常工作。 以下内容对我来说启用或禁用cull都可以正常工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | std::vector<GLfloat> vertices; std::vector<GLfloat> normals; std::vector<GLfloat> texcoords; std::vector<GLushort> indices; float const R = 1./(float)(rings-1); float const S = 1./(float)(sectors-1); int r, s; vertices.resize(rings * sectors * 3); normals.resize(rings * sectors * 3); texcoords.resize(rings * sectors * 2); std::vector<GLfloat>::iterator v = vertices.begin(); std::vector<GLfloat>::iterator n = normals.begin(); std::vector<GLfloat>::iterator t = texcoords.begin(); for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) { float const y = sin( -M_PI_2 + M_PI * r * R ); float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R ); float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R ); *t++ = s*S; *t++ = r*R; *v++ = x * radius; *v++ = y * radius; *v++ = z * radius; *n++ = -x; *n++ = -y; *n++ = -z; } indices.resize(rings * sectors * 4); std::vector<GLushort>::iterator i = indices.begin(); for(r = 0; r < rings-1; r++) for(s = 0; s < sectors-1; s++) { /* *i++ = r * sectors + s; *i++ = r * sectors + (s+1); *i++ = (r+1) * sectors + (s+1); *i++ = (r+1) * sectors + s; */ *i++ = (r+1) * sectors + s; *i++ = (r+1) * sectors + (s+1); *i++ = r * sectors + (s+1); *i++ = r * sectors + s; } |
编辑:关于如何绘制此问题...在我的代码中,我将这些值封装在G3DModel类中。 这是我的代码来设置框架,绘制模型并结束它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | void GraphicsProvider3DPriv::BeginFrame()const{ int win_width; int win_height;// framework of choice here glfwGetWindowSize(window, &win_width, &win_height); // retrieve window float const win_aspect = (float)win_width / (float)win_height; // set lighting glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); GLfloat lightpos[] = {0, 0.0, 0, 0.}; glLightfv(GL_LIGHT0, GL_POSITION, lightpos); GLfloat lmodel_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); // set up world transform glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT|GL_ACCUM_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45, win_aspect, 1, 10); glMatrixMode(GL_MODELVIEW); } void GraphicsProvider3DPriv::DrawModel(const G3DModel* model, const Transform3D transform)const{ G3DModelPriv* privModel = (G3DModelPriv *)model; glPushMatrix(); glLoadMatrixf(transform.GetOGLData()); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(3, GL_FLOAT, 0, &privModel->vertices[0]); glNormalPointer(GL_FLOAT, 0, &privModel->normals[0]); glTexCoordPointer(2, GL_FLOAT, 0, &privModel->texcoords[0]); glEnable(GL_TEXTURE_2D); //glFrontFace(GL_CCW); glEnable(GL_CULL_FACE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, privModel->texname); glDrawElements(GL_QUADS, privModel->indices.size(), GL_UNSIGNED_SHORT, &privModel->indices[0]); glPopMatrix(); glDisable(GL_TEXTURE_2D); } void GraphicsProvider3DPriv::EndFrame()const{ /* Swap front and back buffers */ glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glDisable(GL_CULL_FACE); glfwSwapBuffers(window); /* Poll for and process events */ glfwPollEvents(); } |
这是代码:
1 2 3 4 5 6 | glPushMatrix(); glTranslatef(18,2,0); glRotatef(angle, 0, 0, 0.7); glColor3ub(0,255,255); glutWireSphere(3,10,10); glPopMatrix(); |