HPR camera system

Hi, I have problems implementing a Heading/pitch/Roll Camera system.
I do not want to use the gluLookAt but just transformation matrices. Can anyone tell me the correct order?
Here is my code:

glLoadIdentity();
glRotatef(camR,0,0,-1);
glRotatef(camH,0,-1,0);
glRotatef(camP,-1,0,0);
glTranslatef(-camX,-camY,-camZ);


// Drawing an object
glPushMatrix();
glTranslatef(tx,ty,tz);
glRotatef(rz,0,0,1);
glRotatef(ry,0,1,0);
glRotatef(rx,1,0,0);
DrawObject();
glPopMatrix();

The above code gets weird effects when the heading is between 90-270 meaning that when I increase the pitch the camera turns down when it should turn up

pleaseeeeeeeee help!!!

Well from the way it looks, the reason why the camera rotates the other way is because the direction parameter is -1 not 1 which means to do the opposite of.

cwhite40

No it is not the problem. When the viewing frustum of the camera has turned right you must turn your objects left and thats why -1 is placed instead of 1.

Maybe this’ll work better…

glLoadIdentity();
glRotatef(camR,0,0,-1);
glRotatef(camP,-1,0,0);
glRotatef(camH,0,-1,0);
glTranslatef(-camX,-camY,-camZ);

To think of this in words… first you translate the world into the camera center, then you rotate the world to the heading of the camera, now that the camera is heading down the z axis of the world you rotate the world around the X axis (pitch), and now that the camera is completely facing down the Z axis, you rotate around the Z axis (roll).

The solution to the problem is by using quaternions.
HPR rotation values must be transformed into a quaternion so that its values can be passed to a single glRotatef(…).
The problem I describe is called gimber lock. If anyone has any idea on how to do the quaternion transformation please tell.

It depends on what you are doing, you have not said what this is for. The problem you described above, sounds like you what I posted should change its behavior.

Mostly quaternions are used for interpolation, if you are doing animation that you extracted from an editor/animation program like 3d studio max or lightwave, because their respective APIs might give you data that gives you 0 instead of 360 causing the animation to swing 360 degrees. What I mean to say is that when dealing with interpolation between diffrent orientations, quaternions help.

If you are doing an first person game, where the player directly controls the heading and pitch of the camera (via the mouse or arrow keys), then what I posted should work fine. If you are making a flight simulator then heading pitch and roll have diffrent meanings as they are relative to the objects orientation and not the world orientation and you will have problems with gimble lock, in which you can find information at…
http://www.gamedev.net/reference/programming/features/whyquats/
http://www.gamasutra.com/features/programming/19980703/quaternions_01.htm

Also what would probably be a little bit easier to do is to look at Nvidias code for their quaternions…
http://www.nvidia.com/Marketing/Develope…moSrcShared.zip

Out of curiousity what is this for? Flight simulator or FPS game? Despite the information available, if you are working on a flight simulator your still going to have some trouble in dealing with this, as you have to apply transformation to a quaternion versus simply converting it to a quaternion wont do.

Thanks for the info. I’ll check it out.
I am developing a 3d engine and I want to make a generic camera for the engine. The HPR values are used to set the whole world transformation matrix so that ALL objects are translated and rotated according to my camera. I just want to implement the opengl part of the camera, just like using the gluLookAt() func (with which I had problems).
The camera could be used for first person or third person games. It is of generic use. All I want is to be able to rotate the whole world by -camH,-camR,-camP and the gimber lock might appear on several cases.

You might take a look at my engine at http://utopia3d.sourceforge.net

I am almost rewritting the engine from sratch so the code in the web is quite obsolete.

I am like, 3 weeks into OpenGL programming.
My first little project was a first person spaceship
flying around a small solar system.

I used heading pitch roll and ran into exactly the
problems you’re having. I switched to quaternions
and all was better.

Here are the functions I use… when the user
presses on the joystick, I multiply the current
orientation (represented as a quaternion) with
a new quaternion representing the desired
oreintation change. When I go to render,
I turn the quat to a matrix and multiply it to the
modelview.

Caveat: as I said, I’m 3 weeks into OpenGL programming, so take everything “cum grano salis”

Hope this helps

