Jump to content
  • Advertisement
Sign in to follow this  
scragglypoo

Rotation matrix multiplication causes Gimbal lock

This topic is 426 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

me.rotation = me.rotation * CreateRotation( 5.0, 0.0, 0.0 );

If i spawn and run this code, pitch increases

But if i spawn and turn 90deg left and run this code, it rolls

How do i fix this?

 

Edit: I use a standard rotation matrix formula from wikipedia

Edited by frob
Removed "Solved" mark from title. Please do not mark discussions as solved.

Share this post


Link to post
Share on other sites
Advertisement

If you're using rotation matrices, there's not really a way to avoid gimbal lock. It happens because you're rotating one axis into another axis, effectively removing a degree of freedom.

The best solution (though not necessarily beginner-friendly) is to use quaternions to store your orientations. You can easily (relatively speaking) convert from matrix to quat, and back. I.e., calculate changes in orientation using quaternions, and then convert to matrix when you want to render, so that you can use the matrix to apply the appropriate transformation on demand.

(Honestly, quaternions are the kind of code you copy from somewhere else and apply based on faith.. they're not really the kind of thing you want to study the math theory behind, unless you're into that sort of thing)

Edited by masskonfuzion
Hopefully clarifying a point

Share this post


Link to post
Share on other sites
5 hours ago, masskonfuzion said:

If you're using rotation matrices, there's not really a way to avoid gimbal lock. It happens because you're rotating one axis into another axis, effectively removing a degree of freedom.

The best solution (though not necessarily beginner-friendly) is to use quaternions to store your orientations. You can easily (relatively speaking) convert from matrix to quat, and back. I.e., calculate changes in orientation using quaternions, and then convert to matrix when you want to render, so that you can use the matrix to apply the appropriate transformation on demand.

(Honestly, quaternions are the kind of code you copy from somewhere else and apply based on faith.. they're not really the kind of thing you want to study the math theory behind, unless you're into that sort of thing)

I have to use matrices to store the rotation

me.orientation = (Quaternion( me.rotation ) * CreateQuaternion( 5.0, 0.0, 0.0 )).toMatrix();

i tried this code and i get the same result

5 hours ago, Alberth said:

Looks like a fundamental limitation in using Euler angles: https://en.wikipedia.org/wiki/Gimbal_lock#Loss_of_a_degree_of_freedom_with_Euler_angles

 

Suggested fix is "don't use Euler angles", not sure how feasible that is for you.

How do I convert 5 degrees pitch to a non-euler method?

Edited by scragglypoo

Share this post


Link to post
Share on other sites

I don't think the issue has to do with the matrix representation, and it certainly doesn't seem to be gimbal lock to me. Have you tried multiplying the matrices the other way around?

me.rotation = CreateRotation( 5.0, 0.0, 0.0 ) * me.rotation;

Share this post


Link to post
Share on other sites
On 7/21/2017 at 10:56 PM, alvaro said:

I don't think the issue has to do with the matrix representation, and it certainly doesn't seem to be gimbal lock to me. Have you tried multiplying the matrices the other way around?

 


me.rotation = CreateRotation( 5.0, 0.0, 0.0 ) * me.rotation;

 

If I reverse the order, pitch rotations are correct, but then yaw rotations decrease the pitch to 0

If I reverse order again, yaw rotations work again, but the pitch rolls if I turned 90deg left

 

I can make a weird fix by doing this:
it works for either operand order as well.  But why?

Matrix operator * ( const Matrix& rotation ) {
	auto x = CreateRotation( rotation.Pitch(), 0.0, 0.0 );
	auto y = CreateRotation( 0.0, rotation.Yaw(), 0.0 );
	return x * (*this) * y;
}

 

Edited by scragglypoo

Share this post


Link to post
Share on other sites

If you want to keep a constant up/down direction (ie gravity) then here's a simple trick I use:  First, be sure to reset your rotation every frame.  Then perform pitch (x) rotation first.  Then do your roll (z) rotation in local space.  And then perform the yaw (y-rotation) in world space.

Share this post


Link to post
Share on other sites
On 7/22/2017 at 3:58 PM, masskonfuzion said:

I guess I'm not sure what the transformation pipeline looks like in this scenario.  @scragglypoo, what library are you using to make your game/project?

Reversing a very old game.  I can try to show what I can figure out.

eye = me.position;
rotationProjectionMatrix = me.rotation;

// This is not standard vector multiplication?  
// Note: It uses a vector instead of a matrix for projection.
rotationProjectionMatrix.right *= projectionVector.x;
rotationProjectionMatrix.up *= projectionVector.y;
rotationProjectionMatrix.look *= projectionVector.z;

// Projection:
screen = mesh.position - eye;
screen *= rotationProjectionMatrix; // screen = local_position * rotation * projection;

 

Edited by scragglypoo

Share this post


Link to post
Share on other sites

Thanks for sharing some code.  It helps give me perspective (pun not intended :-D).  Unfortunately, I'm not following the code -- it looks to be very non-standard/customized, in terms of what I'd expect to see in a 3D application.

For starters, the name, "rotationProjectionMatrix" is confusing.  Rotation and projection are two very different kinds of transformation.  Without getting into too much "math speak", rotation simply transforms axes to point in different directions; it does not "deform" the relationships among the axes (i.e., after any rotation, the X, Y, and Z axes stay at 90 degree angles with respect to each other).

On the other hand, projections are not guaranteed to preserve that property (especially not perspective projections, which "squash" from 3D onto 2D, removing an entire dimension/axis/coordinate space).  That's why, e.g., OpenGL treats the "model/view" transformation matrix (which includes rotation) as an entirely separate entity from the "projection" matrix.  In OpenGL, you apply all of your model/view transformations first (rotation/translation/scaling/shear/whatever) with the "MODELVIEW" matrix.  Then after that, you use the "PROJECTION" matrix to flatten your transformed 3D geometry into a convincing 2D image, for display on whatever screen/monitor you're using (if you didn't know that, now you do :-D).

Based on your code, the "rotationProjectionMatrix" looks not like a matrix, but like a camera object.  It has an eye position vector, view space basis vectors (up/look/right) and a projection "object" -- you called the projection object a vector, but I contend that it should be a matrix, because projection is a transformation that really can only be done with a matrix.

This series of articles might be useful: http://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-introduction  <-- but it gets very heavy into math; I had to read and re-read it 4 or 5 times before it clicked

Lastly, you seem to have 2 "lookAt" vectors.. The object named "vector" appears to serve the same purpose that the rotationProjectionMatrix.look vector should serve.  Here's how OpenGL does it: https://www.khronos.org/opengl/wiki/GluLookAt_code

Whew.. This turned into a long post. Does this make sense?

Edited by masskonfuzion
Correcting an improper gerund on my participle

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!