-
-
Save blevok/0b5f4c821f019dd1d74fce98c9de3d5f to your computer and use it in GitHub Desktop.
Gyro camera rotation for Android, tested in Unity 2019.3.2 for API level 28, in landscape left orientation.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Gyro camera rotation for Android, tested in Unity 2019.3.2 for API level 28, in landscape left orientation. | |
// Extended to include X and Z axis when claibrating, so you can re-center when looking in any direction, and at a variable speed. | |
// Attach this script to the parent GameObject of your camera. To re-center, from your main script, call CalibrateAngle, set a bool "letsGoToCenter" to true, a bool "goToCenterSlowly" to true or false, and a string "centerRotSpeed" to slow or fast. | |
// centerRotSpeed is ignored when goToCenterSlowly is false. You can use "Unity Remote 5" in the Play store to test Android gyro in Unity editor. | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class GyroCamera : MonoBehaviour | |
{ | |
// your main script where the rest of your app functions live | |
public mainAppScript mainappscript; | |
// STATE | |
private float _initialXAngle = 0f; | |
private float _appliedGyroXAngle = 0f; | |
private float _calibrationXAngle = 0f; | |
private float _initialYAngle = 0f; | |
private float _appliedGyroYAngle = 0f; | |
private float _calibrationYAngle = 0f; | |
private float _initialZAngle = 0f; | |
private float _appliedGyroZAngle = 0f; | |
private float _calibrationZAngle = 0f; | |
public Transform _rawGyroRotation; | |
Quaternion currentOffset = Quaternion.Euler(0f, 0f, 0f); | |
Quaternion currentAngle; | |
Quaternion newAngle; | |
float timeToLerp = 1f; | |
float timeLerped = 0.0f; | |
private float _tempSmoothing; | |
// SETTINGS | |
[SerializeField] private float _smoothing = 0.1f; | |
private IEnumerator Start() | |
{ | |
Input.gyro.enabled = true; | |
_initialXAngle = transform.eulerAngles.x; | |
_initialYAngle = transform.eulerAngles.y; | |
_initialZAngle = transform.eulerAngles.z; | |
_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(CalibrateAngle()); | |
} | |
private void Update() | |
{ | |
ApplyGyroRotation(); | |
ApplyCalibration(); | |
// stop moving towards center if x and y are within a certain range of center | |
if ((transform.rotation.eulerAngles.x >= -1 && transform.rotation.eulerAngles.x <= 1) && (transform.rotation.eulerAngles.y >= -1 && transform.rotation.eulerAngles.y <= 1)) | |
{ | |
mainappscript.letsGoToCenter = false; | |
} | |
if (mainappscript.letsGoToCenter == true) | |
{ | |
if (mainappscript.goToCenterSlowly == true) | |
{ | |
if (mainappscript.centerRotSpeed == "slow") | |
{ | |
timeToLerp = 1f; | |
timeLerped += Time.deltaTime; | |
newAngle = Quaternion.Euler(0, 0, 0); | |
transform.rotation = Quaternion.Slerp(transform.rotation, newAngle, (timeLerped / timeToLerp) / 2); | |
} | |
else if (mainappscript.centerRotSpeed == "fast") | |
{ | |
timeToLerp = 0.5f; | |
timeLerped += Time.deltaTime; | |
newAngle = Quaternion.Euler(0, 0, 0); | |
transform.rotation = Quaternion.Slerp(transform.rotation, newAngle, (timeLerped / timeToLerp) / 2); | |
} | |
} | |
else | |
{ | |
newAngle = Quaternion.Euler(0, 0, 0); | |
transform.rotation = Quaternion.Slerp(currentAngle, newAngle, 1f); | |
} | |
} | |
else | |
{ | |
newAngle = _rawGyroRotation.rotation * Quaternion.Inverse(currentOffset); | |
transform.rotation = Quaternion.Slerp(transform.rotation, newAngle, _smoothing); | |
} | |
} | |
public IEnumerator CalibrateAngle() | |
{ | |
_tempSmoothing = _smoothing; | |
_smoothing = 1; | |
// Offsets the angle in case it wasn't 0 at edit time. | |
_calibrationXAngle = _appliedGyroXAngle - _initialXAngle; | |
_calibrationYAngle = _appliedGyroYAngle - _initialYAngle; | |
_calibrationZAngle = _appliedGyroZAngle - _initialZAngle; | |
yield return null; | |
_smoothing = _tempSmoothing; | |
currentOffset = _rawGyroRotation.rotation; | |
currentAngle = transform.rotation; | |
timeLerped = 0.0f; | |
} | |
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. | |
// Save the angle around axis for use in calibration. | |
_appliedGyroXAngle = _rawGyroRotation.eulerAngles.x; | |
_appliedGyroYAngle = _rawGyroRotation.eulerAngles.y; | |
_appliedGyroZAngle = _rawGyroRotation.eulerAngles.z; | |
} | |
private void ApplyCalibration() | |
{ | |
// Rotates back however much it deviated when calibrationAngle was saved. | |
_rawGyroRotation.Rotate(_calibrationXAngle, -_calibrationYAngle, _calibrationZAngle, Space.World); | |
} | |
} |
Hi is there a way to lock Y axis rotation
It's been a while since i messed with this or any rotations, but try replacing line 93 with this:
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(newAngle.eulerAngles.x, 0f, newAngle.eulerAngles.z), _smoothing);
It might not be that simple though. You might need to also set the y values for the calibrated and applied angles, and maybe for the input value as well. Doing it without setting every place where the y value could change could result in stuttering.
Rotations are just really confusing to me, so i can't say exactly what will happen unless i actually try it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi is there a way to lock Y axis rotation