diff --git a/com.unity.render-pipelines.universal/CHANGELOG.md b/com.unity.render-pipelines.universal/CHANGELOG.md index 96de62eefdf..e7398ab8f4f 100644 --- a/com.unity.render-pipelines.universal/CHANGELOG.md +++ b/com.unity.render-pipelines.universal/CHANGELOG.md @@ -179,6 +179,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Support undo of URP Global Settings asset assignation (case 1342987). - Removed unsupported fields from Presets of Light and Camera [case 1335979]. - Fixed graphical artefact when terrain height map is used with rendering layer mask for lighting. +- Fixed URP's vignette effect to respect XR's view center, since with Asymmetric FOV, the center of the view is not always the center of the texture [case 1358336](https://issuetracker.unity3d.com/issues/xr-sdk-urp-vignette-post-processing-effect-is-overlapping-between-eyes) - Fixed an issue where screen space shadows has flickering with deferred mode [case 1354681](https://issuetracker.unity3d.com/issues/screen-space-shadows-flicker-in-scene-view-when-using-deferred-rendering) ### Changed diff --git a/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs b/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs index 5752bfed6c7..3461c1f1ab8 100644 --- a/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs +++ b/com.unity.render-pipelines.universal/Runtime/Passes/PostProcessPass.cs @@ -510,7 +510,7 @@ void Swap(ref ScriptableRenderer r) // Setup other effects constants SetupLensDistortion(m_Materials.uber, isSceneViewCamera); SetupChromaticAberration(m_Materials.uber); - SetupVignette(m_Materials.uber); + SetupVignette(m_Materials.uber, cameraData.xr); SetupColorGrading(cmd, ref renderingData, m_Materials.uber); // Only apply dithering & grain if there isn't a final pass. @@ -1263,12 +1263,25 @@ void SetupChromaticAberration(Material material) #region Vignette - void SetupVignette(Material material) + void SetupVignette(Material material, XRPass xrPass) { var color = m_Vignette.color.value; var center = m_Vignette.center.value; var aspectRatio = m_Descriptor.width / (float)m_Descriptor.height; + +#if ENABLE_VR && ENABLE_XR_MODULE + if (xrPass != null && xrPass.enabled) + { + if (xrPass.singlePassEnabled) + material.SetVector(ShaderConstants._Vignette_ParamsXR, xrPass.ApplyXRViewCenterOffset(center)); + else + // In multi-pass mode we need to modify the eye center with the values from .xy of the corrected + // center since the version of the shader that is not single-pass will use the value in _Vignette_Params2 + center = xrPass.ApplyXRViewCenterOffset(center); + } +#endif + var v1 = new Vector4( color.r, color.g, color.b, m_Vignette.rounded.value ? aspectRatio : 1f @@ -1531,6 +1544,7 @@ static class ShaderConstants public static readonly int _Chroma_Params = Shader.PropertyToID("_Chroma_Params"); public static readonly int _Vignette_Params1 = Shader.PropertyToID("_Vignette_Params1"); public static readonly int _Vignette_Params2 = Shader.PropertyToID("_Vignette_Params2"); + public static readonly int _Vignette_ParamsXR = Shader.PropertyToID("_Vignette_ParamsXR"); public static readonly int _Lut_Params = Shader.PropertyToID("_Lut_Params"); public static readonly int _UserLut_Params = Shader.PropertyToID("_UserLut_Params"); public static readonly int _InternalLut = Shader.PropertyToID("_InternalLut"); diff --git a/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs b/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs index 2fcdb1f0ee7..0cb049c1520 100644 --- a/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs +++ b/com.unity.render-pipelines.universal/Runtime/XR/XRPass.cs @@ -38,6 +38,7 @@ internal struct XRView internal readonly Rect viewport; internal readonly Mesh occlusionMesh; internal readonly int textureArraySlice; + internal readonly Vector2 eyeCenterUV; internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int dstSlice) { @@ -46,6 +47,8 @@ internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int dstSlice) viewport = vp; occlusionMesh = null; textureArraySlice = dstSlice; + + eyeCenterUV = ComputeEyeCenterUV(proj); } internal XRView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.XRRenderParameter renderParameter) @@ -61,6 +64,18 @@ internal XRView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.X viewport.width *= renderPass.renderTargetDesc.width; viewport.y *= renderPass.renderTargetDesc.height; viewport.height *= renderPass.renderTargetDesc.height; + + eyeCenterUV = ComputeEyeCenterUV(projMatrix); + } + + private static Vector2 ComputeEyeCenterUV(Matrix4x4 proj) + { + var projectionParameters = proj.decomposeProjection; + float left = Math.Abs(projectionParameters.left); + float right = Math.Abs(projectionParameters.right); + float top = Math.Abs(projectionParameters.top); + float bottom = Math.Abs(projectionParameters.bottom); + return new Vector2(left / (right + left), top / (top + bottom)); } } @@ -436,6 +451,26 @@ internal void RenderOcclusionMesh(CommandBuffer cmd) } } + // Take a point that is center-relative (0.5, 0.5) and modify it to be placed relative to the view's center instead, + // respecting the asymmetric FOV (if it is used) + internal Vector4 ApplyXRViewCenterOffset(Vector2 center) + { + Vector4 result = Vector4.zero; + float centerDeltaX = 0.5f - center.x; + float centerDeltaY = 0.5f - center.y; + + result.x = views[0].eyeCenterUV.x - centerDeltaX; + result.y = views[0].eyeCenterUV.y - centerDeltaY; + if (singlePassEnabled) + { + // With single-pass XR, we need to add the data for the 2nd view + result.z = views[1].eyeCenterUV.x - centerDeltaX; + result.w = views[1].eyeCenterUV.y - centerDeltaY; + } + + return result; + } + // Store array to avoid allocating every frame private Matrix4x4[] stereoProjectionMatrix = new Matrix4x4[2]; private Matrix4x4[] stereoViewMatrix = new Matrix4x4[2]; diff --git a/com.unity.render-pipelines.universal/Shaders/PostProcessing/UberPost.shader b/com.unity.render-pipelines.universal/Shaders/PostProcessing/UberPost.shader index 1b52f04e263..11416a8aab5 100644 --- a/com.unity.render-pipelines.universal/Shaders/PostProcessing/UberPost.shader +++ b/com.unity.render-pipelines.universal/Shaders/PostProcessing/UberPost.shader @@ -46,6 +46,9 @@ Shader "Hidden/Universal Render Pipeline/UberPost" float _Chroma_Params; half4 _Vignette_Params1; float4 _Vignette_Params2; + #ifdef USING_STEREO_MATRICES + float4 _Vignette_ParamsXR; + #endif float2 _Grain_Params; float4 _Grain_TilingParams; float4 _Bloom_Texture_TexelSize; @@ -68,7 +71,12 @@ Shader "Hidden/Universal Render Pipeline/UberPost" #define LensDirtIntensity _LensDirt_Intensity.x #define VignetteColor _Vignette_Params1.xyz + #ifdef USING_STEREO_MATRICES + #define VignetteCenterEye0 _Vignette_ParamsXR.xy + #define VignetteCenterEye1 _Vignette_ParamsXR.zw + #else #define VignetteCenter _Vignette_Params2.xy + #endif #define VignetteIntensity _Vignette_Params2.z #define VignetteSmoothness _Vignette_Params2.w #define VignetteRoundness _Vignette_Params1.w @@ -191,6 +199,12 @@ Shader "Hidden/Universal Render Pipeline/UberPost" UNITY_BRANCH if (VignetteIntensity > 0) { + #ifdef USING_STEREO_MATRICES + // With XR, the views can use asymmetric FOV which will have the center of each + // view be at a different location. + const float2 VignetteCenter = unity_StereoEyeIndex == 0 ? VignetteCenterEye0 : VignetteCenterEye1; + #endif + color = ApplyVignette(color, uvDistorted, VignetteCenter, VignetteIntensity, VignetteRoundness, VignetteSmoothness, VignetteColor); }