ValveSoftware / steamvr_unity_plugin

SteamVR Unity Plugin - Documentation at: https://valvesoftware.github.io/steamvr_unity_plugin/
BSD 3-Clause "New" or "Revised" License
1.03k stars 256 forks source link

Enabling/disabling VR with SteamVR v.2 #307

Open martamartino86 opened 5 years ago

martamartino86 commented 5 years ago

Hi everybody!

As the title says, I'm trying to enable/disable VR between different applications, and I need to do it as many times as I want. I'm working with Unity 2017.4 and SteamVR 2.0.1 (I also tried with 2.2, same behaviour).

There is a simple solution for this:

IEnumerator SwitchOutOfVr() {
        XRSettings.LoadDeviceByName(""); // Empty string loads the "None" device.
        // Wait one frame!
        yield return null;
        XRSettings.enabled = false;
}

but I got nasty exceptions since Actions and Poses don't seem to be handled correctly after disabling VR; instead, the update functions are still called:

NullReferenceException: Object reference not set to an instance of an object Valve.VR.SteamVR_Action_Pose_Source.UpdateValue (Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Pose.cs:571) Valve.VR.SteamVR_Action_Skeleton_Source.UpdateValue (Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:904) Valve.VR.SteamVR_Action_Skeleton.UpdateValue (Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65) Valve.VR.SteamVR_Input.UpdateSkeletonActions (Boolean skipSendingEvents) (at Assets/SteamVR/Input/SteamVR_Input.cs:355) Valve.VR.SteamVR_Input.LateUpdate () (at Assets/SteamVR/Input/SteamVR_Input.cs:269) Valve.VR.SteamVR_Behaviour.LateUpdate () (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)

I'd like to know if I'm doing something wrong or it's something that will be fixed. Thanks in advance for any hint.

zite commented 5 years ago

You could try destroying the SteamVR_Behaviour component after trying to disable VR. Not sure how much that will fix your issues though if you still have VR components in your scene. What is your expected behaviour here?

Also, can you describe your scenario in which you're enabling/disabling vr in the same application?

martamartino86 commented 5 years ago

Hi zite, this is my scenario:

I have multiple VR applications running in local and communicating with each other using UNET. I need to be able to switch from one application to the other whenever I want, maintaining the current state of the apps (I can't quit them). Since VR can't be "owned" by more than one process at a time, I thought it should be handled with XRSettings.enabled = false.

I tried your solution, disabling/enabling SteamVR_Behaviour component, right before XRSettings.LoadDeviceByName(""), and no exceptions are raised.

        {
            print("Disabling VR ...");
            EnableSteamVRBehaviour(false);
            XRSettings.LoadDeviceByName("");
            yield return null;
            XRSettings.enabled = false;
        }

But these exceptions appear when I enable it back:

<b>[SteamVR]</b> GetPoseActionData error (/actions/default/in/SkeletonLeftHand): InvalidHandle Handle: 1152921831024361729. Input source: Any
UnityEngine.Debug:LogError(Object)
Valve.VR.SteamVR_Action_Pose_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Pose.cs:574)
Valve.VR.SteamVR_Action_Skeleton_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:904)
Valve.VR.SteamVR_Action_Skeleton:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65)
Valve.VR.SteamVR_Input:UpdateSkeletonActions(Boolean) (at Assets/SteamVR/Input/SteamVR_Input.cs:355)
Valve.VR.SteamVR_Input:LateUpdate() (at Assets/SteamVR/Input/SteamVR_Input.cs:269)
Valve.VR.SteamVR_Behaviour:LateUpdate() (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)

<b>[SteamVR]</b> GetSkeletalActionData error (/actions/default/in/SkeletonLeftHand): InvalidHandle handle: 1152921831024361729
UnityEngine.Debug:LogError(Object)
Valve.VR.SteamVR_Action_Skeleton_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:910)
Valve.VR.SteamVR_Action_Skeleton:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65)
Valve.VR.SteamVR_Input:UpdateSkeletonActions(Boolean) (at Assets/SteamVR/Input/SteamVR_Input.cs:355)
Valve.VR.SteamVR_Input:LateUpdate() (at Assets/SteamVR/Input/SteamVR_Input.cs:269)
Valve.VR.SteamVR_Behaviour:LateUpdate() (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)

