I am attempting to render a sphere in OpenGL. Unfortunately, the screen always comes up with only the background. I've tried reorienting the camera to no avail (although I may be doing it wrong). Any insight would be appreciated.
Here is the function OpenGL calls to update the screen:
//The draw function - I have confirmed that this is called periodically.
void draw()
{
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, (globals.wireframe == true) ? GL_LINE : GL_FILL);
glViewport(0, 0, globals.window_size.x, globals.window_size.y);
mat4 prj = perspective(globals.fov, float(globals.window_size.x) / float(globals.window_size.y), globals.hither, globals.yon);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(value_ptr(prj));
glMatrixMode(GL_MODELVIEW);
mat4 context = mat4(1.0f);
globals.ship.draw(context); //the ship only draws a sphere for now
mat4 mv = lookAt(vec3(0.0f, 0.0f, -5.5f), vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
glLoadMatrixf(value_ptr(mv));
glutSwapBuffers();
}
And the definition of Ship:
GLuint Ship::sphere_handle; //static
bool Ship::is_initialized; //static
mat4 Ship::draw(mat4 context) const {
glLoadMatrixf(value_ptr(context));
glCallList(sphere_handle);
return context;
}
//called when program starts, after window created
bool Ship::initialize() {
if (sphere_handle == BAD_GL_VALUE)
{
GLUquadric *q = gluNewQuadric();
if (q != NULL)
{
if ((sphere_handle = glGenLists(1)) == 0)
{
cout << "Model::Initialize() - Failed to GenLists()" << endl;
return false;
}
glNewList(sphere_handle, GL_COMPILE);
gluSphere(q, 1.0, 10, 10);
glEndList();
gluDeleteQuadric(q);
is_initialized = true;
}
else
{
return false;
}
}
return true;
}
The main problem lies here:
glMatrixMode(GL_MODELVIEW);
mat4 context = mat4(1.0f);
globals.ship.draw(context); //the ship only draws a sphere for now
mat4 mv = lookAt(vec3(0.0f, 0.0f, -5.5f), vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
glLoadMatrixf(value_ptr(mv));
OpenGL is a state based drawing API, not a scene graph. When you draw something, OpenGL takes the current state (matrices, etc.) and uses those to put points, lines, or triangles to the screen. In the above code, you're drawing the ship before you bother to calculate a view transform.
Add to that that glLoadMatrix simply replaces whatever is on the matrix stack right now. So when you load several transformations in succession, they won't compound. It's actually great that you try to not rely on the OpenGL matrix math functions (they've been deprecated and removed from later versions of OpenGL). So how to change this? You must create a compound modelview matrix. So replace the above with this:
mat4 view = lookAt(
vec3(0.0f, 0.0f, -5.5f),
vec3(0.0f, 0.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f));
globals.ship.draw(view);
Moment, where'd the matrix mode and matrix load go? Away, we don't need them here. But you must slightly adjust your ship drawing code.
void Ship::draw(mat4 view) const {
/* transform depending on your ships location and orientation */
mat4 model = …;
/* order of operations matters. OpenGL uses column major indexing
* hence matrix multiplication is right associative, i.e. column
* vectors (like vertex positions) enter on the right and "go"
* through the compound toward the left.
* Since model is the first transformation to apply, and view
* after the multiplication for the whole compound transform is */
mat4 mv = view * model;
glLoadMatrixf(value_ptr(mv));
So you went to great length to avoid using old and dusted OpenGL matrix math functions (which is great); you just have to replace all glLoadMatrix
calls with glUniform
calls in a modern, shader based approach.
glCallList(sphere_handle);
}
But why are you using the so-old-that-it's-decomposing display lists here? *Yuck* They're not available in modern OpenGL either, but can't be as trivially migrated away from, as with your matrix code.
Use a vertex array here.