ColinLeung-NiloCat/UnityURP-MobileScreenSpacePlanarReflection

Does not work correctly in Unity 2020.1

SniperED007 opened this issue · 13 comments

After upgrading to Unity 2020.1.3f1 the results are not the same as Unity 2019.4

image

The same error occurred after upgrading to URP 7.4.1. I may have found the difference between 7.3.1 and 7.4.1:

// see https://github.com/Unity-Technologies/Graphics/blob/7.3.x/release/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipeline.cs#L950-L954
// UNITY_MATRIX_I_VP in 7.3.1
Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
Matrix4x4 viewMatrix = camera.worldToCameraMatrix;
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);
Shader.SetGlobalMatrix(PerCameraBuffer._InvCameraViewProj, invViewProjMatrix);

// see https://github.com/Unity-Technologies/Graphics/blob/7.4.x/release/com.unity.render-pipelines.universal/Runtime/UniversalRenderPipelineCore.cs#L85-L88
// UNITY_MATRIX_I_VP in 7.4.1
public Matrix4x4 GetGPUProjectionMatrix()
{
    return GL.GetGPUProjectionMatrix(m_ProjectionMatrix, IsCameraProjectionMatrixFlipped());
}

In URP 7.4.1, IsCameraProjectionMatrixFlipped() return true. Maybe you can pass your own I_VP matrix to compute shader:

Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
Matrix4x4 viewMatrix = camera.worldToCameraMatrix;
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);
cb.SetComputeMatrixParam(cs, "_InverseVPMatrix", invViewProjMatrix);

I'm on URP 10.1 and the feature is completely broken.

First off the feature draws to whatever the previous active target was, in my case a render feature earlier in the stack set the target to an RT, context.DrawRenderers from this feature is now drawing to that same RT. What is the intended target? The camera back buffer?

Setting the target to the camera back buffer doesn't fully help, the plane used to sample the reflection just draws invisible. Maybe its just redrawing that bit of screen space? URP doesn't have overdraw tools so it's hard to say if it makes any change what-so-ever.

It could be that this is related to the issue huyinxain found so I'm going to try and implement something along those lines and see what happens

@CianNoonan In URP 7, SSPRRenderPass.renderPassEvent cannot be set to BeforeRenderingTransparents, because the CopyColorPass may render after SSPRRenderPass. That's why we should use context.DrawRenderers to draw the ssr plane after all transparent objects done.

In URP 8.0 (or above), the RenderPassEvent of the CopyColorPass is changed from BeforeRenderingTransparents to AfterRenderingSkybox.

// see https://github.com/Unity-Technologies/Graphics/blob/7.4.x/release/com.unity.render-pipelines.universal/Runtime/ForwardRenderer.cs#L81
m_CopyColorPass = new CopyColorPass(RenderPassEvent.BeforeRenderingTransparents, m_SamplingMaterial);

// see https://github.com/Unity-Technologies/Graphics/blob/8.x.x/release/com.unity.render-pipelines.universal/Runtime/ForwardRenderer.cs#L76
m_CopyColorPass = new CopyColorPass(RenderPassEvent.AfterRenderingSkybox, m_SamplingMaterial);

It's mean that you can set SSPRRenderPass.renderPassEvent from AfterRenderingTransparents to BeforeRenderingTransparents:

m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingTransparents;

// Dont need this code
//DrawingSettings drawingSettings = CreateDrawingSettings(lightMode_SSPR_sti, ref renderingData, SortingCriteria.CommonOpaque);
//FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.all);
//context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref filteringSettings);

Thanks so much for replying! I'll have another crack at it and see if those changes help

I'm able to implement your suggestions to get the reflections to render but they still don't work as the projection is wrong.
image

@CianNoonan You can pass your own UNITY_MATRIX_I_VP to compute shader:

Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
Matrix4x4 viewMatrix = camera.worldToCameraMatrix;
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);
cb.SetComputeMatrixParam(cs, "_InverseVPMatrix", invViewProjMatrix);

I tried that exact code snippet and got a blank resulting RT

Emmm... maybe its the wrong plane height? I'm not sure.

In Unity2020.2 and URP 10.2 I tried the code and result does not change. It is still wrong.

image

JLuij commented

@huyinxian Thanks! I modified MobileSSPRComputeShader.compute as follows:

float4x4 _InverseVPMatrix;         << ADDED  
float _ScreenLRStretchIntensity;

And changed
float4 posHWS = mul(UNITY_MATRIX_I_VP, posCS); //posCS -> posHWS` to `float4 posHWS = mul(_InverseVPMatrix, posCS); //posCS -> posHWS

And added the following at line 175 of MobileSSPRRendererFeature.cs

Matrix4x4 viewMatrix = camera.worldToCameraMatrix;  
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;  
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);  
cb.SetComputeMatrixParam(cs, "_InverseVPMatrix", invViewProjMatrix);

This made it all work! I know almost nothing about (compute) shaders so your suggestion helped a ton.

@huyinxian Thanks! I modified MobileSSPRComputeShader.compute as follows:

float4x4 _InverseVPMatrix;         << ADDED  
float _ScreenLRStretchIntensity;

And changed
float4 posHWS = mul(UNITY_MATRIX_I_VP, posCS); //posCS -> posHWS` to `float4 posHWS = mul(_InverseVPMatrix, posCS); //posCS -> posHWS

And added the following at line 175 of MobileSSPRRendererFeature.cs

Matrix4x4 viewMatrix = camera.worldToCameraMatrix;  
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;  
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);  
cb.SetComputeMatrixParam(cs, "_InverseVPMatrix", invViewProjMatrix);

This made it all work! I know almost nothing about (compute) shaders so your suggestion helped a ton.

thanks to your find,but to MobileSSPRRendererFeature.cs,it should be

Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);
Matrix4x4 viewMatrix = camera.worldToCameraMatrix;
Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;
Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);
cb.SetComputeMatrixParam(cs, "_InverseVPMatrix", invViewProjMatrix);

a fix has been merged, you can pull the latest version and retry it in Unity2020.3.x