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
\$\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\$
  • \$\begingroup\$ Now I put everything together in my sphere script but it does not work. It shows the opposite direction \$\endgroup\$ – Petrit Sep 10 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 Sep 10 at 11:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.