0
\$\begingroup\$

I am making a mobile VR project in Unity, and I have a 360-degree video that starts playing where I can look around using a VR headset.

I am trying to set the start rotation of the video to the same rotation as my phone. So no matter where I look when I start the video, that should be my start rotation. I used Input.gyro.attitude in the start but that did not fix my problem. I think I am using it wrong.

This is my code (on the camera inside the sphere):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Gyroscope : MonoBehaviour
{
    private bool gyroEnabled;
    private Gyroscope gyro;
    private GameObject cameraContainer; //A camera container for my main camera
    private GameObject videoSphere; //The sphere my video is in
    private Quaternion rot;

    private void Start()
    {
        videoSphere = GameObject.FindGameObjectWithTag("Video");
        cameraContainer = new GameObject("Camera Container");

        gyroEnabled = EnableGyro();

        cameraContainer.transform.position = transform.position; // put the cameracontainer into the sphere
        cameraContainer.transform.rotation = Input.gyro.attitude; // here I want to set the cameracontainer to the rotation of my phones gyroscope 
        transform.SetParent(cameraContainer.transform); // make my main camera a child of the camera Container

        videoSphere.transform.localRotation = cameraContainer.transform.rotation; // Here I wanted to set my sphere rotation to the camera rotation
        Debug.Log(videoSphere.transform.localRotation);
    }

    private bool EnableGyro()
    {
        if (SystemInfo.supportsGyroscope)
        {
            Input.gyro.enabled = true; // turn on my gyroscope

            cameraContainer.transform.rotation = new Quaternion(0, 90, -90, 0); // rotate my camera container so the video shows good
            rot = new Quaternion(0, 0, 1, 0); // set the variable rot so that you can turn your device
            return true;
        }
        return false;
    }

    private void Update()
    {
        if (gyroEnabled)
        {
            transform.localRotation = Input.gyro.attitude * rot; //this makes you turn the device and it recognizes the input of the phones gyroscope        
        }
    }
}
\$\endgroup\$
1

1 Answer 1

1
\$\begingroup\$

If you want to rotate the video sphere counter to the head's rotation (to make it look like the head is rotating within a stationary sphere), then you want something like this on the sphere:

// Track the sphere's starting orientation in your scene.
Quaternion _startingOrientation;

void Start() {
    _startingOrientation = transform.rotation;
}

// Re-orient the sphere to reflect the head's attitude.
public void CounterRotate(Quaternion headAttitude) {
    transform.rotation = Quaternion.Inverse(headAttitude) * _startingOrientation;
}

Now, if you want to "neutralize" the player's starting orientation (so they're always looking at a standard "North" to begin with), you can store their starting orientation as a correction.

You'll probably want to ignore pitch and roll here (the player can feel the tilt of their head relative to the horizon — if the horizon they see doesn't match, it can cause simulation sickness)

// Since the phone is mounted sideways in the VR device, we'll need to account for that.
// Store the angle of your sensor here in the inspector.
public Vector3 sensorAngleInHeadset = new Vector3(0, 0, 90);

// Store a correction to neutralize the starting orientation of the head.
Quaternion _neutralizer = Quaternion.identity;

// Compute the attitude of an upright sensor, from the phone's tilted mounting.
Quaternion GetUprightAttitude() {
    return Input.gyro.attitude * Quaternion.Euler(-sensorAngleInHeadset);
}

// Call this when initializing, or when the player chooses to "re-center"
public void Neutralize() {
    // Look at only the forward vector to ignore roll.
    Vector3 forward = GetUprightAttitude() * Vector3.forward;

    // Flatten the forward to the horizon to ignore pitch.
    forward.y = 0;

    // Form a view orientation looking in this direction.
    var neutral = Quaternion.LookRotation(forward);

    // Form a correction that undoes this orientation,
    // bringing its "forward" back to world Z+
    _neutralizer = Quaternion.Inverse(neutral);
}

// Each frame, rotate our video sphere according to the corrected orientation.
void Update() {
     var corrected = _neutralizer * GetUprightAttitude();
     videoSphere.CounterRotate(corrected);
}

Or, if you want to keep your sphere stationary and rotate the camera inside, then change that last line to:

camera.transform.rotation = corrected;

Either way, make sure you're rotating either just the camera or just the video screen, not both at once, or you'll get a very confusing outcome.

\$\endgroup\$
2
  • \$\begingroup\$ Now I put everything together in my sphere script but it does not work. It shows the opposite direction \$\endgroup\$
    – Petrit
    Commented Sep 10, 2019 at 9:20
  • \$\begingroup\$ Looks like I neglected the fact that the phone sits sideways inside the headset. I've added a method to correct that above - you can adjust the angle if your phone has a different standard orientation inside the headset. If you're still observing a discrepancy in movements, then we'll need a very explicit test case to diagnose it. Like "I start with my head level, facing north. Input.gyro.attitude.eulerAngles reports (X1, Y1, Z1). I see A. I rotate my head slowly to the left until printing my eulerAngles reports (X2, Y2, Z2). I see B, but I expect to see C" \$\endgroup\$
    – DMGregory
    Commented Sep 10, 2019 at 11:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .