Search Unity

Resolved Can I use ScriptableRenderContext.Cull() to get another culling results in ScriptableRenderPass?

Discussion in 'Universal Render Pipeline' started by douduck, Mar 16, 2021.

  1. douduck

    douduck

    Joined:
    Jan 15, 2014
    Posts:
    4
    I tried to implement planar reflection in URP without the second camera.

    Here is my thought:
    1. Create a custom renderer feature and a render pass.
    2. In the render pass (After render shadowmap),
    2-1. Calculate projection and view matrix about the reflection camera. (but not really create a camera)
    2-2. Get and set a CullingParameters with custom culling matrix. ( = projection * view)
    2-3. Use ScriptableRenderContext.Cull() to get another CullingResults.
    2-4. Draw renderers with the matrices and the new CullingResults on a RenderTexture.
    2-5. Set GlobalTexture property of shader.​
    3. Render the plane in normal steps of URP, with a custom shader to sample reflection RenderTexture.

    If all works well, I can render lighting reflection objects with the shadowmap of main camera. Saving the batches of using another camera and a second shadowmap. (like the 1st image)

    However, I actually met the Problem on using ScriptableRenderContext.Cull(). When the objects aren't visible in the camera original culling results, they will not be drawn in the reflection view. (the 2nd image, make the camera look down a little)

    Its seen that ScriptableRenderContext.Cull() didn't return a correct culling result when I called.

    Maybe I use the API in the wrong way or It is not designed to be use twice in a rendering loop?





    And there is part of codes:
    Code (CSharp):
    1. public class ReflectionPass : ScriptableRenderPass {
    2.  
    3.     // create and set render target in ScriptableRenderPass.Configure()
    4.  
    5.     public override void Execute (ScriptableRenderContext context, ref RenderingData renderingData) {
    6.         var reflectionMatrix = CalculateReflectionMatrix ();
    7.         var viewMatrix = cameraData.GetViewMatrix ();
    8.         viewMatrix = viewMatrix * reflectionMatrix;
    9.          
    10.         var projectionMatrix = cameraData.GetProjectionMatrix ();
    11.         gpuProjectionMatrix = GL.GetGPUProjectionMatrix (projectionMatrix, cameraData.IsCameraProjectionMatrixFlipped ());
    12.  
    13.         // get another culling results, the PROBLEM part
    14.         camera.TryGetCullingParameters (out var cullingParameters)
    15.         cullingParameters.cullingMatrix = projectionMatrix * viewMatrix;
    16.         var cullResults = context.Cull (ref cullingParameters);
    17.  
    18.         // Rendering parts, all works well
    19.         var cmd = CommandBufferPool.Get (profilerTag);
    20.         RenderingUtils.SetViewAndProjectionMatrices (cmd, viewMatrix, gpuProjectionMatrix, false);
    21.         cmd.SetInvertCulling (true);
    22.         context.ExecuteCommandBuffer (cmd);
    23.         cmd.Clear ();
    24.  
    25.         // rendering
    26.         context.DrawRenderers (cullResults, ref drawingSettings, ref filteringSettings);
    27.  
    28.         // restore rendering state
    29.         RenderingUtils.SetViewAndProjectionMatrices (cmd, cameraData.GetViewMatrix (), cameraData.GetGPUProjectionMatrix (), false);
    30.         cmd.SetInvertCulling (false);
    31.         cmd.SetGlobalTexture (ShaderIds.reflectionTexture, reflectionRT);
    32.      
    33.         context.ExecuteCommandBuffer (cmd);
    34.         CommandBufferPool.Release (cmd);
    35.     }
    36. }
     
  2. douduck

    douduck

    Joined:
    Jan 15, 2014
    Posts:
    4
    I fixed the problem!

    Set a culling matrix will not update culling planes, you should update the planes by yourself.

    Code (CSharp):
    1. camera.TryGetCullingParameters (out var cullingParameters);
    2. cullingParameters.cullingMatrix = projectionMatrix * viewMatrix;
    3.  
    4. var planes = GeometryUtility.CalculateFrustumPlanes (cullingParameters.cullingMatrix);
    5. for (int i = 0; i < 6; i++) {
    6.     cullingParameters.SetCullingPlane (i, planes[i]);
    7. }
    8.  
    9. var cullResults = context.Cull (ref cullingParameters);
     
  3. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    This was very helpful, thanks for sharing the code and solution!