Quaternion values keep inverting depending on spawn rotation

Hi, please help me to understand what is happening with Quaternions in Unity whilst spawning my Oculus Touch Controllers.

Let me explain my use case. Picture a helicopter with the Player moving in the helicopter, the user controls the pitch/roll/yaw using tilt with the 3 axis of the right tracked controller. This is why I must use local space tracking.

Issue. Depending on where the player points the controllers when the level starts/spawns will determine the signs of the values returned by transform.localRotation.

e.g Point the controller towards your right on level start, the localRotation.y value when twisting the controller right will move up in the positive ++ direction. Now point the controller towards your left on level start, localRotation.y value when twisting right will move down in the negative – direction. It seems to invert all the values depending on start orientation, and thus inverts the vehicles movement direction in a very bad way.

helicopter.VRInputYaw (transform.localRotation.y * yawTwistAmount);

I’ve tested my code with the Vive a thousand times and never have a problem. My guess it’s gimbal lock related. I have no solution to this problem, do you know how I can get reliable values from localRotation or why it is occurring or an alternate solution?

It’s very confusing. Many thanks.

The “y” value of a Quaternion in Unity is the equivalent of the “c” value of the normal Quaternion notation. Those values are not angles but coefficients of a four-dimensional complex number of the form

a + b*i + c*j + d*k

In Unity it’s

w + x*i + y*j + z*k

If you have never seen this before i suggest you watch this Numberphile video on Quaternions carefully. After that you should realise that reading just the “y” component of a quaternion makes not much sense.

If you want the current localRotation in eulerAngles representation you can use transform.localEulerAngles or transform.eulerAngles. However be warned that the conversion from Quaternion to eulerAngles isn’t unique (due to eulerAngles are “over specified”, there are two ways to express the same rotation). Also eulerangles suffers from gimbal lock while quaternions don’t.

It’s not really clear what kind of input you actually get and how you want to apply it to an object. If you just have 3 control axes around the localspace up(yaw), forward(roll) and right(pitch) axis, you can simply use Quaternion.AngleAxis 3 times for each axis and multiply it with the current rotation.

Quaternion pitch = Quaternion.AngleAxis(pitchDelta, transform.right);
Quaternion yaw = Quaternion.AngleAxis(yawDelta, transform.up);
Quaternion roll = Quaternion.AngleAxis(rollDelta, transform.forward);

transform.rotation = pitch * yaw * roll * transform.rotation;

Haven’t tested it but it should work that way. However if you want to determine the current “absolute” pitch, yaw and roll angle that requires some more “fiddling”. If you need that, just leave a comment and i add some more examples for that.