Search Unity

Question [CommandBuffer] RenderTextures lag behind rendering

Discussion in 'High Definition Render Pipeline' started by ssurget, May 6, 2022.

  1. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    (Unity 2021 LTS)

    Hello,

    In my game, I have some objects that need to render outlines under specific conditions, and need to be able to animate those outlines within their shaders for special effects. It does work, but when rotating the camera, it is obvious the outline is lagging and is not in sync with object rendering :

    Screen Shot 05-06-22 at 04.13 PM 001.PNG

    Screen Shot 05-06-22 at 04.21 PM.PNG

    I'm using a Command Buffer during the "beginCameraRendering" step, rendering the needed objects in two Render Textures, one with the Normals in the rgb channels, and one for the Depth. The result is then Blit with an Outline shader similar to a post-process. The final texture is used within the objects shaders :

    Code (CSharp):
    1. void InitializeOnce()
    2.     {
    3.         m_BaseCommands = new CommandBuffer { name = "AzurineBaseCommand" };
    4.  
    5.         DepthRT = new RenderTexture(TextureSize.x, TextureSize.y, 16, RenderTextureFormat.Depth)
    6.         {
    7.             hideFlags = HideFlags.DontSave,
    8.             filterMode = FilterMode.Point,
    9.             name = "DepthRT"
    10.         };
    11.  
    12.         NormalRT = new RenderTexture(TextureSize.x, TextureSize.y, 0, GraphicsFormat.R16G16B16A16_SFloat)
    13.         {
    14.             hideFlags = HideFlags.DontSave,
    15.             filterMode = FilterMode.Point,
    16.             name = "NormalRT"
    17.         };
    18.  
    19.         OutlineRTH = RTHandles.Alloc(TextureSize.x, TextureSize.y, colorFormat: GraphicsFormat.R16_SFloat, dimension: TextureDimension.Tex2D, name: "OutlineRTH");
    20.  
    21.         Shader.SetGlobalTexture("_outlineRT", OutlineRTH.rt, RenderTextureSubElement.Color);
    22.  
    23.         OutlineMaterial.SetTexture("_DepthTex", DepthRT);
    24.  
    25.         RenderPipelineManager.beginCameraRendering += BeginCameraRendering;
    26.         m_initialized = true;
    27.     }
    Code (CSharp):
    1. void BeginCameraRendering(ScriptableRenderContext context, Camera camera)
    2.     {
    3.         m_BaseCommands.SetRenderTarget(NormalRT, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare, DepthRT, RenderBufferLoadAction.DontCare, RenderBufferStoreAction.DontCare);
    4.         m_BaseCommands.ClearRenderTarget(true, true, Color.black);
    5.  
    6.         foreach (AzurineRegisterOutline azs in Setters)
    7.         {
    8.             if (!azs.Azurine) // Include renderer only if powered
    9.                 continue;
    10.  
    11.             m_BaseCommands.DrawRenderer(azs.Rend, NormalMaterial);
    12.         }
    13.  
    14.         m_BaseCommands.Blit(NormalRT, OutlineRTH, OutlineMaterial);
    15.  
    16.         context.ExecuteCommandBuffer(m_BaseCommands);
    17.         context.Submit();
    18.  
    19.         m_BaseCommands.Clear();
    20.     }
    The final texture is handled in the shaders like this:
    Screen Shot 05-06-22 at 04.18 PM.PNG

    The frame debugger shows that the command buffer happens before the camera rendering, so it should be OK:
    Screen Shot 05-06-22 at 04.16 PM.PNG


    Does someone knows why the effect is lagging? Is there a better way to achieve the effect?

    Thanks!
     
    Passeridae likes this.
  2. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    I tried to just display the final RenderTexture on top of the screen using a post process, I still have the issue.

    Screen Shot 05-07-22 at 12.07 AM.PNG

    This means it's not linked to Shader Graph at least, but more probably on the write / read timing for custom buffers. The RenderTexture used by either ShaderGraphs or PostProcesses seems to be one frame late, even though it is recalculated at the beginning of the frame.

    This is a serious issue for any custom effect I'm afraid.
     
  3. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    It appears the issue is not linked to the RenderTexture itself but rather the camera movement. If I move the object, I have no issue at all and everything is rendered correctly, which makes me think everything is rendering in the correct order and is well synced.

    I tried to deactivate the motion vectors in HDRP settings, and remove all sort of anti-aliasing, with no success.

    I checked if the camera projection matrix is the same during BeginCameraRendering and EndCameraRendering, and it is the same indeed.

    There is "something" when the camera moves that makes the objects render at the wrong place when using a CommandBuffer.

    Since it doesn't seem to come from motion vectors or the projection matrix, I have no clue :(
     
  4. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    Update : I switched for a Custom Pass, at the BeforeRendering injection point, with the same shaders and same RTHandle.

    Everything works fine and there is no delay. I quite dislike using CustomPass because layers are shared with the Physics system and it's a pain to rework collision masks when adding rendering layers, but it will do the works.

    The issue may be linked to the fact that BeforeRendering CustomPasses happen inside the "HDRenderPipeline::Render Main Camera" step, while the BeginCameraRendering CommandBuffers happen before it. Maybe some camera data is lacking here.

    Is it a bug or expected behavior ?
     
  5. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    262

    Indeed, between the BeginCameraRendering and the BeforeRendering custom pass, there is the camera setup for HDRP to prepare the rendering of the current frame. So before this step, all the variables in shaders are using the values of the previous frame.

    Right now, I'd say that this is expected since the BeginCameraRendering even is supposed to be called before any camera-specific code is executed.
     
  6. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    Ok, that makes sense. Thanks for the reply.

    Do you know if in the future we will have different layers systems for general uses, Physics and/or CustomPasses, as we have for Light layers?
     
  7. antoinel_unity

    antoinel_unity

    Unity Technologies

    Joined:
    Jan 7, 2019
    Posts:
    262
    For now, nothing is planned regarding the addition of new types of layers. Note that it's possible to use the rendering layers of the renderers to filter the objects rendered inside the custom pass, but for that, you need to write a C# custom pass and do the Draw manually.
    There are some custom pass examples here that can show you how to do that: https://github.com/alelievr/HDRP-Custom-Passes
     
  8. ssurget

    ssurget

    Joined:
    Jun 18, 2015
    Posts:
    23
    Oh right! That's good for me.
    Thank you :)
     
    antoinel_unity likes this.