Skip to content

Instantly share code, notes, and snippets.

@kormyen
Last active September 22, 2023 13:37
Show Gist options
  • Star 46 You must be signed in to star a gist
  • Fork 10 You must be signed in to fork a gist
  • Save kormyen/a1e3c144a30fc26393f14f09989f03e1 to your computer and use it in GitHub Desktop.
Save kormyen/a1e3c144a30fc26393f14f09989f03e1 to your computer and use it in GitHub Desktop.
Unity3D script for rotating camera with a phone's gyro. Includes smoothing and initial offset. Edited from https://forum.unity3d.com/threads/sharing-gyroscope-camera-script-ios-tested.241825/
using UnityEngine;
using System.Collections;
public class GyroCamera : MonoBehaviour
{
// STATE
private float _initialYAngle = 0f;
private float _appliedGyroYAngle = 0f;
private float _calibrationYAngle = 0f;
private Transform _rawGyroRotation;
private float _tempSmoothing;
// SETTINGS
[SerializeField] private float _smoothing = 0.1f;
private IEnumerator Start()
{
Input.gyro.enabled = true;
Application.targetFrameRate = 60;
_initialYAngle = transform.eulerAngles.y;
_rawGyroRotation = new GameObject("GyroRaw").transform;
_rawGyroRotation.position = transform.position;
_rawGyroRotation.rotation = transform.rotation;
// Wait until gyro is active, then calibrate to reset starting rotation.
yield return new WaitForSeconds(1);
StartCoroutine(CalibrateYAngle());
}
private void Update()
{
ApplyGyroRotation();
ApplyCalibration();
transform.rotation = Quaternion.Slerp(transform.rotation, _rawGyroRotation.rotation, _smoothing);
}
private IEnumerator CalibrateYAngle()
{
_tempSmoothing = _smoothing;
_smoothing = 1;
_calibrationYAngle = _appliedGyroYAngle - _initialYAngle; // Offsets the y angle in case it wasn't 0 at edit time.
yield return null;
_smoothing = _tempSmoothing;
}
private void ApplyGyroRotation()
{
_rawGyroRotation.rotation = Input.gyro.attitude;
_rawGyroRotation.Rotate(0f, 0f, 180f, Space.Self); // Swap "handedness" of quaternion from gyro.
_rawGyroRotation.Rotate(90f, 180f, 0f, Space.World); // Rotate to make sense as a camera pointing out the back of your device.
_appliedGyroYAngle = _rawGyroRotation.eulerAngles.y; // Save the angle around y axis for use in calibration.
}
private void ApplyCalibration()
{
_rawGyroRotation.Rotate(0f, -_calibrationYAngle, 0f, Space.World); // Rotates y angle back however much it deviated when calibrationYAngle was saved.
}
public void SetEnabled(bool value)
{
enabled = true;
StartCoroutine(CalibrateYAngle());
}
}
@thesanketkale
Copy link

@kormyen
Hi. First and foremost thank you for a wonderful code combination.
Now extending your work, I was thinking on rotating the main camera transform such that +Z-axis is always aligned to North direction and +X-axis is aligned to East direction. I was able to achieve this by just setting the _initialYAngle to Input.compass.trueHeading
This works great and as expected, except for 2 cases. I have mentioned all the details at this post on Unity Answers - Help Room. If possible please reply to the answer there or post some hints or direction where I can start debugging over here.
Thanks in advance. :-)

@dalexdm
Copy link

dalexdm commented Apr 12, 2018

This is really, really tight and smooth. Thanks for sharing, man.

@BlazeArtemis
Copy link

Hi, thanks for sharing the code :).
It really flows well with the phone movement, however the objects in front of the camera are always trembling, how can we avoid that?

@mracoder
Copy link

@kormyen - thanks alot for this piece. Nice solution indeed...
..still, I further faced to the following problem:
For my game idea I'd need to camera also translate with the moving body in space.
To do that I placed the Camera and the Player (body) object under the GyroCamera object, so that they pick up the orientation.
In the same time I used force to move the Player body forward or backward - under the Player's FixedUpdate method.
rb.AddRelativeForce(movement * 100 * speed * Time.deltaTime)

And now the problem starts - after moving from the starting position, when the rotation is made, the Player too is begining to rotate around the starting (I guess the calibration) point. Therefore, the result is not rotating view around the current Player object's position, but about the starting point (before the translation).
To be precise, the Player object should, of course, stay still while looking around.
I need the Player to be aware of the current camera orientation to know where to go forward and backward relative to it.

Anybody has the idea to properly manage this to act as it should ?

P.S. I'm pretty much new here with Unity

@mracoder
Copy link

Ok, I've solved it - I made the rotation rather directly to the Player object underneath.

@kanishkaCemtrex
Copy link

Hi , Thanks for sharing the code.
It works absolutely perfect with the phones sensors.

@barleymalt
Copy link

Love you!

@Dendeveloper
Copy link

Hi, i just want to contribute here, here is the shorter :)

using UnityEngine;
using System.Collections;

public class Main_Script : MonoBehaviour
{
private Quaternion Rotation_Origin;
private Gyroscope Gyroscope_Reference;

private void Awake()
{
    Gyroscope_Reference = Input.gyro;
    Gyroscope_Reference.enabled = true;
    StartCoroutine(Coroutine_Method());
}

private IEnumerator Coroutine_Method()
{
    yield return null;
    Quaternion Rotation_Origin_Addend = Quaternion.Euler(0, 0, 180);
    Rotation_Origin = Gyroscope_Reference.attitude * Rotation_Origin_Addend;

    Quaternion Gyroscope_Attitude_Difference_Addend = Quaternion.Euler(180, 180, 0);

    while (true)
    {
        Quaternion Gyroscope_Attitude_Difference = Quaternion.Inverse(Rotation_Origin) * Gyroscope_Reference.attitude;
        Gyroscope_Attitude_Difference *= Gyroscope_Attitude_Difference_Addend;

        Quaternion Lerped_Quaternion = Quaternion.Lerp(transform.rotation, Gyroscope_Attitude_Difference, 8 * Time.deltaTime);
        transform.rotation = Lerped_Quaternion;

        //transform.Rotate(0f, 0f, 180f, Space.Self);
        //transform.Rotate(-180f, 180f, 0, Space.World);
        yield return null;
    }
}

}

@smborgesMobile
Copy link

Thank you for sharing.
It will help me a lot.

@metehelde
Copy link

Having some issues with this code as the rotation keeps trying to stabilize, creating some weird twitching left and right in view. Is there a way to make this happen less?

@mracoder
Copy link

mracoder commented Nov 9, 2019

@metehelde
check if you have real physical gyro installed in your device - sometimes gyro is emulated with the accelerometer/compass combination, but then it often is not so perfect like with the real gyro, and more or less twitching can be observed then.

@that1phillips
Copy link

I can't thank you enough, man. Two weeks on this jittering... What I gained from the code was learning how to create an additional game object to handle the attitude data. I can't tell you how many iterations I have gone through in trying to resolve the jittering. I couldn't put a game out there like that. Literally saved my project to find this and dissect it to get what I needed out of it. One of the best nights I have had in at least two weeks. lol This made it all come together. Thank you a thousand times over.

@kormyen
Copy link
Author

kormyen commented Dec 5, 2019

All goods. I just stole it from the link in the description really.

@that1phillips the new gameobject is kinda just to visualize what it's doing in the editor. You could store the rotations n things just as a variable in the script instead. [SerializeField] is cool for that if you don't know. https://answers.unity.com/questions/21198/viewing-private-variables-in-the-inspector.html
It's a good way to learn just figuring out what others do well, and improve on it. Keep going :D

@blevok
Copy link

blevok commented May 3, 2020

Thank you for sharing this. I extended it to include X and Z axis when calibrating so you can re-center in any direction and at a variable speed.
https://gist.github.com/blevok/0b5f4c821f019dd1d74fce98c9de3d5f

@choeehb
Copy link

choeehb commented May 26, 2020

Goooooooood

@marcusx2
Copy link

marcusx2 commented Jul 29, 2020

@kormyen I like your script, but is there away to avoid that abrupt snap on the start? Which I assume has to do with the calibration. Maybe do it like threejs does? Take a look at this, no snapping. If you find a way to remove the initial snap your script will be perfect!

@paulks-software
Copy link

paulks-software commented Oct 7, 2020

Thank you!!! Spent like 40$ on plugins before I found this, this should be included in unity gyro sample!

@vicsay1
Copy link

vicsay1 commented Oct 10, 2020

you are the best man!

@felixsuto
Copy link

This code is amazing!
Thank you!

@avnish64
Copy link

Thanks a lot for the solution

@BranCo2
Copy link

BranCo2 commented Apr 7, 2021

@that1phillips
How exactly did you manage to stop the jittering?

@that1phillips
Copy link

that1phillips commented Apr 7, 2021 via email

@BranCo2
Copy link

BranCo2 commented Apr 9, 2021

@that1phillips
Hi. You mentioned controlling the slerp? I'm not very experienced with coding sorry. Can you please give me an example of what you mean?

@Maexcee
Copy link

Maexcee commented Apr 21, 2021

Is there a way to lock every rotation except Y axis?

@johsteven
Copy link

Nice project broo

@jiayi99
Copy link

jiayi99 commented Sep 29, 2021

How to I lock the Y axis rotation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment