I'm trying to get some hands-on experience with OpenGL so I've been writing a few basic programs. The short program below is my first attempt at rendering a solid object --a rotating cube-- but for some reason some back polygons seem to be getting drawn over front polygons. My question is what could cause this? Does it have something to do with the depth buffer? I've found that enabling face culling will hide the effect in this case, but why should that be necessary? Shouldn't a face which is occluded by a nearer face be hidden regardless?
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
typedef struct{
int width;
int height;
char * title;
} window;
window win;
float theta = 0;
const float rotRate = 0.05;//complete rotations per second
int lastTime;
const float verts[][3] = {
{0.0,0.0,0.0},
{1.0,0.0,0.0},
{0.0,1.0,0.0},
{0.0,0.0,1.0},
{0.0,1.0,1.0},
{1.0,0.0,1.0},
{1.0,1.0,0.0},
{1.0,1.0,1.0}};
const int faceIndices[][4] = {
{3,5,7,4},//front
{1,0,2,6},//back
{4,7,6,2},//top
{0,1,5,3},//bottom
{5,1,6,7},//right
{0,3,4,2}};//left
void display(){
//timing and rotation
int currentTime = glutGet(GLUT_ELAPSED_TIME);
int dt = lastTime - currentTime;
lastTime = currentTime;
theta += (float)dt/1000.0*rotRate*360.0;
if (theta > 360.0) theta += -360.0;
//draw
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glRotatef(theta, 0.0, 1.0, 0.0);
glTranslatef(-1.0,-1.0,-1.0);
glScalef(2.0, 2.0, 2.0);
int f;
for(f=0; f<6;f++){
glBegin(GL_POLYGON);
int v;
for(v=0; v<4; v++){
glColor3fv(verts[faceIndices[f][v]]);
glVertex3fv(verts[faceIndices[f][v]]);
}
glEnd();
}
glutSwapBuffers();
}
void initializeGLUT(int * argc, char ** argv){
glutInit(argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(win.width, win.height);
glutCreateWindow("OpenGL Cube");
glutDisplayFunc(display);
glutIdleFunc(display);
}
void initializeGL(){
//Setup Viewport matrix
glViewport(0,0,win.width, win.height);
//Setup Projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,(float) win.width/win.height, 0.1, 100.0);
//Initialize Modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Other
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearDepth(1.0);
}
int main(int argc, char** argv){
win.width = 640;
win.height = 480;
initializeGLUT(&argc, argv);
initializeGL();
glutMainLoop();
return 0;
}
Does it have something to do with the depth buffer?
Yes, this is a depth buffer issue, you enabled depth buffer in your code, but obviously you lost some steps, to use depth buffer
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL);
the default value is GL_LESS.glClearDepth
to set the cleared value, the initial value is 1.0, this step is not mandatory if you want the default value.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
I've found that enabling face culling will hide the effect in this case, but why should that be necessary?
By default, OpenGL does't cull any face, the recommend option is
In your case, you defined the polygon vertices all in CCW order, so they are all front faces by default, you just need to cull the back-faces to prevent them from drawing, so the following code also solves your problem.
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
Shouldn't a face which is occluded by a nearer face be hidden regardless?
Yes, that make sense as we are human being, but for the computer, it's your responsibility to tell it how to do that.