Depth buffer + GL_PROJECTION problems

I am implementing a shadow volume scheme, where I need to change the projection matrix after rendering the scene with ambient light (both to color and depth buffer). Then depth write is disabled, shadow volumes are rendered to the stencil buffer and the scene is rendered lit with glDepthFunc(GL_EQUAL).

When inserting the following four lines of code after rendering the scene in shadow, but before rendering shadow volumes the final rendered image get distorted:

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glPopMatrix();

According to my knowledge these should not change anything, but apparantly something happens to the depth buffer precision when rendering the scene for the second time. It is crucial that nothing has changed since I render with glDepthFunc(GL_EQUAL).

I tried reading the depth and the stencil buffer before and after executing the following above four lines. Nothing changes.

Doing the following:

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glPopMatrix();

Does not create distortion.

What is the problem here? Can anyone please help me?


CODE SNIPPET

glColor3f(0.2f, 0.2f, 0.2f); //ambient light
model.draw();

glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);

glClear(GL_STENCIL_BUFFER_BIT);

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, ~0);
glStencilMask(~0);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

// --------------------
// Render shadow volumes
//--------------------

glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity(); // THIS LINE SCREWS THINGS UP ??? Without it everything is OK.
glPopMatrix();

glMatrixMode(GL_MODELVIEW);

zpass();

// --------------------
// Render scene lit
//---------------------

glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glColor3f(0.6f, 0.6f, 0.6f); //light on.

glStencilFunc(GL_EQUAL, 0, ~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);

glDepthFunc(GL_EQUAL);

model.draw();

glDepthFunc(GL_LESS);

Check the API specification , appendix A about invariance. OpenGL can only guarantee depth invariant rasterization under certain conditions. As strange as it may seems, just changing matrix mode is not listed under state changes guaranteed to produce invariant rendering. It is listed under “strongly suggested” though, but that’s not a requirement.

Even though changin projection mode apparently shouldn’t affect anything, OpenGL does not guarantee invariant rendering. Same goes for just pushing, loading the identity matrix and popping the stack.

If you need invariant rendering, you must setup the matrix stacks before rendering, and don’t touch them at all (not even change matrix mode) until all passes are completed.

edit: And if you check the specification, you may see that changing depth test mode isn’t listed under required state changes either. That means if you draw the first pass with GL_LESS and second pass with GL_EQUAL, OpenGL doesn’t guarantee invariant rendering again. You need to draw both passes with the same depth test function; GL_LEQUAL.