From 8fbaa7674feee593cb55e44362043ec9d53d998d Mon Sep 17 00:00:00 2001 From: TrevorDaschOculus Date: Tue, 13 Jun 2023 11:06:25 -0400 Subject: [PATCH 1/3] Update OculusMotionVectorPass to support all renderers, added debug UI to see motion vector buffer in editor --- .../Editor/Debug.meta | 8 ++ .../OculusMotionVectorDebugShader.shader | 72 ++++++++++++ .../OculusMotionVectorDebugShader.shader.meta | 10 ++ .../Editor/Debug/OculusMotionVectorWindow.cs | 105 ++++++++++++++++++ .../Debug/OculusMotionVectorWindow.cs.meta | 11 ++ .../Includes/OculusMotionVectors.hlsl | 7 ++ .../Editor/ShaderGraph/Includes/Varyings.hlsl | 40 +++---- .../ShaderGraph/Targets/UniversalTarget.cs | 9 +- .../Debug/DebugOculusMotionVectorSettings.cs | 22 ++++ .../DebugOculusMotionVectorSettings.cs.meta | 11 ++ .../Runtime/Passes/OculusMotionVectorPass.cs | 12 +- .../Runtime/UniversalRenderer.cs | 17 ++- .../Runtime/XR/XRPass.cs | 24 ++-- .../ShaderLibrary/OculusMotionVectorCore.hlsl | 32 +++--- .../OculusMotionVectorStatic.hlsl | 50 +++++++++ .../OculusMotionVectorStatic.hlsl.meta | 10 ++ 16 files changed, 380 insertions(+), 60 deletions(-) create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Debug.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs create mode 100644 Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs.meta create mode 100644 Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl create mode 100644 Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl.meta diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Debug.meta b/Packages/com.unity.render-pipelines.universal/Editor/Debug.meta new file mode 100644 index 00000000000..19aa3146ce7 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Debug.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f06321421d2f7a42af4c226d8395e59 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader new file mode 100644 index 00000000000..bd144139674 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader @@ -0,0 +1,72 @@ +Shader "Unlit/OculusMotionVectorDebugShader" +{ + Properties + { + _MainTex ("Texture", 2DArray) = "white" {} + _MinValue ("Min Value", Float) = 0 + _MaxValue ("Max Value", Float) = 1 + [Toggle] _OnlyRed ("Only Red", Float) = 0 + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + + #pragma require 2darray + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD0; + }; + + struct v2f + { + float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + UNITY_DECLARE_TEX2DARRAY(_MainTex); + + float _MinValue; + float _MaxValue; + float _OnlyRed; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = float2(v.uv.x, 1 - v.uv.y); + return o; + } + + float3 inv_lerp(const float from, const float to, const float3 value){ + return (value - from) / (to - from); + } + + fixed4 frag (v2f i) : SV_Target + { + // sample the texture + float3 col = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(i.uv, 0)).rgb; + + if (_OnlyRed == 1.0) + { + col.gb = col.rr; + } + + // Map to the specified range + col = inv_lerp(_MinValue, _MaxValue, col); + + return float4(col, 1); + } + ENDCG + } + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader.meta b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader.meta new file mode 100644 index 00000000000..bd168f25cc9 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorDebugShader.shader.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 28c37e9a1009104429adb673051c63bf +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs new file mode 100644 index 00000000000..e4c74fed7f8 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using UnityEngine; +using UnityEditor; +using UnityEngine.Rendering; + +public class OculusMotionVectorWindow : EditorWindow { + + private const int k_MotionVectorTextureSize = 512; + + private Material m_DebugMotionVectorMaterial; + private Material m_DebugDepthMaterial; + + private float m_MaxVectorValue = 0.1f; + private float m_MaxDepth = 0.01f; + + [MenuItem ("Oculus/Debug Motion Vectors")] + public static void ShowWindow () + { + EditorWindow.GetWindow(typeof(OculusMotionVectorWindow)); + } + + private Material GetNamedMaterial(string name) { + var shaderGuid = AssetDatabase.FindAssets($"t:Shader {name}").FirstOrDefault(); + + return shaderGuid != null ? new Material(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(shaderGuid))) : null; + } + + private void InitMotionVectors() { + + if (UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.motionVectorRenderTarget == null) + { + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.motionVectorRenderTargetDesc = new RenderTextureDescriptor(k_MotionVectorTextureSize, k_MotionVectorTextureSize, RenderTextureFormat.ARGBFloat, 0) { vrUsage = VRTextureUsage.TwoEyes, dimension = TextureDimension.Tex2DArray, volumeDepth = 2 }; + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.motionVectorRenderTarget = new RenderTexture(UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.motionVectorRenderTargetDesc); + } + + if (UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.depthRenderTarget == null) + { + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.depthRenderTargetDesc = new RenderTextureDescriptor(k_MotionVectorTextureSize, k_MotionVectorTextureSize, RenderTextureFormat.Depth, 24) { vrUsage = VRTextureUsage.TwoEyes, dimension = TextureDimension.Tex2DArray, volumeDepth = 2 }; + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.depthRenderTarget = new RenderTexture(UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.depthRenderTargetDesc); + } + } + + private void Awake() { + + InitMotionVectors(); + m_DebugMotionVectorMaterial = GetNamedMaterial("OculusMotionVectorDebugShader"); + m_DebugMotionVectorMaterial.SetFloat("_OnlyRed", 0.0f); + m_DebugDepthMaterial = GetNamedMaterial("OculusMotionVectorDebugShader"); + m_DebugDepthMaterial.SetFloat("_OnlyRed", 1.0f); + } + + private void OnDestroy() { + + DestroyImmediate(m_DebugMotionVectorMaterial); + } + + void Update() { + + Repaint(); + } + + void OnGUI () { + + InitMotionVectors(); + if (m_DebugMotionVectorMaterial == null) { + Awake(); + } + + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.enableDebugMotionVectors = + EditorGUILayout.Toggle("Enable Motion Vectors", + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.enableDebugMotionVectors); + + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.BeginVertical(); + + m_DebugMotionVectorMaterial.SetFloat("_MinValue", -m_MaxVectorValue); + m_DebugMotionVectorMaterial.SetFloat("_MaxValue", m_MaxVectorValue); + EditorGUI.DrawPreviewTexture( + EditorGUILayout.GetControlRect(false, GUILayout.Height(k_MotionVectorTextureSize), GUILayout.Width(k_MotionVectorTextureSize)), + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.motionVectorRenderTarget, + m_DebugMotionVectorMaterial); + + m_MaxVectorValue = 1 / EditorGUILayout.Slider("Vector Scale", 1 / m_MaxVectorValue, 1, 100); + EditorGUILayout.EndVertical(); + + EditorGUILayout.BeginVertical(); + + m_DebugDepthMaterial.SetFloat("_MinValue", 0); + m_DebugDepthMaterial.SetFloat("_MaxValue", m_MaxDepth); + + EditorGUI.DrawPreviewTexture( + EditorGUILayout.GetControlRect(false, GUILayout.Height(k_MotionVectorTextureSize), GUILayout.Width(k_MotionVectorTextureSize)), + UnityEngine.Rendering.Universal.DebugOculusMotionVectorSettings.depthRenderTarget, + m_DebugDepthMaterial); + + m_MaxDepth = 1 / EditorGUILayout.Slider("Depth Scale", 1 / m_MaxDepth, 1, 100); + EditorGUILayout.EndVertical(); + EditorGUILayout.EndHorizontal(); + + } +} diff --git a/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs.meta b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs.meta new file mode 100644 index 00000000000..e2cd7ad492e --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Editor/Debug/OculusMotionVectorWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a8f55013bf26ac4689abe1fead6ebda +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/OculusMotionVectors.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/OculusMotionVectors.hlsl index 6476ec378cc..e68606e4797 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/OculusMotionVectors.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/OculusMotionVectors.hlsl @@ -15,6 +15,13 @@ half4 frag(PackedVaryings packedInput) : SV_TARGET Varyings unpacked = UnpackVaryings(packedInput); UNITY_SETUP_INSTANCE_ID(unpacked); + #if _ALPHATEST_ON + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(unpacked); + SurfaceDescription surfaceDescription = BuildSurfaceDescription(unpacked); + + clip(surfaceDescription.Alpha - surfaceDescription.AlphaClipThreshold); + #endif + float3 screenPos = unpacked.curPositionCS.xyz / unpacked.curPositionCS.w; float3 screenPosPrev = unpacked.prevPositionCS.xyz / unpacked.prevPositionCS.w; half4 color = (1); diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl index 648ce1101bc..5e5d9424221 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl @@ -10,15 +10,6 @@ float3 _LightPosition; #endif -#ifdef VARYINGS_NEED_PREVIOUS_POSITION_CS - bool IsSmoothRotation(float3 prevAxis1, float3 prevAxis2, float3 currAxis1, float3 currAxis2) - { - float angleThreshold = 0.984f; // cos(10 degrees) - float2 angleDot = float2(dot(normalize(prevAxis1), normalize(currAxis1)), dot(normalize(prevAxis2), normalize(currAxis2))); - return all(angleDot > angleThreshold); - } -#endif - #if defined(FEATURES_GRAPH_VERTEX) #if defined(HAVE_VFX_MODIFICATION) VertexDescription BuildVertexDescription(Attributes input, AttributesElement element) @@ -44,6 +35,15 @@ VertexDescription BuildVertexDescription(Attributes input) #endif #endif +float3 TransformPrevWorldToObject(float3 positionWS) +{ + #if !defined(SHADER_STAGE_RAY_TRACING) + return mul(GetPrevWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; + #else + return (float3)0; + #endif +} + Varyings BuildVaryings(Attributes input) { Varyings output = (Varyings)0; @@ -207,24 +207,18 @@ Varyings BuildVaryings(Attributes input) #ifdef VARYINGS_NEED_PREVIOUS_POSITION_CS if (unity_MotionVectorsParams.y == 0.0) { - output.prevPositionCS = float4(0.0, 0.0, 0.0, 1.0); + output.prevPositionCS = output.curPositionCS; } else { bool hasDeformation = unity_MotionVectorsParams.x > 0.0; - float3 effectivePositionOS = (hasDeformation ? input.uv4.xyz : input.positionOS.xyz); - float3 previousWS = TransformPreviousObjectToWorld(effectivePositionOS); - - float4x4 previousOTW = GetPrevObjectToWorldMatrix(); - float4x4 currentOTW = GetObjectToWorldMatrix(); - if (!IsSmoothRotation(previousOTW._11_21_31, previousOTW._12_22_32, currentOTW._11_21_31, currentOTW._12_22_32)) - { - output.prevPositionCS = output.curPositionCS; - } - else - { - output.prevPositionCS = TransformWorldToPrevHClip(previousWS); - } + // interpolate to our next deformed position + float3 effectivePositionOS = (hasDeformation ? (2.0 * input.positionOS.xyz - input.previousPositionOS) : input.positionOS.xyz); + // transform to our next world position + float3 nextWS = TransformObjectToWorld(TransformPrevWorldToObject(TransformObjectToWorld(effectivePositionOS))); + // interpolate back to our new 'previous' position + float3 previousWS = 2.0 * curWS - nextWS; + output.prevPositionCS = TransformWorldToPrevHClip(previousWS); } #endif diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs index 82ddc70e4a1..1ed23967af3 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Targets/UniversalTarget.cs @@ -892,6 +892,7 @@ public static PassDescriptor MotionVectors(UniversalTarget target) // Port Mask validVertexBlocks = CoreBlockMasks.Vertex, + validPixelBlocks = CoreBlockMasks.FragmentAlphaOnly, // Fields structs = CoreStructCollections.Default, @@ -899,7 +900,7 @@ public static PassDescriptor MotionVectors(UniversalTarget target) fieldDependencies = CoreFieldDependencies.Default, // Conditional State - renderStates = CoreRenderStates.Default, + renderStates = CoreRenderStates.DepthNormalsOnly(target), pragmas = CorePragmas.DOTSInstanced, includes = CoreIncludes.MotionVectors, defines = new DefineCollection(), @@ -1509,11 +1510,11 @@ static class CoreIncludes public static readonly IncludeCollection MotionVectors = new IncludeCollection { // Pre-graph - { CoreIncludes.CorePregraph }, - { CoreIncludes.ShaderGraphPregraph }, + { CorePregraph }, + { ShaderGraphPregraph }, // Post-graph - { CoreIncludes.CorePostgraph }, + { CorePostgraph }, { kMotionVectors, IncludeLocation.Postgraph }, }; } diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs new file mode 100644 index 00000000000..8834269de48 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs @@ -0,0 +1,22 @@ +#if UNITY_EDITOR && ENABLE_VR && ENABLE_XR_MODULE + +using System; +using System.Collections.Generic; +using UnityEngine.XR; + + namespace UnityEngine.Rendering.Universal + { + + public static class DebugOculusMotionVectorSettings + { + public static bool enableDebugMotionVectors; + + public static RenderTexture motionVectorRenderTarget; + public static RenderTextureDescriptor motionVectorRenderTargetDesc; + public static RenderTexture depthRenderTarget; + public static RenderTextureDescriptor depthRenderTargetDesc; + } + +} + +#endif \ No newline at end of file diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs.meta b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs.meta new file mode 100644 index 00000000000..3106aa46a5b --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Debug/DebugOculusMotionVectorSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fe7dc3f22f1c9046a29f72c2c05d2ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/OculusMotionVectorPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/OculusMotionVectorPass.cs index b784800eb85..711323031f2 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/Passes/OculusMotionVectorPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/Passes/OculusMotionVectorPass.cs @@ -14,9 +14,13 @@ public class OculusMotionVectorPass : ScriptableRenderPass FilteringSettings m_FilteringSettings; ProfilingSampler m_ProfilingSampler; + private static readonly ShaderTagId s_MotionVectorTag = new ShaderTagId("MotionVectors"); + RenderTargetIdentifier motionVectorColorIdentifier; RenderTargetIdentifier motionVectorDepthIdentifier; + private static readonly int s_MotionVectorsEnabledID = Shader.PropertyToID("_MotionVectorsEnabled"); + public OculusMotionVectorPass(string profilerTag, bool opaque, RenderPassEvent evt, RenderQueueRange renderQueueRange, LayerMask layerMask, StencilState stencilState, int stencilReference) { base.profilingSampler = new ProfilingSampler(nameof(OculusMotionVectorPass)); @@ -57,10 +61,16 @@ public override void Execute(ScriptableRenderContext context, ref RenderingData cmd.Clear(); Camera camera = renderingData.cameraData.camera; + Shader.SetGlobalFloat(s_MotionVectorsEnabledID, (float)(camera.depthTextureMode & DepthTextureMode.MotionVectors)); + var filterSettings = m_FilteringSettings; - var drawSettings = CreateDrawingSettings(new ShaderTagId("MotionVectors"), ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags); + var drawSettings = CreateDrawingSettings(s_MotionVectorTag, ref renderingData, renderingData.cameraData.defaultOpaqueSortFlags); drawSettings.perObjectData = PerObjectData.MotionVectors; + + context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings); + drawSettings.perObjectData = PerObjectData.None; + filterSettings.excludeMotionVectorObjects = true; context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings); } context.ExecuteCommandBuffer(cmd); diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs index 8b573328232..bae415b3fd1 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/UniversalRenderer.cs @@ -288,7 +288,8 @@ public UniversalRenderer(UniversalRendererData data) : base(data) m_RenderOpaqueForwardOnlyPass = new DrawObjectsPass("Render Opaques Forward Only", forwardOnlyShaderTagIds, true, RenderPassEvent.BeforeRenderingOpaques, RenderQueueRange.opaque, data.opaqueLayerMask, forwardOnlyStencilState, forwardOnlyStencilRef); } - m_OculusMotionVecPass = new OculusMotionVectorPass(URPProfileId.DrawMVOpaqueObjects, true, RenderPassEvent.BeforeRenderingOpaques, RenderQueueRange.opaque, data.opaqueLayerMask, m_DefaultStencilState, stencilData.stencilReference); + m_OculusMotionVecPass = new OculusMotionVectorPass(URPProfileId.DrawMVOpaqueObjects, true, RenderPassEvent.BeforeRenderingOpaques - 1, RenderQueueRange.all, data.opaqueLayerMask | data.transparentLayerMask, m_DefaultStencilState, stencilData.stencilReference); + // Always create this pass even in deferred because we use it for wireframe rendering in the Editor or offscreen depth texture rendering. m_RenderOpaqueForwardPass = new DrawObjectsPass(URPProfileId.DrawOpaqueObjects, true, RenderPassEvent.BeforeRenderingOpaques, RenderQueueRange.opaque, data.opaqueLayerMask, m_DefaultStencilState, stencilData.stencilReference); @@ -729,18 +730,22 @@ public override void Setup(ScriptableRenderContext context, ref RenderingData re EnqueuePass(m_XROcclusionMeshPass); #endif -#if !UNITY_EDITOR if (cameraData.xr.motionVectorRenderTargetValid) { RenderTargetHandle motionVecHandle = new RenderTargetHandle(cameraData.xr.motionVectorRenderTarget); - var rtMotionId = motionVecHandle.Identifier(); - rtMotionId = new RenderTargetIdentifier(rtMotionId, 0, CubemapFace.Unknown, -1); + var rtMotionId = new RenderTargetIdentifier(motionVecHandle.Identifier(), 0, CubemapFace.Unknown, -1); // ID is the same since a RenderTexture encapsulates all the attachments, including both color+depth. - m_OculusMotionVecPass.Setup(rtMotionId, rtMotionId); + var depthId = rtMotionId; + + if (cameraData.xr.depthRenderTargetValid) { + RenderTargetHandle depthHandle = new RenderTargetHandle(cameraData.xr.depthRenderTarget); + depthId = new RenderTargetIdentifier(depthHandle.Identifier(), 0, CubemapFace.Unknown, -1); + } + + m_OculusMotionVecPass.Setup(rtMotionId, depthId); EnqueuePass(m_OculusMotionVecPass); } -#endif if (this.actualRenderingMode == RenderingMode.Deferred) { diff --git a/Packages/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs b/Packages/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs index ac71052fdd0..160462c540f 100644 --- a/Packages/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs +++ b/Packages/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs @@ -88,12 +88,15 @@ class XRPass // Same but for motion vectors internal RenderTargetIdentifier motionVectorRenderTarget { get; private set; } internal RenderTextureDescriptor motionVectorRenderTargetDesc { get; private set; } + internal RenderTargetIdentifier depthRenderTarget { get; private set; } + internal RenderTextureDescriptor depthRenderTargetDesc { get; private set; } static RenderTargetIdentifier invalidRT = -1; internal bool renderTargetValid { get => renderTarget != invalidRT; } internal bool renderTargetIsRenderTexture { get; private set; } internal bool motionVectorRenderTargetValid { get => motionVectorRenderTarget != invalidRT; } internal bool motionVectorRenderTargetIsRenderTexture { get; private set; } + internal bool depthRenderTargetValid { get => depthRenderTarget != invalidRT; } internal bool isLateLatchEnabled { get; set; } internal bool canMarkLateLatch { get; set; } @@ -240,18 +243,23 @@ internal static XRPass Create(XRDisplaySubsystem.XRRenderPass xrRenderPass, int if (xrRenderPass.hasMotionVectorPass) { passInfo.motionVectorRenderTarget = new RenderTargetIdentifier(xrRenderPass.motionVectorRenderTarget, 0, CubemapFace.Unknown, -1); - - RenderTextureDescriptor xrMotionVectorDesc = xrRenderPass.renderTargetDesc; - RenderTextureDescriptor rtMotionVectorDesc = new RenderTextureDescriptor(xrMotionVectorDesc.width, xrMotionVectorDesc.height, xrMotionVectorDesc.colorFormat, xrMotionVectorDesc.depthBufferBits, xrMotionVectorDesc.mipCount); - rtMotionVectorDesc.dimension = xrRenderPass.renderTargetDesc.dimension; - rtMotionVectorDesc.volumeDepth = xrRenderPass.renderTargetDesc.volumeDepth; - rtMotionVectorDesc.vrUsage = xrRenderPass.renderTargetDesc.vrUsage; - rtMotionVectorDesc.sRGB = xrRenderPass.renderTargetDesc.sRGB; - passInfo.motionVectorRenderTargetDesc = rtMotionVectorDesc; + passInfo.motionVectorRenderTargetDesc = xrRenderPass.motionVectorRenderTargetDesc; + passInfo.depthRenderTarget = -1; Debug.Assert(passInfo.motionVectorRenderTargetValid, "Invalid motion vector render target from XRDisplaySubsystem!"); } +#if UNITY_EDITOR + if (DebugOculusMotionVectorSettings.enableDebugMotionVectors) + { + passInfo.motionVectorRenderTarget = new RenderTargetIdentifier(DebugOculusMotionVectorSettings.motionVectorRenderTarget, 0, CubemapFace.Unknown, -1); + passInfo.motionVectorRenderTargetDesc = DebugOculusMotionVectorSettings.motionVectorRenderTargetDesc; + + passInfo.depthRenderTarget = new RenderTargetIdentifier(DebugOculusMotionVectorSettings.depthRenderTarget, 0, CubemapFace.Unknown, -1); + passInfo.depthRenderTargetDesc = DebugOculusMotionVectorSettings.depthRenderTargetDesc; + Debug.Assert(passInfo.motionVectorRenderTargetValid, "Invalid motion vector render target from XRDisplaySubsystem!"); + } +#endif return passInfo; } diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl index e7d2e5d93d0..881fc16ac29 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl @@ -15,11 +15,13 @@ struct Varyings UNITY_VERTEX_OUTPUT_STEREO }; -bool IsSmoothRotation(float3 prevAxis1, float3 prevAxis2, float3 currAxis1, float3 currAxis2) +float3 TransformPrevWorldToObject(float3 positionWS) { - float angleThreshold = 0.984f; // cos(10 degrees) - float2 angleDot = float2(dot(normalize(prevAxis1), normalize(currAxis1)), dot(normalize(prevAxis2), normalize(currAxis2))); - return all(angleDot > angleThreshold); + #if !defined(SHADER_STAGE_RAY_TRACING) + return mul(GetPrevWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; + #else + return (float3)0; + #endif } Varyings vert(Attributes input) @@ -35,24 +37,18 @@ Varyings vert(Attributes input) output.curPositionCS = TransformWorldToHClip(curWS); if (unity_MotionVectorsParams.y == 0.0) { - output.prevPositionCS = float4(0.0, 0.0, 0.0, 1.0); + output.prevPositionCS = output.curPositionCS; } else { bool hasDeformation = unity_MotionVectorsParams.x > 0.0; - float3 effectivePositionOS = (hasDeformation ? input.previousPositionOS : input.positionOS.xyz); - float3 previousWS = TransformPreviousObjectToWorld(effectivePositionOS); - - float4x4 previousOTW = GetPrevObjectToWorldMatrix(); - float4x4 currentOTW = GetObjectToWorldMatrix(); - if (!IsSmoothRotation(previousOTW._11_21_31, previousOTW._12_22_32, currentOTW._11_21_31, currentOTW._12_22_32)) - { - output.prevPositionCS = output.curPositionCS; - } - else - { - output.prevPositionCS = TransformWorldToPrevHClip(previousWS); - } + // interpolate to our next deformed position + float3 effectivePositionOS = (hasDeformation ? (2.0 * input.positionOS.xyz - input.previousPositionOS) : input.positionOS.xyz); + // transform to our next world position + float3 nextWS = TransformObjectToWorld(TransformPrevWorldToObject(TransformObjectToWorld(effectivePositionOS))); + // interpolate back to our new 'previous' position + float3 previousWS = 2.0 * curWS - nextWS; + output.prevPositionCS = TransformWorldToPrevHClip(previousWS); } return output; diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl new file mode 100644 index 00000000000..93b5e411ded --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl @@ -0,0 +1,50 @@ +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + +struct Attributes +{ + float4 positionOS : POSITION; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct Varyings +{ + float4 positionCS : SV_POSITION; + float4 curPositionCS : TEXCOORD8; + float4 prevPositionCS : TEXCOORD9; + UNITY_VERTEX_OUTPUT_STEREO +}; + +// Custom Flag for Static MotionVectors +half _MotionVectorsEnabled; + +Varyings vert(Attributes input) +{ + Varyings output = (Varyings)0; + UNITY_SETUP_INSTANCE_ID(input); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + output.positionCS = vertexInput.positionCS; + + float3 curWS = TransformObjectToWorld(input.positionOS.xyz); + output.curPositionCS = TransformWorldToHClip(curWS); + if (_MotionVectorsEnabled == 0.0) + { + output.prevPositionCS = output.curPositionCS; + } + else + { + output.prevPositionCS = TransformWorldToPrevHClip(curWS); + } + + return output; +} + +half4 frag(Varyings i) : SV_Target +{ + float3 screenPos = i.curPositionCS.xyz / i.curPositionCS.w; + float3 screenPosPrev = i.prevPositionCS.xyz / i.prevPositionCS.w; + half4 color = (1); + color.xyz = screenPos - screenPosPrev; + return color; +} diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl.meta b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl.meta new file mode 100644 index 00000000000..46230267c17 --- /dev/null +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorStatic.hlsl.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2fa45f2e143f45643ad46f27edd80ecd +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + preprocessorOverride: 0 + userData: + assetBundleName: + assetBundleVariant: From ead3bb59ec34138d31627b59e60df33e52bc6db3 Mon Sep 17 00:00:00 2001 From: Trevor Dasch Date: Wed, 24 Jan 2024 12:00:24 -0500 Subject: [PATCH 2/3] Revert custom motion vector forward projection so that motion vectors point to previous frame clip pos. --- .../Editor/ShaderGraph/Includes/Varyings.hlsl | 14 +------------- .../ShaderLibrary/OculusMotionVectorCore.hlsl | 14 +------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl index 5e5d9424221..7b999874fe1 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl @@ -35,15 +35,6 @@ VertexDescription BuildVertexDescription(Attributes input) #endif #endif -float3 TransformPrevWorldToObject(float3 positionWS) -{ - #if !defined(SHADER_STAGE_RAY_TRACING) - return mul(GetPrevWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; - #else - return (float3)0; - #endif -} - Varyings BuildVaryings(Attributes input) { Varyings output = (Varyings)0; @@ -214,10 +205,7 @@ Varyings BuildVaryings(Attributes input) bool hasDeformation = unity_MotionVectorsParams.x > 0.0; // interpolate to our next deformed position float3 effectivePositionOS = (hasDeformation ? (2.0 * input.positionOS.xyz - input.previousPositionOS) : input.positionOS.xyz); - // transform to our next world position - float3 nextWS = TransformObjectToWorld(TransformPrevWorldToObject(TransformObjectToWorld(effectivePositionOS))); - // interpolate back to our new 'previous' position - float3 previousWS = 2.0 * curWS - nextWS; + float3 previousWS = TransformPreviousObjectToWorld(effectivePositionOS); output.prevPositionCS = TransformWorldToPrevHClip(previousWS); } #endif diff --git a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl index 881fc16ac29..90cdfca4b06 100644 --- a/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl +++ b/Packages/com.unity.render-pipelines.universal/ShaderLibrary/OculusMotionVectorCore.hlsl @@ -15,15 +15,6 @@ struct Varyings UNITY_VERTEX_OUTPUT_STEREO }; -float3 TransformPrevWorldToObject(float3 positionWS) -{ - #if !defined(SHADER_STAGE_RAY_TRACING) - return mul(GetPrevWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; - #else - return (float3)0; - #endif -} - Varyings vert(Attributes input) { Varyings output = (Varyings)0; @@ -44,10 +35,7 @@ Varyings vert(Attributes input) bool hasDeformation = unity_MotionVectorsParams.x > 0.0; // interpolate to our next deformed position float3 effectivePositionOS = (hasDeformation ? (2.0 * input.positionOS.xyz - input.previousPositionOS) : input.positionOS.xyz); - // transform to our next world position - float3 nextWS = TransformObjectToWorld(TransformPrevWorldToObject(TransformObjectToWorld(effectivePositionOS))); - // interpolate back to our new 'previous' position - float3 previousWS = 2.0 * curWS - nextWS; + float3 previousWS = TransformPreviousObjectToWorld(effectivePositionOS); output.prevPositionCS = TransformWorldToPrevHClip(previousWS); } From 0e9ee65cff2122b04ec0d2a18a471eff6f6c66fc Mon Sep 17 00:00:00 2001 From: Trevor Dasch Date: Wed, 24 Jan 2024 17:14:26 -0500 Subject: [PATCH 3/3] Revert additional forward prediction --- .../Editor/ShaderGraph/Includes/Varyings.hlsl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl index 7b999874fe1..c513b750e91 100644 --- a/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl +++ b/Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl @@ -203,8 +203,7 @@ Varyings BuildVaryings(Attributes input) else { bool hasDeformation = unity_MotionVectorsParams.x > 0.0; - // interpolate to our next deformed position - float3 effectivePositionOS = (hasDeformation ? (2.0 * input.positionOS.xyz - input.previousPositionOS) : input.positionOS.xyz); + float3 effectivePositionOS = (hasDeformation ? input.uv4.xyz : input.positionOS.xyz); float3 previousWS = TransformPreviousObjectToWorld(effectivePositionOS); output.prevPositionCS = TransformWorldToPrevHClip(previousWS); }