Page 1 of 2
OpenGL Rotatef
Posted: Fri Jul 31, 2009 12:41 pm
by ibly31
For some reason, every time I use glRotatef() in my iphone programs, it rotates the object I want to rotate around in what seems to be a circle... I think it might be rotating the entire viewport, but thats just my guess. Here is my code:
Drawing code:
Code: Select all
- (void)drawView:(GLView*)view;
{
glClearColor(0.7, 0.7, 0.7, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
CGPoint point = CGPointMake(100.0, 100.0);
[texture drawAtPoint:point rot: rotat];
rotat++;
}
Texture2D's modified drawing code:
Code: Select all
- (void) drawAtPoint:(CGPoint)point rot:(GLfloat)rota
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
GLfloat coordinates[] = { 0, _maxT,
_maxS, _maxT,
0, 0,
_maxS, 0 };
GLfloat width = (GLfloat)_width * _maxS,
height = (GLfloat)_height * _maxT;
GLfloat vertices[] = { -width / 2 + point.x, -height / 2 + point.y, -1.0,
width / 2 + point.x, -height / 2 + point.y, -1.0,
-width / 2 + point.x, height / 2 + point.y, -1.0,
width / 2 + point.x, height / 2 + point.y, -1.0 };
glLoadIdentity();
glRotatef(rota, 0.0, 0.0, 1.0);
glBindTexture(GL_TEXTURE_2D, _name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
I don't know what is wrong. It seems that every time I start a GL project, everything works up until I try to do texture mapping, then rotation is weird.
Any help?
EDIT: All the other tutorials involving rotation that Ive seen, the object is at 0.0,0.0,0.0 maybe glRotatef rotates the entire 3D world? Is there a way to just rotate one object?
Re: OpenGL Rotatef
Posted: Fri Jul 31, 2009 1:38 pm
by Falco Girgis
You need to rotate after you've translated your object rather than before.
Code: Select all
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
I am not sure if VertexPointer actually translates around the vertices or not, but the rotation should be applied after this.
Re: OpenGL Rotatef
Posted: Fri Jul 31, 2009 2:01 pm
by Innerscope
This rotates the scene around the origin.
To rotate an object do something like:
Code: Select all
glPushMatrix();
glRotatef(angle,x,y,z);
//Draw object
glPopMatrix();
This saves the previous view transformation, transforms the view, then restores it.
[Edit] Also glLoadIdentity() resets the modelview matrix, you should only call this once per render. (for what you're trying to accomplish)
Side note: I keep getting blacklisted
Re: OpenGL Rotatef
Posted: Fri Jul 31, 2009 4:25 pm
by ibly31
Hmm... I have tried both of these, putting the rotation code after the vertexpointer call and then the rotation after the pushmatrix, draw then popmatrix... neither seem to have worked...
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 1:11 am
by Innerscope
ibly31 wrote:Hmm... I have tried both of these, putting the rotation code after the vertexpointer call and then the rotation after the pushmatrix, draw then popmatrix... neither seem to have worked...
Are you still rotating about the origin?
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 3:55 am
by imran.hoshimi
Hello,
I was wondering why are you even caring about Z coordinate when you are using the Texture2D class. AS you have tried to change the Texture2D class to suit your own needs I see that you might have made a slight mistake. Take a look...
Code: Select all
- (void) drawAtPoint:(CGPoint)point rot:(GLfloat)rota
{
glPushMatrix();
// Rotate around the Z axis by the angle defined for this image
glTranslatef(point.x, point.y, 0);
glRotatef(-rota, 0.0f, 0.0f, 1.0f);
// if it still doesn't work, try uncommenting this line also. I will explain later why. :)
// glTranslatef(-point.x, -point.y, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
GLfloat coordinates[] = { 0, _maxT,
_maxS, _maxT,
0, 0,
_maxS, 0 };
GLfloat width = (GLfloat)_width * _maxS,
height = (GLfloat)_height * _maxT;
GLfloat vertices[] = {
-width / 2 + point.x, -height / 2 + point.y,
width / 2 + point.x, -height / 2 + point.y,
-width / 2 + point.x, height / 2 + point.y,
width / 2 + point.x, height / 2 + point.y
};
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glBindTexture(GL_TEXTURE_2D, _name);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 4:12 am
by qpHalcy0n
You need to determine the center of the object you're trying to draw in model space. A simple bounding box test will suffice. You also need to save the current model/view matrix before modifying the state, otherwise you wont be able to get the previous matrix back (actually, you CAN...but it's more math than I'm sure you'd care to go into). The way the glScalef, rotatef, translatef and so forth work is by performing a *postmultiplication* on the current matrix state. So, the order of multiplication DOES matter, and it happens in the order that you think it does. This is the opposite of how most other strict math libs deal with it, which is a *premultiplication* where the order of multiplication (concatenation) happens in the reverse of what you think it does. This applies to 2D cases as well.
So the point in the middle of the object's bounding box is also equal to the vector from the origin to it. So the reversed vector takes you to the origin. Your concatenation becomes:
// Make model/view matrix current //
glMatrixMode(GL_MODELVIEW);
// Save matrix state //
glPushMatrix();
// Translate to origin //
glTranslatef(-objCenter.x, -objCenter.y, -objCenter.z);
// Rotate //
glRotatef(rotX, rotY, rotZ);
// Translate back //
glTranslatef(objCenter.x, objCenter.y, objCenter.z);
RenderStuff();
// Restore matrix //
glPopMatrix();
When you start concatenating more complex transforms you need to pay special attention to order.
Even using glDrawArrays or what have you to render from user/hardware buffers will be passed through the current matrix state.
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 10:41 am
by ibly31
Hmm, but if I do your method with multiple objexts, wont everything ve rotates along with the object im rotating?
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 10:48 am
by ibly31
What exactly are GL_MODELVIEW and another one I think its called GL_PROJECTION
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 11:10 am
by Falco Girgis
ibly31 wrote:Hmm, but if I do your method with multiple objexts, wont everything ve rotates along with the object im rotating?
No, because he popped the matrix when he was done.
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 12:02 pm
by qpHalcy0n
The GL_MODELVIEW matrix is a concatenated model transform and view transform. A model (or world) transform describes objects relationships to each other in a common coordinate frame. After a modelling transformation the objects are said to be in "worldspace". The view transform is a transformation that transforms the scene around the camera such that the camera resides at the origin, objects are said to be in "view space" after this transform. The projection transform (GL_PROJECTION) describes the shape of the camera volume...there are TONS of different types of projections but the two most frequently used are a perspective projection (gives illusion of depth but does not preserve linearity), and orthographic projection (no depth illusion, but preserves linearity). The result of this puts the vertices in "clip space". After a perspective divide (divide by w), the vertices are in NDC (normalized device coordinates, which in OpenGL is a unit cube from 0-1, in DX is a unit cube from -1 to 1). Texturing is performed generally after the perspective divide and there are ...you guessed it...matrices for that. The texture matrix stack (GL_TEXTURE, GL_TEXTURE0-7) just transforms incoming texture coordinates into a 0-1 UV correct space (which for OpenGL it already is).
OpenGL state matrices are on "stacks" which is a LIFO structure. The modelview stack is at least 32 deep, and the projection stack is at least 2 deep. Anytime you're doing operations to a matrix you're doing them to the one that is on the top of the stack. By pushing a matrix down you're making a copy of it, and pushing the COPY on top of the stack. So you're in effect, saving the old matrix. You do your rendering, then you pop the copy off. Thus giving you the old matrix back.
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 4:44 pm
by ibly31
I tried a bunch of the things you said to do... this is my code now:
Code: Select all
- (void) drawAtPoint:(CGPoint)point
{
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
GLfloat coordinates[] = { 0, _maxT,
_maxS, _maxT,
0, 0,
_maxS, 0 };
GLfloat width = (GLfloat)_width * _maxS,
height = (GLfloat)_height * _maxT;
GLfloat vertices[] = { -width / 2 + point.x, -height / 2 + point.y, -1.0,
width / 2 + point.x, -height / 2 + point.y, -1.0,
-width / 2 + point.x, height / 2 + point.y, -1.0,
width / 2 + point.x, height / 2 + point.y, -1.0 };
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, _name);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTranslatef(-point.x, -point.y, 0); // I'm doing 2D so I dont think I need a number for the Z
glRotatef(_rota, 0.0, 0.0, 1.0);
glTranslatef(point.x, point.y, 0); // same here?
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
With the translate sandwhich around the glRotatef, the object spins around the center, off the screen, then never comes back. Without the glTranslatef's it rotates around the center and will do so until you quit.
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 7:08 pm
by qpHalcy0n
Sorry, I made a small mistake, I'd forgotten matrices in OpenGL are row major. (its been awhile :P). Which when multiplying 4 component vectors is the same as pre-multiplying a column major matrix Sorry bout that I just thought about that when reading your code there. So: while logically you're saying "translate to origin, rotate, then translate back". The matrix concatenation should read more like "translate back, rotate, translate to origin".
The second issue you have going on there is that yes, indeed you DO need to translate on the z-axis as well. Most likely you're using an orthographic projection to emulate a 2D environment, and clever usage of the viewport can allow you to map world space positions directly to screen space. However, this does not detract from the fact that you are still using an orthographic projection and the vertices are still a 3 dimensional space.
So, your transformation code should look more like the following:
Code: Select all
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Desired translation //
glTranslatef(point.x, point.y, 1.0F);
// Desired rotation //
glRotatef(rotangle, rotx, roty, rotz);
// Translate to origin //
glTranslatef(-point.x, -point.y, -1.0F);
DrawStuff();
// Restore matrix //
glPopMatrix();
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 9:56 pm
by ibly31
That did the trick! Thank you so much! Most of your last post made pretty much no sense to me, because of all the terms. I'm pretty new to OpenGL ES (well this is my first experience with it), so I don't really know what any of the terms mean.
Re: OpenGL Rotatef
Posted: Sat Aug 01, 2009 10:02 pm
by Falco Girgis
So what in the hell was his call to glVertexPointer() even doing? I guessed that it was maybe doing the equivalent of a pushMatrix on the vertices.