Rotating Camera via Tablet or Android device's Rotation

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.

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:

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.

1 Like

Thank you very much for the reply! I will look into these and see if it works!

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;
}

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

I’ve confirmed it also doesn’t work on my device. Htc One Android 4.4.3 on unity 4.6.0f3. This post says to use Input.acceleration: Android Gyroscope not working ? - Questions & Answers - Unity Discussions

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.

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 :wink:

using UnityEngine;
using System.Collections;

public class gyro : MonoBehaviour {

    Vector3 angle = Vector3.zero;
    //TextMesh text; <-- I was using a text mesh to test displaying

    void Start() {
        //text = GetComponent<TextMesh>();
    }

    void Update() {
        angle.x = Input.acceleration.x * 360;
        transform.rotation = Quaternion.Euler(angle);
        //text.text = Input.acceleration.x.ToString();
    }
}

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!

Put a script similar to that on ā€˜proxyRotateObject’
Then create a script on your object or camera to rotate and use something like this:

public GameObject rotateTarget; // Set this to be proxyRotateObject
public float matchSpeed = 1f; // The speed at which the camera will try to match the rotation of rotateTarget

void Update() {
    transform.rotation = Quaternion.Lerp(transform.rotation, rotateTarget.transform.rotation, Time.deltaTime * matchSpeed);
}

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() 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.

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?

public float smooth = 2.0F;
    public float tiltAngle = 10.0F;

        void Update () {
        float tiltAroundZ = Input.acceleration.x * tiltAngle;
        float tiltAroundX = Input.acceleration.y * tiltAngle;
        Quaternion target = Quaternion.Euler(tiltAroundX, 0, tiltAroundZ);
        transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
}

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:

  //Gyro
    public float smooth = 2.0F;
    public float tiltAngle = 90.0F;


   

    void Update ()
    {
        //Gyro
        float tiltAroundZ = -Input.acceleration.x * tiltAngle * 50;
        float tiltAroundX = Input.acceleration.y * tiltAngle * 50;
        Quaternion target = Quaternion.Euler(tiltAroundX, tiltAroundZ, 0);

        transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);

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.

After a little more testing, I’m also getting some crazy results. Oh well, back to the drawing board…

When I get home from work I’ll see if I can put together a clean example.

Thanks Peter!

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?

[Range(0, 355)]
    public float minAngle = 50f;
    [Range(0, 355)]
    public float maxAngle = 310f;
   

   

    void Update ()
    {


        transform.Rotate(Vector3.right * Input.acceleration.y * 2.0f);
        if (transform.eulerAngles.x >= minAngle && transform.eulerAngles.x <= (minAngle))
            transform.eulerAngles = new Vector3(0f, 0f, minAngle);
        if (transform.eulerAngles.x <= maxAngle && transform.eulerAngles.x >= (maxAngle))
            transform.eulerAngles = new Vector3(0f, 0f, maxAngle);

        transform.Rotate(Vector3.down * Input.acceleration.y * 2.0f);
        if (transform.eulerAngles.z >= minAngle && transform.eulerAngles.z <= (minAngle))
            transform.eulerAngles = new Vector3(0f, 0f, minAngle);
        if (transform.eulerAngles.z <= maxAngle && transform.eulerAngles.z >= (maxAngle))
            transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
}

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?

using UnityEngine;
using System.Collections;

public class rotate : MonoBehaviour {

    float xRot, yRot, zRot;
    public float rotSpeed = 20f;
  
    void Update ()
    {
        // This tilts the axis of the camera like shaking a head yes
        xRot = Input.acceleration.z * -180f;
        // This tilts like a driving wheel to make it like shaking head no
        yRot = Input.acceleration.x * -180f;
        zRot = 0f;
        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.Euler(new Vector3(xRot, yRot, zRot)), Time.deltaTime * rotSpeed);
    }
  
}

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!

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:

[Range(0, 355)]
    public float minAngle = 50f;
    [Range(0, 355)]
    public float maxAngle = 310f;
 
 
    void Update ()
    {
        transform.Rotate(Vector3.right * Input.acceleration.y * 2.0f);
        if (transform.eulerAngles.x >= minAngle && transform.eulerAngles.x <= (minAngle))
            transform.eulerAngles = new Vector3(0f, 0f, minAngle);
        if (transform.eulerAngles.x <= maxAngle && transform.eulerAngles.x >= (maxAngle))
            transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
        transform.Rotate(Vector3.down * Input.acceleration.x * 2.0f);
        if (transform.eulerAngles.z >= minAngle && transform.eulerAngles.z <= (minAngle))
            transform.eulerAngles = new Vector3(0f, 0f, minAngle);
        if (transform.eulerAngles.z <= maxAngle && transform.eulerAngles.z >= (maxAngle))
            transform.eulerAngles = new Vector3(0f, 0f, maxAngle);
}

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. :frowning: