- Home /
Encountering Gimbal Lock when using Transform.Rotate(Axis, Angle)
Hi, folks! I have a question about avoiding gimbal lock when using Transform.Rotate(). So, I'm making a simple "Inspection" interface, where users can drag the cursor across the screen to rotate a 3D object. Here's what it looks like when it works.
I'm rotating the object using Transform.Rotate() and an angle/axis pair, calculated from the cross product of the user's mouse direction and the camera's forward vector. Everything works pretty darn well, except for when the camera I'm using is pointed 90 degrees straight down (euler 90, 0, 0) -- suddenly, I can only rotate the object horizontally to the camera. Here's what you get when it fails!.
Rotate that camera back down to (85, 0, 0) and things work again, but I do need the straight-down angle to work and I'm pulling my hair out trying to deal with this one. I dimly remember dealing with a similar problem -- which my peers called gimbal lock -- back when I was a little more naive, and would try to rotate objects by directly changing the components of transform.eulerAngles. It's been my impression that the whole angle-axis system wouldn't be prone to the same issues, but it seems that's not the case.
Anyway, I'd greatly appreciate it if you guys have some information about how I can solve this problem. For reference, here's the source for the rotation functionality:
//Get the vector direction of the user's mouse / finger as they drag:
Vector2 mouseDiff = (Vector2)Input.mousePosition - oldMousePos;
//Calculate the desired axis of rotation by crossing mouseDiff with the camera's forward vector
Vector3 axis = Vector3.Cross((Vector3)mouseDiff.normalized, camera.transform.forward).normalized;
//Calculate the amount to rotate this frame:
float angleDiff = mouseDiff.magnitude * rotateMouseSensitivity * Mathf.Deg2Rad;
//Do the deed! :
Object.transform.Rotate(axis, angle, Space.World);
//Update oldMousePos
oldMousePos = Input.mousePosition;
Also, this is silly, but I'd like to clarify that where I wrote "Object.transform.Rotate(...)" in the question field, my code actually says "[NameOfObject].transform.Rotate(...)". Just thought I'd clarify, in case that was tripping you up
Answer by Dave-Carlile · Jul 14, 2015 at 03:05 PM
If you don't want gimbal lock you'll most likely need to use Quaternions instead of angles.
Thanks for the answer, Dave.
Unfortunately, I've tried a few quaternion-based approaches just now, and have recieved identical results. So far, I've tried replacing Object.transform.Rotate(axis,angle,Space.World);
with a straightforward quaternion multiplication:
Quaternion newRotation = Quaternion.AngleAxis(angle, axis) * Object.transform.rotation;
Object.transform.rotation = newRotation
As well as a more complicated version of the above that stabilized the rotation against its inverse:
Vector3 correctedAxis = Quaternion.Inverse(Object.transform.rotation) * axis;
Quaternion axisRotation = Quaternion.AngleAxis(angle, correctedAxis);
Quaternion targetRotation = Object.transform.rotation * axisRotation;
Object.transform.rotation = targetRotation;
Both of the above systems exhibit behaviors identical to each other and to the approach in the original question; they work properly when the camera used to calculate the axis is tilted at (85, 0, 0), but fail when the camera is pointed straight down at (90, 0, 0).
Given these test cases and their failure, is there something specific that I'm not doing right with the Quaternion-based approach, or do you think the problem resides somewhere else?
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Rotate Texture Over Time 1 Answer
Mixing mecanim movement with script rotation problem 1 Answer