Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Question Visualize Stencil in RenderTexture

Discussion in 'Universal Render Pipeline' started by alchemist_wurzelpurzel, Nov 18, 2021.

  1. alchemist_wurzelpurzel

    alchemist_wurzelpurzel

    Joined:
    Sep 4, 2018
    Posts:
    43
    Hi all!

    TLDR: Trying to use _CameraDepthTexture & fullscreenMesh with custom Shader that displays color for != 0 stencil values to visualize stencil in custom RenderTexture. Works with scene geometry using that shader but not with custom render pass and fullscreenMesh.


    In Unity 2020.3.17 and URP 10.6.0 my goal is to visualize the main stencil buffer in a render texture to use for post processing.

    I have gone through several steps of getting my code where it needs to be over in this thread already:
    https://forum.unity.com/threads/urp-visualize-stencil-in-texture.1195735/#post-7665799

    I have a simple scene:
    A plane with the standard Lit shader.
    A huge cube behind the plane that only writes to the stencil buffer whereever it passes the ZTest with LEqual.

    I have a simple vertex shader that displays a color wherever the stencil is not 0 and when using any geometry inside my scene and moving it around, it works as expected. The color is displayed everywhere except on the plane.

    Now when I try to draw a fullscreen mesh with the same shader to a custom RenderTexture I seem to have lost the stencil buffer. I am using a custom RenderPass for this and it looks like this:

    Code (CSharp):
    1. [Serializable]
    2.     internal class BlackBoxSettings
    3.     {
    4.         [SerializeField] internal RenderPassEvent m_eRenderPassEvent = RenderPassEvent.AfterRenderingOpaques;
    5.         [SerializeField] internal Material m_stencilColorMaterial;
    6.         [SerializeField] internal Color m_color = Color.red;
    7.     }
    8.  
    9.     internal class BlackBoxPass : ScriptableRenderPass
    10.     {
    11.         private readonly ProfilingSampler m_profilingSampler;
    12.         private BlackBoxSettings m_settings;
    13.         private RenderTargetIdentifier m_sourceID;
    14.         private RenderTextureDescriptor m_rtDescriptorStencilColor;
    15.         private RenderTargetHandle m_rtStencilColor;
    16.         private RenderTargetHandle m_rtDepthPrepass;
    17.  
    18.         private static readonly int s_stencilColorID = Shader.PropertyToID("_StencilColor");
    19.         private const string c_strUnityDepthTexture = "_CameraDepthTexture";
    20.         private const string c_strStencilColorTexture = "_StencilColorTexture";
    21.  
    22.         public BlackBoxPass(BlackBoxSettings _settings)
    23.         {
    24.             m_profilingSampler = new ProfilingSampler(GetType().Name);
    25.             m_settings = _settings;
    26.             m_rtDepthPrepass.Init(c_strUnityDepthTexture);
    27.             m_rtStencilColor.Init(c_strStencilColorTexture);
    28.             renderPassEvent = _settings.m_eRenderPassEvent;
    29.         }
    30.  
    31.         public void SetSource(RenderTargetIdentifier _source)
    32.         {
    33.             m_sourceID = _source;
    34.         }
    35.  
    36.         public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    37.         {
    38.             m_rtDescriptorStencilColor = cameraTextureDescriptor;
    39.             m_rtDescriptorStencilColor.depthBufferBits = 32;
    40.             m_rtDescriptorStencilColor.msaaSamples = 1;
    41.             m_rtDescriptorStencilColor.colorFormat = RenderTextureFormat.ARGB32;
    42.             cmd.GetTemporaryRT(m_rtStencilColor.id, m_rtDescriptorStencilColor, FilterMode.Point);
    43.  
    44.             ConfigureClear(ClearFlag.Color, Color.white);
    45.             ConfigureInput(ScriptableRenderPassInput.Depth);
    46.             ConfigureTarget(m_rtStencilColor.Identifier(), m_rtDepthPrepass.Identifier());
    47.         }
    48.  
    49.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    50.         {
    51.             CommandBuffer cmd = CommandBufferPool.Get("BlackBox");
    52.  
    53.             using (new ProfilingScope(cmd, m_profilingSampler))
    54.             {
    55.                 cmd.SetGlobalVector(s_stencilColorID, m_settings.m_color);
    56.                 cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_settings.m_stencilColorMaterial, 0, 0);
    57.  
    58.                 //Blit(cmd, m_rtStencilColor.Identifier(), m_sourceID);
    59.             }
    60.  
    61.             context.ExecuteCommandBuffer(cmd);
    62.             CommandBufferPool.Release(cmd);
    63.         }
    64.  
    65.         public override void FrameCleanup(CommandBuffer cmd)
    66.         {
    67.             cmd.ReleaseTemporaryRT(m_rtStencilColor.id);
    68.         }
    69.     }
    70.  
    71.     internal class BlackBoxRenderFeature : ScriptableRendererFeature
    72.     {
    73.         [SerializeField] private BlackBoxSettings m_settings;
    74.  
    75.         private BlackBoxPass m_blackBoxPass;
    76.  
    77.         public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    78.         {
    79.             m_blackBoxPass.SetSource(renderer.cameraColorTarget);
    80.             renderer.EnqueuePass(m_blackBoxPass);
    81.         }
    82.  
    83.         public override void Create()
    84.         {
    85.             m_blackBoxPass = new BlackBoxPass(m_settings);
    86.         }
    87.     }
    In RenderDoc I can see that the depth texture contains the stencil when opaque geometry is drawn, but it's gone once my own pass starts, still containing depth information though.

    I would greatly appreciate any help on this!
     

    Attached Files:

  2. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    Sorry; I think I may have steered you wrong in the last topic since if you bind to
    _CameraDepthTexture
    , you're binding to the depth prepass, which is done before drawing other things. So that's why the stencil is missing. But the question still remains as to how to bind to the actual camera stencil in a render pass, which hopefully someone can answer.
     
  3. alchemist_wurzelpurzel

    alchemist_wurzelpurzel

    Joined:
    Sep 4, 2018
    Posts:
    43
    After some further investigation it seems that the stencil information can be found in the _CameraColorTexture and I also had to do some projection magic.

    Code (CSharp):
    1. public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    2.         {
    3.             CommandBuffer cmd = CommandBufferPool.Get("BlackBox");
    4.  
    5.             using (new ProfilingScope(cmd, m_profilingSampler))
    6.             {
    7.                 cmd.SetGlobalVector(s_stencilColorID, m_settings.m_stencilColor);
    8.  
    9.                 cmd.CopyTexture(m_cameraColorID, m_rtStencilColor.Identifier());
    10.  
    11.                 cmd.SetViewProjectionMatrices(Matrix4x4.identity, Matrix4x4.identity);
    12.                 Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(0, 0, -1), Quaternion.identity, Vector3.one);
    13.  
    14.                 cmd.DrawMesh(RenderingUtils.fullscreenMesh, matrix, m_settings.m_stencilColorMaterial, 0, -1);
    15.  
    16.                 Camera camera = renderingData.cameraData.camera;
    17.                 cmd.SetViewProjectionMatrices(camera.worldToCameraMatrix, camera.projectionMatrix);
    18.  
    19.                 //Blit(cmd, m_rtStencilColor.Identifier(), m_sourceID);
    20.             }
    21.  
    22.             context.ExecuteCommandBuffer(cmd);
    23.             CommandBufferPool.Release(cmd);
    24.         }
    Now what I need is my RT to be black where the Stencil does not match so I guess just copying the camera color target won't work.
    In the end I need my RT to display white where the stencil has my target value and black where it doesn't. Then I want to blur it and reapply it to the main image with black color so the stencil areas seem like dark shadows around any geometry I have.
     

    Attached Files: