Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

CommandBuffer.Blit() isn't stencil buffer friendly

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

  1. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    EDIT: I'm consolidating this thread to keep it short and simple.

    THE ISSUE:
    Creating a black and white image of a stencil buffer, for later use in a post-processing effect, requires too many blits with CommandBuffer.Blit().

    Here's the summary:

    1) If you blit from the screen to a rendertexture, you can't use a custom shader... or else the resulting render texture is blank. Also, it never copies the stencil to any render texture. I believe both these issues are bugs. (Case 834634)

    2) If you blit from a render texture, to another render texture, the stencil can't be access in the shader. Probably because as I said in #1, stencils aren't copied to render textures. I believe this is a bug.

    3) If you blit from a render texture to the screen, everything works including the stencil (weee!!), but now you just over-written the picture on the screen. You'd then have to fix that, I suppose with another blit to put the picture back again.

    4) You can't blit from screen to screen, or from one render texture to itself, unless your shader specifically uses a global texture (not _MainTex). Otherwise result is blank picture.

    5) Any attempt to render the camera to a render texuture will result in no ability to access or use the stencil buffer, due to issue #1 above.

    In the end it's possible but it requires too many blits.

    -> first blit is from screen to render texture, and you can't use a shader, as I said in #1 above.
    -> second blit is from that render texture to screen, to make the stencil image, since as I said in #2, you can't blit from a RT to another RT, or else there is no stencil... but anyway now you just put the black and white picture on your screen so screen is screwed up.
    -> third blit is from screen to render texture, again with no shader allowed (see #1 above), just to "save" the stencil image you made. Or else, if you skip this step, how are you gonna use it later?
    -> fourth blit is from the original render texture, back to the screen again, with a shader to do some post processing effect. You'd have to set the stencil image to a global property, so that this shader would have it also to work with. This step is required for another reason also: to put the picture back on the screen, since you screwed it up on the second blit.

    That's a minimum of 4 blits just to make (and use) this stencil texture. I'd happily do it if it could be done with just one blit from screen to screen, but can't (see #4 above).

    Acceptable solutions:

    A) It should be possible to blit from screen to render texture, and use a custom shader. Currently, this isn't possible (see point #1 above)

    B) Any blits from the screen to a render texture, should copy the stencil buffer to that render texture. Currently, it does not copy it, which probably is what results in point no. "C" below.

    C) Any blits from render texture to another render texture should be able to access the stencil. Currently, it is not accessible.

    D) It would be nice if it were possible to blit from the screen, to the screen, with a custom shader. This would cut down on the number of blits needed to do many post processing effects.
     
    Last edited: Sep 25, 2016
  2. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
  3. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    The issue here seems to be working in the version of unity I am using (some 5.5 based version). I've pinged QA to investigate what is happening in 5.4 here.

    This is intentional. Only the color target is copied when blitting RT's and blitting depth / stencil is not normally needed and has a performance cost. If you want to do this you can't use blit and have to do a custom render. It's not too hard to do and we do this for many of the command buffer image effects. One thing to note is that we DO NOT currently have a way to nicely copy the depth and stencil buffer, but you can use one that has already been created with a different color buffer. In command buffers you can do it like so:

    Code (csharp):
    1.  
    2.             cmdBuffer = new CommandBuffer();
    3.             cmdBuffer.name = "cmdBuffer";
    4.             int texID = Shader.PropertyToID("_OlderTexture");
    5.             cmdBuffer.GetTemporaryRT(texID, -1, -1, 0);
    6.  
    7.             // set the target to be the temp created texture + the current depth / stencil buffer
    8.             // when we draw now we will be using the old depth stencil but a NEW color target
    9.             cmdBuffer.SetRenderTarget(texID, BuiltinRenderTextureType.Depth);
    10.             cmdBuffer.DrawMesh(MyMesh, MeshMatrix, material);
    11.             Camera.main.AddCommandBuffer(CameraEvent.AfterForwardAlpha, cmdBuffer);
    12.  
    We are working on API to make this cleaner and nicer right now.

    Well it will as you are using the stencil from the target.

    This is how GPU's work. You can't read and write from the same target unless the API supports framebuffer fetch. https://www.khronos.org/registry/gles/extensions/EXT/EXT_shader_framebuffer_fetch.txt

     
  4. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Thanks bunches for the reply.

    Did you test this? I assume this also is working in your version of Unity (5.5)? This doesn't work in 5.4.1f1. Gives this error:



    I tested this at least a dozen times in the last week, and it never did work although I didn't add it to my list of errors. I'm curious, if this is working in 5.5, are you able to use this to Blit from one RT to another RT and use the stencil?

    Understand, I'm not "trying to copy the stencil to a RT". I don't care if the stencil is copied. Only reason I ever was trying to copy the stencil to the RT, is because you COULDN'T use something like BuiltinRenderTextureType.Depth in your SetRenderTarget(), so I was trying to find a work-around.

    Also if this is possible in 5.5, then no need to use .DrawMesh() as you suggested... I should be able to just set the depth buffer and blit()!

    Sounds like good times await me in 5.5.
     
  5. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    I'll upload the project when I'm at work tomorrow (I was using the one from you bug report as a basis). And yes I did test this.

    Some things are a bit broken / unintuitive with command buffers currently (mostly depth / stencil related). We have a developer scheduled to fix a bunch of issues in this area in a few months. This won't be just a 'oh lets fix some bugs' pass but a real sold 'how should they work, whats broken'. So please raise bugs / feedback about CB's as you encounter it.

    When I was putting together the project on my PC I was using renderdoc just to see what was being done on the GPU. If you don't use it currently I recommend looking at some captures as it is a massive time saver.
     
  6. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Okay will do. How do I make sure this future developer will get / see my reports?

    I mean right now, off the top of my head, even though I think we've established that a few issues I reported may be already fixed in 5.5, I would still say the following issues exist / should be looked at:

    1) Stencils really should copy to RT's, maybe not by default but at least as an option.
    2) BuiltinRenderTextureType.Depth should work (it doesn't in 5.4.1).

    And then, there are functions that don't seem to work with stencils:

    3) cmdBuffer.SetRenderTarget() doesn't seem to do anything.
    3) Camera.main.depthTextureMode = DepthTextureMode.Depth doesn't seem to do anything.
    4) Camera.main.SetTargetBuffers(color, depth) doesn't seem to do anything.
    5) cmdBuffer.GetTemporaryRT(, , , 24)... the "24" on this call doesn't seem to do anything.

    If line #1 on all these functions/options is simply "return;", I wouldn't be surprised, because they seem to do nothing.

    None of the documentation talks about which functions work with stencils, and which don't. So, since stencil's are part of the depth, I had to include all these functions in my tests to make sure that my problems weren't being caused by a wrong setting on one of these. Documentation on these and other depth functions need to mention their interactions if any with stencil buffers.

    Another issue:

    If all cameras are set to render to RT's, there is no way to blit to the screen! It seems messy that I should have to set up another camera, and tell it to cull everything, just so that I can have a dummy camera to give me a means to put a picture on the screen (by blitting to that dummy camera's CameraTarget). There should be a BuiltinRenderTextureType.Screen, which will always point to the screen, and allow a blit to the screen even if there are NO cameras rendering to the screen at the time.

    And then, there are these errors:



     
    Last edited: Sep 27, 2016
  7. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Some of these things I'm mentioning here isn't necessarily bugs. Obviously I'm not doing things right. But then that begs the question, why am I doing so many things wrong? Several reasons:

    1) The bugs we mentioned above (some of which might be fixed in 5.5 already).
    2) The fact that stencil is mixed with depth, but almost all depth-related functions aren't working with stencil.
    3) The fact that documentation doesn't mention what functions interact with stencils.
     
  8. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Also, in the documentation for Graphics.Blit, it says:

    This is all wrong, and the documentation shouldn't say this. You can do a blit with the stencil, with a render texture as the source. I donno why this statement is in the documentation but it threw me off for some time.

    Also, it seems to indicate that the stencil is part of the render texture. That also threw me off. And furthermore, this whole statement is a nightmare. A scary, evil nightmare. Sends you off on a wild goose chase trying to learn how to do all of this, and in the end, nothing about any of this will help a single bit with any problem you are having with stencil buffers.
     
  9. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    But that statement IS correct. You can use SetRenderTarget with a color buffer and a separate depth/stencil from a different target. And it does work as expected.

    It is part of the render texture. It's part of the depth/stencil target.

    Historically unity has treated render textures as a color + depth target, this is due to a bunch of legacy GL FBO fun from when unity was first written and it has leaked through into the API layer. Modern API's treat targets as individual / separable textures, which is why there is now api on render texture to get the associated RenderBuffer. Internally though there is still some coupling between the RT and the Depth target.

    These don't seem to do what you think they do, and it is documented.
    It does, we have tests and post processing that use this functionality. If it didn't work a large number of features would not work. See here: https://bitbucket.org/Unity-Technol...sion.cs?at=trunk&fileviewer=file-view-default

    https://docs.unity3d.com/Manual/SL-CameraDepthTexture.html This is well documented. You get access to a resolved depth texture.

    I haven't seen this is any of my testing.

    Can you describe exactly what you are trying to do and show me the code you have for what you are trying to achieve? You are saying a lot of things are broken, but I can't actually see what you are doing or what your expectations are in these cases.
     
  10. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    No. 1:
    The statement in question says it (the stencil) is part of the source, not target. But you just said it (I assume you mean stencil) is part of the target. Not sure if this makes a difference, but just pointing this out for the sake of exactness.

    No. 2:
    The statement says that the stencil is part of a (Render)texture. But earlier, you said:
    So, it says "...stencil buffer that is part of the source RT", and you say stencil buffers are never copied to RT's, so how can a stencil buffer be "part of the RT"?

    No. 3:
    As you requested, I'm attaching an example package. It includes two scenes. One scene is called test_GraphicsBlit.scene, and it uses Graphics.Blit, and it works as expected. The next scene is called test_CommandBufferBlit.scene, and it attempts to re-create the same functionality line for line. And it doesn't work, and generates errors.

    Please also observe that in my attached scene, I use a Graphics.Blit(), and it works with the stencil just fine. So the documentation seems to indicate that to get the stencil to work, you must do a complex manual drawing of a quad.

    So the doc is misleading because it:

    1) Suggests that a stencil can be part of a RT. Which sends you on a quest to learn how to read/write stencils to RT's.
    2) Suggests you can't use stencil without drawing a manual quad. Which sends you on a quest to learn how all that.

    I loaded it AmbientOcclusion.cs. And I commented out the line in question:
    Code (CSharp):
    1. //cb.SetRenderTarget(mrt, BuiltinRenderTextureType.CameraTarget);
    It didn't make any visible difference.


    Full-size screenshots: http://imgur.com/a/7xizQ

    Alright I concede this one. I commented out this line from the AmbientOcclusion.cs, and it did make a difference. Maybe no difference for stencil (which has been my focus). But a difference for the depth.
     

    Attached Files:

  11. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    In case it's any help, I submitted this package also as a bug report, case # 836103.

    Note that I'm still using 5.4.1f1.
     
  12. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    A render texture has a color target, and a depth/stencil target. I was referring to this. Specifically the depth/stencil target of the source texture. Yeah, this wasn't super precise language.

    Yeah I was imprecise here. Like I said in 1; a RT is a combination of a color + depth/stencil target. When a blit happens we only blit the color portion of the RT from one RT to the other. The source and target may have a depth / stencil, but we do not read and write between the two. This isn't to say that it doesn't have one, just that we don't do anything with it during a blit operation.

    There a few reasons for this:
    • It's slower and (generally) not needed
    • Very difficult to match between MSAA RT's (blits happen with resolved RT's that have NO associated depth /stencil)
    • Manual reuse of depth targets is generally better even if the api right now sucks and is easy to mess up
    Stencils are part of the RT. But right now there is no way to read / write them between RT's. We have ways of doing this for depth. But not for stencil. This is an API limitation currently. I'm not sure if it's in unity or at the gfx level (i know that stencil is a weird thing that is not always well supported).

    Well a blit IS a quad, it's a helper function that render with a texture and sets up some things like texture and render targets. But it does TOO much for the use case you have.

    That path is only used for deferred + ambient + HDR only I believe, make sure you have that turned on.

    Depth and stencil are ONE buffer on the hardware. It's a 32 bit buffer with 24 bits for depth, and 8 bits for stencil.
     
    Last edited: Sep 29, 2016
  13. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    Anyway, enough text.

    So I just spent some taking a look into this and managed to make a working command buffer version. That is pretty simple in the end. It's attached here (note: I did this on 5.5, i believe it will also work on 5.4, but if it does not let me know because that IS a bug).

    So in your original code you do this (added some comments inline):
    Code (csharp):
    1.  
    2. if (cmdBuffer == null)
    3. {
    4.     // code also requires a custom target render texture
    5.     // and then blit to screen :(
    6.     cmdBuffer = new CommandBuffer();
    7.     cmdBuffer.name = "cmdBuffer";
    8.  
    9.     // this is fine, set up the target and clear
    10.     cmdBuffer.SetRenderTarget(StencilTempTextureID);
    11.     cmdBuffer.ClearRenderTarget(true, true, Color.black);
    12.  
    13.     // setting a render target then blitting does nothing,
    14.     // unity will set the target (inclding depth / stencil target)
    15.     // to whatever the second argument is here. In this case this will be
    16.     // either the FINAL camera target or the backbuffer
    17.     cmdBuffer.SetRenderTarget(StencilTempTextureID, CameraRenderTextureID);
    18.     cmdBuffer.Blit(CameraRenderTextureID, BuiltinRenderTextureType.None, PostprocessMaterial);
    19.  
    20.     // once again same issue as above.
    21.     cmdBuffer.SetGlobalTexture("_StencilTempTexture", StencilTempTexture);
    22.     cmdBuffer.SetRenderTarget(BufferID, CameraRenderTextureID);
    23.     cmdBuffer.Blit(CameraRenderTextureID, BuiltinRenderTextureType.None, stencil_is_on);
    24.  
    25.     GetComponent<Camera>().AddCommandBuffer(CameraEvent.BeforeImageEffects, cmdBuffer);
    26. }
    27.  
    Mine has some changes I will detail inline
    Code (csharp):
    1.  
    2.  
    3. // NEED TO ADD THIS
    4. // forces camera to go via an internal RT for rendering
    5. // it's easier than allocating and managing your own.
    6. // Any image effect on the camera will remove the need
    7. // for this.
    8. // In 5.6 there will be an API on camera for forceIntoRenderTexure
    9. void OnRenderImage (RenderTexture src, RenderTexture dst)
    10. {
    11.     Graphics.Blit (src, dst);
    12. }
    13.  
    14.  
    15. void OnEnable()
    16. {
    17.     // moved these to here
    18.     // can still be in OnStart, but I prefer to
    19.     // lifescycle manage in OnEnable
    20.     PostprocessMaterial = new Material(Shader.Find("StencilToBlackAndWhite"));
    21.  
    22.     // We need one temp texture here for the loop,
    23.     // allocation + clearning can be moved into the
    24.     // cmd allocation below unless you want to reuse it.
    25.     StencilTempTexture = new RenderTexture(Screen.width, Screen.height, 24);
    26.     StencilTempTexture.name = "Stencil";
    27.  
    28.     StencilTempTextureID = new RenderTargetIdentifier(StencilTempTexture);
    29.  
    30.     if (cmdBuffer == null)
    31.     {
    32.         cmdBuffer = new CommandBuffer();
    33.         cmdBuffer.name = "cmdBuffer";
    34.  
    35.         // now we have a RT from the camera render we can reuse the depth / stencil from that
    36.         cmdBuffer.SetRenderTarget(StencilTempTextureID, BuiltinRenderTextureType.CameraTarget);
    37.         // clear just the color
    38.         cmdBuffer.ClearRenderTarget(false, true, Color.black);
    39.  
    40.         // We can't use blit here as it will internal set destination,
    41.         // so draw a quad instead. Vertex shader in the shader has been changed
    42.         // see the code attached.
    43.         cmdBuffer.DrawMesh(quad, Matrix4x4.identity, PostprocessMaterial, 0, 0);
    44.  
    45.         // set the global texture
    46.         cmdBuffer.SetGlobalTexture("_StencilTempTexture", StencilTempTexture);
    47.         // for now blit to camera texture, you could blit this
    48.         // somewhere else if you want. Right now it will overright the
    49.         // camera texture.
    50.         cmdBuffer.Blit(null, BuiltinRenderTextureType.CameraTarget, stencil_is_on);
    51.  
    52.         GetComponent<Camera>().AddCommandBuffer(CameraEvent.BeforeImageEffects, cmdBuffer);
    53.  
    54.     }
    55. }
    56. This does the change in a clear + 2 blits.
    57.  
    ONE VERY IMPORTANT NOTE! This will not work properly with MSAA as it's written(require additional work). When using MSAA rendering rendering happens to a special texture type. If you want to use this as a source texture for blits this needs to be resolved into a normal texture for the hardware to use. When a resolve happens only the color surface is resolved from the GPU side to the usable render texture side. This means there will NOT be a valid depth stencil present for doing the stencil pass on.
     

    Attached Files:

    Noisecrime likes this.
  14. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Wow I didn't expect this.

    Okay so, trying to get your example to work with 5.4...

    1) You can't open a 5.5 scene in 5.4, ha ha. But I think I can guess from your code that your scene had just one camera, so I'm recreating it like that. If you had two cameras (like my scenes did), let me know.

    2) You didn't seem to include the StencilToBlackandWhite.shader file in your package. Did you make any changes to this shader? You said you updated the vertex shader, so I assume you did? If you could post that shader, that's the only file missing.

    3) I tried it with my current StencilToBlackandWhite.shader file and it continually spams this error:

    This could be because I'm missing your modified StencilToBlackandWhite.shader?

    4) Using 5.4, I had to change the line: Blit(null, to Blit((Texture)null, to avoid an ambiguous call error.

    5) Besides the above errors, it simply displays a solid black screen at the moment.

    Send me that shader if you can, and I'll give it another spin.

    PS. I have some comments on some of the other things you said, but I'd like to get your example working for now. :)
     
  15. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    Oops. :( Yeah there are changes to that shader.

    Attached a 5.4 zip version. Has both the 5.4 project AND the .package.
     

    Attached Files:

  16. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    This is getting weirder.

    So, I ran it in the project you included (thanks for that by the way), and it worked.

    But, I created a brand new project, and copied your Assets folder in, and it still was spamming my console with this same error:

    But when I loaded your project folder (at zip/5.4CmdBliT ) into 5.4.1f1, it worked great.

    So after trying this and that, I copied your ProjectSettings folder (from zip/5.4CmdBliT/ProjectSettings) into my new project, and the error went away.



    Looks like your ProjectSettings files are all about 5 times smaller than mine. Yet, my project is brand new, I didn't touch a thing. Any idea what's going on here? *scratches head*. You didn't happen to send me a projectsettings folder that was created in 5.5?

    I'm attaching my project, this time the whole project folder structure in a zip.
    It contains an exact copy of your assets folder, but the rest of the project (including the ProjectSettings folder) is simply a brand new project created by Unity 5.4.1f1. I deleted the Library folder just to keep the zip small.
    I also included your ProjectSettings folder, it's named "ProjectSettings -- From Tim-C".
    Right now, it doesn't work, it spams that error.
    But if you replace the ProjectSettings folder with "ProjectSettings -- From Tim-C", the error goes away.
     

    Attached Files:

  17. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    my project has MSAA disabled as i mentioned in my original post. its also using text serialization thats why the files are different sizes,
     
  18. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Oh, right, duh. I read that, but it didn't click that I actually needed to check it. :) Turning off AA fixed it. Although if I comment out your mysterious Graphics.Blit(), the error returns. Interesting.

    Thanks Tim for all your help with all of this.

    I have some feedback.

    You seem to have done some kind of wizardry in your solution that only a dev who knows the internal workings of the engine would know. Your comments say that Graphics.Blit(src, dst) is needed because of some internal issue.

    This looks like features written by the devs, for the devs. :p

    CommandBuffer Feedback:

    1) Need documentation. Example code in the docs. A mile long list of examples codes.
    2) depthSurface == NULL || rcolorZero->backBuffer == depthSurface->backBuffer isn't comprehendable to non-devs.
    3) BuiltinRenderTextureType.Screen would be nice to have, to always be able to blit to the screen.
    4) Making Blit's "set destination" feature to be optional would be nice.
    5) AA being ON, causing Blits to not work in this example, is probably not documented.
    6) OnRenderImage being needed to Blit in this example, is probably not documented.
    7) SetRenderTarget before a Blit doing "nothing", should probably be mentioned in Blit's documentation, even if it seems obvious to you, it wasn't obvious to me.
    8) CommandBuffer should not ever have to rely on Graphics.Blit(), like in this example.
    9) "Temporary render texture _CameraDepthTexture not found" needs a lot more explanation in the error message, or a link to a documentation page that explains possible causes and solutions.
    10) "Built-in render texture type X not found while executing" needs a lot more explanation, and a help page, same as above.
    11) The documentation on Camera.main.depthTextureMode = DepthTextureMode.Depth should give a brief summery of where this texture is, and how its accessed, and a list of which functions and features would depend on it, and if it does or doesn't contain stencil information. As it is right now, its documentation reads almost as if it thinks you already know all of this.
    12) The statement on Graphics.Blit's documentation page concerning stencils, and the need to manually draw a quad, is still unsettling to me, and a lot (all?) my previous complaints about it still stand I think. Also it's vague, and doesn't give any example code specific to stencils.
    13) There are too many render textures, render targets, and target buffers.
    ----> OnRenderImage creates what you describe as a "Internal RT".
    ----> Camera.main.targetTexture creates, I suppose, a different RT.
    ----> Camera.main.depthTextureMode = DepthTextureMode.TheThreeStooges.
    ----> _CameraDepthTexture, another RT?
    ----> "permanent" RTs.
    ----> "temporary" RTs.
    ----> BuiltinRenderTextureType.RTs (bunches here)
    ----> color and depth buffers so you can make, even more RT's.
    ----> Then there is the screen itself, which seems to be something other than all of this, and very mysterious.
    All this is fine, I like to have lots of control. That is, if it all just works. But when these functions give out incomprehensible error messages, and the stencil can't be accessed, having this many different things to search through to try to find the cause is a nightmare.
    14) The documentation on almost all these CommandBuffer features only describes what they do when they're working perfectly, on a perfect day.
    15) Need more troubleshooting type of documentation.
    16) Need more relationship type of documentation, detailing which features would affect others, and which wouldn't, and to what extent, and any potential conflicts between features. This would greatly reduce the research time needed to fix a problem.
    17) Especially need more stencil documentation as it relates to Graphics.Blit and especially CommandBuffer.Blit, since stencil is one of the most problematic features.

    You don't have to answer any the above, unless you want this discussion to go on forever. But maybe you could try to forward the above feedback to whoever will be working on this stuff in the future.

    I'll submit your example scene as a bug report, since... eh... turning on or off AA should not spam an incomprehensible console error, and because commenting out OnRenderImage gives the same error, and plus that's just too much of a hack you did, anything that requires that much internal knowledge and hacking to work around should probably be looked at as a bug.

    For all other people who found this thread, who like me were struggling to get CommandBuffer.Blit to work with or without stencils, I'm attaching all of my example scenes that I made in the last 10 days or so, not including the ones posted above.
     

    Attached Files:

    Noisecrime and GoGoGadget like this.
  19. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    ...and one more example (won't let me attach more than 5 in a single message lol)
     

    Attached Files:

  20. GoGoGadget

    GoGoGadget

    Joined:
    Sep 23, 2013
    Posts:
    626
    +1 to more command buffer documentation (more techy stuff is fine, just something that's not Aras's super old cb examples from 5.0 which have to be downloaded as a package).
     
  21. Simod

    Simod

    Joined:
    Jan 29, 2014
    Posts:
    147
    Gotta use this topic as a bible now. Seriously CommandBuffers seems messy from that side...

    PS. Thank you for examples !!!
     
  22. Tycho

    Tycho

    Joined:
    Nov 24, 2012
    Posts:
    159
    This thread has been super useful!

    I'm currently trying to get this to work with MSAA as well. Any tips on how I can resolve the MSAA texture into a normal texture (using a Command Buffer) while preserving the depth and stencil buffer?
     
  23. boehmz1990

    boehmz1990

    Joined:
    Feb 2, 2017
    Posts:
    3
    I'm trying to use your solution, but not even the example project seems to work for me.
    When I play in the editor, it shows all black and I get the errors:
    - Dimensions of color surface does not match dimensions of depth surface
    - depthSurface == NULL || rcolorZero->backBuffer == depthSurface->backBuffer
    repeatedly. Additionally, when I tried to implement similar code into my own Unity project I got a crash after these same errors.
    Would you know what the issue is?

    [EDIT]
    I missed the part about turning off MSAA. I turned that off in project settings and it removed the depth surface == NULL error. However I am still seeing a black screen with:
    - Dimensions of color surface does not match dimensions of depth surface
     
  24. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Just wanted to drop in and say, I finally got around to testing this on Unity 5.5.0f3 and all 6 of the points that I made at the beginning of the first post of this thread, are still issues. Nothing appears to be any different as of 5.5.0f3. Still requires 4 blit calls to perform the described action, which I still think it excessive.
     
  25. cpetry

    cpetry

    Joined:
    Jun 30, 2014
    Posts:
    29
    I'm also trying to get some information about this buggy CommandBuffer blit() from your examples.
    My case seems to be a bit easier but I'm also struggling with it.

    Here is what I'm trying to do:
    - Fetch the depth buffer created by a custom shader after rendering transparent ("BuiltinRenderTextureType.Depth" ?!).
    - Write that depth buffer to a RenderTexture (Depth, R half - doesn't matter).
    - Use that RenderTexture as input for another shader ( "_MainTex" ?!)

    For now I'm only able to fetch the color buffer from current output. No depth.

    How do I approach this?
     
  26. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    From what I understand (and my understanding of death buffers is very little) is that you can't really do anything with a depth buffer. You can copy them, supposedly. Just can't use them. For anything. At all.

    Which seems silly, so I could be wrong. But wouldn't it be nice indeed if you could just copy a depth buffer to a texture. Maybe all the depth values appear in various shades of red. We could all retire and go home in peace.

    But it's my understanding that "depth" isn't a color. It's something else. Something mysterious. Hard to know what it is, because I've never been able to get my hands on a depth buffer.

    Depth buffers are like dangling cheese in front of a mouse. You know you want it. You know it'll taste just right when it's between your teeth. But you can't have it. Lol.
     
  27. AaronBrownLM

    AaronBrownLM

    Joined:
    Mar 6, 2014
    Posts:
    196
    Maybe @Tim-C could help you more than me. ;p
     
  28. cpetry

    cpetry

    Joined:
    Jun 30, 2014
    Posts:
    29
    That would be very disappointing...
    In fact I would only need the depth buffer created from a forward rendering (transparent) inside my ImageEffects.

    It seems to be such a trivial thing... but as you said:
    I'm feeling very much like a mouse in front of a dangling cheese. I just can't get it! :)
     
  29. cpetry

    cpetry

    Joined:
    Jun 30, 2014
    Posts:
    29
  30. cpetry

    cpetry

    Joined:
    Jun 30, 2014
    Posts:
    29
    Still no luck.
    The only solution that worked is using a second camera that renders the whole scene into a separate depth texture.
    Performance though is really bad.

    Isn't there a better solution?
     
  31. steven3Dim

    steven3Dim

    Joined:
    Feb 21, 2017
    Posts:
    12
    Actually, I got that working. And yes @AaronBrownLM, the result is a red gradient. You need to blit with (USE ResolvedDepth!):
    Code (CSharp):
    1. cmdBuffer.Blit(BuiltinRenderTextureType.ResolvedDepth, TempRenderTexture);
    at step BeforeLighting or later. This worked ONLY IN DEFERRED!

    See image:
     

    Attached Files:

  32. steven3Dim

    steven3Dim

    Joined:
    Feb 21, 2017
    Posts:
    12
    Actually I got it to work to get the stencil buffer in a single pass.

    I got it working by following the hint from https://docs.unity3d.com/ScriptReference/Graphics.Blit.html
    Note that if you want to use depth or stencil buffer that is part of the source(Render)texture, you'll have to do equivalent of Blit functionality manually - i.e. Graphics.SetRenderTarget with destination color buffer and source depth buffer, setup orthographic projection (GL.LoadOrtho), setup material pass(Material.SetPass) and draw a quad(GL.Begin).

    I got this working for command buffers (which are a bit more restricted (in 5.5 and earlier you can't even set the Camera-Projection, so I just drew a plane in front of the near-plane of the camera)). The relevant code snippets are:

    Code (CSharp):
    1.  
    2. /* COMMAND BUFFER SET-UP CODE:
    3. commandBufferStencil = new CommandBuffer();
    4. commandBufferStencil.name = "commandBufferStencil";
    5.  
    6. RenderTextureStencil = RenderTexture.GetTemporary((int)width, (int)height, depth, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear /* Linear color space */);
    7. RenderTextureStencil.antiAliasing = 1;  // number of samples per pixel
    8. RenderTextureStencil.autoGenerateMips = false;
    9. RenderTextureStencil.filterMode = FilterMode.Point; // use point filtering, we want boolean true or false, no interpolation.
    10.  
    11. commandBufferStencil.SetRenderTarget(RenderTextureStencil, BuiltinRenderTextureType.CameraTarget);  // Use the Stencil as color target, but use the depth of the camera (the stencil is part of the depth (on 24 bit depth)
    12.  
    13. /* Only available from version 5.6: Possibly we already at identity and orthogonal projection
    14.                     Matrix4x4 MIden = Matrix4x4.identity;
    15.                     Matrix4x4 MOrth = Matrix4x4.Ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 2.0f);   // (float left, float right, float bottom, float top, float zNear, float zFar);
    16.  
    17.                     commandBufferStencil.SetViewProjectionMatrices(MIden, MOrth);
    18. */
    19.                    
    20. Shader StencilShader = Shader.Find("Stencil/Blit_to_BlackAndWhite2");
    21. StencilToBlackAndWhiteMaterial = new Material(StencilShader);
    22.  
    23. Camera cam = GetScreenshotCamera();
    24. Matrix4x4 PlaneTransform = cam.cameraToWorldMatrix;
    25. Mesh PlaneMesh = CreateProjectionPlaneMesh(cam.nearClipPlane);
    26.  
    27. commandBufferStencil.DrawMesh(PlaneMesh, PlaneTransform, StencilToBlackAndWhiteMaterial);
    28.  
    29. // AfterForwardOpaque is best Insertion Point
    30. camera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, commandBufferStencil);
    31.  
    Now I extract the stencil via a commandbuffer call, but this requires an additional blit and a temporary render texture of the screen size. I want to see if I can use the same method directly on my end-result, to extract the stencil from the source buffer instead of the destination buffer. Must be possible. So instead of 5 blits as indicated by the topic starter I now have 1 blit and want to combine it in the final step, making the usage of the stencil at effectively 0 blits costs!
     
    GoGoGadget likes this.
  33. raunaqbn

    raunaqbn

    Joined:
    Mar 30, 2018
    Posts:
    1
    @Tim-C : Is there a solution for this in MSAA? I’m trying to copy over the depth and stencil for post processing effects with MSAA on and try to do that sampling the _CameraDepthTexture in my shader and blitting that to a destination depth render texture.

    It seems like the depth gets blit correctly but the stencil is left out.