-
-
Save kormyen/a1e3c144a30fc26393f14f09989f03e1 to your computer and use it in GitHub Desktop.
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()); | |
} | |
} |
This is really, really tight and smooth. Thanks for sharing, man.
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?
@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
Ok, I've solved it - I made the rotation rather directly to the Player object underneath.
Hi , Thanks for sharing the code.
It works absolutely perfect with the phones sensors.
Love you!
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;
}
}
}
Thank you for sharing.
It will help me a lot.
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?
@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.
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.
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
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
Goooooooood
@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!
Thank you!!! Spent like 40$ on plugins before I found this, this should be included in unity gyro sample!
you are the best man!
This code is amazing!
Thank you!
Thanks a lot for the solution
@that1phillips
How exactly did you manage to stop the jittering?
@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?
Is there a way to lock every rotation except Y axis?
Nice project broo
How to I lock the Y axis rotation
@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. :-)