Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is it possible to manually write to the normal buffer?

Discussion in 'Shaders' started by 0xDEADCODE, Dec 8, 2011.

  1. 0xDEADCODE

    0xDEADCODE

    Joined:
    Jul 26, 2011
    Posts:
    25
    Is it possible to access and manually write to the normals buffer before it is used in the pre-pass lighting? ie. Using Graphics.Blit()? And if so, how is this done?

    Cheers.
     
  2. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    Not easily, but what do you want to accomplish?
     
  3. 0xDEADCODE

    0xDEADCODE

    Joined:
    Jul 26, 2011
    Posts:
    25
    I am working on implementing a decal system that takes advantage of the pre-pass lighting rather than the old school method of recreating geometry and applying the decal to that. I have the decals working using forward rendering, but of course this means that large numbers of decals can become quite expensive when it comes to lighting them. If I can modify the NormalTexture buffer prior to the pre-light pass, I can determine the decals normals and add them into the NormalTexture buffer so that lighting the decals will essentially become free. Then in my forward pass I only need output the Albedo of the decal. This would also allow for cool effects like having a decal that is only a normal map, to create things such as carvings out of a slab of rock.

    At first glance the idea of a surface shader sounds like it would solve all these problems as you can write the normals and albedo to the SurfaceShaderOutput, but of course these decals need to be transparent and as soon as they are declared as such, the compiled shader is forced to use forward rendering and thus no normals are written to the buffer prior to the pre-pass lighting.

    This is how the decals currently look if I cheat the lighting to keep them very cheap. Here its simply taking the light values from the pre-pass light buffer and no lighting is being done on the actual decal itself. This means that decals can not have normal maps.


    This decal is handling all of its own lighting through forward rendering but is now much more expensive, but can of course have normal maps.


    I hope this explains my intentions with the normal buffer, and any advice on how to manipulate it would be greatly appreciated.
     
  4. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    Deferred decals would be extremely welcome. Sorry I can't answer your question :(
     
  5. 0xDEADCODE

    0xDEADCODE

    Joined:
    Jul 26, 2011
    Posts:
    25
    I have also gone through and set up a shader using the two pass method of PrePassBase and PrePassFinal rather than using a straight surface shader in the hopes of being able to make things work since the PrePassBase is the pass that writes to the Normals buffer. But of course as soon as I set the SubShader to "ZWrite Off" all hope is lost and nothing is rendered, so I guess something is still being done in the background that I don't have access to?

    Anyhow, I'm still trying to figure out a way around this problem, but if anyone out there has any ideas, please let me know :)

    Thanks.
     
  6. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    I've taken a stab at deferred decals in Unity before but hit the same kinks. Also very keen on discovering a way to make them work.
     
  7. 0xDEADCODE

    0xDEADCODE

    Joined:
    Jul 26, 2011
    Posts:
    25
    Anyone with some suggestions? Aras maybe? :) I'm currently using my forward rendering method as the visual gain is worth the very minor performance hit, but It would be nice to at some point switch over to a method that costs only a fraction to render. I just need to know how to modify that normal buffer.
     
  8. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
  9. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    Hmm, that should work.

    Of course if you're not writing to Z buffer you should make sure your decal is always rendered after other opaque geometry ,e.g. Tags {"Queue"="Geometry+100"} or something like that in the SubShader.

    But other than that, there are no assumptions in Unity. If there's a PrePassBase pass, it's used in the base pass to write normals + specular. It can have any rendering states it wants.
     
  10. Cameron_SM

    Cameron_SM

    Joined:
    Jun 1, 2009
    Posts:
    915
    The issue I found with this was that _CameraDepthTexture seems to be bound after pre-pass base, so if you're doing projective texturing onto the normals by re-constructing position from depth the data is a whole frame late thus you get this really funky temporal-depth-paralax artefact, it also freaks out the editor scene view.

    Any chance we could get a special Geometry+499 queue that we can hook into after the depth has been bound in _CameraDepthTexture but before pre pass lighting is done?

    Or even better if we could get a Camera class message/event after pre-pass base (where both _CameraDepthTexture _CameraNormalsTexture are valid for that frame) so we can render any way we choose (graphics.drawnow, blit) into into depth/normal RTs prior to lighting pass.
     
    Last edited: Dec 18, 2011
  11. 0xDEADCODE

    0xDEADCODE

    Joined:
    Jul 26, 2011
    Posts:
    25
    Happy New Year!

    Thanks Aras for the info. I just got back from a nice two week vacation so I am going to look over the issue with fresh eyes....

    OK, so first off, my first little mistake is that I once again messed up my "Queue" tag with "RenderType" which I had set to "Geometry+100". That made me very happy to realize that it not rendering was because of a small stupid mistake on my part :). So now I have the normals and spec rendering in the PrePassBase, but then came across an interesting issue in the Editor. At first I thought my calculated world position was not being calculated correctly in the PrePassBase (though it is being done exactly the same way in the final pass) because the positioning of the decal normal was very small and moved around the rasterized area as I moved around the scene. It seemed as if it was pulling the depth position from a different camera, and it was! I perfectly understand why when running a shader in the editor which is dependent on a game camera that it will cause incorrect rendering in the editor render window as that camera does not move while you are running your game, but in this case it was the other way around. I think I will take some screenshots to better explain myself.


    -The scene view is on the left and the game view is on the right. In the next image you can see that if the scene camera is pulled back, the normals in the game view changes.





    - As you can see in this image, once the scene is built and run from the .EXE file, everything is fine, but when running through the editor the PrePassBase reads the scene camera. This does not occur on the PrePassFinal or any other shader I have written and thus my interest and confusion.

    I know this issue does not prevent the final outcome from working but having to build the project to test the decals will quickly become a tedious job. :eek:

    Cheers.
     
  12. stevesan

    stevesan

    Joined:
    Aug 14, 2011
    Posts:
    65
    Any resolution to this? I'm trying to write a deferred-lit screen space decal as well, but I'm getting the frame-delay due to accessing _CameraDepthTexture in PrePassBase...
     
  13. GeraldOBBI

    GeraldOBBI

    Joined:
    Sep 13, 2012
    Posts:
    7
    Aras, I've written a similar deferred decal implementation to the OP's description however, I'm having issues controlling the draw order.

    I expect that if my decal shader is set to "Queue"="Geometry+100" (for pre-pass base and pre-pass final), its normals and combined colour output will be written to before other shaders, which are at "Queue"="Geometry+200" (and above).

    I'm running into the problem where the decals are drawing overtop of anything which is not transparent (and/or rendered in forward mode). Is there anything in the vert/frag shaders which may prevent the queues form being respected? I've verified that nothing is touching/instancing the materials and that they are in the correct render queues. I've also changed the render queues of the materials manually by putting the inspector into debug mode.

    Any thoughts?