ExtendRealityLtd / Zinnia.Unity

A collection of design patterns for solving common problems.
http://vrtk.io
MIT License
320 stars 38 forks source link

VRTK_ScreenFade does not work with scriptable render pipelines #481

Closed krzys-h closed 3 years ago

krzys-h commented 5 years ago

Environment

Steps to reproduce

Set up a project using experimental LWRP for VR in Unity. Import VRTK into it. Do the following:

VRTK_HeadsetFade fade = gameObject.AddComponent<VRTK_HeadsetFade>();
fade.Fade(Color.black, 5.0f);

Expected behavior

The screen should fade.

Current behavior

The screen does not fade. OnPostRender in the VRTK_ScreenFade script is not called when scriptable render pipelines are used.

krzys-h commented 5 years ago

Also see https://forum.unity.com/threads/feedback-wanted-scriptable-render-pipelines.470095/page-8#post-3408481 for explanation why OnPostRender was removed

krzys-h commented 5 years ago

I tested on SteamVR now as well - it doesn't work either, the SteamVR_Fade script has exactly the same problem.

Here is the solution I ended up with for now, it took a while to figure out since there aren't many resources about the scriptable pipelines yet but it works:

using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.LightweightPipeline;
using UnityEngine.Rendering;
using VRTK;

public class VRTK_ScreenFade_LWRP : VRTK_ScreenFade, IAfterRender
{
    private FadeRenderPass fadeRenderPass;

    public ScriptableRenderPass GetPassToEnqueue()
    {
        return fadeRenderPass ?? (fadeRenderPass = new FadeRenderPass(this));
    }

    private class FadeRenderPass : ScriptableRenderPass
    {
        private VRTK_ScreenFade_LWRP screenFade;
        private Mesh quad;

        public FadeRenderPass(VRTK_ScreenFade_LWRP screenFade)
        {
            this.screenFade = screenFade;

            quad = new Mesh();

            Vector3[] newVertices = new Vector3[4];
            newVertices[0] = new Vector3(0f, 0f, 0.9999f);
            newVertices[1] = new Vector3(0f, 1f, 0.9999f);
            newVertices[2] = new Vector3(1f, 0f, 0.9999f);
            newVertices[3] = new Vector3(1f, 1f, 0.9999f);
            quad.vertices = newVertices;

            Vector2[] newUVs = new Vector2[newVertices.Length];
            newUVs[0] = new Vector2(0, 0);
            newUVs[1] = new Vector2(0, 1);
            newUVs[2] = new Vector2(1, 0);
            newUVs[3] = new Vector2(1, 1);
            quad.uv = newUVs;

            int[] newTriangles = new int[] { 0, 1, 2, 3, 2, 1 };
            quad.triangles = newTriangles;

            Vector3[] newNormals = new Vector3[newVertices.Length];
            for (int i = 0; i < newNormals.Length; i++)
                newNormals[i] = Vector3.forward;
            quad.normals = newNormals;
        }

        public override void Execute(ScriptableRenderer renderer, ScriptableRenderContext context, ref RenderingData renderingData)
        {
            // interpolation code copy-pasted from current OnPostRender implementation
            if (screenFade.currentColor != screenFade.targetColor)
            {
                if (Mathf.Abs(screenFade.currentColor.a - screenFade.targetColor.a) < Mathf.Abs(screenFade.deltaColor.a) * Time.deltaTime)
                {
                    screenFade.currentColor = screenFade.targetColor;
                    screenFade.deltaColor = new Color(0, 0, 0, 0);
                }
                else
                {
                    screenFade.currentColor += screenFade.deltaColor * Time.deltaTime;
                }
            }

            if (screenFade.currentColor.a > 0 && screenFade.fadeMaterial)
            {
                screenFade.currentColor.a = (screenFade.targetColor.a > screenFade.currentColor.a && screenFade.currentColor.a > 0.98f ? 1f : screenFade.currentColor.a);

                screenFade.fadeMaterial.color = screenFade.currentColor;
                screenFade.fadeMaterial.SetPass(0);

                CommandBuffer cmd = CommandBufferPool.Get("ScreenFade");
                cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.Ortho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 100.0f));
                cmd.DrawMesh(quad, Matrix4x4.identity, screenFade.fadeMaterial);
                context.ExecuteCommandBuffer(cmd);
                CommandBufferPool.Release(cmd);
            }
        }
    }
}
diff --git a/Assets/VRTK/Source/SDK/SteamVR/SDK_SteamVRHeadset.cs b/Assets/VRTK/Source/SDK/SteamVR/SDK_SteamVRHeadset.csindex d54988d..3e59f49 100644
--- a/Assets/VRTK/Source/SDK/SteamVR/SDK_SteamVRHeadset.cs
+++ b/Assets/VRTK/Source/SDK/SteamVR/SDK_SteamVRHeadset.cs
@@ -133,7 +133,9 @@ namespace VRTK
         /// <param name="fadeOverlay">Determines whether to use an overlay on the fade.</param>
         public override void HeadsetFade(Color color, float duration, bool fadeOverlay = false)
         {
-            SteamVR_Fade.Start(color, duration, fadeOverlay);
+            // PATCH: SteamVR_Fade is also broken in LWRP ~krzys_h
+            //SteamVR_Fade.Start(color, duration, fadeOverlay);
+            VRTK_ScreenFade.Start(color, duration);
         }

         /// <summary>
(and then add the VRTK_ScreenFade_LWRP on the camera manually so that VRTK doesn't automatically add the other one)
Manuel-Meyer commented 5 years ago

The Solution above doesn't work for me (Unity 2019).

IAfterRenderer is not part of UnityEngine.Rendering.LWRP and LightweightPipeline is not in namespace using UnityEngine.Experimental.Rendering anymore. Has anyone found a solution for this problem?

huseyingulgen commented 5 years ago

Does not work for me also. I just use ui image for fade now. It is not working well but you can use for now. If somebody has better a way , They can share solution here for LWRP please ? @Manuel-Meyer @krzys-h

krzys-h commented 5 years ago

I'm pretty sure Unity 2019 moved UnityEngine.Experimental.Rendering to just UnityEngine.Rendering.

Anyway, as it later turned out my solution didn't work on the actual headset for some reason, only on the simulator - I ended up switching to directly calling OpenVR.Compositor.FadeToColor() which worked even better for my purposes (fade between changing scenes - Unity would sometimes hang while loading and drop out to the compositor, this way the compositor keeps the screen black even if Unity stops rendering for a moment). Of course that is only valid when you are using OpenVR, but I guess other platforms must have something similar.

            try
            {
                if (OpenVR.Compositor == null)
                    throw new Exception("OpenVR not available");
                OpenVR.Compositor.FadeToColor(0.75f, 0.0f, 0.0f, 0.0f, 1.0f, false);
            }
            catch(Exception e) // throws the exception above if OpenVR is disabled or "dll not found" on platforms that don't support it at all (anything Android based like Oculus Quest or GearVR)
            {
                // TODO: add some fallback here, I'm just calling the VRTK fade for now to have it look correct when testing on the simulator
            }
            yield return new WaitForSeconds(0.75f);

            AsyncOperation asyncLoadOp = SceneManager.LoadSceneAsync(sceneToLoad, new LoadSceneParameters() { loadSceneMode = LoadSceneMode.Additive });
            yield return asyncLoadOp;
            if (previousScene.HasValue)
                yield return SceneManager.UnloadSceneAsync(previousScene.Value);
            SceneManager.SetActiveScene(SceneManager.GetSceneByName(sceneToLoad));

            try
            {
                if (OpenVR.Compositor == null)
                    throw new Exception("OpenVR not available");
                OpenVR.Compositor.FadeToColor(0.75f, 0.0f, 0.0f, 0.0f, 0.0f, false);
            }
            catch (Exception e)
            {
                // TODO: add fallback here
            }
            yield return new WaitForSeconds(0.75f);
cocapasteque commented 4 years ago

Any ETA for this issue ?

bddckr commented 4 years ago

We'll not look at SRP support before Unity stabilizes that functionality. Additionally Unity currently does offer no way to support multiple SRPs in a single codebase/package.

You can observe changes to this issue to know about the progress on this.

thestonefox commented 4 years ago

Some further work has been done on this in the PR https://github.com/ExtendRealityLtd/Zinnia.Unity/pull/477

But it's still not working on Oculus Quest so still not ready for merge.

thestonefox commented 4 years ago

Proposed solution https://gist.github.com/hawkwood/41b0b361fdfa7a14acd21ae4a571f4dc

thestonefox commented 3 years ago

PR with fix

https://github.com/ExtendRealityLtd/Zinnia.Unity/pull/543

ExtendReality-Bot commented 3 years ago

:tada: This issue has been resolved in version 1.36.1 :tada:

The release is available on:

Your semantic-release bot :package::rocket: