Get forward, right, up vectors from pitch, yaw, roll

Started by
6 comments, last by Ledneh 17 years, 7 months ago
I know this is probably a common question, and I'm sorry for having to ask it, but I really need the help--all my geometry/trig skills have completely failed me, as well as Google (which I never expected :( ). I'm building a camera for my engine. Right now the important bits look like this:

void CCamera::SetPos(float x, float y, float z)
{
	mXpos = x;
	mYpos = y;
	mZpos = z;

	mIsChanged = true;
}

void CCamera::SetPYR(float pitch, float yaw, float roll)
{
	mPitch = pitch;
	mYaw = yaw;
	mRoll = roll;

	mIsChanged = true;
}

void CCamera::Render()
{
	glLoadIdentity();
	glRotatef(-mPitch, 1, 0, 0); // +degrees = pitch up (move environ down, so to speak)
	glRotatef(mYaw, 0, 1, 0); // +degrees = yaw to right (move environ left)
	glRotatef(mRoll, 0, 0, 1); // +degrees = roll clockwise (rotate environ counterclockwise)
	glTranslatef(-mXpos, -mYpos, -mZpos);

	mIsChanged = false;
}
This works all well and dandy for now, but when I came to the point of moving forward/backward, strafing left/right, or floating up/down RELATIVE TO THE CAMERA'S ORIENTATION, I realized I was stymied without forward/right/up vectors. Unfortunately, the REASON I went with pitch/yaw/roll instead of forward/right/up is because I've completely forgotten how to calculate one from the other, and pitch/yaw/roll made the most sense to me mentally. Can anyone tell me how, using the camera's current position, pitch, yaw, and roll, I would be able to calculate a forward, right, and up vector? Thanks!
-=-=-=-=-=-=-=-"We are the Dyslexia of Borg. Your ass will be laminated. Futertility is resistant.""SWEET LADY FREEDOM! LET'S MAKE OUT!!"
Advertisement
Setting aside for the moment whether Euler angles are the best representation to use here, let's try to solve your problem. Looking at your code:
glRotatef(-mPitch, 1, 0, 0);glRotatef(mYaw, 0, 1, 0);glRotatef(mRoll, 0, 0, 1);
The first thing I would say is that it would be more conceptually correct to negate mYaw and mRoll in the above code as well as mPitch, and then adjust your code elsewhere to accomodate this. This is because you are in essence constructing the inverse of the camera object transform here, and each call to glRotatef() represents the inverse of the corresponding rotation matrix.

Anyway, going with what you have, the first step is to invert it:
glRotatef(-mRoll, 0, 0, 1);glRotatef(-mYaw, 0, 1, 0);glRotatef(mPitch, 1, 0, 0);
And we now see that you're using the Euler angle order XYZ, with angles mPitch, -mYaw, and -mRoll.

Next you need an Euler-angle-to-matrix conversion function that uses column-vector convention. To save you time, I'd recommend heading over to geometrictools.com and checking out the math code. IIRC the 3x3 matrix class includes functions for Euler angle conversion in every (non-repeating) order, and follow column-vector convention.

Once you've performed the conversion, the direction vectors you're looking for are simply the three columns of the matrix.

An alternative (and a somewhat inadvisable one) is to query the OpenGL modelview matrix immediately after you set it up using the code you posted, at which point the direction vectors will be the first three rows of this matrix (e.g. the side vector is matrix elements 0, 4, and 8). For various reasons though it would really be better to perform the calculations yourself.
Thanks for the response. You'll have to forgive my newbish response questions, but there are a lot of things I still don't know well enough here--kind of flying by the seat of my pants, more or less.

First off, why would having a Euler representation be a bad idea? Intuitively it seems to make the most logical sense, but if there's some important reason that I would use forward, right, and up normally instead of roll, pitch, and yaw, I'd like to hear it.

Also, are there any alternatives besides Euler and forward/right/up? Or are those the only practical ones?


Let's see, what else... oh yeah, why would it be an unadvisable idea to pull the forward, right, and up vectors out of the modelview and store them right after I set up the camera? To me that seems almost like an ideal solution.

Thanks for any further clarification you can provide! :)
-=-=-=-=-=-=-=-"We are the Dyslexia of Borg. Your ass will be laminated. Futertility is resistant.""SWEET LADY FREEDOM! LET'S MAKE OUT!!"
Quote:Original post by Ledneh
Thanks for the response. You'll have to forgive my newbish response questions, but there are a lot of things I still don't know well enough here--kind of flying by the seat of my pants, more or less.

