Steam VR Plugin : Reset Position and orientation

Hello,

I’m currently working with Steam VR Plugin for Unity and i’m converting my whole project for the fantastic HTC Vive Pre and forward.

UNFORTUNATELY i didn’t figured out the equivalent to :
" UnityEngine.VR.InputTracking.Recenter(); "

I tried SteamVR.instance.hmd.ResetSeatedZeroPose(); without any success…
Seems on the web i’m not alone but didn’t found any answer.

Does anyone can help ?

This problem may be Unity5.3.3 Bug

    public KeyCode reOrient;

    void Update()
    {
        if (Input.GetKeyDown(reOrient) == true)
        {
            Valve.VR.OpenVR.System.ResetSeatedZeroPose();

            //transform.parent.localEulerAngles -= transform.localEulerAngles + transform.parent.localEulerAngles;
        }
        //transform.parent.localPosition = -transform.localPosition;
    }

Valves reset seems like the way to go, but it does nothing I can detect. Use the commented lines and remove/comment the ResetSeatedZeroPose line, make sure the camera (origin) is a child of something that looks at your centre. And dont forget to set a reOrient key in the inspector (This code can create strange offsets when reorienting)

1 Like

alert @VirtualisDev and others…

Actual miracle solution is here:

OpenVR - How to reset camera properly? - Unity Engine - Unity Discussions

thanks to TODD-WASSON

I spent a lot of time looking for a answer on this. Tried all of the options on this thread and the miracle one without success. Looked like several of the SteamVR/Valve and native solutions stopped working after a recent update. Eventually wrote this script which took care of it to my liking.

This script will allow a reset of the SteamVR camera rig to align with a transform representing the desired head position in the scene. Attach to any GameObject in the scene. Useful for seated experiences like cockpits.

using UnityEngine;

public class ResetSeatedPosition : MonoBehaviour {
    [Tooltip("Desired head position of player when seated")]
    public Transform desiredHeadPosition;
    private Transform steamCamera;
    private Transform steamController;

    // Update is called once per frame
    void Update () {

        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (desiredHeadPosition != null)
            {
                ResetSeatedPos(desiredHeadPosition);
            }
            else
            {
                Debug.Log("Target Transform required. Assign in inspector.");
            }
        
        }
    }

    private void ResetSeatedPos(Transform desiredHeadPos){

        //find VR Camera and CameraRig transforms in scene
        steamCamera = FindObjectOfType<SteamVR_Camera>().gameObject.transform;   
        steamController = FindObjectOfType<SteamVR_ControllerManager>().transform;

        if ((steamCamera != null) && (steamController != null))
            {
            //{first rotation}
                //get current head heading in scene
                //(y-only, to avoid tilting the floor)
                float offsetAngle = steamCamera.rotation.eulerAngles.y;
                //now rotate CameraRig in opposite direction to compensate
                steamController.Rotate(0f, -offsetAngle, 0f);

            //{now position}
                //calculate postional offset between CameraRig and Camera
                Vector3 offsetPos = steamCamera.position - steamController.position;
                //reposition CameraRig to desired position minus offset
                steamController.position = (desiredHeadPos.position - offsetPos);

                Debug.Log("Seat recentered!");
            }
        else
            {
                Debug.Log("Error: SteamVR objects not found!");
            }
    }
}

Turned out to be simpler than I expected. Hope it can save someone else the time!

Cheers,

Gerry

PS: Running Unity 2017.2

5 Likes

The solution @gstarch suggested is the way to go. It works both for Room Scale & Seated Experiences.

Some things to remember though:

  • An important change is that the SteamVR_ControllerManager-script isn’t attached to the [CameraRig]-prefab coming with the SteamVR-plugin anymore (in SteamVR version 1.2.3 and up).

  • This also means that the variable steamController is supposed to be set to the [CameraRig]-prefab coming with the SteamVR-plugin.

  • How Unity.XR works:

  • The function UnityEngine.XR.InputTracking.Recenter(); ONLY works for Seated/Standing Experiences, ie. it won’t do anything if you have set up a Room Scale-experience.

Here’s our modified version of @gstarch 's solution. Works with Unity 2018.3.0b11 & SteamVR Version 1.2.3

Hope this helps someone!

using UnityEngine;

public class PlayAreaController : MonoBehaviour
{
    [Tooltip("Desired head position of player when seated")]
    public Transform desiredHeadPosition;

