glRotatef confusion

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: glRotatef confusion

Post by Falco Girgis »

^ That was an amazingly good read. Your description of a vector as a distance between two points versus a point really helped my right brain wrap around something that my left brain had been doing blindly for awhile.
User avatar
MarauderIIC
Respected Programmer
Respected Programmer
Posts: 3406
Joined: Sat Jul 10, 2004 3:05 pm
Location: Maryland, USA

Re: glRotatef confusion

Post by MarauderIIC »

qpHalcy0n wrote: OpenGL's matrix state is very simple. Know that ALL operations to matrices happen to "the topmost matrix on the stack". That is glTranslatef, glRotatef, glMultMatrix, glScalef, and so forth all operate on the topmost matrix. When you push a matrix, it pushes the current matrix one level down on the stack and in it's place puts a copy of that matrix. When you pop the matrix, it discards the topmost matrix where the next matrix from the top becomes the topmost. This is LIFO structure..and is also a very generic data structure. Do readup on stacks/queues if this does not make sense. The reason for the need to do this is in a state machine, you must always undo what you have done when you are finished, a stack suits this very well. I'll save the matrix as is....operate on its copy......then resurrect it when I'm done.
short0014 wrote:I thought this was what pushing and popping the matrix did. I thought it was supposed to save the state of the modelview matrix (ie when popping the matrix it was supposed to return the matrix how it was before i called the translation)..
Right, so you operate on its copy, and then go back to the original. So short seems to be asking, "why do I have to go back to the origin instead of just popping the matrix?" And I don't think halcyon answered the question?
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: glRotatef confusion

Post by qpHalcy0n »

Well hmm, then there's probably just some way I'm not saying it for it to click.

Popping the matrix would have no effect on the primitives' transformation. As I said in my prior post, all vertex assembly occurs IMMEDIATELY at the conclusion of the glEnd of a glBegin/glEnd pair, so you can be assured the vertices have been transformed by the time you've hit the glEnd call. In the pseudocode you'll note that the matrix isn't popped until after the drawing is complete (glEnd). To a lesser point, the matrix you pushed down a level on the stack to begin with doesnt describe a translation that takes the object back to where it was.

So. Look at the code in sequence.

1) Push the current matrix down a level (we dont want an identity matrix, but we want a COPY of the original because we still need the VIEW matrix (which would have already been created), this is good because this is what glPushMatrix does).
So you may ask: "Why not just use the original matrix instead of a copy of it". Well, the copy is disposable. Once you muck with a matrix it becomes very difficult to get it back. Note I said it's not impossible.
Once you're done with the COPY you simply pop the matrix off, thus restoring the original.

2) The matrix concatenations happen in reverse order. Translating to the origin unifies two spaces. These spaces are WORLD space and OBJECT space. Lets say your object is at 100, 100, 100 in the world. Well if we simply
use a rotation matrix, then the vertices are rotated IN THAT SPACE. Which is WORLD space. Therefore they rotate about the WORLD ORIGIN (a massive arc around the world origin). This is not what we want, we want object space. We want the object to rotate about ITSELF. How do we get to object space?

Easy: Translate to the worldspace origin. This is simply stated as the negated vector from the world origin to the object center. This is why we must do this

Secondly we have to rotate. There's nothing to explain here, this is what we were trying to do in the first place.

Third, this seems to be where the confusion is. If we give up now, we have a rotated object at 0, 0, 0. Not 100, 100, 100. We have to put it back into world space. Therefore the translation from object to worldspace is the
vector from the world origin to the original object position.

This is now gives us the summation of ALL transforms in one neat package. A single matrix that represents all of those separate transforms. This saves us tons of calculations, what if we had to transform every vertex by a negative translation matrix, an inverse scaling matrix, a rotation matrix, a scaling matrix, a shearing matrix, then a translation matrix back to where it was, then a desired translation matrix.....thats a WHOLE LOT of matrix ops (yes, they CAN get that complicated.....and thats just a world transformation). Matrix concatenation preserves individual transforms AS LONG AS: they are concatenated in correct order. This matrix resides as the topmost one on a stack, and as such is the ONLY one used in any ensuing operations. Whether they are operations on the matrix, or whether primitives are passed. Note: our previous matrix resides one level below this one.

3) We call glBegin....pass some vertices.....then glEnd().
Each separate call to glVertex stores the vertices in a vertex cache on the card and are transformed by the modelview and projection matrices. When you call glEnd, the vertices in this cache are assembled into meaningful primitives and are lit, depth tested, alpha tested, backface culled, etc, (if specified) then clipped, and now sit in the backbuffer. They're done! Waiting...for you to swap the buffer. All this happens before the glPopMatrix. So you can see that they have already been transformed!

4) We pop the matrix off. This gets rid of what we have JUST done, and restores the original matrix that we pushed on. It merely serves to restore state, NOT as a mechanism of your desired transformation. You can see in step #3, that the object is already transformed, there's nothing we can do with it now. The call has been submitted, the primitive(s) was/were transformed and lit (called T&L) and is already in the backbuffer.

Hopefully that little trip down the (very simplified) T&L pipeline makes it a bit clearer. My teachers have always said, "There's just some way I'm not telling you to make it click" :] So if it still doesn't really make sense, feel free to either post here or contact me privately. On this matter I've explained about as much as I can on text, anything further would require voice and/or pictures. Or if you have any *specific* questions...feel free.
Post Reply