Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Custom Renderer Pass. Override material + render + blit recursively in same frame?

Discussion in 'Universal Render Pipeline' started by XANTOMEN, Sep 14, 2020.

  1. XANTOMEN

    XANTOMEN

    Joined:
    Dec 18, 2012
    Posts:
    41
    Hi there! I have quite a specific use-case in mind, and me not understanding much about rendering in general is leaving me in an awkward spot, and I'm not getting anywhere by just searching, so I'd like to ask what I think is a bit of a theoretical question about URP:

    For my current effect, I'm trying to see if this setup is possible:

    - Have one CustomRenderer, with a CustomRenderFeature, which calls a CustomRenderPass.
    - Have a single camera, set to use that CustomRenderer, output texture being the camera itself.
    - CustomRenderPass' Execute function to do the following actions:

    Block1:
    - Create a new instance (newMaterial1) of a material given in the Feature Settings and assign as an overrideMaterial to drawingSettings.
    - Set a Float and a Texture in newMaterial1 (floatIndex to 0, texture to null)
    - Trigger context.DrawRenderers with those drawingSettings.
    - Have the result of context.DrawRenderers (the on screen meshes with the new shader applied) blitted to destinationRenderTexture0 from Camera color texture.

    Block2:
    - Create a new instance (newMaterial2) of the original overrideMaterial and assign to drawingSettings.
    - Set a new Float and Texture in newMaterial2 (floatIndex to 1, texture to destinationRenderTexture0)
    - At this point, the shader in newMaterial2 should be able to use the already rendered previously destinationRenderTexture0 to alter what is going to be rendered on camera in the next step.
    - Trigger context.DrawRenderers again, with the changed drawingSettings.
    - Have the result of context.DrawRenderers blitted to destinationRenderTexture1

    Block3,4,5,6.... (recursive) :
    - Same instructions, just each time the floatIndex is incremented by 1, and destinationRenderTexture uses the resulting texture from the previous block.

    For clarity, the shader in newMaterial(s) samples the assigned renderTexture to alter the render of the meshes.

    I think the problem is, it does not look like DrawRenderers works the way I think it does, (the second one does not actually wait for destinationRenderTexture0 to be blitted), as newMaterial2 is not producing the output it is expected from it if destinationRenderTexture0 was renderered by the time the newMaterial2 override occurs. (destinationRenderTexture0 and destinationRenderTexture1 end up looking exactly the same).

    I have tested that it all works as expected (the shader logic is fine) if instead of trying to do those steps n times in the same renderer and camera, I instead create n cameras, n renderers, and use the feature once in each with different parameters (I need to use a different floatIndex and destinationTexture in the feature settings in each). The problem with that approach is that it generates a messy manual setup, whereas I want a recursive rendering strategy in which the user only needs to specify how many times will the repeat happen.

    Other approaches that don't work the way I described above:

    - Having a single camera, single renderer, single feature, and just enqueuing n different instances of CustomRenderPass with the "renderer.EnqueuePass" instruction.
    - Having a single camera, single renderer, but adding the feature n times with different parameters to the renderer.

    In other words, I guess my question comes down to: Is it possible to cramp the same functionality I would have with multiple cameras and renderers into a single camera, single renderer, single feature?

    Thank you to anyone that reads this and to anyone that is able to give me some tips!

    Sample Execute function code with two blocks (won't make it into a loop of n blocks until two hardcoded blocks work):

    Code (CSharp):
    1. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    2.         {
    3.             SortingCriteria sortingCriteria = (renderQueueType == RenderQueueType.Transparent)
    4.                 ? SortingCriteria.CommonTransparent
    5.                 : renderingData.cameraData.defaultOpaqueSortFlags;
    6.  
    7.             DrawingSettings drawingSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, sortingCriteria);
    8.             //drawingSettings.overrideMaterial = new Material(overrideMaterial);
    9.             drawingSettings.overrideMaterialPassIndex = overrideMaterialPassIndex;  
    10.  
    11.             CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
    12.  
    13.             sliceDepth = 0;
    14.  
    15.             using (new ProfilingScope(cmd, m_ProfilingSampler))
    16.             {
    17.                 context.ExecuteCommandBuffer(cmd);
    18.                 cmd.Clear();
    19.        
    20.                 Material newMaterial = new Material(overrideMaterial);
    21.  
    22.                 newMaterial.SetFloat("_SliceDepth", sliceDepth);
    23.                 newMaterial.SetTexture("_SamplerTexture", null);
    24.  
    25.                 drawingSettings.overrideMaterial = newMaterial;
    26.  
    27.                 context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings,
    28.                     ref m_RenderStateBlock);
    29.  
    30.                 var destinationTexture_RT = (RenderTexture)Shader.GetGlobalTexture("_SamplerTexture" + sliceDepth);
    31.                 cmd.Blit(cameraColorTargetIdent, destinationTexture_RT);
    32.                 cmd.Blit(destinationTexture_RT, cameraColorTargetIdent);
    33.  
    34.                 //Also tried without these two lines
    35.                 context.ExecuteCommandBuffer(cmd);
    36.                 cmd.Clear();
    37.  
    38.                 Material newMaterial2 = new Material(overrideMaterial);
    39.  
    40.                 newMaterial2.SetFloat("_SliceDepth", sliceDepth + 1);
    41.                 newMaterial2.SetTexture("_SamplerTexture", destinationTexture_RT);
    42.  
    43.                 drawingSettings.overrideMaterial = newMaterial2;
    44.  
    45.                 //Have also tried having another separate instance of drawingSettings(2)
    46.                 context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref m_FilteringSettings,
    47.                     ref m_RenderStateBlock);
    48.  
    49.                 var destinationTexture_RT2 = (RenderTexture)Shader.GetGlobalTexture("_SamplerTexture" + (sliceDepth + 1));
    50.                 cmd.Blit(cameraColorTargetIdent, destinationTexture_RT2);
    51.                 cmd.Blit(destinationTexture_RT2, cameraColorTargetIdent);
    52.             }
    53.    
    54.             context.ExecuteCommandBuffer(cmd);
    55.             CommandBufferPool.Release(cmd);
    56.         }
    57.     }
     
    Last edited: Sep 14, 2020
  2. XANTOMEN

    XANTOMEN

    Joined:
    Dec 18, 2012
    Posts:
    41
    For reference, I've also tried the approach of doing this in the Feature instead of the Pass, in the following way, with the same result. Both RenderTextures end up with the same exact content:


    Code (CSharp):
    1. public override void Create()
    2.         {
    3.             lastDestinationTexture_RT = null;
    4.             settings.depthSlice = 0;
    5.  
    6.             var newMaterial0 = new Material(settings.overrideMaterial);
    7.  
    8.             newMaterial0.SetFloat("_SliceDepth", settings.depthSlice);
    9.             destinationTexture_RT = (RenderTexture)Shader.GetGlobalTexture("_SamplerTexture" + settings.depthSlice);
    10.             newMaterial0.SetTexture("_SamplerTexture", lastDestinationTexture_RT);
    11.  
    12.             renderObjectsAndBlitToTexturePass = new RenderObjectsAndBlitToTexturePass(settings.passTag, settings.Event,
    13.                 settings.layerMask, settings.depthSlice, destinationTexture_RT);
    14.  
    15.             lastDestinationTexture_RT = destinationTexture_RT;
    16.  
    17.             renderObjectsAndBlitToTexturePass.overrideMaterial = newMaterial0;
    18.             renderObjectsAndBlitToTexturePass.overrideMaterialPassIndex = settings.overrideMaterialPassIndex;
    19.  
    20.             var newMaterial1 = new Material(settings.overrideMaterial);
    21.  
    22.             newMaterial1.SetFloat("_SliceDepth", settings.depthSlice + 1);
    23.             destinationTexture_RT2 = (RenderTexture)Shader.GetGlobalTexture("_SamplerTexture" + (settings.depthSlice + 1));
    24.             newMaterial1.SetTexture("_SamplerTexture", lastDestinationTexture_RT);
    25.  
    26.             renderObjectsAndBlitToTexturePass1 = new RenderObjectsAndBlitToTexturePass(settings.passTag, settings.Event,
    27.                 settings.layerMask, settings.depthSlice + 1, destinationTexture_RT2);
    28.  
    29.             renderObjectsAndBlitToTexturePass1.overrideMaterial = newMaterial1;
    30.             renderObjectsAndBlitToTexturePass1.overrideMaterialPassIndex = settings.overrideMaterialPassIndex;
    31.         }
    32.  
    33.         public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    34.         {
    35.             // Gather up and pass any extra information our pass will need.
    36.             // In this case we're getting the camera's color buffer target
    37.             var cameraColorTargetIdent = renderer.cameraColorTarget;
    38.  
    39.             renderObjectsAndBlitToTexturePass.Setup(cameraColorTargetIdent);
    40.             renderObjectsAndBlitToTexturePass1.Setup(cameraColorTargetIdent);
    41.  
    42.             renderer.EnqueuePass(renderObjectsAndBlitToTexturePass);
    43.             renderer.EnqueuePass(renderObjectsAndBlitToTexturePass1);
    44.         }
    45.     }