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
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

glRotatef confusion

Post by short »

Hey guys, I'm really trying to get a better understanding of opengl, but I keep running into this problem. The red book isn't helping me to much with this, so hopefully somebody here can help. I have a rectangle class which I believe is working perfectly, so I won't post the class file (I can if needed).

Anyways, the desired effect I am looking for is the rectangle to spin according to m_orientation in two dimensions. It works fine when the rectangle is at position 0,0,0 but when I move the rectangle away from the origin (wasd keys move the rectangle) the rotation gets messed up. I think it has something to do with where my camera is, or I am not understanding where I need to move it. My draw function is this (it is called every frame):

Code: Select all

void Engine::draw(Rect * rectangle)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
	glLoadIdentity();					// Reset The Current Modelview Matrix

    glTranslatef(0.0f, 0.0f, -8.0f);				// Move everything 8 units into the screen

    drawRectangle(rectangle, &rectangle->m_colors);

    

    //drawSpriteOnRectangle(Vertex(100, 100, 0), Vertex(228, 100, 0), Vertex(228, 228, 0), Vertex(100, 228, 0));
}
I can't think of anything else that would be relevant, hopefully somebody can point me in the correct direction.

Code: Select all

void Engine::drawRectangle(Rect * rectangle, vector<Vertex>* color_vector)
{
    glPushMatrix();
	glRotatef(rectangle->m_orientation, rectangle->getPosition()->x, rectangle->getPosition()->y, 1);

	//m_RotationAngle += .1f; // increase rotation angle
    rectangle->m_orientation += .1f;

	if(rectangle->m_orientation > 360.0) //prevent from having an angle greater than a float value can store ^^
	{
		rectangle->m_orientation -= 360.0;
	}

    glBegin(GL_QUADS);
        glColor3f(rectangle->m_colors[TOP_LEFT].x, rectangle->m_colors[TOP_LEFT].y,rectangle->m_colors[TOP_LEFT].z);
        glVertex3f(rectangle->m_vertices[TOP_LEFT].x, rectangle->m_vertices[TOP_LEFT].y, rectangle->m_vertices[TOP_LEFT].z);
        
        glColor3f(rectangle->m_colors[TOP_RIGHT].x, rectangle->m_colors[TOP_RIGHT].y,rectangle->m_colors[TOP_RIGHT].z);
        glVertex3f(rectangle->m_vertices[TOP_RIGHT].x, rectangle->m_vertices[TOP_RIGHT].y, rectangle->m_vertices[TOP_RIGHT].z);

        glColor3f(rectangle->m_colors[BOTTOM_RIGHT].x, rectangle->m_colors[BOTTOM_RIGHT].y,rectangle->m_colors[BOTTOM_RIGHT].z);
        glVertex3f(rectangle->m_vertices[BOTTOM_RIGHT].x, rectangle->m_vertices[BOTTOM_RIGHT].y, rectangle->m_vertices[BOTTOM_RIGHT].z);

        glColor3f(rectangle->m_colors[BOTTOM_LEFT].x, rectangle->m_colors[BOTTOM_LEFT].y,rectangle->m_colors[BOTTOM_LEFT].z);
        glVertex3f(rectangle->m_vertices[BOTTOM_LEFT].x, rectangle->m_vertices[BOTTOM_LEFT].y, rectangle->m_vertices[BOTTOM_LEFT].z);
     glEnd();

     glPopMatrix();

}
Please let me know if I forgot to include anything related to this. :worship:
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
User avatar
RyanPridgeon
Chaos Rift Maniac
Chaos Rift Maniac
Posts: 447
Joined: Sun Sep 21, 2008 1:34 pm
Current Project: "Triangle"
Favorite Gaming Platforms: PC
Programming Language of Choice: C/C++
Location: UK
Contact:

Re: glRotatef confusion

Post by RyanPridgeon »

glRotate rotates around the origin. So basically the center of rotation is wherever you've translated to.

So just make sure to translate to where you want the center of rotation to be, and rotation should work fine. Other than that it would be helpful to explain your problem better.
Ryan Pridgeon
C, C++, C#, Java, ActionScript 3, HaXe, PHP, VB.Net, Pascal
Music | Blog
User avatar
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

