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(); 
}
1 upvote
  flag
Be more specific. What have you tried? – Kiril Kirov
1 upvote
  flag
Please show the code that doesn't work. – Jackson Pope
upvote
  flag
@Kiril:I wanted to know how can i implement a 3D sphere for my mini project ,which is a pendulum, in opengl..am using visual c++. – Lloyd
1 upvote
  flag
#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(); } – Lloyd
1 upvote
  flag
@Lloyd - I've added the code to the original question, you should do that in future... there is a little "edit" button at the bottom. – Dennis
upvote
  flag
@Dennis:Thanks..Wil do so the next time fr sure.!! – Lloyd
upvote
  flag

6 Answers 11

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-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;
        }
    }

    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;
}
upvote
  flag
Excellent stuff - do you have code to generate the texture co-ords as well? – trojanfoe
upvote
  flag
@trojanfoe: Depends on what kind of mapping you're interested. Spheres have two poles, at which it's difficult to supply proper texture coordinates. But a good choice is simply using the spherical coordinates, mapped to ST. See my edit. – datenwolf
upvote
  flag
@datenwolf: Many thanks. I like your approach; for me this would form part of a Model class where vertices, normals, etc are attributes and solidSphere() would be one of many methods used to generate the geometry which is later drawn using draw(). – trojanfoe
upvote
  flag
@trojanfoe: I'd make this two classes: Model and Mesh. And instead of having a Sphere class implement generator functions, that create the desired mesh. Because after the mesh is created it's just a mesh. Model could consists of a number of meshes. – datenwolf
1 upvote
  flag
@datenwolf: Ok, I'll look into that. I have implemented the code above (I assume the glDrawElement() call should be using GL_UNSIGNED_INT given the vector stores GLuints) but it's just generating the lower quarter of the sphere and also backface culling is culling the outside of the sphere, unless I use glFrontFace(GL_CW) to change the winding. Can you help with these problems? Sorry to be a pain - I know what it's like to try and help and then be burdened with support requests :-/ – trojanfoe
upvote
  flag
@trojanfoe: Yes, I copied that code from another example, and missed that. However I suggest you change the datatype from GLuint to GLushort, as current GPUs perform best with unsigned short indices. – datenwolf
1 upvote
  flag
@datenwolf: OK, will do - and the issue with the rendering? Are you sure the indices are being populated correctly? – trojanfoe
upvote
  flag
@datenwolf: For example the index population code uses the same r/s loop values as the vertices, normals, tex-coord, so couldn't it be moved into that loop? But each index is supposed to represent a single 3-float vertex, so shouldn't there be something like 1/4 or 1/3 the number of indices as there are vertices? – trojanfoe
upvote
  flag
@trojanfoe: Yes, the looping variables are the same, so in theory they could be merged. However I didn't to be more cache friendly. The index array generation utilizes different registers and has a different access mode; the loop itself comes almost for free, cache locality is much more important. Also take a look on the sizing of vertex arrays and index array: Each ring/sector segment has 4 vertices, so the index array size is rings * sectors * 4, whereas the vertex array is created between the faces; only because a sphere has cyclic coordinates the loops look identical. – datenwolf
upvote
  flag
Excellent answer. – Alon Amir
upvote
  flag
Drawing this code with GL_TRIANGLE_STRIP brings ugly results.Seems like the indices gen is wrong. – Michael IV
upvote
  flag
@MichaelIV: Triangle Strips require an entirely different index order than quads. No wonder the sphere looks odd if used with something different than GL_QUADS – datenwolf
upvote
  flag
Thanks for the headups. Yes I changed to TRIANGLES and it worked with some minor modifications :) – Michael IV
upvote
  flag
Tried to implement this and ran into problems. See the following question for details. An edit may be in place for this question. – toeplitz
upvote
  flag
@toeplitz: Thanks for the heads up. I'll see into it. – datenwolf
2 upvote
  flag
@toeplitz: Okay, I fixed all the issues. – datenwolf
upvote
  flag
I like your use of the const modifier after the type. You don't see that often enough. :-) – Victor Zamanian
upvote
  flag
