Search Unity

Stencil buffer problems using CommandBuffer.DrawMesh with deferred rendering

Discussion in 'General Graphics' started by OskarSigvardsson, Apr 19, 2018.

  1. OskarSigvardsson

    OskarSigvardsson

    Joined:
    Sep 30, 2016
    Posts:
    5
    Hello everyone! I'm new to the forums, so please redirect me if this is not the place to ask.

    I'm playing around with CommandBuffers and deferred rendering, and to get a feel for it I wanted to try and just do a basic test. Basically, render a simple mesh with CommandBuffers in deferred rendering, and have it look the same as it would if you rendered it with a MeshRenderer. I've hit a road-block. This is my tiny test scene:



    The mesh on the right is rendered with a MeshRenderer, the mesh on the left is rendered with CommandBuffers. The material is just a simple material with the Standard shader and a slightly yellow albedo (no textures).

    So, I've been digging into the Frame Debugger, and I think I know what's going on: everything goes just fine until I get to the "RenderDeferred.Lighting" stage, at which point it seems to totally ignore the mesh drawn with CommandBuffers. These are the passes in the Frame Debugger for the MeshRenderer and CommandBuffer meshes (I turned off both shadows and deferred reflections to simplify the rendering):



    As far as I can tell, the only difference in rendering these is that the "normally rendered" mesh enables writing to the stencil buffer. It makes sense that this is the problem: the reason my mesh is ignored during the Lighting pass because it's outside of the stencil. Testing this problem, I figured I would "trick" the stencil buffer by putting the correctly rendered mesh behind my mesh, so that at least some of it would be inside the stencil:



    It's a bit tricky to see, but it works: the parts of my CommandBuffer mesh that is directly in front of the other bird is rendered correctly, the rest is not. It seems clear that the stencil buffer is at fault.

    Clearly, CommandBuffer.DrawMesh does not set whatever stencil settings is needed for deferred rendering. I've been digging through the docs and googling around, but I haven't found any answers to this. Is this a bug, or is there some way I can tell the command buffer to write to the stencil buffer as part of rendering the G-buffer?

    Here's my code for setting up the CommandBuffer, btw:

    Code (CSharp):
    1.  
    2. buf = new CommandBuffer();
    3. buf.name = "Draw meshes";
    4.  
    5. // This is the only material keyword the MeshRenderer
    6. // sets that isn't set when using the command buffer,
    7. // so set it here.
    8. Material.EnableKeyword("SHADOWS_SHADOWMASK");
    9.  
    10. // Simplest possible DrawMesh. The last argumenet (the
    11. // 3) is the Deferred pass in the shader. Mesh and material
    12. // are provided as fields set in the editor.
    13. buf.DrawMesh(mesh, Matrix4x4.identity, mat, 0, 3);
    14.  
    15. cam = GetComponent<Camera>();
    16.  
    17. cam.AddCommandBuffer(CameraEvent.AfterGBuffer, buf);
    18.  
    19.  
    I've tried a bunch of variants (different camera events, etc.) but I haven't found anything that works. Help would be much appreciated!
     
  2. OskarSigvardsson

    OskarSigvardsson

    Joined:
    Sep 30, 2016
    Posts:
    5
    Bump. Anyone got any ideas?
     
  3. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Unity's deferred renderer stomps on a lot of stencil stuff. A few years ago there was some wiggle room there, but it seems in the last year or so they completely ignore anything stencil related in the shader files during the GBuffer passes.

    If you want to play with stencils, you have to use the forward renderer. Either completely disable the deferred renderer, or use shaders with no deferred pass and render them after the gbuffer pass. If you want to affect objects that render to the gbuffer you'll likely have to solve the problem using a completely different approach, like rendering a mask to a render texture prior to the gbuffer passes and sampling that texture in a custom shader to clip an object.
     
    Last edited: May 15, 2018
  4. cphinton

    cphinton

    Joined:
    Jul 5, 2018
    Posts:
    18
    I used RenderDoc to figure out what Unity was doing with the stencil buffer. Putting these stencil settings in the shader worked for me, at least in CameraEvent.AfterGBuffer.
    Code (CSharp):
    1. Stencil {
    2.         Ref 192
    3.         ReadMask 255
    4.         WriteMask 207
    5.         Comp Always
    6.         Fail Keep
    7.         ZFail Keep
    8.         Pass Replace
    9. }
     
    paulatwarp and littledwarf like this.
  5. OskarSigvardsson

    OskarSigvardsson

    Joined:
    Sep 30, 2016
    Posts:
    5
    Thanks so much for the tips! I'll definitely try this out.
     
  6. paulatwarp

    paulatwarp

    Joined:
    May 17, 2018
    Posts:
    135
    Thanks, this worked for me in 2021.3 for a BeforeGBuffer event. I've also suggested this as missing information in the CameraEvent.BeforeGBuffer documentation.