First off, why would having a Euler representation be a bad idea? Intuitively it seems to make the most logical sense, but if there's some important reason that I would use forward, right, and up normally instead of roll, pitch, and yaw, I'd like to hear it.

Also, are there any alternatives besides Euler and forward/right/up? Or are those the only practical ones?


Let's see, what else... oh yeah, why would it be an unadvisable idea to pull the forward, right, and up vectors out of the modelview and store them right after I set up the camera? To me that seems almost like an ideal solution.

Thanks for any further clarification you can provide! :)
Quick answers:

Euler angles are fine for some types of motion, not for others. If it's doing what you want, then perhaps it's the right solution for you.

The real issue isn't so much Euler angles vs. other representations, but incremental rotation vs. 'from scratch' rotation (you're doing the latter). For completely free 6DOF motion you need the former, while the latter is perfectly satisfactory for an FPS or similar game.

As for other representations, rotation matrices and quaternions are the most common and useful.

Finally, it would certainly be a lot easier to pull the vectors directly from OpenGL than to write your own math library code or adapt someone else's, and if you just want to get it working it may be the way to go. However, doing your math via OpenGL is very limited and limiting, so sooner or later you'll need your own math code anyway, and this would be a good opportunity to get started on it :)
Quote:Original post by jyk
Quote:Original post by Ledneh
Thanks for the response. You'll have to forgive my newbish response questions, but there are a lot of things I still don't know well enough here--kind of flying by the seat of my pants, more or less.

First off, why would having a Euler representation be a bad idea? Intuitively it seems to make the most logical sense, but if there's some important reason that I would use forward, right, and up normally instead of roll, pitch, and yaw, I'd like to hear it.

Also, are there any alternatives besides Euler and forward/right/up? Or are those the only practical ones?


Let's see, what else... oh yeah, why would it be an unadvisable idea to pull the forward, right, and up vectors out of the modelview and store them right after I set up the camera? To me that seems almost like an ideal solution.

Thanks for any further clarification you can provide! :)
Quick answers:

Euler angles are fine for some types of motion, not for others. If it's doing what you want, then perhaps it's the right solution for you.

The real issue isn't so much Euler angles vs. other representations, but incremental rotation vs. 'from scratch' rotation (you're doing the latter). For completely free 6DOF motion you need the former, while the latter is perfectly satisfactory for an FPS or similar game.

As for other representations, rotation matrices and quaternions are the most common and useful.

Finally, it would certainly be a lot easier to pull the vectors directly from OpenGL than to write your own math library code or adapt someone else's, and if you just want to get it working it may be the way to go. However, doing your math via OpenGL is very limited and limiting, so sooner or later you'll need your own math code anyway, and this would be a good opportunity to get started on it :)


Ah, okay, I understand now. For now, yeah, 'from-scratch' rotation is what I need--for the game I have in mind, incremental rotations would be useful only for special effects, and I just plain don't have the time patience or expertise to worry about that yet to be honest.

As for the rest, hopefully this project won't be long or large enough to worry about running headlong into OpenGL math barriers anymore, but I guess we'll just have to see.

Thanks again for all your help :)
-=-=-=-=-=-=-=-"We are the Dyslexia of Borg. Your ass will be laminated. Futertility is resistant.""SWEET LADY FREEDOM! LET'S MAKE OUT!!"
*sigh* Well, turns out I don't have it all right. I'm tempted to scrap Euler angles altogether and rewrite the camera using position, forward, right, and up vectors--except I don't know the maths necessary to determine NEW forward, right, and up vectors as I slide around or (especially) change where I'm looking with the mouse.

According to what I could find the MODELVIEW has the current right vector as indices 0 1 and 2, up as 4 5 and 6, and out as 8 9 and 10, but no matter how I fiddle with the numbers my results get REALLY inconsistent once I try to change my pitch and yaw.

Any recommended reading on how I can figure out new forward, right, and up vectors (or even just forward and up, since right is a cross product of the two) when I want my orientation, etc. to change?

Thanks!
-=-=-=-=-=-=-=-"We are the Dyslexia of Borg. Your ass will be laminated. Futertility is resistant.""SWEET LADY FREEDOM! LET'S MAKE OUT!!"
Quote:Original post by Ledneh
Any recommended reading on how I can figure out new forward, right, and up vectors (or even just forward and up, since right is a cross product of the two) when I want my orientation, etc. to change?


My personal solution to this:
when I want to rotate Upwards for ex, I add .05(variable)* percent of the Up vector onto my Forward vector. This changes it's direciton slightly to be more 'upwards' but also makes it longer than normal.
To correct the changed length, I re-Normalize that vector.
There is also a new problem, the angle between Forward and Up is no longer 90.
To correct this I cross Forward and Right to get a new Up vector that matches the change.

For looking to the Right, I do a similar process, just with the roles reversed.
add a bit of Right onto Forward. Normalize, Cross to find new Right.

As long as all changes are small incremental changes(split them up if they're big!), it should look nice and smooth. (no need for quaternion rotations)


-A more 'Proper' Solution, is to actually use sin/cos and angles to calculate new direction vectors; via rotation transform/matrix. But I never use angle meaures anyway so for me this is more intuitive...
*Here rather than rotating by actual angles, you just tweak that variable to get different rotation speeds



P.S.
-dont read this section unless the above made sense-
You're probably wondering, if I never use actual angles for the rotations; how do I 'target' or 'lookat' an object?
Thats easy, take a vector from my character(or camera) to the target location.
Normalize that target direction.
Then Dot it agains the Up and Right vectors, to see the relative rotation needed for each axis.
Highly innacurate, but since limit our rotation speeds to something low and keep repeating this each update, it converges to point the right direction.
VICTOLY!

Once I realized I could ignore roll for purposes of my project, the maths got easier for calculating the three vectors straight from the Euler angles.

Check it

void CCamera::MoveForward(float l){	float fX, fY, fZ, mag;		// Calculate forward based on yaw and pitch	fX = sin(mYaw * DEG_2_RAD) * cos(mPitch * DEG_2_RAD);	fY = sin(mPitch * DEG_2_RAD);	fZ = -cos(mYaw * DEG_2_RAD) * cos(mPitch * DEG_2_RAD);	// Calculate magnitude, normalize	mag = sqrt(fX*fX + fY*fY + fZ*fZ);	fX /= mag; fY /= mag; fZ /= mag;	// Scale vector by movement distance	fX *= l; fY *= l; fZ *= l;		//cout << "Vel = " << sqrt(fX*fX + fY*fY + fZ*fZ) << endl;	// Add new components to current location to get new destination	mXpos += fX; mYpos += fY; mZpos += fZ;	mIsChanged = true;}void CCamera::MoveUp(float l){	float fX, fY, fZ, mag;		// Calculate up based on yaw and pitch	fX = sin(mYaw * DEG_2_RAD) * cos((mPitch+90) * DEG_2_RAD);	fY = sin((mPitch+90) * DEG_2_RAD);	fZ = -cos(mYaw * DEG_2_RAD) * cos((mPitch+90) * DEG_2_RAD);	// Calculate magnitude, normalize	mag = sqrt(fX*fX + fY*fY + fZ*fZ);	fX /= mag; fY /= mag; fZ /= mag;	// Scale vector by movement distance	fX *= l; fY *= l; fZ *= l;		//cout << "Vel = " << sqrt(fX*fX + fY*fY + fZ*fZ) << endl;	// Add new components to current location to get new destination	mXpos += fX; mYpos += fY; mZpos += fZ;	mIsChanged = true;}void CCamera::MoveRight(float l){		float fX, fY, fZ, mag;		// Calculate right based on yaw (pitch is irrelevant)	fX = sin((mYaw+90) * DEG_2_RAD);// * cos(mPitch * DEG_2_RAD);	//fY = sin(mPitch * DEG_2_RAD);	fY = 0;	fZ = -cos((mYaw+90) * DEG_2_RAD);// * cos(mPitch * DEG_2_RAD);	// Calculate magnitude, normalize	mag = sqrt(fX*fX + fY*fY + fZ*fZ);	fX /= mag; fY /= mag; fZ /= mag;	// Scale vector by movement distance	fX *= l; fY *= l; fZ *= l;		//cout << "Vel = " << sqrt(fX*fX + fY*fY + fZ*fZ) << endl;	// Add new components to current location to get new destination	mXpos += fX; mYpos += fY; mZpos += fZ;	mIsChanged = true;}


Thanks for all your help, folks :)
-=-=-=-=-=-=-=-"We are the Dyslexia of Borg. Your ass will be laminated. Futertility is resistant.""SWEET LADY FREEDOM! LET'S MAKE OUT!!"

This topic is closed to new replies.

Advertisement