Camera Rotation

Started by
10 comments, last by haegarr 12 years, 6 months ago
[font=arial, verdana, tahoma, sans-serif][size=2]Hey guys, I've currently got a camera class, and I can't get it to rotate properly.

Currently I'm rotate my camera by it's Up, Right, and Forward axis. But when I rotate the camera it is doing a very strange rotation, almost like it's rotating around the orgin. Here is my basic setup:




//////////////////////////////////////////////////////////////////////////
// TranslateCamera
void
TCCamera::TranslateCamera( TCVector3F vector )
{
mEye.X = mEye.X + vector.X;
mEye.Y = mEye.Y + vector.Y;
mEye.Z = mEye.Z + vector.Z;

UpdateViewMatrix();
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// RotateCameraLocalX
void
TCCamera::RotateCameraLocalX( f32 rotationValue )
{
TCMatrixF rotationMatrix;

// Create our rotation matrix.
rotationMatrix.MakeAxisAngle( mRight, rotationValue );

// Transform our Up and our Forward
mUp = rotationMatrix.TransformVector( mUp );
mForward = rotationMatrix.TransformVector( mForward );

// Reconstruct our matrix
UpdateViewMatrix();
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// RotateCameraLocalY
void
TCCamera::RotateCameraLocalY( f32 rotationValue )
{
TCMatrixF rotationMatrix;

// Create our rotation matrix.
rotationMatrix.MakeAxisAngle( m_matViewMatrix.YAxis, rotationValue );

// Transform our Up and our Forward
mRight = rotationMatrix.TransformVector( mRight );
mForward = rotationMatrix.TransformVector( mForward );

// Reconstruct our matrix
UpdateViewMatrix();
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// RotateCameraLocalZ
void
TCCamera::RotateCameraLocalZ( f32 rotationValue )
{
TCMatrixF rotationMatrix;

// Create our rotation matrix.
rotationMatrix.MakeAxisAngle( mForward, rotationValue );

// Transform our Up and our Forward
mRight = rotationMatrix.TransformVector( mRight );
mUp = rotationMatrix.TransformVector( mUp );

// Reconstruct our matrix
UpdateViewMatrix();
}
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// UpdateViewMatrix
void
TCCamera::UpdateViewMatrix()
{
TCMatrixF translation;

// Normalize our forward
mForward.Normalize();

// Calculate our right axis
mRight = CrossProduct( WorldUpVector, mForward );
mRight.Normalize();

// Calculate our up axis
mUp = CrossProduct( mForward, mRight );
mUp.Normalize();

// Set our axis
m_matViewMatrix.XAxis = mRight;
m_matViewMatrix.YAxis = mUp;
m_matViewMatrix.ZAxis = mForward;

// Recalculate our translation
m_matViewMatrix.Translation.MakeZero();
translation.MakeIdentity();
translation.Translation = mEye;
m_matViewMatrix = m_matViewMatrix * translation;

// Get our View Proj
m_matViewProjectionMatrix = m_matViewMatrix * m_matProjectionMatrix;
}
//////////////////////////////////////////////////////////////////////////




Do you guys see anything terribly off? And I understand there are other option to doing this, such as Quaternions, and there are inherit issue involving Gimbal Lock, but I'd like to get this working, then attempt a quaternion solution. Also I wrote ( re: googled and copied the formula ) for the math functions.[/font]
Perception is when one imagination clashes with another
Advertisement
// Create our rotation matrix.
rotationMatrix.MakeAxisAngle( mRight, rotationValue );


What does that code mean to do? Rotate on the cameras current x axis? or the global x axis? One thing you can do is take the current
camera matrix and apply your newest matrix first:

Perform rotation locally on the cameras current x-axis:
NewMatrix = OldMatrix*XRotation; (xrotation applied first so it will effectively rotate on the cameras x-axis, and not the global x).

Perform rotation locally on the cameras current x-axis again.
NewMatrix = OldMatrix*XRotation;

No matter what OldMatrix is, XRotation will rotate on the cameras local x-axis whichever way it is currently pointing.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Thanks for you reply :)

That will create an Axis Angle matrix built with mRight and the rotation value. Its so I can rotate around my local right axis.

And I'm a little confused by what you mean, do I multiply my current view matrix with my right axis? (In this example)
And then do it again?
That seems a little off.

I tried it, but it streched the geometry...
Perception is when one imagination clashes with another
The point is that if you wouldn't store the 3 columns of the cameras rotation matrix as three separate vectors (right/up/forward) you could just apply a straightforward rotation around (1,0,0) and it would ALREADY use your local "right" (or the global right, if you switch the order of your matrix multiplication).

Two things: where are you inverting your viewMatrix? What you call viewMatrix is just the cameras transformation which is not doing what it is supposed to do (transform the world in the _opposite_ way).

In fact, it seems rather redundant and pointless to store the misnamed transformation matrix AND each column as a vector.

Also, matrix multiplication is applied right to left. While nobody can stop you from imlpementing yours the other way, it is going to confuse the heck out of anyone looking at your code.

What one would expect it to look like is more like

//rotate around camera right
camTransformation = rotationMatrix(1,0,0, angle) * camTransformation;

//move along world x
camTransformation = camTransformation * translationMatrix(10,0,0); //Sure, it's somewhat overkill compared to matrix.m(3,0) += 10

viewProjectionMatrix = projectionMatrix * camTransformation.inverse();
f@dzhttp://festini.device-zero.de
[color=#1C2837][size=2]Two things: where are you inverting your viewMatrix? What you call viewMatrix is just the cameras transformation which is not doing what it is supposed to do (transform the world in the _opposite_ way).[/quote]
[color="#1c2837"]I assume he already took into account for this. If not, then all your rotations should be negative to the actual rotation on the camera OR just compute the final thing and invert it.
[color="#1c2837"]

[color="#1c2837"]

[color=#1C2837][size=2]//rotate around camera right
camTransformation = rotationMatrix(1,0,0, angle) * camTransformation;
[color=#1C2837][size=2][/quote]
[color=#1C2837][size=2]He means this:
[color=#1C2837][size=2]camTransformation = camTransformation*[color=#1C2837][size=2]rotationMatrix(1,0,0, angle)[color=#1C2837][size=2];
[color=#1C2837][size=2]

[color=#1C2837][size=2]Local has to be first, your new matrix is on the x-local axis of your camera, then you can apply the same matrix you had before.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal


[color="#1c2837"]

[color="#1c2837"]//rotate around camera right
camTransformation = rotationMatrix(1,0,0, angle) * camTransformation;
[color="#1c2837"]

[color="#1c2837"]He means this:
[color="#1c2837"]camTransformation = camTransformation*[color="#1c2837"]rotationMatrix(1,0,0, angle)[color="#1c2837"];
[color="#1c2837"]
[color="#1c2837"]Local has to be first, your new matrix is on the x-local axis of your camera, then you can apply the same matrix you had before.
[/quote]

No, I didn't. Matrix multiplication applies transformations right to left and the rotation is supposed to be applied _after_ the existing transformation. Applying the rotation first would use the worlds x-axis and not the objects x-axis.
f@dzhttp://festini.device-zero.de
Right, assuming the camera in local space IS the global access (which it is, the identity matrix for the camera is the world axis), then you would be rotating on the world x-axis which is also the cameras x-axis. Rotations are always by a global vector, you gave the global x-axis as that vector, so by givign 1,0,0 you are rotating by the global x axis and not the local camera anyway. You must always do local matrices first, rotating on the camera's x = camera x = local. If he wants to compute the cameras x in world space, then he can do that, but its not going to be a rotation about 1,0,0 (the global x-axis), it would be a global rotation about the cameras world x vector which is always changing and obviously is not 1,0,0 all the time. If you stay locally and apply it after the identity, the camera and world x-axis = 1,0,0, so if you apply it on the right hand side, any x-rotation can be about 1,0,0 (locally to the camera), and then just apply the current camera matrix.

To the original question, probably going to need to see a video or something, or more code.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Hey guys, sorry it's taken me so long to respond,

I found out the issue, it was an issue with the order that I was multiplying my rotation matrices.

Thanks for the help though guys!
Perception is when one imagination clashes with another

Right, assuming the camera in local space IS the global access (which it is, the identity matrix for the camera is the world axis), then you would be rotating on the world x-axis which is also the cameras x-axis. Rotations are always by a global vector, you gave the global x-axis as that vector, so by givign 1,0,0 you are rotating by the global x axis and not the local camera anyway.


You seem to be missing the point. Building a rotation matrix around axis (1,0,0) is not specifying a space at all unless you give it context in the form of the matrix you multiply it WITH. By applying this rotation to the objects matrix, you ALWAYS use that spaces x-axis which is the objects "right". Applying the objects transformation to the rotation matrix will in turn first rotate using the identity (world space) and effectively rotate the object around the global x-axix.

I was pretty much pointing out that it is completely unnecessary to ever extract the objects local axis for a rotation around that (cardinal) axis, because of how matrix multiplication works out.

You must always do local matrices first[/quote]

Please define how matrices can be local or global.

If he wants to compute the cameras x in world space, then he can do that[/quote]

If he wants to simply _know_ the cameras x in world space he will simply look at the first column of his cameras transformation matrix. But extracting that, then invest extra effort to build a generic rotation matrix and rotate around that global axis is utterly silly when you could just rotate around (1,0,0) without screwing up the multiplication order.

Again, a rotation matrix around (1,0,0) _has no space_. It will be using the space described by the matrix it is applied to and always uses that spaces x-axis.

That's also exactly what you see in OpenGL when using glRotate. Using glRotate(angle, 1,0,0) will always rotate around the objects current "right". Of course confused people and even teachers who insists on always thinking in global space then will tell students nonsense like "all OpenGL transformations are applied in reverse order" which causes tons of head ache in combination with push/push and tracing transformations over several function calls. In fact, since OpenGL was hiding all the matrix math from the user and didn't allow swapping the multiplication order (at least not without glLoadMatrix and glMultMatrix) using glRotate to rotate around a global axis is extra work and requires to use the axes of the inverted transformation matrix.

About the original issue, I already pointed out a few strange things. Assuming that his matrix multiplication is not implemented backwards two obvious bugs are:

-viewmatrix is never inverted
-projection matrix is applied before view transformation
-what about the objects OWN transformation... the order to apply them is view -> model -> projection, so the multiplication is projectionMatrix * modelMatrix * viewMatrix (unless non of your objects ever move or rotate or you do something ridiculously inefficient like recalculating all objects geometry by hand).
f@dzhttp://festini.device-zero.de
What I'm getting at is if you have some camera or say airplane with some matrix, and you want to rotate by its x-vector (IE pull the joystick up or down), then you start with the identity matrix. If your object is exported aligned with the xyz global axis, then you can simply rotate on the x (which if currently the identity the x of the plane and x of the world match). After that you can apply your previous matrix that said the airplane was upside down pointing in this random direction. So you are in the identity space (local)first, apply the x-rotation (locally), then apply the old global matrix that you had.


Using glRotate(angle, 1,0,0) will always rotate around the objects current "right". Of course confused people and even teachers who insists on always thinking in global space
[/quote]

What if that objects x axis = 0,1,0. Calling rotate around the vector (1,0,0), is going to rotate around the x-axis of the world, not the y-axis. the objects "right" is currently the y-axis. It is constantly changing.


But his problem is solved. And view matrix doesnt need to be inverted, he could be sending negative angles anyway. So I have camera x_angle, and I just pass -x_angle to compute my matrices.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

This topic is closed to new replies.

Advertisement