Re: glRotatef confusion

Post by short »

I believe you are correct, thank you for explaining that to me.
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
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 »

Let me guess, you wound up with a rectangle that "orbited" the origin, rather than rotating about itself? It's a simple mistake with a simple fix. Just rotate before your translation. You will run into this kind of thing all the time when you get into OGL and matrix transformations. Usually if you play with it enough, you will start to understand it better.

Everybody has that exact same problem the first time they try to rotate a sprite. :)
User avatar
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

Re: glRotatef confusion

Post by short »

I think I understand that the translate code goes before the rotation code to produce the rotation before the translation. Correct me if I am wrong, but I did try putting the rotation before the translation in the code, and it didn't work either.

Let me do some out loud thinking.

First we push the matrix

Then we rotate the current viewing matrix (happens second)

Then we translate to the center of the rectangle (happens first because of matrices multiplication)

Then draw the rectangle

Lastly we pop the old matrix

In my head it makes sense, but I am still getting undesired effects (spinning around the 0,0,0 origin instead of ).


Code: Select all

void Engine::drawRectangle(Rect * rectangle, vector<Vertex>* color_vector)
void Engine::drawRectangle(Rect * rectangle, vector<Vertex>* color_vector)
{
    glPushMatrix();

	glLoadIdentity();
    glTranslatef(rectangle->getPosition()->x, rectangle->getPosition()->y, rectangle->getPosition()->z);  
	glRotatef(rectangle->m_orientation, 0.0f,0.0f,1.0f);

	if(rectangle->m_orientation > 360.0) //prevent from having an angle greater than a float value can store ^^
	{
		rectangle->m_orientation -= 360.0;
	}

    glBegin(GL_QUADS);
        glColor3f(rectangle->m_colors[TOP_LEFT].x, rectangle->m_colors[TOP_LEFT].y,rectangle->m_colors[TOP_LEFT].z);
        glVertex3f(rectangle->m_vertices[TOP_LEFT].x, rectangle->m_vertices[TOP_LEFT].y, rectangle->m_vertices[TOP_LEFT].z);

        glColor3f(rectangle->m_colors[TOP_RIGHT].x, rectangle->m_colors[TOP_RIGHT].y,rectangle->m_colors[TOP_RIGHT].z);
        glVertex3f(rectangle->m_vertices[TOP_RIGHT].x, rectangle->m_vertices[TOP_RIGHT].y, rectangle->m_vertices[TOP_RIGHT].z);

        glColor3f(rectangle->m_colors[BOTTOM_RIGHT].x, rectangle->m_colors[BOTTOM_RIGHT].y,rectangle->m_colors[BOTTOM_RIGHT].z);
        glVertex3f(rectangle->m_vertices[BOTTOM_RIGHT].x, rectangle->m_vertices[BOTTOM_RIGHT].y, rectangle->m_vertices[BOTTOM_RIGHT].z);

        glColor3f(rectangle->m_colors[BOTTOM_LEFT].x, rectangle->m_colors[BOTTOM_LEFT].y,rectangle->m_colors[BOTTOM_LEFT].z);
        glVertex3f(rectangle->m_vertices[BOTTOM_LEFT].x, rectangle->m_vertices[BOTTOM_LEFT].y, rectangle->m_vertices[BOTTOM_LEFT].z);
     glEnd();

	glPopMatrix();
}

edit: I added the following code to the end of the function to make sure I was getting the correct position. It works beautifully, the line always goes to the center of the rectangle, as expected.

Code: Select all

glBegin(GL_LINES);
        glColor3f(1.0, 1.0, 1.0);
		glVertex3f(rectangle->getPosition()->x, rectangle->getPosition()->y, rectangle->getPosition()->z);
		glVertex3f(100.0f,100.0f,-6.0f);
    glEnd();
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
User avatar
RyanPridgeon
Chaos Rift Maniac
Chaos Rift Maniac
Posts: 447
Joined: Sun Sep 21, 2008 1:34 pm
Current Project: "Triangle"
Favorite Gaming Platforms: PC
Programming Language of Choice: C/C++
Location: UK
Contact:

