-
Notifications
You must be signed in to change notification settings - Fork 850
[XR][URP] Fix issue with vignette location in XR #5471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
a31f3bc
118a617
263cb31
348e23b
9364b7d
323a155
3b89c75
890ee1f
3c100ed
875610e
958d05c
85c3375
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Vignette center needs to respect the real view center since in XR, with asymmetric FOV, the center of the render taget is not always the center of the view. We deduce the real center via the projection matrix data and use that to offset the vignette's center.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -485,7 +485,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. | ||
|
@@ -1235,7 +1235,7 @@ 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; | ||
|
@@ -1250,9 +1250,35 @@ void SetupVignette(Material material) | |
m_Vignette.intensity.value * 3f, | ||
m_Vignette.smoothness.value * 5f | ||
); | ||
#if ENABLE_VR && ENABLE_XR_MODULE | ||
var v3 = new Vector4(0.0f, 0.0f, 0.0f, 0.0f); | ||
if (xrPass != null && xrPass.enabled) | ||
{ | ||
float centerDeltaX = 0.5f - center.x; | ||
float centerDeltaY = 0.5f - center.y; | ||
|
||
XRView view0 = xrPass.views[0]; | ||
v2.x = view0.eyeCenterUV.x + centerDeltaX; | ||
v2.y = view0.eyeCenterUV.y + centerDeltaY; | ||
if (xrPass.views.Count == 1) | ||
{ | ||
v3.z = v2.x; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this part ever used ? if we're in multipass mode (where views.Count == 1) then the _Vignette_Params3 will never be read in the shader. |
||
v3.w = v2.y; | ||
} | ||
else | ||
{ | ||
XRView view1 = xrPass.views[1]; | ||
v3.x = view1.eyeCenterUV.x + centerDeltaX; | ||
v3.y = view1.eyeCenterUV.y + centerDeltaY; | ||
} | ||
} | ||
#endif | ||
|
||
material.SetVector(ShaderConstants._Vignette_Params1, v1); | ||
material.SetVector(ShaderConstants._Vignette_Params2, v2); | ||
#if ENABLE_VR && ENABLE_XR_MODULE | ||
material.SetVector(ShaderConstants._Vignette_Params3, v3); | ||
#endif | ||
} | ||
|
||
#endregion | ||
|
@@ -1502,6 +1528,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_Params3 = Shader.PropertyToID("_Vignette_Params3"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe call this "_Vignette_ParamsXR" since that's what it is and it's easier to read later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we can do that |
||
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"); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ internal struct XRView | |
internal readonly Rect viewport; | ||
internal readonly Mesh occlusionMesh; | ||
internal readonly int textureArraySlice; | ||
internal readonly Vector2 eyeCenterUV; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quick note : this will create a merge conflict with #3557 |
||
|
||
internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int dstSlice) | ||
{ | ||
|
@@ -46,6 +47,13 @@ internal XRView(Matrix4x4 proj, Matrix4x4 view, Rect vp, int dstSlice) | |
viewport = vp; | ||
occlusionMesh = null; | ||
textureArraySlice = dstSlice; | ||
|
||
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); | ||
eyeCenterUV = new Vector2(left / (right + left), top / (top + bottom)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add a method to avoid code duplication : computeEyeCenterUV(Matrix4x4 proj) ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we sure can ! |
||
} | ||
|
||
internal XRView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.XRRenderParameter renderParameter) | ||
|
@@ -56,6 +64,13 @@ internal XRView(XRDisplaySubsystem.XRRenderPass renderPass, XRDisplaySubsystem.X | |
occlusionMesh = renderParameter.occlusionMesh; | ||
textureArraySlice = renderParameter.textureArraySlice; | ||
|
||
var projectionParameters = projMatrix.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); | ||
eyeCenterUV = new Vector2(left / (right + left), top / (top + bottom)); | ||
|
||
// Convert viewport from normalized to screen space | ||
viewport.x *= renderPass.renderTargetDesc.width; | ||
viewport.width *= renderPass.renderTargetDesc.width; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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_Params3; | ||
#endif | ||
float2 _Grain_Params; | ||
float4 _Grain_TilingParams; | ||
float4 _Bloom_Texture_TexelSize; | ||
|
@@ -68,7 +71,14 @@ Shader "Hidden/Universal Render Pipeline/UberPost" | |
#define LensDirtIntensity _LensDirt_Intensity.x | ||
|
||
#define VignetteColor _Vignette_Params1.xyz | ||
#ifdef USING_STEREO_MATRICES | ||
// With XR, the views can use asymmetric FOV which will have the center of | ||
// each eyes to be at a different location | ||
#define VignetteCenterEye0 _Vignette_Params2.xy | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since we're already differentiating with center and Eye0, Eye1 we could just pack all the XR Eye data to Params3 (or ParamsXR). I think it would be a tiny bit cleaner as it would avoid this interleaving There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I'll get the XR single-pass data to its own variable then to group it all together |
||
#define VignetteCenterEye1 _Vignette_Params3.xy | ||
#else | ||
#define VignetteCenter _Vignette_Params2.xy | ||
#endif | ||
#define VignetteIntensity _Vignette_Params2.z | ||
#define VignetteSmoothness _Vignette_Params2.w | ||
#define VignetteRoundness _Vignette_Params1.w | ||
|
@@ -191,6 +201,10 @@ Shader "Hidden/Universal Render Pipeline/UberPost" | |
UNITY_BRANCH | ||
if (VignetteIntensity > 0) | ||
{ | ||
#ifdef USING_STEREO_MATRICES | ||
const float2 VignetteCenter = unity_StereoEyeIndex == 0 ? VignetteCenterEye0 : VignetteCenterEye1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general, we'd like to be able to support more than 2 views. Can we evaluate moving this code to an array with indexing instead ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this use case is very specific to eyes, I don't know if we would even need that for "more than two" displays. Also, for more than 2 display scenarios, like domes, super panoramic views or stuff like that we would need to change the whole vignette post-process to have a center in world space to be able to sync all views to work together, a screen-space effect might not work well in that case without being fully custom. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update: I had a chat with Fabien and I will implement "more than 2 views" for XR as there is some use-cases for it with some specific headsets There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update 2 : Returning to 2 views to keep the code simple and we'll add more when we need to. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of our partners is moving away from asymmetric frustums. We should keep this fix as simple as possible. What about extracting the center from the current stereo projection matrix in either vertex or pixel shader directly? Then there's no need to pass in per eye centers or changing script code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't expect this change to prevent symmetric FOV from being used, it will only allow asymmetric FOV to work correctly. This change will work with both symmetric and asymmetric FOV, the center calculated for symmetric FOV will be (0.5, 0.5) for both eyes since in that case leftFov == rightFov && topFov == bottomFov. Extracting the data from the shader (Vertex or Fragment) will make this change more complicated than it currently is since this is a post process and uses a generic Vertex Shader which does not have information about the projection. Changing that will introduce code duplication and as a side effect, more possible point of failures. I believe that the eye center should be calculated on the CPU since it is something that will likely be used by other post process or shaders that rely on knowing where the center of the view is (any type of radial post-process, some screen space effects or more), it is also something that I expect some games will want to know too (I used these values for a few things in StarWars Squadrons VR). In fact, I was very surprised that the XR view center coordinates was not already available in our XR C# code ! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, the points sound reasonable. |
||
#endif | ||
|
||
color = ApplyVignette(color, uvDistorted, VignetteCenter, VignetteIntensity, VignetteRoundness, VignetteSmoothness, VignetteColor); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move the XR specific block into a function, easier to read than bunch of defines.
That function could even be in xrPass.
Something like
vec4 xrPass.applyXREyeOffset(vec2 center); which packs XR eye data into Vec4. Or xrPass.applyEyeOffset( ref vec2 centerAsLeft, out vec2 right);
But just moving this block to SetupVignetteXR() would be tiny bit better IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can extract a good amount of code to the XRPass class, but we still need to do some part of the work in SetupVignette() since when we are rendering in Multi-pass (each eye are rendered completely separately), the center still need to be corrected for each eyes and then placed in v2.xy since AFAIK the shader does not have a variation for "XR enabled, but not single-pass".
I'll see what I can do to reduce the amount of XR specific code in here.