Sign in to follow this  
Seabolt

Camera Rotation

Recommended Posts

[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:

[code]


//////////////////////////////////////////////////////////////////////////
// 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;
}
//////////////////////////////////////////////////////////////////////////

[/code]


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.[/size][/font]

Share this post


Link to post
Share on other sites
// 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.

Share this post


Link to post
Share on other sites
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...

Share this post


Link to post
Share on other sites
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();

Share this post


Link to post
Share on other sites
[quote][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][/size][/color]
[size="2"][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][/size]
[size="2"][color="#1c2837"]
[/color][/size]
[size="2"][color="#1c2837"][quote][/color][/size]
[color=#1C2837][size=2]//rotate around camera right
camTransformation = rotationMatrix(1,0,0, angle) * camTransformation;[/size][/color]
[color=#1C2837][size=2][/quote][/size][/color]
[color=#1C2837][size=2]He means this:[/size][/color]
[color=#1C2837][size=2]camTransformation = camTransformation*[/size][/color][color=#1C2837][size=2]rotationMatrix(1,0,0, angle)[/size][/color][color=#1C2837][size=2];[/size][/color]
[color=#1C2837][size=2]
[/size][/color]
[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.[/size][/color]

Share this post


Link to post
Share on other sites
[quote name='dpadam450' timestamp='1318866196' post='4873492']
[size="2"][color="#1c2837"][quote][/color][/size]
[color="#1c2837"][size="2"]//rotate around camera right
camTransformation = rotationMatrix(1,0,0, angle) * camTransformation;[/size][/color]
[color="#1c2837"][size="2"][/quote][/size][/color]
[color="#1c2837"][size="2"]He means this:[/size][/color]
[color="#1c2837"][size="2"]camTransformation = camTransformation*[/size][/color][color="#1c2837"][size="2"]rotationMatrix(1,0,0, angle)[/size][/color][color="#1c2837"][size="2"];[/size][/color]
[color="#1c2837"] [/color]
[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.[/size][/color]
[/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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
[quote name='dpadam450' timestamp='1318876834' post='4873575']
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.[/quote]

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.

[quote]You must always do local matrices first[/quote]

Please define how matrices can be local or global.

[quote]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).

Share this post


Link to post
Share on other sites
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.

[quote]
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.

Share this post


Link to post
Share on other sites
[quote name='dpadam450' timestamp='1318918244' post='4873773']
[quote]
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.
[/quote]

Calling glRotate always rotates around the current local x-axis.

[url="http://www.opengl.org/resources/faq/technical/transformations.htm"]http://www.opengl.or...sformations.htm[/url]
[quote]
If you rotate an object around its Y-axis, you'll find that the X- and Z-axes rotate with the object. A subsequent rotation around one of these axes rotates around the newly transformed axis and not the original axis. It's often desirable to perform transformations in a fixed coordinate system rather than the object’s local coordinate system.
[/quote]

My mistake was tricking myself by changing the order in my rotate functions. So the corrected version is this:

Matrix multiplication is happening right-left, but _only_ when using world space as a reference. When thinking in object space it actually is left-right. On the bright side it means that once you think local nothing is happening "backwards".

This also means
transformation * rotationMatrix(angle, 1, 0 ,0) == rotationMatrix(angle, <local x-axis extracted from transformation>) * transformation

Pretty much all the other points remain, except for the multiplication order. One order uses local axes and one uses global axes (also local/global origin as pivot in case of rotations).


Edit: if for whatever reason we were talking about row-major matrices, one would have to ignore the correction and go with the original order.

Share this post


Link to post
Share on other sites
[quote name='Trienco' timestamp='1319000606' post='4874146']
[quote name='dpadam450' timestamp='1318918244' post='4873773']
[quote]
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.
[/quote]

Calling glRotate always rotates around the current local x-axis.

[url="http://www.opengl.org/resources/faq/technical/transformations.htm"]http://www.opengl.or...sformations.htm[/url]

...
[/quote]
Just a tip for the OP: It is IMHO better not to think in API calls but in matrix math, because an API may impose restrictions (e.g. column vs row vector us, or GL's post-multiply only) and is bound to a specific solution, where an understanding of the underlying math gives you the full picture. Things like particular transformation orders, local spaces, parenting and forward kinematics, transforming camera vs transforming the world, left vs right handedness, ... suddenly loose their "problem state". Furthermore, the effect of API calls and their purposeful use became clear a-priori. (With such knowledge one usually stops using GL's particular transformation routines and starts using a well suited matrix library anyway ;))


[quote name='Trienco' timestamp='1319000606' post='4874146']
Edit: if for whatever reason we were talking about row-major matrices, one would have to ignore the correction and go with the original order.
[/quote]
To clarify: The term "row major" is commonly used in the context of the layout of matrices in memory or streams. This plays no role for the given discussion. What is meant here is especially the use of row vs. column vectors. BTW, this and their transposition is an issue that should also be understood well, too.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this