Pedro Gonçalves
Pedro Gonçalves

Reputation: 121

Rotating object around itself

I have an object that I want to to move around using the following mechanic: the left and right arrows change its rotation and the up arrow increments its position. My problem is that I either can't rotate the object around itself, or I can't move it in the direction being looked at.

The draw function is as follows:

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(SCALE, SCALE, SCALE);
glTranslatef(x, 0, 0);
glRotatef(rotationZ, 0, 0, 1);
glTranslatef(-x, 0, 0);

// Draw the object...

glPopMatrix();

Key press detection code:

 case GLUT_KEY_UP:
        teclas.up = GL_TRUE;
        glutPostRedisplay();
        break;
case GLUT_KEY_LEFT:
        teclas.left = GL_TRUE;
        glutPostRedisplay();
        break;
case GLUT_KEY_RIGHT:
        teclas.right = GL_TRUE;
        glutPostRedisplay();
        break;

Timer function:

if (teclas.up) {
    x++;
}

if (teclas.left) {
    rotationZ++;
}
if (teclas.right) {
    rotationZ--;
}

glutPostRedisplay();

I've seen multiple threads about this, and I've tried changing the signal of the x variable but nothing seems to work.

Edit(solved):

I just changed the part of the Timer function that is responsible for the forward movement to this:

if (estado.teclas.up) {

    homer.x+= (float)cos(homer.rotationZ * M_PI / 180);
    homer.y+= (float)sin(homer.rotationZ * M_PI / 180);
}

And also, my Draw function:

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(SCALE, SCALE, SCALE);
glTranslatef(x, 0, 0);
glRotatef(rotationZ, 0, 0, 1);

// Draw the object...
glPopMatrix();

This way, the object always moves towards what it's facing

Upvotes: 1

Views: 851

Answers (1)

Swift - Friday Pie
Swift - Friday Pie

Reputation: 14589

This is a case of problem with Moving Reference Frame, those are the keywords. Unless you simulate physics of process as well, for OpenGL rendering all we have to worry about are the coordinates. Here we have the stationary reference frame, sometimes called a world frame (especially if observer is moving relative to it as well), and a moving reference frame (MRF )connected to object. MRF can have arbitrary rotation and translation relative to world frame, there are traditional ways how it is defined.

For example for Earth globe MRF defined as origin in center of Earth, positive X axis intersecting equator and 0 meridian, positive Z - north pole and Y is complementary to them. For static point on surface of earth (local geographic coordinates) it usually Y directed to zenith and positive Z - toward North in plane of horizon and positive X - toward east. In case of moving vehicle's the positive Y- or pitch axis always points to its left, and the positive Z- or yaw axis always points up, X - the roll axis is pointed straight forward. This one seem to match your case.

Regardless of axis specification, the rotation of vehicle is equivalent of changing matrix corresponding to it. Lets call it transformation matrix. In local coordinates vehicle speed v = {vx,0,0} is a vector collinear to positive X axis. But in world coordinates it is equal to

v' = M*v

where M is a transformation matrix of MRF. As v is change of coordinates per unit of time, then any translations should follow this formula too. There are two ways to solve this , if you're using legacy OpenGL, you have two options:

First: you would start with identity matrix and recreate all transforms in proper order.

  1. Set identity matrix.
  2. Translate by value required (in local cords)
  3. Apply rotations of vehicle
  4. Translate by values of last known position of vehicle.
  5. Either calculate new position of vehicle, knowing transforms, or read that value , by getting matrix from OpenGL (by glGetFloatv(GL_MODELVIEW_MATRIX, ptr)) and extracting offset from it.

Downside of this method is that you have to use functions of OpenGL,where each call of glTranslate or glRotate is creating another matrix that is getting multiplied with other (in opposite order). That's excess math operations and precision of them isn't brilliant either. It can get quite interesting in Chinese manner if you have several frames of reference, especially nested.

Second method is to do all matrix math yourself, for example using some math library like GLM (glm.h) and store matrix for each frame of reference, modifying or regenerating them when needed. You can supply matrix directly to OpenGL even in legacy mode by glLoadMatrix. If you worry about performance, you should know that all modern implementations are done that math on CPU anyway, GPUs do not work with matrix stack anymore, for long time. It can be found quickly by inspecting open-source implementations.

In case of modern, flexible pipeline you don't have glScale, glTranslate, glRotate available at all. Entire matrix stack is deprecated in OpenGL 3. You can do it only in second way, but in this case you would supply matrices to shader program through uniforms.

Upvotes: 1

Related Questions