<b>[SteamVR]</b> GetPoseActionData error (/actions/default/in/SkeletonRightHand): InvalidHandle Handle: 1152921831024361730. Input source: Any
UnityEngine.Debug:LogError(Object)
Valve.VR.SteamVR_Action_Pose_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Pose.cs:574)
Valve.VR.SteamVR_Action_Skeleton_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:904)
Valve.VR.SteamVR_Action_Skeleton:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65)
Valve.VR.SteamVR_Input:UpdateSkeletonActions(Boolean) (at Assets/SteamVR/Input/SteamVR_Input.cs:355)
Valve.VR.SteamVR_Input:LateUpdate() (at Assets/SteamVR/Input/SteamVR_Input.cs:269)
Valve.VR.SteamVR_Behaviour:LateUpdate() (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)

<b>[SteamVR]</b> GetSkeletalActionData error (/actions/default/in/SkeletonRightHand): InvalidHandle handle: 1152921831024361730
UnityEngine.Debug:LogError(Object)
Valve.VR.SteamVR_Action_Skeleton_Source:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:910)
Valve.VR.SteamVR_Action_Skeleton:UpdateValue(Boolean) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65)
Valve.VR.SteamVR_Input:UpdateSkeletonActions(Boolean) (at Assets/SteamVR/Input/SteamVR_Input.cs:355)
Valve.VR.SteamVR_Input:LateUpdate() (at Assets/SteamVR/Input/SteamVR_Input.cs:269)
Valve.VR.SteamVR_Behaviour:LateUpdate() (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)

Also, the controller mesh has changed to the "default one" without hand/glove, but it seems like I can still perform actions. Right now I'm using a very basic scene just for testing, and I'm afraid more issues are going to pop up if I don't handle this thing in a consistent way.

Thanks again for your help.

zite commented 5 years ago

You could try destroying the component, then calling disable vr. Then instead of enabling it call SteamVR.Initialize(true); to force a full reinitialization. Actions aren't really meant to be reinitialized, which is what's required here, so I'm not positive this will work.

martamartino86 commented 5 years ago

Apparently, this will do the trick:

IEnumerator EnableVR(bool enable)
{
        // ** ENABLE VR **
        if (enable)
        {
            print("Enabling VR ...");
            SteamVR.Initialize(true);
        }
        // ** DISABLE VR **
        else
        {
            print("Disabling VR ...");
            Destroy(FindObjectOfType<SteamVR_Behaviour>());
            XRSettings.LoadDeviceByName(""); // still needed to release the Vive
            yield return null;

            XRSettings.enabled = false;
        }

        yield return new WaitForSeconds(2);
}

No exceptions, no strange behaviours. I'm testing just one action, so I'm not 100% sure this solution won't raise issues in the future, but it works so far. Thank you so much for your help! Can I ask you if this is something that will be handled in a "safer" way from SteamVR in the future?

zite commented 5 years ago

Yeah, being able to disable steamvr seems like a reasonable request. I'll add it to the feature request list.

blevesque commented 5 years ago

Hey @martamartino86, did you do something special to initialize VR settings ? Like a "XRSettings.LoadDeviceByName("OpenVR");" at start of program ? Thanks !

martamartino86 commented 5 years ago

Hi @blevesque, no, it's a standard VR application, so VR gets initialized automatically.

JorgeZubog commented 4 years ago

Hello, I have exactly the same problem, I need enabling/disabling VR as many times as the player wants, however in the second time I get the same errors and in the application build I lose the controllers tracking. I’m working with the player prefab, I have the current plugin version 2.5.0 (sdk 1.8.19) and SteamVR 1.8.20 version.

I’ll be very glad with any help :)

This is my code:

IEnumerator EnableVR(bool enable)
    {
        // ** ENABLE VR **
        if (enable)
        {
            mainCamera.SetActive(false);

            if (string.Compare(XRSettings.loadedDeviceName, "OpenVR", true) != 0)
            {
                XRSettings.LoadDeviceByName("OpenVR");
                yield return null;
            }
            XRSettings.enabled = true;

            yield return null;

            player.SetActive(true);

            print("Enabling VR ...");
            SteamVR.Initialize(true);
        }
        // ** DISABLE VR **
        else
        {
            player.SetActive(false);

            print("Disabling VR ...");
            Destroy(FindObjectOfType<SteamVR_Behaviour>());
            XRSettings.LoadDeviceByName(""); // still needed to release the Vive
            yield return null;

            XRSettings.enabled = false;
            yield return new WaitForSeconds(2);

            mainCamera.SetActive(true);
        }

    }

This are the errors:

NullReferenceException: Object reference not set to an instance of an object
Valve.VR.SteamVR_Action_Pose_Source.UpdateValue (System.Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Pose.cs:575)
Valve.VR.SteamVR_Action_Skeleton_Source.UpdateValue (System.Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:917)
Valve.VR.SteamVR_Action_Skeleton.UpdateValue (System.Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Action_Skeleton.cs:65)
Valve.VR.SteamVR_Input.UpdateSkeletonActions (System.Boolean skipSendingEvents) (at Assets/SteamVR/Input/SteamVR_Input.cs:355)
Valve.VR.SteamVR_Input.LateUpdate () (at Assets/SteamVR/Input/SteamVR_Input.cs:269)
Valve.VR.SteamVR_Behaviour.LateUpdate () (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:230)

NullReferenceException: Object reference not set to an instance of an object
Valve.VR.SteamVR_ActionSet_Manager.UpdateActionStates (System.Boolean force) (at Assets/SteamVR/Input/SteamVR_ActionSet_Manager.cs:57)
Valve.VR.SteamVR_Input.UpdateVisualActions (System.Boolean skipStateAndEventUpdates) (at Assets/SteamVR/Input/SteamVR_Input.cs:315)
Valve.VR.SteamVR_Input.OnPreCull () (at Assets/SteamVR/Input/SteamVR_Input.cs:302)
Valve.VR.SteamVR_Behaviour.PreCull () (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:219)
Valve.VR.SteamVR_Behaviour.OnBeforeRender () (at Assets/SteamVR/Scripts/SteamVR_Behaviour.cs:189)
UnityEngine.BeforeRenderHelper.Invoke () (at C:/buildslave/unity/build/Runtime/Export/Graphics/BeforeRenderHelper.cs:92)
UnityEngine.Application.InvokeOnBeforeRender () (at C:/buildslave/unity/build/Runtime/Export/Application/Application.cs:318)
Eyap53 commented 4 years ago

@zite what is the current status of this feature request ?

slages commented 4 years ago

Hi @zite, I'm Serge from Unity, we've had multiple users reporting this issue, do you have any estimation on when it could be solved?

Thanks!

AnriEU commented 4 years ago

I tried 3 variants and no one is working in Unity 2020.1 So, how to create VR and NON VR game? I get no errors, but Checkbox no react at all.

https://drive.google.com/file/d/13_H831oEyvbzTCi3KJ5sIs7ITqEOc8lF/view?usp=sharing

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.XR;

Var 1

    public bool enableXR = false;
    public GameObject[] XRGameObjects;

    void Awake()
    {
        XRSettings.enabled = enableXR;
        foreach (var go in XRGameObjects)
        {
            go.SetActive(enableXR);
        }
    }

Var 2

    IEnumerator LoadDevice(string newDevice, bool enable)
    {
        XRSettings.LoadDeviceByName(newDevice);
        yield return null;
        XRSettings.enabled = enable;
    }

    void EnableVR()
    {
        StartCoroutine(LoadDevice("daydream", true));
    }

    void DisableVR()
    {
        StartCoroutine(LoadDevice("", false));
    }

    void Start()
    {
        DisableVR();
    }

Var 3

    void Start()
    {
        XRSettings.LoadDeviceByName("");
        XRSettings.enabled = false;
    }