Update up, forward, right vectors.

Started by
15 comments, last by haegarr 12 years, 11 months ago
I am trying to write my first game, and want to create a simple airplane / flight type of game. I have been brushing up on my vector math but am getting stuck. At this point I'm just working out some pseudocode so I can just get an airplane flying around the world. Here's the basic idea of what I am trying to do:

My airplane will start out flying level and I will be able to start with up, right, and forward/heading vectors. On each frame the plane will move along the forward vector to its new position. If the user inputs up/down the pitch will be affected by "n" degrees, and the same for left/right and the roll affecting the up vector. I am planning ahead for yaw, though I haven't worked out the user control yet.

So I am trying to figure out how I update the up/right/forward vectors based on the degree of rotation. I have found lots of information about how to calculate the axis or the angle of rotation. Perhaps I am going about this in a harder way than necessary, but I know how I want to use these vectors and am sure it will work once I figure out how to calculate the new vectors.

I am using Opengl (Android) and want to use the gluLookat function. It simply accepts values of eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ. Obviously I will need a new up vector here for each frame, and of course my airplane will not always be aligned with the world up vector. Calculating the other values I have solved, based on knowing the updated vector.

I will simplify my question to just one rotation. I have a forward, right, and up vector. I receive input to move pitch up and I know the number of degrees. My rotation axis is the right vector. Given the rotation axis and amount of rotation (in degrees), how do I find the new up & foward vectors?

Thanks in advance!
Advertisement
The 3 vectors together build up the basis of a rotation matrix. Using e.g. column vectors and the 4th component for the homogeneous coefficients, the first 3 column vectors of a rotation matrix are just the vectors you're looking for. So applying a (delta) rotation matrix onto a (orientation) rotation matrix will yield in another (orientation) rotation matrix where you can simply pick the resulting vectors from. In fact the whole thing is nothing else but rotating the current state of vectors to yield in the next state of vectors.

With a rotation axis and angle you have all parameters of the so-called axis/angle rotation representation. The internet (e.g. euclideanspace.com) tells about conversion, e.g. to a rotation matrix.
Thank you haegarr,

I will need to brush up on my matrices before I get going. Several of the sites that I found were leading me toward using rotation matrices and I guess I just was avoiding them. The opengl documentation is what has made me shy away from using matrices. I suppose I can setup a class for the matrix math similar to the one I am using for my 3d vectors.

So if I setup a rotation matrix do you know if I can just apply it to my code with an opengl call? I was looking at glMultimatrix and it seems like that may work. Or would it be better to just compute the matrices and extract the vectors, then use them in my code as I was already intending?

Well, I will get in some studying and probably test out both ways. I will report back if I have any serious struggles. Thanks again for your help.

So if I setup a rotation matrix do you know if I can just apply it to my code with an opengl call? I was looking at glMultimatrix and it seems like that may work. Or would it be better to just compute the matrices and extract the vectors, then use them in my code as I was already intending?

Provided it's arranged in memory the way OpenGL expects (that is, the data occupies a contiguous block of 16 elements and the elements of each basis vector appear consecutively), you can upload the matrix directly using glLoadMatrix*() or glMultMatrix*().
Thanks, I think I will try both to help me grasp how each will work, and decide which works best. Now I'm goong to read some more. I appreciate the help guys, thanks a lot.
Sorry, double post
Sorry, triple post
Well, I got the matrices figured out and was able to build some basic rotation matrices. I built one for each axis and they work when I call glMultimatrixf. I am still running into the same problem which is where my original question lies. Basically, if I were to say pitch up/down to start, everything works fine because my rotations are around the x axis. However, if I try to then roll, I rotate around the z axis. But the z axis is no longer the roll axis/vector, it is still the world z axis. From lots of reading I believe this is gimbal lock, which I understand to an extent.

So how do I update the actual forward/up/right vectors and rotate around them. I'm sure I can figure out the math behind it, once I know the right steps to take. Also, the matrices I used for rotation seem to be locked to rotate around the world axes. It seems I should be using a matrix that would rotate around an arbitrary axis. I'm just not sure if this would be the right solution, or if more is needed to update the vectors.
Here is a bit of the code I am using that I think should work. Maybe someone can tell what I am doing wrong. At this time I am just trying to draw my airplane, pop/push the matrix. Then rotate, draw the ground and sky. This way my airplane stays in the center and the world moves around. I have two matrices. One called mOrientMatrix, which stores the current orientation. The other is mArbRotMatrix, which is a rotation matrix for an arbitrary axis. The void setRotPitch() rotates by the angle (pitch/yaw) around the current vectors from the mOrientMatrix. Then the mOrientMatrix is updated with the values produced.

If I only make one rotation, the code works as expected. However, as soon as I make a second rotation the axis is incorrect. (For whichever comes last in the code, pitch or roll)

public class BARenderer implements Renderer {

private float[] mArbRotMatrix = new float[16];
private float[] mOrientMatrix = new float[16];

public static boolean moveLeft;
public static boolean moveRight;
public static boolean moveUp;
public static boolean moveDown;
private Context mContext;

private F22 F22;
private Ground Ground1;
private Sky Sky1;

private GL10 mGl;
private int frame;
private float pitch;
private float yaw;
private float roll;


public BARenderer(Context context) {
mContext = context;

Init();
}

public void Init() {

mOrientMatrix[0] = 1;
mOrientMatrix[1] = 0;
mOrientMatrix[2] = 0;
mOrientMatrix[3] = 0;

mOrientMatrix[4] = 0;
mOrientMatrix[5] = 1;
mOrientMatrix[6] = 0;
mOrientMatrix[7] = 0;

mOrientMatrix[8] = 0;
mOrientMatrix[9] = 0;
mOrientMatrix[10] = 1;
mOrientMatrix[11] = 0;

mOrientMatrix[12] = 0;
mOrientMatrix[13] = 0;
mOrientMatrix[14] = 0;
mOrientMatrix[15] = 1;

pitch = 0;
yaw = 0;
roll = 0;

}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mGl = gl;

gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW )
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glEnable(GL10.GL_BLEND);
gl.glEnable(GL10.GL_DITHER);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //Black Background
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing
gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do
gl.glEnable(GL10.GL_ALPHA_TEST);
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE);

gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
}


@Override
public void onDrawFrame(GL10 gl) {

if (gl == null)
return;

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

// Replace the current matrix with the identity matrix
gl.glLoadIdentity();

gl.glTranslatef(0, 0, -30);

//Plane
gl.glPushMatrix();

gl.glScalef(0.5f, 0.5f, 0.5f);

if(F22 != null)
F22.draw(mGl);

gl.glPopMatrix();


gl.glPushMatrix();

gl.glMultMatrixf(mOrientMatrix, 0);


//Ground

gl.glPushMatrix();

gl.glTranslatef(0, -100, 0);

if(Ground1 != null)
Ground1.draw(mGl);

gl.glPopMatrix();


//Sky
gl.glPushMatrix();

gl.glTranslatef(0, -1000, 0);

if(Sky1 != null)
Sky1.draw(mGl);

gl.glPopMatrix();
gl.glPopMatrix();


frame += 1;
speedframe += speed;

if (moveLeft){
roll += -0.1;
}

if (moveRight){
roll += 0.1;
}

if (moveUp){
pitch += 0.1;
}

if (moveDown){
pitch += -0.1;
}


setRotPitch(pitch, mOrientMatrix[0], mOrientMatrix[1], mOrientMatrix[2]);
mOrientMatrix = mArbRotMatrix;
setRotPitch(pitch, mOrientMatrix[8], mOrientMatrix[9], mOrientMatrix[10]);
mOrientMatrix = mArbRotMatrix;

}

public void setRotPitch(double angle, double x, double y, double z) {

double c = Math.cos(angle);
double s = Math.sin(angle);
double t = 1 - Math.cos(angle);

mArbRotMatrix[0] = (float) ((t*x*x) + c);
mArbRotMatrix[1] = (float) ((t*x*y) - (s*z));
mArbRotMatrix[2] = (float) ((t*x*y) + (s*y));
mArbRotMatrix[3] = 0;

mArbRotMatrix[4] = (float) ((t*x*y) + (s*z));
mArbRotMatrix[5] = (float) ((t*y*y) + c);
mArbRotMatrix[6] = (float) ((t*y*z) - (s*x));
mArbRotMatrix[7] = 0;

mArbRotMatrix[8] = (float) ((t*x*z) - (s*y));
mArbRotMatrix[9] = (float) ((t*y*z) + (s*x));
mArbRotMatrix[10] = (float) ((t*z*z) + c);
mArbRotMatrix[11] = 0;

mArbRotMatrix[12] = 0; // x movement
mArbRotMatrix[13] = 0; // y movement
mArbRotMatrix[14] = 0; // z movement
mArbRotMatrix[15] = 1;
}


}


Any suggestions?
I got it working now! There were two main problems with the code above. First the pitch/roll values were not needed to be added on every input. They should be =0.01f or =0 dependent on input. (not +=0.01f) The second problem was that I was making the mOrientMatrix = mArbRotMatrix, when I should have been multiplying them together. Though I had tried this, I finally realized that I had transposed my matrix multiplication, therefore getting incorrect values in return. Coupled with the first problem any time I tried a multiplied matrix I was getting very strange rotations. Once I fixed both of these everything fell into place. I actually ended up removing the two rotation on arbitrary axes, and used on combined matrix for rotation on x,y,z axes. I added a translation matrix and got that working as well. Finally I am able to fly around my world, even straight through the ground. I guess I am ready for some collision detection.

Thanks again for the pointing me in the right direction!

This topic is closed to new replies.

Advertisement