Rotating a moving object

Hi,

I’m encountering the following problem. I’ve got a dinosaur which I’d like to rotate around a point that is not the origin. Well that’s not the problem, but here it comes.

I’m moving the dinosaur using the numeric keyboard, 4+6 rotates, 8 moves, 2 stops the dinosaur. I cannot rotate the dinosaur and then translate it into it’s correct position. This is my code:

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
gluLookAt(camera[0], camera[1], camera[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

drawEnvironment();

if (move)
	moveDino();

glTranslatef(10.5, 0.0, 1.55);
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-10.5, 0.0, -1.55);

drawDino();

glFlush();
glutSwapBuffers();

}

void keyboard(unsigned char key, int posx, int posy)
{
if (tolower(key) == ‘q’)
exit(0);

if (key == '8')
	move = GL_TRUE;
else if (key == '4')
	rotateDino(left);
else if (key == '6')
	rotateDino(right);
else if (key == '2') 
	move = GL_FALSE;

}


As you can see, I try to rotate the dino itself around the y-axis at the point (10.5, 0.0, 1.55). But I have to translate the dino to the position (dino_pos[0], dino_pos[1], dino_pos[2]). I’ve tried to add those coordinates to the rotation point, but that doesn’t work, at least not in the way I’m doing it .

Can anybody please help me out (trying to be really desperate here…) ??

You always rotate around the origin. But you can fake a rotation around an arbitary point by moving the objects to make the new center point to be at the origin.
So if you want to rotate around (10.5,0.0,-1.5) then move your dino with (-10.5,0.0,1.5), rotate it, then move back by (10.5,0.0,-1.5) thus you’ve rotated it around the new center point

Hope this helps
FooLman

Thanx for your help, but I already do that…

The problem is translating the object to another position than (10.5, 0.0, 1.55). If I do that, the dino is making circles instead of rotating on the same position.

Hello !

Try this :


glPushMatrix();
glTranslatef(x,y,z);
glRotatef(angle,0,1,0);
drawDino();
glPopMatrix();

I’m not home so I can’t try it but it might work…

Osku

Thanx for your reply,
but after the rotation the dino has to be translated into its current position. That’s the tricky business, at least for me…

glTranslatef(10.5, 0.0, 1.55);
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-10.5, 0.0, -1.55);

This code makes no sence to me.
I am not sure but i think it’s the same as
glRotatef(angle, 0.0, 1.0, 0.0) only.

Maybe You need something like this …

glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(10.5, 0.0, 1.55);
drawDino();
glTranslatef(-10.5, 0.0, -1.55);

[CS]

I think this is what you need

getNewPos()
{
float mat[4][4];
glGetFloatv(GL_MODELVIEW_MATRIX,(float *)mat);

Z+=deltaz*mat[2][2]+deltay*mat[2][1]+deltax*mat[2][0];
Y-=deltaz*mat[1][2]+deltay*mat[1][1]+deltax*mat[1][0];
X+=deltaz*mat[0][2]+deltay*mat[0][1]+deltax*mat[0][0];

}

where Z is your original z position
X is your original x position
and Y is your original y position
and the deltas are the speed you want your dino to move …

run this everyframe (or time step or whatever)

then in the display func do this

glRotatef(-roll, 0,0,1);
glRotatef(pitch,1,0,0);
glRotatef(-yaw,0,1,0);
glTranslatef(X, -Y, Z);

of course your original xyz and rpy should be

(10.5, 0.0, 1.55)
and
(0,0,0) respectively

//to move to a PARTICULAR position is easy too just figure out the deltas

deltaz= zdest-zorig
deltax= xdest-xorig
deltay= ydest-yorig

cheers

write back to tell me if this works

I think you’ve been misunderstood. You want the dinosaur to be at position {10.5,0,1.55} and to rotate in place there, right? When you say you want him to rotate around that point, people think you want him to move in a circle around that point.

glTranslate is not relative and is not affected by glRotate. However, glRotate IS affected by glTranslate. If the dino is centered around the origin, and you call glRotate, he’ll rotate in place. If you call glTranslate first, then glRotate, he’ll rotate in a circle around the origin, since he no longer is at the origin.

Basically, the radius of his rotation circle is his distance from the origin. If he’s at the origin, that distance is zero. To create third-person games, you translate the camera back a bit (0,0,-Amount) and then call glRotate.

Anyway, what you want is this:

glPushMatrix( ); // Save ModelView
//
glRotatef( angle, 0, 1, 0 );
glTranslatef( 10.5, 0, 1.55 );
drawDino( );
//
glPopMatrix( ); // Restore ModelView

[This message has been edited by CGameProgrammer (edited 12-12-2000).]

What my code should do is rotate you around an arbitrary point in space (X, Y, Z) and then you can translate with respect to that point and your rotation

so if you are at 1,0,0 and have rotated so the dino is facing the positive x axis and you want to move forward you just move and you will be rotating around 2,0,0 and you will be there too

when I mean move I mean move the center of your object and when I say rotate around I mean the center of your object is at that point and you are spinning about it (not in a circle)

What my program should do is this. This is my dino:

x---------------
-------------o-
---------------
---------------

‘x’ is at the origin, and ‘o’ is the position to rotate around. This is because ‘x’ is the end of the dino’s tail, and ‘o’ is the point between the legs. So if I rotate around ‘o’ it looks a bit more real. I’ve used Edward Angel’s book to see how to rotate around a point that is not the origin (see page 180-181 if you got it too). This is the code that is used:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(4.0, 5.0, 6.0);
glRotatef(45.0, 1.0, 2.0, 3.0);
glTranslatef(-4.0, -5.0, -6.0);

So first you translate, then rotate, and then translate back. This works if my dino (read pos ‘x’) is at the origin. So I do this:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(10.5, 0.0, 1.55);
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-10.5, 0.0, -1.55);

And it works if my dino is at the origin. But now the dino position is variable, so the dino is at (dino_pos[0], dino_pos[1], dino_pos[2]). I still need to rotate around the point (10.5, 0.0, 1.55), but when I want to translate it back to the correct position, it doesn’t work. Now it rotates around in circles, instead of rotating at the same point.

I’ve tried translating the dino back to (dino_pos[0] - 10.5, 0.0, dino_pos[2] - 1.55), and I’ve also tried to switch the signs, but nothing works.

I hope this makes the problem a bit clearer.

Can’t you just rotate around the origin, and then translate the dino back a little when you render?

What is moveDino() supposed to do in your program? If it changes the coordinates of the vertices from which you build your dino, then this is not the good way to move your dino. All the movement should be accomplished through glTransfer. The vertices from which you build your dino should be constant relatively to the point O. So the code should look something like this:

moveDino();

glPushMatrix();
glLoadIdentity();
glTranslatef(X,Y,Z);
// X,Y,Z calculated in moveDino.
glRotatef(angle,0.0,1.0,0.0);

drawDino();

glPopMatrix();

glFlush();

This way your Dino will be rotated round his legs and then displaced to the new point.

GA

The moveDino method should determine the new position of the dino and make sure it won’t fall of the earth. Right now it is not correct, because before the dino could only move in the x or z direction…

You might take a look at the following picture to see what it should look like…
http://www.nat.vu.nl/~pwgroen/cg/images/screen-dino.jpg

Below is my complete code…

#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>
#include <glutil.h>
#include <math.h>
#include <dino.h>
#include <readtex.h>

typedef GLfloat point3[3];

point3 dino_pos = {0.0, 0.0, 0.0};
point3 dino_dir = {0.0, 0.0, 0.0};

int move;
int current = 0;
int direction = 0;
int body = 1,
arm = 2,
leg = 3,
eye = 4;

GLfloat angle;
GLfloat left = 2.0;
GLfloat right = -2.0;
GLfloat floor_end = 100.0;

double camera[3] = {15.0, 15.0, 15.0}; /* The position of the camera /
double view[3] = {0.0, 0.0, 0.0}; /
Viewing position of the camera /
double up[3] = {0.0, 1.0, 0.0}; /
Up direction of the camera */

RGBImage *ground, *dino, *brick, rock; / The textures */

void init(void)
{
GLfloat mat_ambient[]={1.0,1.0,1.0,1.0};
GLfloat mat_diffuse[]={1.0,1.0,1.0,1.0};
GLfloat mat_specular[]={1.0,1.0,1.0,1.0};
GLfloat mat_shininess={100.0};
GLfloat light_ambient[]={0.0,0.0,0.0,1.0};
GLfloat light_diffuse[]={1.0,1.0,1.0,1.0};
GLfloat light_specular[]={1.0,1.0,1.0,1.0};
GLfloat light_position[]={0.0,150.0,150.0,1.0};

glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GLUT_RGB);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

glShadeModel(GL_SMOOTH);
glClearColor(0.611764705, 0.878431372, 0.964705882, 1.0);

glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);


#if defined(WIN32)
	ground = LoadRGB("/Courses 2000/Cg/resources/texture/ground.rgb");
	dino = LoadRGB("/Courses 2000/Cg/resources/texture/lez.rgb");
	brick = LoadRGB("/Courses 2000/Cg/resources/texture/brick.rgb");
	rock = LoadRGB("/Courses 2000/Cg/resources/texture/rock.rgb");
#else
	ground = LoadRGB("../../resources/texture/ground.rgb");
	dino = LoadRGB("../../resources/texture/lez.rgb");
	brick = LoadRGB("../../resources/texture/brick.rgb");
	rock = LoadRGB("../../resources/texture/rock.rgb");
#endif

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

MakeDino(&body, &arm, &leg, &eye);

glMatrixMode(GL_PROJECTION);			/* Setup the viewing volume */
glLoadIdentity();
//glOrtho(-200.0, 200.0, -200.0, 200.0, -200.0, 200.0);
//glFrustum(-150.0, 150.0, -150.0, /*150.0 * (GLfloat) height / (GLfloat) width*/ 150.0, 0.1, 50.0);
glOrtho(-150.0, 150.0, -150.0, 150.0, -150.0, 150.0);
glMatrixMode(GL_MODELVIEW);

}

void loadTexture(RGBImage *image)
{
glTexImage2D(GL_TEXTURE_2D, 0, image->components,
image->sizeX, image->sizeY,0, image->format,
GL_UNSIGNED_BYTE, image->data);
}

void drawFloor(void)
{
loadTexture(brick);

glDisable(GL_LIGHTING);

glBegin(GL_QUADS);
	glTexCoord2f(0.0, 0.0);
	glVertex3f(-floor_end, 0.0, -floor_end);
	glTexCoord2f(8.0, 0.0);
	glVertex3f(-floor_end, 0.0, floor_end);
	glTexCoord2f(8.0, 8.0);
	glVertex3f(floor_end, 0.0, floor_end);
	glTexCoord2f(0.0, 8.0);
	glVertex3f(floor_end, 0.0, -floor_end);
glEnd();

}

void drawBuildings(void)
{
}

void drawEnvironment(void)
{
drawFloor();
drawBuildings();

}

void drawEyes(void)
{
loadTexture(brick);
glCallList(eye);
}

void drawBody(void)
{
loadTexture(ground);
glTranslatef(0.0,0.0,-3.1);
glCallList(body);
}

void drawArms(void)
{
glTranslatef(0.0,0.0,-0.4);
glCallList(arm);
glTranslatef(0.0,0.0,-3.7);
glCallList(arm);
}

void drawLegs(void)
{
glTranslatef(0.0, 0.0, 1.7);
glCallList(leg);
glTranslatef(0.0,0.0,-4.2);
glCallList(leg);
}

void rotateDino(GLfloat rot)
{
if (angle >= 360.0)
angle -= 360.0;
else if (angle <= -360.0)
angle += 360.0;

angle += rot;

}

void moveDino(void)
{

/* Now we have to move the dino, and be sure the
 * dino won't fall off the earth
 */

if (current == 0) {		  /* moving along the x axis */
	if (direction &lt; 0) {  /* moving in the negative direction */

		if (dino_pos[current] - 12.3 &lt;= -floor_end) {
			current = 2;

			if (dino_pos[2] - 4.1 &lt;= -floor_end) {
				direction = 1;
				rotateDino(left);
				dino_pos[0] -= 8.2;
				dino_pos[current] -= 12.7;
				dino_pos[current] += 0.5;
			} else {
				direction = -1;
				rotateDino(right);
				dino_pos[0] -= 11.4;
				dino_pos[current] += 9.0;
				dino_pos[current] -= 0.5;
			}
		} else {
			dino_pos[current] -= 0.5;
		}
	} else {	/* direction &gt; 0 */
		if (dino_pos[current] + 12.3 &gt;= floor_end) {
			current = 2;

			if (dino_pos[current] + 4.1 &gt;= floor_end) {
				direction = -1;
				rotateDino(left);
				dino_pos[0] += 8.2;
				dino_pos[current] += 12.7;
				dino_pos[current] -= 0.5;
			} else {
				rotateDino(right);
				dino_pos[0] += 11.4;
				dino_pos[current] -= 9.0;
				dino_pos[current] += 0.5;
			}
		} else {
			dino_pos[current] += 0.5;
		}
	}
} else {	/* moving along the z axis */
	if (direction &lt; 0) {
		if (dino_pos[current] - 12.3 &lt;= -floor_end) {
			current = 0;

			if (dino_pos[0] + 4.1 &gt;= floor_end) {
				rotateDino(left);
				dino_pos[2] -= 8.2;
				dino_pos[current] += 12.7;
				dino_pos[current] -= 0.5;
			} else {
				direction = 1;
				rotateDino(right);
				dino_pos[2] -= 11.4;
				dino_pos[current] -= 9.0;
				dino_pos[current] += 0.5;
			}
		} else {
			dino_pos[current] -= 0.5;
		}
	} else {	/* direction &gt; 0 */
		if (dino_pos[current] + 12.3 &gt;= floor_end) {
			current = 0;

			if (dino_pos[0] - 4.1 &lt;= -floor_end) {
				rotateDino(left);
				dino_pos[2] += 8.2;
				dino_pos[current] -= 12.7;
				dino_pos[current] += 0.5;
			} else {
				direction = -1;
				rotateDino(right);
				dino_pos[2] += 11.4;
				dino_pos[current] += 9.0;
				dino_pos[current] -= 0.5;
			}
		} else {
			dino_pos[current] += 0.5;
		}
	}
}

}

