- Home /
Problem with localEulerAngles (180 degrees error?)
Hello,
I just started learning Unity and I got a problem: I want to rotate a wheel around X axis (simulate movement) and around Y axis (simulate steering), using the following code:
wheel.Rotate(collider.rpm * 6 * Time.deltaTime, 0, 0); //rotate around X
wheel.localEulerAngles = new Vector3(wheel.localEulerAngles.x, collider.steerAngle, wheel.localEulerAngles.z); //rotate around Y
The problem is with wheel.localEulerAngles.z : sometimes it returns -1 or -2 and sometimes 180. - and this makes my wheel rotate on Z axis about 180 degrees constantly, something that I don't want. If I try to modify it's value (for example add only the values which are lower than 180) it "partially" fixes it but the wheel is not rotating correctly on the X axis.
Any simple solution is greatly appreciated.
*simple = not-very-complicated quaternions or no quaternions at all
@Fattie wheel.Rotate will rotate my wheel constantly, and I want to use this only for steering (rotating the wheels on Y axis only a bit, to allow the car to change it's direction).
Answer by aldonaletto · Sep 06, 2012 at 01:47 PM
The conversion quaternion->euler isn't reliable: there are several different xyz combinations corresponding to any quaternion, and many times the combination returned isn't the one we expect - specially when more than one axis is != zero.
Fortunately, the conversion euler->quaternion is reliable, thus we can use the following approach: get the initial Euler angles and rotate them mathematically, assigning the result to the actual Euler angles in Update (or other periodic function):
Vector3 euler;
void Start(){ euler = wheel.localEulerAngles; // save initial rotation }
void Update(){ // "rotate" wheel angle around X: euler.x = (euler.x + collider.rpm 6 Time.deltaTime) % 360; // set wheel Y angle: euler.y = collider.steerAngle; // update actual wheel localEulerAngles: wheel.localEulerAngles = euler; } NOTE: This works fine because Unity applies the Euler rotations in the order Z-X-Y, thus the angle about X will be set before the angle about Y. This trick would fail if the wheel rotated about Y and steered about X, for instance.
Fortunately, the conversion euler->quaternion is reliable
Where did you read that? I'm curious.
Thank you! It works.
Sorry I couldn't reply earlier (question starter here) - this board has some problems with redirects but I'll mark this as answer once I'll be able to log in on my main account.
@$$anonymous$$ryptos: the way Unity applies the rotations prevents gimbal lock. The rotations are applied to the object in the order Z-X-Y, but the axes are fixed and orthogonal. Gimbal lock may occur when you use an algorithm that somehow emulates real world gimbals: the gimbal axes are free to rotate, and in some situations two of them may become parallel (the famous gimbal lock). Unity probably uses some optimized form of Quaternion.AngleAxis(euler.y, Vector3.up) Quaternion.AngleAxis(euler.x, Vector3.right) Quaternion.AngleAxis(euler.z, Vector3.forward), which always produces a valid rotation (provided that the euler angles are valid, of course).
Answer by Kryptos · Sep 06, 2012 at 11:47 AM
As a general rule, never modify localEulerAngles directly. Use quaternions instead.
Answer by jaskij · Sep 06, 2012 at 01:28 PM
IMO when it comes to coding, Euler angles are more complicated than quaternions, since there are so many friggin' exceptions you need to consider to avoid a gimbal lock.
Although I cannot give you a simple answer to your problem (there are too many unknows for now). Try putting Debug.Log(wheel.localEulerAngles.ToString()); there and look how the value changes (you need to open a Console window in Unity to see the output).