@datenwolf I tried to check your page for a contact info, but I couldn't find anything. Maybe this will work. I have a Q (see my prof). Tried to implement your A in OSG, but I failed at it (quite hard). Do you have any experience with OSG? Ps.: Your domain will expire in 04 January. – Shiki
upvote
  flag
@Shiki: I've marked your question and await your posting of a code snippet to work with. – datenwolf
upvote
  flag
It would be good to have the fixed code posted, please. As posted when rotated around the Y axis, the tetxure appears to revolve the opposite direction... which suggests Im seeing back faces. Ive been playing with this and found it works as expected IF I reverse the normals AND set the cull to CCW. Feel like a winding problem but Im unsure how to fix that in your code... – user430788
upvote
  flag
Okay, if i reverse the normals and the winding it works correctly culled and unculled. Fixed code below: – user430788
upvote
  flag
hey, what is M_PI ? =) – Volodymyr Balytskyy
upvote
  flag
@RareFever: M_PI is a pi number ~ 3.14159, M_PI_2 is a half of it. – tepl
upvote
  flag
excuse me for a noobish question, but how do I render the display function on the screen? So far I have this: pastebin.com/cXugwcYg – Mark
upvote
  flag
@Mark: The code I gave in the StackOverflow answer uses old style OpenGL-1.1 client side vertex arrays. Your program stub uses shaders and server side vertex attribute arrays. These are very similar, but you'll have to port my sphere generation code for use with shaders first. Otherwise you'll not see anything usefull. – datenwolf
upvote
  flag
@datenwolf could you please point me in the right direction, so I don't get even more lost? Thank you! – Mark

I don't understand how can datenwolf`s index generation can be correct. But still I find his solution rather clear. This is what I get after some thinking:

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);
        }
    }
}
upvote
  flag
You should indicate that this answer does not uses glutSolidSphere as the question called for it. – Tibo
upvote
  flag
:) you a right. I just found this question seeking for a manual generation method WITHOUT glutSolidSphere... – coin
upvote
  flag
btw datenwolf`s index generation appears to be correct. But I did't know about ogl capability to draw a square instead of triangle. I'm noob in this. – coin
upvote
  flag
Is this version better for buffer object creation to have higher speed of drawing while elliminating pci-e actions? – huseyin tugrul buyukisik
upvote
  flag
one quesiton from a java developer: what is M_PI_2 ?? – T_01
upvote
  flag
ou just found it. its a half of pi. but why you need it here? – T_01
upvote
  flag
but... could someone explain how to implement this with indexed drawing now?? thank you! – T_01
upvote
  flag
What do you mean by indexed drawing? The above is a indexed polygon. If you mean in immediate draw mode, then just loop through the resulting arrays and set the coords. – user430788

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!

3 upvote
  flag
This should be the accepted answer for the actual question by the OP. – legends2k
upvote
  flag
Thank you for that feedback, @legends2k. I added some more detail regarding the exact proportions of projected area that makes the circle very difficult to see when it is being drawn in the corner of the window. This in order to more clearly explain where I am getting my numbers and why the circle isn't being shown even though it is being drawn. – Victor Zamanian

Here's the code:

glPushMatrix();
glTranslatef(18,2,0);
glRotatef(angle, 0, 0, 0.7);
glColor3ub(0,255,255);
glutWireSphere(3,10,10);
glPopMatrix();
13 upvote
  flag
It's always nice if you leave some words describing your code. – smerny

Datanewolf's code is ALMOST right. I had to reverse both the winding and the normals to make it work properly with the fixed pipeline. The below works correctly with cull on or off for me:

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;

}

Edit: There was a question on how to draw this... in my code I encapsulate these values in a G3DModel class. This is my code to setup the frame, draw the model, and end it:

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();
    }
upvote
  flag
Your normals end up pointing in the opposite direction like this - are you sure you aren't seeing your sphere inside out? – darklon

I like the answer of coin. It's simple to understand and works with triangles. However the indexes of his program are sometimes over the bounds. So I post here his code with two tiny corrections:

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);
        }
    }
}
upvote
  flag
@coin Thank you for your Code! Helped me much :) – Harald

Not the answer you're looking for? Browse other questions tagged or ask your own question.