Search Unity

  1. The 2022.1 beta is now available for testing. To find out what's new, have a look at our 2022.1 beta blog post.
    Dismiss Notice

Has anyone ever gotten a stencil buffer to copy with CommandBuffer.Blit?

Discussion in 'General Graphics' started by AaronBrownLM, Sep 22, 2016.

  1. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    I can 100% confirm that I have been able to successfully do a Graphics.Blit where my custom material/shader was able to read from the stencil buffer.

    But I have NOT been able to get CommandBuffer.Blit() to do it. The custom material/shader always skips every pixel if you set the stencil check to "Equals" or anything other than "Always".

    Has anyone ever been able to access the stencil buffer from a shader that's being fired from a CommandBuffer.Blit command? If so, I'd really like to know how you did it.

    I've been working on this for 36 solid hours trying to get this to work.
     
  2. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
  3. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    I got it working!

    I honestly don't even know how I got it working, and it's so dang easy I can't even particularly figure out WHY it was so hard, or why it's working now. But all of a sudden after trying this and that a thousand different ways, all of a sudden it just worked.





    This is done with nothing but a single camera, a single CommandBuffer, and a single Blit() in CameraEvents.BeforeImageEffects.

    It took me nearly 40 SOLID hours of trial and error to get this working.

    And no, I do not know why it is working, only that it is.

    I'm attaching the whole scene in case anyone else is struggling with this.
     

    Attached Files:

    Egad_McDad, misabiko, jister and 2 others like this.
  4. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    For anyone who's trying to figure out how to use CommandBuffers to take a screenshot (a rendertexture) of a previous spot in the rendering pipeline, and then use that texture in a later spot in the rendering pipeline, I've got that working also.





    This uses two command buffers.

    The first command buffer takes a "screenshot" (a rendertexture) AFTER opaque objects are drawn, but BEFORE transparent objects are drawn.

    The second command buffer activates after everything is finished being drawn. It does its thing only onto the stencil side (the left side), using the stencil buffer. And it takes the previously saves "screenshot" and simply draws it on the left side of the image, which is where the stencil buffer pixels are. So on the left side you see only opaque objects from the previously-saved RenderTexture "screenshot", and the right side you see everything. The top cube is fully opaque, so it's seen on both sides. But the bottom cube is using a transparent shader, so it's not seen on the left side where the previously-saved "screenshot" is being displayed.

    I'm attaching a scene showing the above in action, with comments in the script that explain how it works.

    NOTE: There is currently a bug in Unity where Blit() is flipping the whole picture upside down. So I have to blit several times in this example, to flip it back right-side-up again. I assume Unity will fix this bug soon. When they do, simply comment out the extra Blits() that I added, as they are entirely unnecessary except to compensate for this bug.
     

    Attached Files:

    jister and SAM-tak like this.
  5. Shawn-Halwes

    Shawn-Halwes

    Joined:
    Jul 17, 2013
    Posts:
    51
    Thanks for putting this up. I am curious what version of Unity you were researching this with?
     
  6. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    5.4.1f1, and incidentally these scenes are also made with 5.4.1f1.
     
  7. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    As one and (hopefully) last contribution, I posted an example showing how that CommandBuffer.Blit() is currently bugged, in that it doesn't pass information correctly to _MainTex in the shader (if working with temporary variables). To work around this bug, I attached an example scene, see: http://forum.unity3d.com/threads/co...internal_blitcopy-shader.432699/#post-2798713

    Hope all this helps someone. And I hope Unity fixes this, but at the moment there are TWO bugs in CommandBuffer.Blit(), one that it flips the picture up-side-down, and two that it doesn't pass anything to the shader's _MainTex if you're working with a temporaryRT. Sigh.
     
    AntonChegurov and Olli_wurghi like this.
  8. steven3Dim

    steven3Dim

    Joined:
    Feb 21, 2017
    Posts:
    12
    Very good work. I downloaded your first example. I had to set the Camera Rendering Path to "Forward" from "Use Graphics Settings" in order to make it work. Any idea why it doesn't work in deferred?

    My goal is to copy the stencil buffer to a RenderTexture for use later on. Is this possible?

    I get an error when I quit your example.
    Assertion failed on expression: 'go.IsActive() && go.GetTag() != 0'
    I see that you call:
    Code (CSharp):
    1. OnEnable(){
    2. ...
    3. Camera.main.AddCommandBuffer(CameraEvent.BeforeImageEffects, cmdBuffer);
    4. }
    5. OnDisable(){
    6. ...
    7. Camera.main.RemoveCommandBuffer(CameraEvent.AfterDepthTexture, cmdBuffer);
    8. }
    So your insertion point differs, but even when I make them both BeforeImageEffects the error remains.
     
  9. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    I think I've seen that error before. If it is happening when the game exits, I guess you could try to ensure that all game objects have been fully disabled before the game is allowed to close. Sounds like a problem with cleanup on exit. I figure you could use the OnDisable monobehavior function (or whatever it is called), to do clean up. Cuz the error says go.isactive(), which I assume means "game object isactive", so something about a game object being active... so... a game object related error during cleanup... see if you can make sure everything cleans up? Or submit a bug report.
     
  10. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    Deferred... you need to use CameraEvent.some_event_that_works_in_Deferred. Look at the options under camera event, some of them are specific to deferred. Play around with the options I guess. Should work...
     
  11. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    Also I made a bigger thread, title of that thread is "Commandbuffer.blitz isn't stencil buffer friendly". It's got more examples there.
     
  12. steven3Dim

    steven3Dim

    Joined:
    Feb 21, 2017
    Posts:
    12
    The error arises, because probably the Camera is destroyed before the command buffer is destroyed. When I destroy the command buffer in the update loop, there is no error.

    I have tested all deferred options in a loop in a script, but none of them work (the cube remains standard textured). The forward path works from AfterForwardOpaque (11) and further.

    When I set the dest target of cmdBuffer.Blit to a temporary render texture (instead of BuiltinRenderTextureType.None), the temporary texture becomes completely filled with the texture instead of just the silhouette. The screen is then not textured any more.
     
  13. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    202
    you shoudl try my other thread, i have more complex examples there and one of them might work in deferred.
     
  14. NoiseFloorDev

    NoiseFloorDev

    Joined:
    May 13, 2017
    Posts:
    104
    For anyone else poking at this (or the OP, but he probably knows this already): change the second Blit argument from "BuiltinRenderTextureType.None" to "BuiltinRenderTextureType.CameraTarget" to make this work with MSAA, and probably with other image effects. I think blitting to None is rendering directly to the framebuffer, which gets overwritten by image effects, instead of to the current render texture.
     
    jiajunsh and chrismcmath like this.
  15. Deavn

    Deavn

    Joined:
    Mar 3, 2016
    Posts:
    1
    Sorry for reviving this thread 3 years later.

    Has anyone ever experienced a solid solution for the described problem, that works on Android?

    While the solution with the hint given by NoiseFloorDev works in the editor of my project, it does not if i build the game to Android. On top I am using AR Foundation and i am not sure if that is the problem or what i can do about it.

    I am trying to overlay a transparent color over parts of the screen (stencil). In the editor everything works fine, in production the stencil part is correctly modified but the color is not transparent. While asking myself why it even works in the editor with MSAA enabled and does not if MSAA is disabled. I have no clue why it should act different in the production scenario.
     
unityunity