Here's the code I use.

public class CameraGyro : MonoBehaviour {

private float initialX;
private float initialY;
private float initialZ;

// Use this for initialization
void Start () {
    Input.gyro.enabled = true;

    initialX = Input.gyro.rotationRateUnbiased.x;
    initialY = Input.gyro.rotationRateUnbiased.y;

// Update is called once per frame
void Update () {

    transform.Rotate (initialX - Input.gyro.rotationRateUnbiased.x, initialY - Input.gyro.rotationRateUnbiased.y, 0f);


The thing is when I rotate the phone, the Z axis seems to change even if I've set it to 0f in the code above. Is there a way to really lock this position to 0?

  • \$\begingroup\$ What do you mean "seems to change"? \$\endgroup\$
    – bpgeck
    Feb 23 '16 at 21:07
  • \$\begingroup\$ Well the Z axis change value when it's supposed to stay at 0 \$\endgroup\$
    – Warface
    Feb 23 '16 at 21:15
  • \$\begingroup\$ are you measuring that changed based on how the transform rotates or externally? \$\endgroup\$
    – bpgeck
    Feb 23 '16 at 21:40
  • \$\begingroup\$ you are talking about the Z translate value or Z rotation value? Which is changing and supposed not to change? \$\endgroup\$ Feb 24 '16 at 6:09
  • \$\begingroup\$ Simple explanation... I need to make the gyroscope work by only rotating the X and Y axis. Z should be locked. \$\endgroup\$
    – Warface
    Feb 24 '16 at 14:33

I go into some detail about this phenomenon in this Q&A:

I'm rotating an object on two axes, so why does it keep twisting around the third axis?

The root issue here is that the idea that rotation is naturally/objectively separable into 3 independent components (the way we can do with translation) is a misconception.

Euler angles / Tait-Bryan angles lure us into this belief because they look a lot like a translation vector, but it's easy to show that it's false. Consider the angle triplets (180, 180, 0) and (0, 0, 180): both represent the same orientation, one purely with "x & y" rotations, the other with "purely z" rotation. Or here's another example with compounding rotations in sequence:

Animation showing how rotating x+90, y+90, x-90 is the same as rotating z+90

So, zeroing-out the z component of an angular triplet isn't enough to guarantee you don't get roll.

What to do instead depends on the exact behaviour you want. You could try for instance track a pitch & yaw value independently, and apply the total all at once rather than incrementally compounding rotations:

// in Start(), initialize your x & y angles to match the camera's initial orientation.
pitch = transform.eulerAngles.x;
yaw = transform.eulerAngles.y;

// In Update, accumulate rotational change in these axes:
pitch += input.gyro.rotationRateUnbiased.x * Mathf.RadToDeg() * Time.deltaTime;
yaw += input.gyro.rotationRateUnbiased.y * Mathf.RadToDeg() * Time.deltaTime;
// Apply the result all at once:
transform.eulerAngles = new Vector3(pitch, yaw, 0);

Or you could try rotating the forward / look vector, then construct a "roll-free" orientation that looks in that direction:

Vector3 angularDelta = input.gyro.rotationRateUnbiased * Time.deltaTime;
Vector3 newForward = transform.forward + Vector3.Cross(transform.forward, angularDelta);
transform.rotation = Quaternion.LookRotation(newForward);

Try locking the z axis using "Rotation Constraints": https://docs.unity3d.com/Manual/class-RotationConstraint.html

  • \$\begingroup\$ This answer would be better if it explained how the behaviour of this component differs from manually setting the angle increment to zero. \$\endgroup\$
    – DMGregory
    Dec 16 '18 at 22:03

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .