Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a 3D sphere in Opengl using Visual C++

Tags:

c++

opengl

I am not able to create a simple 3D sphere using the OpenGL library function glutSolidSphere() in C++.

Here's what I tried:

#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();  } 
like image 706
Lloyd Avatar asked May 13 '11 07:05

Lloyd


2 Answers

In OpenGL you don't create objects, you just draw them. Once they are drawn, OpenGL no longer cares about what geometry you sent it.

glutSolidSphere is just sending drawing commands to OpenGL. However there's nothing special in and about it. And since it's tied to GLUT I'd not use it. Instead, if you really need some sphere in your code, how about create if for yourself?

#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; } 
like image 75
datenwolf Avatar answered Sep 20 '22 11:09

datenwolf


It doesn't seem like anyone so far has addressed the actual problem with your original code, so I thought I would do that even though the question is quite old at this point.

The problem originally had to do with the projection in relation to the radius and position of the sphere. I think you'll find that the problem isn't too complicated. The program actually works correctly, it's just that what is being drawn is very hard to see.

First, an orthogonal projection was created using the call

gluOrtho2D(0.0, 499.0, 0.0, 499.0); 

which "is equivalent to calling glOrtho with near = -1 and far = 1." This means that the viewing frustum has a depth of 2. So a sphere with a radius of anything greater than 1 (diameter = 2) will not fit entirely within the viewing frustum.

Then the calls

glLoadIdentity(); glutSolidSphere(5.0, 20.0, 20.0); 

are used, which loads the identity matrix of the model-view matrix and then "[r]enders a sphere centered at the modeling coordinates origin of the specified radius." Meaning, the sphere is rendered at the origin, (x, y, z) = (0, 0, 0), and with a radius of 5.

Now, the issue is three-fold:

  1. Since the window is 500x500 pixels and the width and height of the viewing frustum is almost 500 (499.0), the small radius of the sphere (5.0) makes its projected area only slightly over one fiftieth (2*5/499) of the size of the window in each dimension. This means that the apparent size of the sphere would be roughly 1/2,500th (actually pi*5^2/499^2, which is closer to about 1/3170th) of the entire window, so it might be difficult to see. This is assuming the entire circle is drawn within the area of the window. It is not, however, as we will see in point 2.
  2. Since the viewing frustum has it's left plane at x = 0 and bottom plane at y = 0, the sphere will be rendered with its geometric center in the very bottom left corner of the window so that only one quadrant of the projected sphere will be visible! This means that what would be seen is even smaller, about 1/10,000th (actually pi*5^2/(4*499^2), which is closer to 1/12,682nd) of the window size. This would make it even more difficult to see. Especially since the sphere is rendered so close to the edges/corner of the screen where you might not think to look.
  3. Since the depth of the viewing frustum is significantly smaller than the diameter of the sphere (less than half), only a sliver of the sphere will be within the viewing frustum, rendering only that part. So you will get more like a hollow circle on the screen than a solid sphere/circle. As it happens, the thickness of that sliver might represent less than 1 pixel on the screen which means we might even see nothing on the screen, even if part of the sphere is indeed within the viewing frustum.

The solution is simply to change the viewing frustum and radius of the sphere. For instance,

gluOrtho2D(-5.0, 5.0, -5.0, 5.0); glutSolidSphere(5.0, 20, 20); 

renders the following image.

r = 5.0

As you can see, only a small part is visible around the "equator", of the sphere with a radius of 5. (I changed the projection to fill the window with the sphere.) Another example,

gluOrtho2D(-1.1, 1.1, -1.1, 1.1); glutSolidSphere(1.1, 20, 20); 

renders the following image.

r = 1.1

The image above shows more of the sphere inside of the viewing frustum, but still the sphere is 0.2 depth units larger than the viewing frustum. As you can see, the "ice caps" of the sphere are missing, both the north and the south. So, if we want the entire sphere to fit within the viewing frustum which has depth 2, we must make the radius less than or equal to 1.

gluOrtho2D(-1.0, 1.0, -1.0, 1.0); glutSolidSphere(1.0, 20, 20); 

renders the following image.

r = 1.0

I hope this has helped someone. Take care!

like image 22
Victor Zamanian Avatar answered Sep 18 '22 11:09

Victor Zamanian