googlevr / gvr-unity-sdk

Google VR SDK for Unity
http://developers.google.com/vr/unity/
Other
2.71k stars 1.09k forks source link

GvrCardboardHelpers.SetViewerProfile #949

Open tedtheodore opened 6 years ago

tedtheodore commented 6 years ago

This is to reopen the issue #868. It was assumed fixed in the latest version of GVR v1.150.0, but It doesn't appear to have been addressed.

I assumed the call GvrCardboardHelpers.SetViewerProfile was updated to allow for temporary viewer overrides, or overriding the "session viewer profile", but either this isn't the case or some other approach was taken.

I can't find anything relating to it in the change logs.

Daniel-Dobson commented 6 years ago

This feature is important 👍

tedtheodore commented 6 years ago

I'm glad you're following too! Yeah, it's a big deal for us

Adam-VisualVocal commented 6 years ago

I agree, not quite fixed yet. I was able to make it work but only with some workarounds. My observations:

  1. You still need to be in VR to call it. It would be much more useful if you could call it before entering VR.
  2. We have to call gvr_set_default_viewer_profile ourselves instead of using the GvrCardboardHelpers.SetViewerProfile wrapper because it eats the bool return value which we need for step 3.
  3. If gvr_set_default_viewer_profile succeeds (returning true), you need to call gvr_refresh_viewer_profile AND leave and reenter VR before the new default will take effect.
  4. Also, the iPhone always seems to need a gvr_refresh_viewer_profile call or it uses the wrong one.
Adam-VisualVocal commented 6 years ago

Like this:

#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
        [DllImport(GvrActivityHelper.GVR_DLL_NAME)]
        private static extern bool gvr_set_default_viewer_profile(IntPtr gvr_context,
            [MarshalAs(UnmanagedType.LPStr)] string viewer_profile_uri);

        [DllImport(GvrActivityHelper.GVR_DLL_NAME)]
        private static extern void gvr_refresh_viewer_profile(IntPtr gvr_context);
#endif

public static IEnumerator SetDefaultViewerProfile(string viewerProfileUri)
{
    if (XRSettings.enabled)
    {
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
        // GvrCardboardHelpers.SetViewProfile does not expose the return type so we
        // call gvr_set_default_viewer_profile ourselves.

        IntPtr gvrContextPtr = GvrSettings.GetValidGvrNativePtrOrLogError();
        if (gvrContextPtr == IntPtr.Zero)
        {
            Utils.LogError("Cannot set default viewer profile! No GVR Context Ptr exists! " +
                            "You must first load AND enable a GVR device via UnityEngine.XR.XRSettings.");
            yield break;
        }

        if (gvr_set_default_viewer_profile(gvrContextPtr, viewerProfileUri))
        {
            Debug.Log("gvr_set_default_viewer_profile returned true");

            // setting the default viewer succeeded but we need to do a little dance to make it stick
            gvr_refresh_viewer_profile(gvrContextPtr);

            string deviceName = XRSettings.loadedDeviceName;

            XRSettings.enabled = false;
            XRSettings.LoadDeviceByName(string.Empty);
            yield return null;

            XRSettings.LoadDeviceByName(deviceName);
            yield return null;
            XRSettings.enabled = true;
        }
        else
        {
            Debug.Log("gvr_set_default_viewer_profile returned false");

            // the iPhone always seems to need this or it uses the wrong profile
            gvr_refresh_viewer_profile(gvrContextPtr);
        }
#else
        Debug.Log("Unavailable for non-Android and non-iOS builds");
        yield break;
#endif  // (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
    }
    else
    {
        Utils.LogError("VR must be enabled before calling SetDefaultViewerProfile.");
    }
}
Ethan-VisualVocal commented 6 years ago

👍 This needs a proper fix. These workarounds are prone to breakage between each GVR SDK update, don't solve the temporary override viewer problem on Android, and cycling VR on/off for Android is a bad user experience (screen flicker).

tedtheodore commented 6 years ago

Thanks a lot for that! I think I will adopt this approach for the mean time and halt updates until its confirmed fixed.

Daniel-Dobson commented 6 years ago

Much appreciated @Adam-VisualVocal ! This is very helpful. @Ethan-VisualVocal I fully agree yes.

honkeat commented 5 years ago

Like this:

#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
        [DllImport(GvrActivityHelper.GVR_DLL_NAME)]
        private static extern bool gvr_set_default_viewer_profile(IntPtr gvr_context,
            [MarshalAs(UnmanagedType.LPStr)] string viewer_profile_uri);

        [DllImport(GvrActivityHelper.GVR_DLL_NAME)]
        private static extern void gvr_refresh_viewer_profile(IntPtr gvr_context);
#endif

public static IEnumerator SetDefaultViewerProfile(string viewerProfileUri)
{
    if (XRSettings.enabled)
    {
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
        // GvrCardboardHelpers.SetViewProfile does not expose the return type so we
        // call gvr_set_default_viewer_profile ourselves.

        IntPtr gvrContextPtr = GvrSettings.GetValidGvrNativePtrOrLogError();
        if (gvrContextPtr == IntPtr.Zero)
        {
            Utils.LogError("Cannot set default viewer profile! No GVR Context Ptr exists! " +
                            "You must first load AND enable a GVR device via UnityEngine.XR.XRSettings.");
            yield break;
        }

        if (gvr_set_default_viewer_profile(gvrContextPtr, viewerProfileUri))
        {
            Debug.Log("gvr_set_default_viewer_profile returned true");

            // setting the default viewer succeeded but we need to do a little dance to make it stick
            gvr_refresh_viewer_profile(gvrContextPtr);

            string deviceName = XRSettings.loadedDeviceName;

            XRSettings.enabled = false;
            XRSettings.LoadDeviceByName(string.Empty);
            yield return null;

            XRSettings.LoadDeviceByName(deviceName);
            yield return null;
            XRSettings.enabled = true;
        }
        else
        {
            Debug.Log("gvr_set_default_viewer_profile returned false");

            // the iPhone always seems to need this or it uses the wrong profile
            gvr_refresh_viewer_profile(gvrContextPtr);
        }
#else
        Debug.Log("Unavailable for non-Android and non-iOS builds");
        yield break;
#endif  // (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
    }
    else
    {
        Utils.LogError("VR must be enabled before calling SetDefaultViewerProfile.");
    }
}

Did anyone get this working? I tried the above code but it doesn't seem like the profile changed on the mobile device.

Ethan-VisualVocal commented 5 years ago

Did anyone get this working? I tried the above code but it doesn't seem like the profile changed on the mobile device.

Which device are you trying this on?

To be clear, on Android, if the user has already manually changed the "Headset" profile to anything, this code won't change it. It will only change the profile if user hasn't set a different one. It's possible that operating your device with Daydream will also prevent this code from working. (Daydream configures your headset when you get it near a device, I believe.)

So, to test this code properly on Android, you basically need to factory reset your phone...


Thus, this issue remains open as an ask to Google (cough @rusmaxham cough) for a new set-viewer-profile method that lets devs temporarily override the "VR Settings > Headset" value for the current app's run session.


On iOS, however, this code should work consistently without a hitch.

An example viewerProfileUri to pass into this method is: http://google.com/cardboard/cfg?p=CgZIb21pZG8SDUhvbWlkbyAibWluaSIdhxZZPSW28309KhAAAEhCAABIQgAASEIAAEhCWAE1KVwPPToIexQuPs3MTD1QAGAC That will set it to Homido "mini"