Original Post
Hey GameDev! I'm having some trouble figuring out how yawing and pitching my camera in 3d works and I was wondering if anyone could help me out. Over the last two, three days I've been trying out all sorts of matrix multiplications and stuff, but I can't seem to find the right order of multiplification. Forgive me for posting these elaborate pieces of code, but I thought it to be better than having to explain this to you without examples. This is what I currently have: A Frame class. Represents an orientation and location in 3d space: A Camera class. Derived from Frame. First I used Frame for the camera orientation, but I got to the conclusion I had to store the yaw, pitch and roll in seperate variables, and then rebuild that camera orientation each frame. Could anyone tell me if this is correct? Then, when the mouse moves horizontal or vertical, I give calls to respectively Camera::Yaw() and Camera::Pitch(), functions that both add fAngle to the corresponding member. Nothing more. When the rendering starts, I give a call to Camera::Compute(): Frame::Yaw() and Frame::Pitch() are both computed in local space, but since the forward and up vector are set back to initial values, Yaw is calculated as if global. Then, after we've turned horizontally, we can turn vertically from that position; pitching. At least, that's my train of thought, but apparently I'm doing something wrong. Then, at last, this function is called with the camera class as argument: Oh, and of course, the actual problem is that, yawing and pitching seperately work fine, but when I combine these two, the orientation starts doing weird things, as if I'm also rolling or something like that. I'm sure this kind of question has been asked before, but I can't seem to get it work with the information I could find on the internet. Thanks for helping out, - Stijn Frishert [Edited by - stenny on February 28, 2009 5:36:46 AM]
class Frame
{
public:
Vector3f vLocation;
Vector3f vForward;
Vector3f vUp;
Frame();
Matrix44f GetMatrix();
void Move(const float fX, const float fY, const float fZ);
void MoveX(const float fDelta);
void MoveY(const float fDelta);
void MoveZ(const float fDelta);
void Rotate(float fYaw, float fPitch, float fRoll);
void Yaw(float fAngle);
void Pitch(float fAngle);
void Roll(float fAngle);
};
class Camera : public Frame
{
public:
float fYaw, fPitch, fRoll;
Camera();
void Yaw(float fAngle);
void Pitch(float fAngle);
void Roll(float fAngle);
void Compute(); // Computes the orientation
};
void Camera::Compute()
{
// Reset the orientation
vForward.x = 0.0f;
vForward.y = 0.0f;
vForward.z = -1.0f;
vUp.x = 0.0f;
vUp.y = 1.0f;
vUp.z = 0.0f;
// AND THIS IS WHERE I THINK THINGS GO WRONG.
Frame::Yaw(fYaw);
Frame::Pitch(fPitch);
}
// More functions down there \/
void Frame::Yaw(float fAngle)
{
// Switch to radians
fAngle /= DEG_TO_RAD;
// Calculate the rotation matrix
Matrix44f m = MatrixRotation(fAngle, vUp.x, vUp.y, vUp.z);
// Rotate the Forward vector
vForward.x = m(0, 0) * vForward.x + m(1, 0) * vForward.y + m(2, 0) * vForward.z;
vForward.y = m(0, 1) * vForward.x + m(1, 1) * vForward.y + m(2, 1) * vForward.z;
vForward.z = m(0, 2) * vForward.x + m(1, 2) * vForward.y + m(2, 2) * vForward.z;
vForward.Normalize();
}
void Frame::Pitch(float fAngle)
{
// Calculate the right vector
Vector3f vRight = CrossProduct(vUp, vForward);
// Convert the angle to radians
fAngle /= DEG_TO_RAD;
Matrix44f m = MatrixRotation(fAngle, vRight.x, vRight.y, vRight.z);
vForward.x = m.f[0] * vForward.x + m.f[4] * vForward.y + m.f[8] * vForward.z;
vForward.y = m.f[1] * vForward.x + m.f[5] * vForward.y + m.f[9] * vForward.z;
vForward.z = m.f[2] * vForward.x + m.f[6] * vForward.y + m.f[10] * vForward.z;
vForward.Normalize();
vUp.x = m.f[0] * vUp.x + m.f[4] * vUp.y + m.f[8] * vUp.z;
vUp.y = m.f[1] * vUp.x + m.f[5] * vUp.y + m.f[9] * vUp.z;
vUp.z = m.f[2] * vUp.x + m.f[6] * vUp.y + m.f[10] * vUp.z;
vUp.Normalize();
}
inline Matrix44f MatrixRotation(float fAngle, float x, float y, float z)
{
// Calculate the sinus and cosinus of the angle
float s = sin(fAngle);
float c = cos(fAngle);
float onemc = 1 - c;
// Create the matrix
Matrix44f n;
// Fill in the data - GOT THIS CODE FROM THE INTERNET, CAN'T REMEMBER SOURCE
n.f[0] = x*x + (1 - x*x) * c;
n.f[1] = x*y * onemc + z*s;
n.f[2] = x*z * onemc - y*s;
n.f[3] = 0.0f;
n.f[4] = y*x * onemc - z*s;
n.f[5] = y*y + (1 - y*y) * c;
n.f[6] = y*z * onemc + x*s;
n.f[7] = 0.0f;
n.f[8] = z*x * onemc + y*s;
n.f[9] = z*y * onemc - x*s;
n.f[10] = z*z + (1 - z*z) * c;
n.f[11] = 0.0f;
n.f[12] = 0.0f;
n.f[13] = 0.0f;
n.f[14] = 0.0f;
n.f[15] = 1.0f;
// Return the matrix
return n;
}
void GraphicsUnit::ApplyFrame(Frame& Frame)
{
gluLookAt(Frame.vLocation.x, Frame.vLocation.y, Frame.vLocation.z,
Frame.vLocation.x + Frame.vForward.x, Frame.vLocation.y + Frame.vForward.y, Frame.vLocation.z + Frame.vForward.z,
Frame.vUp.x, Frame.vUp.y, Frame.vUp.z);
}