void drawDino(void)
{
drawEyes();
drawBody();
drawArms();
drawLegs();
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();
gluLookAt(camera[0], camera[1], camera[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

drawEnvironment();

if (move)
	moveDino();

dino_pos[0] = 10.0;
dino_pos[2] = 15.0;

glPushMatrix();
glTranslatef(10.5, 0.0, 1.55);
glRotatef(angle, 0.0, 1.0, 0.0);
glTranslatef(-10.5, 0.0, -1.55);
glTranslatef(dino_pos[0], dino_pos[1], dino_pos[2]);

printf("[%04f], [%04f], [%04f]

", dino_pos[0], dino_pos[1], dino_pos[2]);

drawDino();
glPopMatrix();

glFlush();
glutSwapBuffers();

}

void reshape(int width, int height)
{
glViewport(0, 0, width, height);
}

void keyboard(unsigned char key, int posx, int posy)
{
if (tolower(key) == ‘q’)
exit(0);

if (key == '8')
	move = GL_TRUE;
else if (key == '4')
	rotateDino(left);
else if (key == '6')
	rotateDino(right);
else if (key == '2')
	move = GL_FALSE;

}

void passiveMouse(int posx, int posy)
{
}

void idle(void)
{
glutPostRedisplay();
}

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(750, 750);

glutCreateWindow(argv[0]);

init();

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glutPassiveMotionFunc(passiveMouse);
glutMainLoop();

return 0;

IMPORTANT NOTE: I think you must load identity after calling glPushMatrix in the function display().

Well, I understood from your program that MakeDino initializes some display lists that help in rebdering the whole dino. Now, these display lists contains primitives you loaded somewhere, and these primitives have coordinates. These coordinates are in respect to some origin other than between-the-legs. Now, you must recalculate these coordinates so that they are in respect to the between-the-legs point and use the code I mentioned before.

If I do that, the whole dino won’t even show up!

If you do what? Did you try to recalculate the coordinates of the dino’sprimitives so that they became in respect to the between-the-legs point. If you do so you won’t need to write:

glTranslatef(10.5, 0.0, 1.55)

and

glTranslatef(-10.5, 0.0, -1.55)

GA

Let’s see if I understand your problem correctly… The origin of your dinosaur is positined on the tail. You want it to rotate around the legs. Try something like this… Assume the following variables…
(X1, Y1, Z1) = world position you want to place the dinosaur
A = angle to rotate the dino
(X2, Y2, Z2) = Offset from the tail to the point between the legs.

Assuming those variables this SHOULD work.

glTranslatef(X1, Y1, Z1);
glRotatef(A, 0.0, 1.0, 0.0);
glTranslatef(X2, Y2, Z2);

The way matrix math works, you effectively do the last call first. (It’s one way of looking at it anyway.) That means the above code will first position your dino so that his feet are at the origin. The dino will be turned to the orientation you want, then the dino will be placed at the appropriate world position. Note that with this, the point between the feet is what will be positioned. If you want to position based on the tail again, just add the X2, Y2, Z2 offsets to that first glTranslate.

Also… it might just be easier to change the vertex data for your dino so that the origin is where you want, rather than the tail.

Thanx Deiussum!!
This works perfectly

No problem. Glad I could help.