Search Unity

Rotating Camera via Tablet or Android device's Rotation

Discussion in 'Scripting' started by Teriander, Dec 1, 2014.

  1. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Can someone show me an example of a script that rotates the camera in FPS view based off the rotation of a tablet or android device? Im at a lost on where to begin with this type of connection.
     
  2. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    Here is a video on the basics of using the accelerometer:
    http://unity3d.com/learn/tutorials/modules/beginner/platform-specific/accelerometer-input

    And a post talking specifically about tilt:
    http://answers.unity3d.com/questions/357754/using-accelerometer-tilt-to-control-a-flying-orb.html

    But you will run into some bigger questions like 'what is down?' because players might play it different ways. Maybe you define it at start or maybe you allow player to recalibrate if they change positions. Ie sometimes I play games laying down with the device above me which would translate differently than if I was sitting up.
     
    biggsthecat likes this.
  3. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Thank you very much for the reply! I will look into these and see if it works!
     
  4. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Peter,

    This is close to what Im looking for. But I'm looking for just the Camera to rotate without moving. the script for the example you provide does a good job of moving my camera on the X and Y directions when moving my phone, but the rotation is what I'm aiming for. I think something like this should do the trick, but it's not:

    void Update ()
    {
    camera.transform.rotation = Input.gyro.attitude;
    }

    http://docs.unity3d.com/ScriptReference/Gyroscope-attitude.html

    Any suggestion to get this to work. This didn't move the camera at all when I rotated my phone.
     
  5. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
  6. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Were you able to get it to work from the link you just sent? I think I'm doing the conversion from JS wrong or something. But it sounds like they are on the right track to get it to work.
     
  7. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    Sorry, I haven't used UnityJs in forever. Here is some code I played with just now that should help put you in the right direction. Depending on your rotation axis and device orientation you will need to swap around x, y, and z. You'll also probably want to figure out some smoothing. I like to have a proxy object for these things that lerps between the rotations multiplied by a set speed.

    Input.acceleration seems like a bit of a misnomer. Maybe normalizedAngle or rotation or something would be more fitting.

    Please bear with me on the quick code - I'm at work so trying to get it working on the down low ;)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class gyro : MonoBehaviour {
    5.  
    6.     Vector3 angle = Vector3.zero;
    7.     //TextMesh text; <-- I was using a text mesh to test displaying
    8.  
    9.     void Start() {
    10.         //text = GetComponent<TextMesh>();
    11.     }
    12.  
    13.     void Update() {
    14.         angle.x = Input.acceleration.x * 360;
    15.         transform.rotation = Quaternion.Euler(angle);
    16.         //text.text = Input.acceleration.x.ToString();
    17.     }
    18. }
     
  8. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    That's a start! it's definitely heading in the direction I'm looking for. But you're right, I am getting some jittering and needing some smoothing. If you know a fix later I'd appreciate it!! Thanks for fixing the code!
     
  9. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    Put a script similar to that on 'proxyRotateObject'
    Then create a script on your object or camera to rotate and use something like this:
    Code (CSharp):
    1. public GameObject rotateTarget; // Set this to be proxyRotateObject
    2. public float matchSpeed = 1f; // The speed at which the camera will try to match the rotation of rotateTarget
    3.  
    4. void Update() {
    5.     transform.rotation = Quaternion.Lerp(transform.rotation, rotateTarget.transform.rotation, Time.deltaTime * matchSpeed);
    6. }
    This is how I do it, but not sure if that's the most efficient way. In fact I recently read that getting the transform of a gameObject is the equivalent to GetComponent<Transform>() so maybe instead of plugging in a GameObject in that first line do a Transform instead. But I'm not sure how to drag a Transform on. If that makes sense.
     
  10. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    I wasn't able to get your method to work. But this method was giving me some interesting results. It starts to work and has some smoothing, but still snaps into strange locations. Do you get the same results?

    Code (CSharp):
    1. public float smooth = 2.0F;
    2.     public float tiltAngle = 10.0F;
    3.  
    4.         void Update () {
    5.         float tiltAroundZ = Input.acceleration.x * tiltAngle;
    6.         float tiltAroundX = Input.acceleration.y * tiltAngle;
    7.         Quaternion target = Quaternion.Euler(tiltAroundX, 0, tiltAroundZ);
    8.         transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
    9. }
     
  11. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Peter,

    This is actually working well for me now! My only issue is aiming the phone down is looking straight in the view. How do you suggest I fix this where holding the phone straight is also looking straight? Here is my code that his this working better:
    Code (CSharp):
    1.   //Gyro
    2.     public float smooth = 2.0F;
    3.     public float tiltAngle = 90.0F;
    4.  
    5.  
    6.    
    7.  
    8.     void Update ()
    9.     {
    10.         //Gyro
    11.         float tiltAroundZ = -Input.acceleration.x * tiltAngle * 50;
    12.         float tiltAroundX = Input.acceleration.y * tiltAngle * 50;
    13.         Quaternion target = Quaternion.Euler(tiltAroundX, tiltAroundZ, 0);
    14.  
    15.         transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
     
  12. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    I'm glad that it's working, but I'm getting crazy results on my side with this code.

    But if it is working for you, then you might be close. Not sure what axis is the one that would make yours point correctly. Find out which one, and try adding or subtracting 90 from that axis. This might take some guess and check, sorry I'm not able to properly replicate it.
     
  13. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    After a little more testing, I'm also getting some crazy results. Oh well, back to the drawing board.....
     
  14. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    When I get home from work I'll see if I can put together a clean example.
     
  15. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Thanks Peter!
     
  16. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Peter,

    Another round of testing. This actually works well for me again with this code. Only problem is trying to get it to start straight. Right now it starts with your phone faced straight down. Does this work for you?

    Code (CSharp):
    1. [Range(0, 355)]
    2.     public float minAngle = 50f;
    3.     [Range(0, 355)]
    4.     public float maxAngle = 310f;
    5.    
    6.  
    7.    
    8.  
    9.     void Update ()
    10.     {
    11.  
    12.  
    13.         transform.Rotate(Vector3.right * Input.acceleration.y * 2.0f);
    14.         if (transform.eulerAngles.x >= minAngle && transform.eulerAngles.x <= (minAngle))
    15.             transform.eulerAngles = new Vector3(0f, 0f, minAngle);
    16.         if (transform.eulerAngles.x <= maxAngle && transform.eulerAngles.x >= (maxAngle))
    17.             transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
    18.  
    19.         transform.Rotate(Vector3.down * Input.acceleration.y * 2.0f);
    20.         if (transform.eulerAngles.z >= minAngle && transform.eulerAngles.z <= (minAngle))
    21.             transform.eulerAngles = new Vector3(0f, 0f, minAngle);
    22.         if (transform.eulerAngles.z <= maxAngle && transform.eulerAngles.z >= (maxAngle))
    23.             transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
    24. }
     
  17. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    Yeah use z instead of x

    I've put together a little script that should help. But I've realized something I never thought about before. This script gets the tilt of my device to move an axis on the camera like shaking my head yes. But I realize I have no idea how to get the axis equivalent to a no head shake with an accelerometer. I think that is how you want to use it right?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class rotate : MonoBehaviour {
    5.  
    6.     float xRot, yRot, zRot;
    7.     public float rotSpeed = 20f;
    8.  
    9.     void Update ()
    10.     {
    11.         // This tilts the axis of the camera like shaking a head yes
    12.         xRot = Input.acceleration.z * -180f;
    13.         // This tilts like a driving wheel to make it like shaking head no
    14.         yRot = Input.acceleration.x * -180f;
    15.         zRot = 0f;
    16.         transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(new Vector3(xRot, yRot, zRot)), Time.deltaTime * rotSpeed);
    17.     }
    18.  
    19. }
    20.  
     
    Last edited: Dec 3, 2014
  18. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Both yes and no head motion, as we all being able to spin around 180 degrees behind in both directions (left and right). I feel like you're on the right track but it's impossible for me to turn around. (Also getting a strange jittering, i tried adjusting "rotSpeed" but it still happens). I'll keep playing with the code you sent to see if I can get some closer results.

    Thanks a lot!
     
  19. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    Unfortunately I haven't had any luck. I also went back to the previous code I posted and took your advice on changing z instead of x, but still no luck. Were you able to get the code I last posted to work with a yes/no head shake motion in 180 degrees?

    Here's the code again Im referencing:
    Code (CSharp):
    1. [Range(0, 355)]
    2.     public float minAngle = 50f;
    3.     [Range(0, 355)]
    4.     public float maxAngle = 310f;
    5.  
    6.  
    7.     void Update ()
    8.     {
    9.         transform.Rotate(Vector3.right * Input.acceleration.y * 2.0f);
    10.         if (transform.eulerAngles.x >= minAngle && transform.eulerAngles.x <= (minAngle))
    11.             transform.eulerAngles = new Vector3(0f, 0f, minAngle);
    12.         if (transform.eulerAngles.x <= maxAngle && transform.eulerAngles.x >= (maxAngle))
    13.             transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
    14.         transform.Rotate(Vector3.down * Input.acceleration.x * 2.0f);
    15.         if (transform.eulerAngles.z >= minAngle && transform.eulerAngles.z <= (minAngle))
    16.             transform.eulerAngles = new Vector3(0f, 0f, minAngle);
    17.         if (transform.eulerAngles.z <= maxAngle && transform.eulerAngles.z >= (maxAngle))
    18.             transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
    19. }
     
    Last edited: Dec 3, 2014
  20. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    I wasn't able to. Your code was rotating at an angle on two axes based on the y value.

    The code I posted has 20 as the speed which is way too fast and makes it choppy - my bad. I had turned that value down to 10 in unity. The reason that you are getting choppiness regardless of the value you put might be because you are changing the number in code but it's being overridden by the set value in the inspector panel in unity.

    I should have been more clear about my thoughts on the no head shake angle. I'm not sure that it's possible. I'm not sure a device's accelerometer can detect rotation around an axis parallel to real world gravity. :(
     
  21. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    It's possible because I saw someone use an iPad to navigate through an architectural scene and moving the tablet's orientation rotated the camera, as if turning the tablet to the left rotated the camera to the left. That's basically what I'm trying to recreate.

    Also, I had noticed I had the two axis of "y". I fixed this in my previous post by changing the second y to x. Sorry about that.
     
  22. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
    This video shows what I'm trying to make happen. But with an Android.

     
    Last edited: Dec 3, 2014
  23. Peter Ples

    Peter Ples

    Joined:
    Mar 12, 2013
    Posts:
    237
    Ah excellent. Well I'm glad that it's possible but I still can't get any movement on that axis. Hopefully someone reading this might know the answer. I plan do use the gyro like this in a future project as well.
     
  24. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
  25. Teriander

    Teriander

    Joined:
    Jan 12, 2012
    Posts:
    113
  26. alias

    alias

    Joined:
    May 14, 2013
    Posts:
    11

    hey peter

    this script of yours works like a charm. up,down,left and right.
    i got only one problem my scene is played in a different orientation
    my scene when played is face down on my telephone,. and it needs
    to be upright.

    could you help me out with your script so i can adjust the begin orientation
    so it matches the unity xyz coordinate system.
     
    Last edited: May 15, 2015
  27. alias

    alias

    Joined:
    May 14, 2013
    Posts:
    11
    i have tried z instead of y.

    but then my movement from left to right is then discarded. and wont work anymore.

    its like my sensor is allright when the phone is layed down. while it needs too be landscape upright.
     
    Last edited: May 20, 2015
  28. Sagi02

    Sagi02

    Joined:
    Feb 6, 2015
    Posts:
    5
    Try this:
    Code (CSharp):
    1. void Start()
    2. {
    3.              Input.compensateSensors = true;
    4.              Input.gyro.enabled = true;
    5. }
    6.  
    7. void FixedUpdate()
    8. {
    9.           transform.Rotate (-Input.gyro.rotationRateUnbiased.x, -Input.gyro.rotationRateUnbiased.y, Input.gyro.rotationRateUnbiased.z);
    10. }
    You may then add calibration functions for the z axis but it worked great for me!
     
    weto likes this.
  29. weto

    weto

    Joined:
    Jul 29, 2014
    Posts:
    4
    Sagi, your code works perfectly fine for me (apart from minor drift)! Thanks a lot for sharing it!
     
  30. UnityParadox

    UnityParadox

    Joined:
    Jun 29, 2016
    Posts:
    1
    @Sagi02 i tried to mix yours with the one previously mentioned to fix any movement errors. Should the code below work?
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class AddGyroCam : MonoBehaviour {
    5.  
    6.     public float AccelerometerUpdateInterval = 1.0f / 100.0f;
    7.     public float LowPassKernelWidthInSeconds = 0.001f;
    8.     public Vector3 lowPassValue = Vector3.zero;
    9.  
    10.     void Start()
    11.     {
    12.         Input.compensateSensors = true;
    13.         Input.gyro.enabled = true;
    14.     }
    15.  
    16.     Vector3 lowpass()
    17.     {
    18.         float LowPassFilterFactor = AccelerometerUpdateInterval / LowPassKernelWidthInSeconds;
    19.         lowPassValue = Vector3.Lerp(lowPassValue, Input.acceleration, LowPassFilterFactor);
    20.         return lowPassValue;
    21.     }
    22.  
    23.     void FixedUpdate()
    24.     {
    25.         transform.Rotate(lowPassValue);
    26.     }
    27.    
    28.    
    29. }
    30.  
     
  31. Emperor

    Emperor

    Joined:
    Feb 13, 2014
    Posts:
    41
    Hey @UnityParadox

    no it doesn't work. First off, you should do


    1. void FixedUpdate()
    2. {
    3. transform.Rotate(lowpass());
    4. }

    But even then it doesn't work because it just kinda rotates aimlessly on an axis instead of accurately following the phone's movements.

    I'm trying to do this as well and will look into it...
     
  32. tenguzame

    tenguzame

    Joined:
    Sep 28, 2016
    Posts:
    3
    Dear all,
    I found this script very useful:

    I have a very small project I'm trying to build, and the script kind of works on my phone. However, it's quite jittery and doesn't rotate along the y axis (only up and down). How can I fix this?

    -MikeT