    //Assign these variables in the inspector, or find them some other way (eg. in Start() )
    public Transform steamCamera;
    public Transform cameraRig;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (desiredHeadPosition != null)
            {
                ResetSeatedPos(desiredHeadPosition);
            }
            else
            {
                Debug.LogError("Target Transform required. Assign in inspector.", gameObject);
            }
        }
    }

    private void ResetSeatedPos(Transform desiredHeadPos)
    {
        if ((steamCamera != null) && (cameraRig != null))
        {
            //ROTATION
            // Get current head heading in scene (y-only, to avoid tilting the floor)
            float offsetAngle = steamCamera.rotation.eulerAngles.y;
            // Now rotate CameraRig in opposite direction to compensate
            cameraRig.Rotate(0f, -offsetAngle, 0f);

            //POSITION
            // Calculate postional offset between CameraRig and Camera
            Vector3 offsetPos = steamCamera.position - cameraRig.position;
            // Reposition CameraRig to desired position minus offset
            cameraRig.position = (desiredHeadPos.position - offsetPos);

            Debug.Log("Seat recentered!");
        }
        else
        {
            Debug.Log("Error: SteamVR objects not found!");
        }
    }
}
4 Likes

This is just what I needed. Thanks.

1 Like

It worked lika a charm!

1 Like

I’m not sure what you are setting as the “Camera Rig”
I can make an object to be the “desiredHeadPosition” and I see the Players “VRCamera” to set as the “steamCamera”
but whats the rig? Is this something that has been removed in SteamVR 2.x (SDK 1.7.15) ?

To reset orientation I use the following:

        public void ResetTracker()
        {
            StartCoroutine( Boresight() );
        }

        private IEnumerator Boresight()
        {
            activeCameraRig.transform.rotation = Quaternion.identity;
            yield return null;

            InputTracking.Recenter();
            yield return null;

            List<XRNodeState> states = new List<XRNodeState>();
            InputTracking.GetNodeStates( states );
            var head = states.Find( s => s.nodeType == XRNode.Head );
            if( head.TryGetRotation( out Quaternion orientation ) )
                activeCameraRig.transform.rotation = Quaternion.Inverse( orientation );
        }

activeCameraRig is the top level transform on your VR rig.

        private void Start()
        {
            switch( XRSettings.loadedDeviceName )
            {
                case "Oculus":
                    activeCameraRig = Instantiate( OculusCameraRig );
                    break;

                case "OpenVR":
                    activeCameraRig = Instantiate( ViveCameraRig );
                    break;

                default:
                    break;
            }
            onCameraRigActive.Invoke( activeCameraRig );
        }
1 Like

Thank you. That image helped clarify things as did the code. Unfortunately when I load from one scene to another the player is still facing the wrong direction in the new scene.

Edit: Silly me. I Just needed to turn the player prefab around.

P.P.S Edit … Turning the player prefab only works for going to the scene if I return to the previous scene The player will now be facing the wrong way in that scene. :frowning:

Just in case someone is looking for this in 2020:
Valve.VR.OpenVR.Chaperone.ResetZeroPose(ETrackingUniverseOrigin.TrackingUniverseSeated);

Introduced by this update:

4 Likes

Hi fgheorghe.
Thank you for posting that 2020 version.
I have given it a go but it resets the Y value as well and puts the floor up to eye level. I have to close and restart SteamVR every time to put the floor back at my feet again.
Would you have any experience on what to do to keep the Y setting?
Cheers,
Lins

Hi Lins, I am wondering if the Y setting changes due to player height settings in SteamVR, outside unity, or depending on your setup, if the camera needs to be a made a child of an empty object set at a desired height - this way if Y is reset to 0, and the camera’s parent is set to 1, then when the position gets reset it will be above the floor at Y 1. Hope this helps!

I think it was a mismatch of the SteamVR_Settings saying tracking space origin seated. When I set that to standing and then in the code set
ETrackingUniverseOrigin.TrackingUniverseSeated
to
ETrackingUniverseOrigin.TrackingUniverseStanding
then it keeps the floor at my feet. Even if I have set my room guardian to stationary or free draw etc. It always sets up as standing for SteamVR.

1 Like

Just in case someone is looking for this in 2024 (me), this line faithfully emulates exactly what the SteamVR recenter button does.

UnityEngine.XR.InputTracking.Recenter();