0
\$\begingroup\$

I'm working on a mobile game in Unity and using the gyroscope to rotate an object along the x and y axes.

float x = Input.gyro.attitude.x; 
float y = Input.gyro.attitude.y;

This code give me the rotation I want when pointed in a certain direction along the z-axis. I want the rotation to not depend on the z-axis. I want the rotation to act the same no matter what direction I'm pointed in the real-world.

Here is a 12 second clip of what I get using a mobile gyroscope when pointed at 1 or North on the z-axis:

Animation of oven mitt holding pan tilting left/right/forward/back

I want the rotation to be the same no matter what direction I am pointed on the z-axis with the gyroscope. Is there some way to rotate the whole coordinate system?

DMGregory
140k23 gold badges256 silver badges392 bronze badges
asked Nov 7, 2019 at 14:37
\$\endgroup\$
2
  • \$\begingroup\$ You're going to have trouble. Rotation in 3D space can only be accurately represented as a Quaternion (W,X,Y,Z). Euler angles (what the Input.gyro gives you) suffer from Gimbal Lock. Restricting yourself down to two axis is just going to not be possible. \$\endgroup\$ Commented Nov 7, 2019 at 16:18
  • \$\begingroup\$ @Draco18s - the particular interaction they want can definitely be done with two axes. They don't need to express every possible orientation, just a small subset. \$\endgroup\$ Commented Nov 7, 2019 at 17:39

1 Answer 1

2
\$\begingroup\$

Input.gyro.attitude gives you a quaternion representing (a best estimate of) the device's absolute orientation in space - including its orientation relative to the north pole.

But that's not what you want here. You want a measure of how the device is tilted relative to the gravity vector - no matter how we're oriented to north/south/east/west.

// Get the vector representing global up (away from gravity)
// within the device's coordinate system.
Vector3 localDown = Quaternion.Inverse(Input.gyro.attitude) * Vector3.down;
// Extract our roll rotation - how much gravity points to our left or right.
float rollDegrees = Mathf.Asin(localDown.x) * Mathf.Rad2Deg;
// Extract our pitch rotation - how much gravity points forward or back.
float pitchDegrees = Mathf.Atan2(localDown.y, localDown.z) * Mathf.Rad2Deg;

This gives 0 pitch when the gravity vector points along the phone's z+ axis. If you want your neutral pitch to sit somewhere else, or adapt based on the player's resting pose when holding the phone, you can shift & wrap the angle accordingly using Mathf.DeltaAngle

answered Nov 7, 2019 at 17:51
\$\endgroup\$
3
  • \$\begingroup\$ Pitching the phone forwards and backwards in any direction appears to produce the correct results, but rolling from left to right changes both the roll and pitch. How would I fix this? Also wouldn't it be more efficient to use Input.gyro.gravity? @DMGregory \$\endgroup\$ Commented Nov 8, 2019 at 3:07
  • \$\begingroup\$ You can use the same Asin technique for both if you like — it'll just give you a somewhat narrower range of pitch and you may need to manually adjust it when playing mostly-horizontal vs mostly-vertical. Re: gravity, feel free to use it if it works for you. \$\endgroup\$ Commented Nov 8, 2019 at 3:10
  • \$\begingroup\$ +1 That worked, thank you so much! I'd upvote your answer, but my reputation is too low. \$\endgroup\$ Commented Nov 8, 2019 at 3:24

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.