Re: glRotatef confusion

Post by RyanPridgeon »

No, you have to translate BEFORE rotating, otherwise you will just be translating along the NEW rotated axis, which will result in the weird orbiting effect

First, push the matrix

Then translate to the object's center

Then glRotate to the desired orientation

Then draw the sprite

Then pop the matrix

Hopefully that will clear it up for you :)
Ryan Pridgeon
C, C++, C#, Java, ActionScript 3, HaXe, PHP, VB.Net, Pascal
Music | Blog
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 »

Then we translate to the center of the rectangle (happens first because of matrices multiplication)
Once the command is done, it's done. It's not done when the matrix is popped, it's done when the semicolon is hit. As such, you aren't really subject to order of operations, which is what your sentence suggests your belief to be.
I realized the moment I fell into the fissure that the book would not be destroyed as I had planned.
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 »

RyanPridgeon wrote:No, you have to translate BEFORE rotating, otherwise you will just be translating along the NEW rotated axis, which will result in the weird orbiting effect

First, push the matrix

Then translate to the object's center

Then glRotate to the desired orientation

Then draw the sprite

Then pop the matrix

Hopefully that will clear it up for you :)
Right. I mean, the rotation is happening before the translation here. That's really what I said also.
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: glRotatef confusion

Post by qpHalcy0n »

MarauderIIC wrote:
Then we translate to the center of the rectangle (happens first because of matrices multiplication)
Once the command is done, it's done. It's not done when the matrix is popped, it's done when the semicolon is hit. As such, you aren't really subject to order of operations, which is what your sentence suggests your belief to be.


