rotation, fixed axis

hi there. I’ve got a problem that seems to be impossible to solve, according to my searching this forum and the web and docs and tutorials ad infinitum.

This is a really simple problem to explain, but apparently really hard to read. People get confused about this issue often, as I could see when searching this forum. Please pay attention to the explanation of what I want to do:

I want to rotate a square around a FIXED AXIS.

Sorry for yelling. Nota bene, this cannot be solved simply by changing the order of glRotate and glTranslate, afaik.

So, how do I do it?
Everytime I rotate a square the “well documented way”, it rotates all the axes with it. I’m not even sure about what do I have to write to make a square rotate on its center.

I just want to move a square with the arrow keys (n.b. I want the UP key to always make the square go up) and be able to rotate this very square on its center with the Q and E keys, but without ever using sine and cosine. I can do this simply when using SDL, but I can’t rotate my graphics on SDL because it’s too slow (I’ve written a routine for it). I’m now moving to OpenGL, so if i’m forced to use sine and cosine, there’s no point on the switch. And yes, I know I could pre-compute all sines and cosines and put them in an array, I know a lot of those so-called “hackings” or “shortcuts” but the fact is I want to do this the simple way, using only openGL tools.

Please, if you know how to do this, tell me in english and C/C++, not maths. My VC++ version does not compile math.

I never had to ask a single question on any forum about anything related to programming, because I could always search and find. But I give up on this, I looked everywhere and it seems like no one has ever done a square that can me moved absolutely (up_arrow always goes up, down_arrow always goes down) and rotated on its center (its diagonals’ intersections).

If it’s not clear yet, I’m looking for something that does exactly what this “ideal function” does:

glRotateAroundThisVertex( 43 degrees, v.x, v.y, v.z );

Thanks.

well, I think I got it (or sort of).
All I did was not computing the translation with glTranslate, but instead doing it myself inside the glVertex call.

Actually, yes, it can be solved using glTranslate and glRotate calls. At least a combination of those 2 calls should be all you need. Just be sure to use the glPushMatrix and glPopMatrix calls to save the GL_MODELVIEW_MATRIX if you need to go back to the previous matrix state. Searching through the messages on this list you should have found many similar questions.

The method you arrived at from your second post is not a good solution. For large polygon counts it would be highly inefficient. If you want help post a snippet of your code for this issue.

hello, and thanks for the attention.
are you saying I’d better leave glVertex alone, and work only with glTranslate and glRotate?
if so, how would you modify the following in order to keep glVertex parameters constant (preferably meaning that they start in 0,0 and end in whatever are the texture dimensions (40,40 in the example below))?

 	glLoadIdentity();

	glPushMatrix();
		//glTranslatef( left, top, 0.1f );
		glRotatef( angle, 0.0f, 0.0f, 1.0f );
		glTranslatef( left, top, 0.1f );
		glScalef(scaleX, scaleY, 1.0f);
		
		glBindTexture( GL_TEXTURE_2D, texture[0] );
		glColor3f( 1.0f, 1.0f, 1.0f );
		glEnable( GL_BLEND );
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

		glBegin( GL_QUADS );
			glTexCoord2f (  0.0f,  0.0f );
			glVertex3f   ( -20.0f, -20.0f,  0.0f );

			glTexCoord2f (  1.0f,  0.0f );
			glVertex3f   (  20.0f, -20.0f,  0.0f );

			glTexCoord2f (  1.0f,  1.0f );
			glVertex3f   (  20.0f,  20.0f,  0.0f );

			glTexCoord2f (  0.0f,  1.0f );
			glVertex3f   ( -20.0f,  20.0f,  0.0f );
		glEnd();

		glBindTexture( GL_TEXTURE_2D, 0 );

		glDisable( GL_BLEND );

	glPopMatrix(); 

P.S.: i’m only drawing 2D.

actually, the first lines are these (the previous chunk has the right glTranslatef commented out):

 		glTranslatef( left, top, 0.1f );
		glRotatef( angle, 0.0f, 0.0f, 1.0f );
		//glTranslatef( left, top, 0.1f );
		glScalef(scaleX, scaleY, 1.0f); 

How do you write a square that can be driven as a car with only 2 calls? I can only do that if I calculate the x and y translation on my on (using sine and cosine).

The driveable square I’m talking about listens only to the arrow keys - the right and left arrows turn the car angle, the up arrow makes the car go forward to where it is facing (i.e. the up arrow not always makes the car go up) and the down arrow makes it go back (rear).

