Is there a connection between glPushMatrix() and glBegin()?

Viewed 363

I'm calculating a lot of vertices and then display them with quad strips for a 3D surface plot.

I had a strange behavior for some vertices, changing colors in unpredictable manner. I tried fixing it and by coincidence, I found that the problem is solved, when I put glPushMatrix() and glPopMatrix before and after. Does anyone know what the underlying problem could be? Should I generally use push/pop around by glBegin/glEnd?

Here my working code:

for (int i = 1; i < vec.size(); i++) {
    glPushMatrix();
    glBegin(GL_QUAD_STRIP);
        for (int j = 0; j < vec[i].size(); j++) {
            glNormal3dv(vertex_normal[i][j]);
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, reflectance[i][j]);
            glVertex3d(vec[i][j].x(), vec[i][j].y(),vec[i][j].z());

            glNormal3dv(vertex_normal[i-1][j]);
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, reflectance[i-1][j]);
            glVertex3d(vec[i-1][j].x(), vec[i-1][j].y(), vec[i-1][j].z());
        }
    glEnd();
    glPopMatrix();
}
2 Answers
  1. The stack size is limited !!!

    so vec.size() must be smaller or equal to your OpenGL implementation matrix stack size - used layers of it before the loop. That is making your hack a bit dangerous.

  2. Use glGetError

    You should check glGetError after every major gl stuff you use (while debugging and also apply it until it return no error). There are also tools like glIntercept that do that for you. It should reveal where the problem really is.

  3. Missing glEnd()

    As you are using the old api try to add few times glEnd(); before the loop. If that helps you got missing glEnd(); somewhere which is usual bug with rookies as glEnd; is also compilable but does nothing.

    That could be reseted by the OpenGL after matrix push/pop but that is pure speculation from my side.

  4. calling glMaterialfv inside glBegin/glEnd

    The OpenGL docs states:

    The material parameters can be updated at any time. In particular, glMaterial can be called between a call to glBegin and the corresponding call to glEnd. If only a single material parameter is to be changed per vertex, however, glColorMaterial is preferred over glMaterial (see glColorMaterial).

    I would try to avoid using glMaterial inside glBegin/glEnd as my experience is that bad OpenGL implementations (like Intel) does not follow the specs to the letter and may cause problems on some platforms/circumstances with uncommon usage if not now then in future...

So to answer your question: No glBegin/glEnd should not be affected by glPushMatrix/glPopMatrix and vice verse if they are used properly (push/pop is not allowed inside glBegin/glEnd and you must not exceed the stack limit).

I'm going to take a different position and say that adding an additional push and pop should make no difference.

In old-fashioned OpenGL, there are several matrix stacks. As well as a bunch of operations that modify whatever is currently on the top of the stack, of which you don't have any, push and pop are offered. Push duplicates whatever is at the top of the stack. So if the stack was A B C D then it becomes A B C D D. Pop just removes whatever is at the top of stack — it'd take you back from A B C D D to A B C D.

That gives a structure that fits nicely with a call stack. By getting a copy of the old top you are inheriting changes to date. You can then make whatever changes you want, and then back out, and it doesn't matter what anybody you call does.

This is completely orthogonal from glBegin and glEnd which merely say "begin a batch of geometry" and "end that batch of geomtry". Geometry is affected by the current values at the top of appropriate stacks, but you're not actually changing the value.

So I assume you're suffering undefined behaviour and have happened upon a placebo fix for your particular machine.

Related