Unfortunately, that is not the case :[

In regards to the transformation pipeline, there is a rather lengthy order of operations that *must* happen in perfect order. In particular world transformations (which is what you're doing) follow a specific order. This is called a matrix concatenation, which is what the calls to glRotate, glScale, glTranslate, and so forth actually do. They postmultiply the topmost matrix on the current matrix mode's stack. Given that GL uses a row major ordering, this is consequently the same as PREmultiplying a column major matrix by a row major vector. Therefore the order of the multiplication of the matrices follows the OPPOSITE order than you think of the transformations in your head. In other words: "I want to translate to the origin, rotate, then translate back". The actual multiplication might look like T(d) * R * T(o). Where T(d) is the desired translation, R is the rotation, and T(o) is the translation to the origin.

Moreover if you are applying several transformations, there is a certain order. In the simplest case remember this: C = T * R * S; Where C is the final concatenation, T is the translation matrix, R is the rotation matrix, and S is a *uniform* scaling. So in that simplest case (where you have an object centered about the origin) the order of execution should be:

Code: Select all

glTranslatef(....);
glRotatef(....);
glScalef(...);
So objects that lie NOT at the origin require two additional steps, and its very simple if you think about it. A translation to the origin, and a translation back. The translation to the origin occurs at the TRAILING end of the equation, the translation back occurs at the LEADING end of the equation which then becomes: C = T(d) * R * S * T(o) where T(d) is the desired translation, and T(o) is the translation to the origin. So to get to the origin, in a 2D space, you translate by the NEGATED center of the object (said: The vertices of the object are centered ABOUT the origin). So for example, you have a box w/ a lower left of (1, 1) and upper right of (2, 2), your translation to the origin looks like (-1.5, -1.5). So then your translation back to where it was looks like (1.5, 1.5). In a 3D space, you can represent the AABB (axis aligned bounding box) of an object w/ 2 points. The center then becomes min + (vec3(min - max) * 0.5); Negate that, and that is your translation to the origin.

I wont even get into non-uniform scales here, it involves finding an inverse matrix for a scale which can be lengthy.

So the reason things APPEAR to happen out of order in most API's is due to matrix PREMULTIPLICATION. Secondly, there is a very specific order of operations. Going out of order will yield undesired results.
User avatar
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

Re: glRotatef confusion

Post by short »

I have my translation code immediately after pushing the matrix.

Code: Select all

glPushMatrix();
    glTranslatef(rectangle->getPosition()->x, rectangle->getPosition()->y, rectangle->getPosition()->z);
    glRotatef(rectangle->m_orientation, 0,0,rectangle->getPosition()->z);
The rotation works fine when the box is at 0,0,0 (it spins like it should around itself)

When I move the box around the screen, the further from the center of the screen, the more it seems to rotate about some arbitrary point.

I believe the following code may be an issue, but I do not know why..

Code: Select all

glRotatef(rectangle->m_orientation, 0,0,rectangle->getPosition()->z);
Since Immediately above the glRotatef call I translate to the center of the rectangle, I think the 2nd and 3rd parameters should be both 0 (which I have them as) since 0 would now be the center of the rectangle.?
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: glRotatef confusion

Post by qpHalcy0n »

Read the above post so that you understand whats going on. Then this is what you'll be looking at (if indeed your positions ARE the *center* of the object to be rotated):

Code: Select all

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(rectangle->getPosition()->x, rectangle->getPosition()->y, rectangle->getPosition()->z);       // THIRD: translate back to original position
glRotatef(degree_measure, rot_axis_x, rot_axis_y, rot_axis_z);                                                          // SECOND: rotate
glTranslatef(-rectangle->getPosition()->x, -rectangle->getPosition()->y, -rectangle->getPosition()-z);    // FIRST: translate to origin

// Draw your stuff //

glPopMatrix();
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: Unfortunately, that is not the case :[
Really? That's interesting.
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 »

MarauderIIC wrote:
qpHalcy0n wrote: Unfortunately, that is not the case :[
Really? That's interesting.
Correct, in general matrix multiplication is not commutative. MN != NM
User avatar
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

Re: glRotatef confusion

Post by short »

qpHalcy0n wrote:Read the above post so that you understand whats going on. Then this is what you'll be looking at (if indeed your positions ARE the *center* of the object to be rotated):

Code: Select all

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(rectangle->getPosition()->x, rectangle->getPosition()->y, rectangle->getPosition()->z);// THIRD: translate to original position
glRotatef(degree_measure, rot_axis_x, rot_axis_y, rot_axis_z);                                                    // SECOND: rotate
glTranslatef(-rectangle->getPosition()->x, -rectangle->getPosition()->y, -rectangle->getPosition()-z);// FIRST: translate to origin

// Draw your stuff //

glPopMatrix();

By adding the following line, it works perfectly

Code: Select all

glTranslatef(-rectangle->getPosition()->x, -rectangle->getPosition()->y, -rectangle->getPosition()->z);
I'm curious though as to why we have to rotate back to the origin. 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)..

Can anyone clarify how this works? BTW I thank you all for taking the time to answer these questions. ;)
Last edited by short on Fri Sep 25, 2009 2:22 pm, edited 2 times in total.
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
qpHalcy0n
Respected Programmer
Respected Programmer
Posts: 387
Joined: Fri Dec 19, 2008 3:33 pm
Location: Dallas
Contact:

Re: glRotatef confusion

Post by qpHalcy0n »

The negated translation is very simple. An object's position is simply expressed as the *VECTOR* from the local origin to that particular position. If you think of the world position in terms of a vector as opposed to a POINT (the object position is the origin (point) plus the vector to get there and a point +/- a vector yields another point), then you'll see that the NEGATED *position* is indeed the vector to get back TO the origin. The reason you need to get to the origin for an object to spin about it's own axis stems from the fact that simple rotation matrices are composed of sin/cos combinants. In a cartesian space, if all vertices lie in the same quadrant (which they do if you're not centered about the origin) then they will all rotate in unison around the unit circle centered at the origin. By translating to the origin, now all vertices are centered ABOUT the origin across all four quadrants. Then the object's center is centered about the world origin, so the object appears to rotate about it's own center. It's a matter of aligning coordinate frames.

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.

All vertices subsequently sent down the pipeline (via a glBegin/glEnd pair) are transformed by the topmost matrices of the matrix stacks...and this happens immediately at the conclusion of glEnd. You probably do not want ALL vertices AFTER you draw this particular object to be transformed by the SAME matrix (because they do not have the same positions, they may not rotate, they may not scale, etc...), this is why you must RESTORE the previous matrix state with a glPop when you are done drawing.
Post Reply