Search Unity

Deferred decals missing in shadow

Discussion in 'Shaders' started by MXAdd, May 20, 2015.

  1. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    Hi

    I'm writing deferred decals system (based on what was shown in example RenderingCommandBuffers).
    All works almost perfect - but there is one thing I don't understand - defered (albedo) decals disappear in full shadow :/ (this problem is also present in the RenderingCommandBuffers example from Unity, just remove one light, so only one is left on scene - and there will be no albedo decals in shadow, but if you assign texture to the material and bump up ambient, texture is shown).
    Why is that ?
    In Frame Debugger decals are clearly painted on albedo channel, but after deferred composition they are not visible. From what component(s) is actually composed image in full shadow, as clearly not from albedo (ore there is some magic behind scenes when pixel is fully shadowed (ambient light only)) ?
     
  2. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    Also - another mystery, when I remove all my lights from the scene, then by custom Internal-DeferredShading.shader is not executed anymore - so where the final composition take place if there is no lights (I need to do custom stuff in composition step - even if there is no light on scene)
     
  3. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    523
  4. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    No, it's not related at all ...
     
  5. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    I had this issue also when I made more "complete" decals. (And bypassed it).
    And it's NOT A BUG!
    What happens is that Ambient light is calculated in the G-Buffer pass, and together with emissive spit out into what will be used as the render target.
    So any decals you use won't get ambient light, and thus they will be "gone" in shadow!
    First I'll present a theoretical solution:
    Make sure your decals calculate and apply ambient light to themselves. Then blend this also into the emissive+Ambient buffer. This can/will cause them to be imperfect, especially as this doesn't work for occlusion/normals modifying decals to well. (If the point is to modify the normals of the underlying object, then this wouldn't need to do anything for the ambient light. Yet it'd mean on glossy surfaces the ambient specular might noticable not be modified!)

    My solution:
    Remove all the ambient code from the g-buffer pass.
    Put it back in the apply lighting pass.

    However:
    1: I have to output the Occlusion into the g-buffer, (unity I think has a channel free by default anyways).
    2: This prevents the usage of reflection probes.
    3: You have to figure out the SH code, and remove it from the vertex shader.
    4: This WILL break lightmaps. (As they are the same as ambient light, and they require per model data).
     
  6. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    Thanks Zicandar

    what do you mean by 'What do you mean by 'Remove all the ambient code from the g-buffer pass.'
    should I rewrite StandardShader and in StandardCore (fragDeferred) remove 'outEmission = half4(color, 1);' there (put: outEmission = float4(0,0,0,1);) ?

    by 'Put it back in the apply lighting pass.' you mean - Internal-DeferredShading.shader 'CalculateLight' right ?

    I don't understand a few things how unity deffered pipeline works - so please clarify (if you can and know what happends behind the scenes) - for now this is my understanding how deferred pipeline works (again If someone have enough knowledge please explain if this is correct :)):

    1] Standard shader(s) writes something down into GBuffer
    (albedo, specular, worldspace normals, occlusion informaton, emissive information (SH+GI+Ambient + material emission - right ?)

    2] now my decals are injected as commandBuffer (in 'BeforeLighting' stage) - they modify albedo only

    3] there are per light passes now that execute Internal-DeferredShading.shader 'CalculateLight' for EACH light right ?
    (BTW. no tiled deferred rendering in unity ? :/)

    4] Now magic unicorn comes and does something where there is no light (I guess just adds _CameraGBufferTexture3 (emissive) to the light buffer ?? - is there any access to modify this shader ?

    5] more magic unicorns - composition step -- is there any way to inject custom shader there ? or there is no composition step at all in unity (by composition step in deferred engine I mean the step when the information from gbuffer is combined with information from light buffer- but in Unity case I suspect there is no such thing - as each light have full acces to gbuffer (with is bad in terms of performance :/)
     
  7. OskarSwierad

    OskarSwierad

    Joined:
    Dec 17, 2014
    Posts:
    25
  8. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Almost but not quite, place is correct, however the emissive you want to keep :)
    Code (CSharp):
    1. UnityGI gi = FragmentGI (
    2.         s.posWorld, occlusion, i.ambientOrLightmapUV, atten, s.oneMinusRoughness, s.normalWorld, s.eyeVec, dummyLight);
    3.  
    4.     float3 color = UNITY_BRDF_PBS (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, gi.light, gi.indirect).rgb;
    5.     color += UNITY_BRDF_GI (s.diffColor, s.specColor, s.oneMinusReflectivity, s.oneMinusRoughness, s.normalWorld, -s.eyeVec, occlusion, gi);
    Pretty much all that code actually does is calculate some GI, so you can dump it :).

    Probably that file yes, at least function name seems correct. Tho you will need to copy the file, and set it as your "custom deferred" in the graphics settings.

    Correct
    Correct
    And once again correct, sadly unity does not have tiled rendering, so forward objects are painfully slow.
    (We use a world space tiled solution, (worldPos.xz), as our game doesn't have enough of a hight changes to be worth the 3d texture.)

    Nope, unity uses _CameraGBufferTexture3 as the TARGET for the previous step :). Quite nice actually.
    (Note unity now uses "proper" deferred and NOT light prepass!)

    This is for the legacy deferred. Doesn't exist anymore. So deferred only renders each mesh ONCE, (unlike forward that renders it twice if you have shadows on the directional light / use depth and/or normals somewhere).
    Shadow maps are the same for both forward and deferred, cause objects to be rendererd more times ofc.

    Now how I put it back is by assuming we only have one directional light, (to save performance), you could ofc put it back using command buffers and a full screen pass.

    Posting what I got from the DBuffer approach in the next post, seems really smart btw! (BUT has a non-trivial cost, and would possibly fit forward mode better)
     
  9. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Now I havn't really looked into the DBuffer approach, at least not the code, but what they do say in one of the posts gives us some clues:
    My GUESS as to what is done is that they first do a z-prepass, then the "apply" decals and store some type of information about each decal per screen pixel it affects.
    10 bytes per pixel is quite a lot. (8*10 = 80 bits! a normal texture is 32 bits (RGBA), a HDR (half) one is 64bits.)
    They probably use something like 2xRGB and 1xRGBA, with 8 bit's per channel. (Or some type of struct).

    So my guess is that they store the decal data, including alpha, per pixel, then apply that when the "base" pass is done. (When writing to g-buffer).

    This doesn't sound very efficient... Then again, they DO mention it's only needed if you have lightmapping! (Reflection probes CAN be solves by have all relevant ones avalible in a cbuffer or such. Light probes/SH can be put into 2D/3D textures and once again sampled nicely without needing per renderer data.
     
  10. MXAdd

    MXAdd

    Joined:
    Apr 23, 2015
    Posts:
    74
    Ok, thanks a lot for clarifications, now I have (almost) full picture of what happends behind scenes ...
     
  11. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    You can use the frame debugger to get a better picture :)
    (Gives a step by step one more or less.)
    Or even better I'd recommend RenderDoc as it will also allow you to see the textures used for every draw call :D
    (And unlike visual studio doesn't require you to make a build, but can start the editor from within it, then in play mode it's easy to capture a frame!)
     
  12. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    I already chatted to Unity staff about this and also Anton at Rust. The short version is, it cannot be done with Unity's deferred design. You will always need some light affecting the shadowed part in order to see the deferred decal.

    Unity could add another pass or do some technical wizardry but it'd have to be at the engine level.

    A similar problem exists for middleware ie TrueSKY, which can't integrate properly because of it and we need to do all culling all over again just to ensure transparency works, which is far from optimal, pretty tired of smashing my head against a wall to the point it sometimes is better to use a different engine.

    IMHO Unity is great for cross platform but just isn't ready for next (this) gen at present if you want to really push things. You can work around all these issues but the result will be a performance hit, depending on your particular case (it could be fine for you).
     
    Last edited: May 21, 2015
  13. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,372
  14. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    I have started work on a (working) deferred decal system for unity. One that will work in shadows, and will also be able to affect roughness!
    Benefits:
    Performance: No geometry that needs to be generated to fit what is beneth the decal.
    Ease of placement: It can easily be moved around, once again without having to regenerate!
    Blending: It can for example modify only the normals, yet leave the rest untouched. (Normal decals are usually run after the g-buffer or in forward mode)
    It does not care about how high poly count the underlying geometry is.
    Now this is a bit special:
    You can create and Exclude layers! So even in a fully dynamic scene you can have it only affect ground, even if there are other objects in the "bounding box".
     
  15. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,372
    Sounds good. Will you publish it on the asset store at some point? Count me in as a customer!
     
  16. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    Yes, that is the plan, however there will be limitations to it, such as lightmaps are likely to not work.
    Then again, as they have no placement cost they are perfect to use for dynamic placement, either in generated levels or simply runtime.
     
  17. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,372
    I want to use it to procedurally generate lines on tarmac. But I am not sure if using textures for that is the best way. The straight lines can be done with textures but there are many different curvatures. Could the decals also be used to project a mesh on a mesh instead?
     
  18. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    I've started a Work In Progress thread here: http://forum.unity3d.com/threads/deferred-decals.337591/#post-2184405
    I'm thinking of how to solve that problem, but it's not simple, a normal decal system would be easy to warp, as it would generate a mesh. However deferred decals do NOT create any meshes! While it's something I would like to add for perfomance reasons against simple surfaces (ex: Your flat tarmac) it's not my focus.

    If your lines on the tarmac are a set of known curvatures, the decals could be placed and project them down, however if they have to adapt to the underlying geometry's angle at that position it would likely not work.

    In your specific case it really depends on how the curvature is known, perhaps the simplest and best solution is to integrate the lines as part of the tarmac shader?

    Perhaps you can give a screenshot? (Or a hand drawn picture of what you want to achieve)
     
  19. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,372
    Thanks, I will continue the discussion on your WIP thread.
     
  20. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    ... how?