Êrelyn
Êrelyn

Reputation: 23

Unity c# Quaternion: Swap y with z axis

I need to rotate an object to have an exact rotation relative to real world. Therefore calling Input.gyro.attitude returns a Quaternion representing the position of the device. On the other hand, this forces me to compute every rotation based upon this quaternion as default rotation. An easy way to set some object facing upwards would be the following:

Vector3 up = Input.gyro.attitude.eulerAngles;
... 
transform.rotation = Quaternion.Euler(up.x, up.y, up.z);

This rotates up.z around z, then up.x around x, and up.y around y.

My problem is, that the coordinate system is not quite right, in my app the y and z axis swapped (I'm using Vuforia, so it's always relative to the marker), meaning that an rotation around z results in a rotation around y and the other way around. Here things get difficult: Obviously

transform.rotation = Quaternion.Euler(up.x, up.z, up.y);

fails, since this still rotates first around z, but now with up.y. The correct order would be to create a rotation, that rotates first around y, then x, then z.

Since the Euler Angles are retrieved from a Quaternion,

    transform.rotation = Quaternion.identity;
    transform.Rotate(0, up.eulerAngles.z, 0);
    transform.Rotate(up.eulerAngles.x, 0, 0);
    transform.Rotate(0, 0, up.eulerAngles.y);

won't work either, of course.

However, I can't find a way to do this. Am I overlooking something?

Upvotes: 2

Views: 4528

Answers (2)

aheigins
aheigins

Reputation: 2684

This might not be mathematically correct but i was using an IMU to change the orientation/rotation of a cube. For me the roll and pitch were swapped. To correct this i just swapped around the x,y and z and it was corrected.

This is the important bit of my code:

            float w = float.Parse(values[1]);
            float x = float.Parse(values[2]);
            float y = float.Parse(values[3]);
            float z = float.Parse(values[4]);

            /// Original code with swapped yaw and pitch
            // this.transform.localRotation = Quaternion.Lerp(this.transform.localRotation,  new Quaternion(w, x, y, z), Time.deltaTime * speedFactor);

            /// Corrected code with correct yaw and pitch (I inverted the x,y and z because they were inverted but matched the correct axis)
            this.transform.localRotation = Quaternion.Lerp(this.transform.localRotation,  new Quaternion(w, -y, -z, -x), Time.deltaTime * speedFactor);

Also fyi I was using the uduino library with this tutorial: https://marcteyssier.com/uduino/projects/connect-a-imu-to-unity

Again maybe not correct mathematically but I didn't need to use Euler angles (so avoid their problems) and it seems to work.

I hope this helps.

Upvotes: 0

Patrick Ferland
Patrick Ferland

Reputation: 201

You should be able to multiply a series of calls to Quaternion.AngleAxis in the order you want, I believe. Have to tried something something like this?

transform.rotation = Quaternion.identity *
    Quaternion.AngleAxis(up.eulerAngles.y, Vector3.up) *
    Quaternion.AngleAxis(up.eulerAngles.x, Vector3.forward) *
    Quaternion.AngleAxis(up.euelerAngles.z, Vector3.right);

Upvotes: 3

Related Questions