/*

  • Multiply two quaternions
  • res is a*b
  • Assumes a and b are normalised
  • res is normalised on return
    */
    void QUAT_Mult(const QUAT *a, const QUAT *b, QUAT res)
    {
    /
    Result is [ ww’ - v.v’, v X v’ + wv’ + v’w ] */

/* Temp */
float t[8];
float norm;

t[0] = (a->w + a->x) * (b->w + b->x);
t[1] = (a->z - a->y) * (b->y - b->z);
t[2] = (a->x - a->w) * (b->y + b->z);
t[3] = (a->y + a->z) * (b->x - b->w);
t[4] = (a->x + a->z) * (b->x + b->y);
t[5] = (a->x - a->z) * (b->x - b->y);
t[6] = (a->w + a->y) * (b->w - b->z);
t[7] = (a->w - a->y) * (b->w + b->z);

res->w = t[1] + ((-t[4] - t[5] + t[6] + t[7]) * 0.5f);
res->x = t[0] - (( t[4] + t[5] + t[6] + t[7]) * 0.5f);
res->y = -t[2] + (( t[4] - t[5] + t[6] - t[7]) * 0.5f);
res->z = -t[3] + (( t[4] - t[5] - t[6] + t[7]) * 0.5f);

/* Normalise result */
norm = sqrt(res->w * res->w +
res->x * res->x +
res->y * res->y +
res->z * res->z);

res->w /= norm;
res->x /= norm;
res->y /= norm;
res->z /= norm;
}

/*

  • Quaternion to matrix
  • Converts quaternion q into a matrix returned in m.
  • m is in GL format (i.e. row-major format)
  • Assumes q is normalised.

*/
void QUAT_ToMatrix(const QUAT *q, float m[16])
{
float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;

x2 = q->x + q->x;
y2 = q->y + q->y;
z2 = q->z + q->z;

xx = q->x * x2; xy = q->x * y2; xz = q->x * z2;
yy = q->y * y2; yz = q->y * z2; zz = q->z * z2;
wx = q->w * x2; wy = q->w * y2; wz = q->w * z2;

/* The following commented out stuff returns the matrix in
column-major format /
/

m[0] = 1.0f - (yy + zz); m[1] = xy - wz;
m[2] = xz + wy; m[3] = 0.0f;

m[4] = xy + wz; m[5] = 1.0f - (xx + zz);
m[6] = yz - wx; m[7] = 0.0f;

m[8] = xz - wy; m[9] = yz + wx;
m[10] = 1.0f - (xx + yy); m[11] = 0.0f;

m[12] = 0.0f; m[13] = 0.0f;
m[14] = 0.0f; m[15] = 1.0f;
/
/
This code returns the matrix in row-major format */
m[0] = 1.0f - (yy + zz); m[4] = xy - wz;
m[8] = xz + wy; m[12] = 0.0f;

m[1] = xy + wz; m[5] = 1.0f - (xx + zz);
m[9] = yz - wx; m[13] = 0.0f;

m[2] = xz - wy; m[6] = yz + wx;
m[10] = 1.0f - (xx + yy); m[14] = 0.0f;

m[3] = 0.0f; m[7] = 0.0f;
m[11] = 0.0f; m[15] = 1.0f;
}

My engine, does not have fixed transformations for all objects, instead I allow objects to have diffrent transformations in any order they need to be in. It includes quaternions for rotation. This also includes cameras and lights, so that I may use diffrent methods of controling them, so that I can easily create orbiting cameras for a 3d editor, a camera attached to a character in an FPS game, or a camera attached to a space ship. This also allows me to control transformations for physics. I have 2 diffrent types of transformations, local/leaf transformations and branch transformations, local transformations can be the basic transformations (scaling rotating translating) or it can also be a morph transformation using morph targets or a bone transformation using bone objects.

I only use quaternions for animations, currently, I plan to use it more. But in reading about what you want to do, gimble lock would not be solved by simpling changing your current usage of HRP to quaternions, as all that is being done is conversion. Try out the changes to the OpenGL code I suggested earlier, the only place you will notice something weird is when you are looking straight down and heading rotations are the same as roll rotations. Since you’re not working on a space/flight simulator, there is little reason to use quaternions in that case, you will need it in the future when you start expanding what your engine could do though, but by that time you will need to implement diffrent transformations and diffrent orders in which to apply them. Good luck.

Ok, I will give it a try.
Thank you all for your support and the “free” code on quaternions.