Below is a simple example of rotation about a fixed axis. It rotates about one corner of the square.

The first glTranslatef moves the square to its orignal position. The glRotatef rotates the square curangle degrees and the second glTranslatef causes the rotation to be about the lower left corner of the square.

Hope it helps.

 
#include <stdio.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

GLuint square;
float rate = 0.01f;
float curangle = 0.0f;

bool init()
{
        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
        square = glGenLists( 1 );
        if( !square )
        {
                printf( "ERROR: Unable to generate lists
" );
                return false;
        }
        glNewList( square, GL_COMPILE );
        glBegin( GL_QUADS );
        glVertex3f( -20.0f, -20.0f, 0.0f );
        glVertex3f( 20.0f, -20.0f, 0.0f );
        glVertex3f( 20.0f, 20.0f, 0.0f );
        glVertex3f( -20.0f, 20.0f, 0.0f );
        glEnd();
        glEndList();
}

void display()
{
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glLoadIdentity();
        glTranslatef( 15.0f, 10.0f, -200.0f );
        glRotatef( curangle, 0.0f, 0.0f, 1.0f );
        glTranslatef( -20.0f, -20.0f, 0.0f );
        glCallList( square );
        curangle += rate;
        glutSwapBuffers();
}

void reshape( int width, int height )
{
        glViewport( 0, 0, width, height );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 35.0f, float( width / height ), 1.0f, 500.0f );
        glMatrixMode( GL_MODELVIEW );
}

int main( int argc, char** argv )
{
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
        glutInitWindowSize( 640, 480 );
        glutInitWindowPosition( 100, 100 );
        glutCreateWindow( "Rotation About Fixed Axis" );
        glutDisplayFunc( display );
        glutIdleFunc( display );
        glutReshapeFunc( reshape );
        if( !init() )
                return 1;
        glutMainLoop();
}

 

Ok, this helps a lot.
It’s exactly what I want. I altered it a bit:

#ifdef WIN32
	#include <windows.h>
#endif

#include <stdio.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

GLuint square;
float
	rate = 0.01f,
	curangle = 0.0f,
	xpos = 0.0f,
	ypos = 0.0f;

bool init()
{
        glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
		return true;
}

void display()
{
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glLoadIdentity();
	glTranslatef( xpos, ypos, -200.0f );
        glRotatef( curangle, 0.0f, 0.0f, 1.0f );
        glTranslatef( 0.0f, 0.0f, 0.0f );

        glBegin( GL_QUADS );
			glVertex3f( -20.0f, -20.0f, 0.0f );
			glVertex3f( 20.0f, -20.0f, 0.0f );
			glVertex3f( 20.0f, 20.0f, 0.0f );
			glVertex3f( -20.0f, 20.0f, 0.0f );
        glEnd();

        curangle += rate;
        glutSwapBuffers();
}

void reshape( int width, int height )
{
        glViewport( 0, 0, width, height );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 35.0f, float( width / height ), 1.0f, 500.0f );
        glMatrixMode( GL_MODELVIEW );
}

// normal WASD movement
void keyread (unsigned char key, int x, int y)
{
	if ( key == 'w' )
		ypos ++;
	else
	if ( key == 's' )
		ypos --;
	else
	if ( key == 'a' )
		xpos --;
	else
	if ( key == 'd' )
		xpos ++;
}

int main( int argc, char** argv )
{
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH );
        glutInitWindowSize( 640, 480 );
        glutInitWindowPosition( 100, 100 );
        glutCreateWindow( "Rotation About Fixed Axis" );
        glutDisplayFunc( display );
        glutIdleFunc( display );
		glutKeyboardFunc( keyread );
        glutReshapeFunc( reshape );
        if( !init() )
                return 1;
        glutMainLoop();
}

I still have doubts about your example.
If openGL really does its stuff backwards (like in a stack, LIFO), then I completely understand how does glTranslatef( 0.0f, 0.0f, 0.0f ); affect the above line (rotation). but how come the line glRotatef( curangle, 0.0f, 0.0f, 1.0f ); does not affect the translation made by the line above it, glTranslatef( xpos, ypos, -200.0f ); ?

And how could I make it affect it so that I’d drive the square like a car? You really seem to understand it and it does seem a simple thing, it’s just a matter of experience with openGL - as I’m able to do all the things I’m asking you to show me on SDL and by my own code (using sine and co-sine). Could you show me, by modifying the code above so that the square can be driven like a car (“w” key not always makes the square go up - relative movement)?

Thanks a bunch.