Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Problem with a simple shader, it's being ignored by depth-related post effects

Discussion in 'Shaders' started by Steven-1, Sep 20, 2019.

  1. Steven-1


    Sep 11, 2010
    I made this simple shader:
    Code (CSharp):
    1.  Shader "Custom/outline"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Main Color", Color) = (1,1,1,1)
    6.     }
    7.     SubShader
    8.     {
    9.         Tags { "RenderType"="Opaque" }
    10.         //LOD 200
    11. CULL Front
    12. Offset 5, 5
    13. ZWrite On
    15.         Pass
    16.         {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.   #pragma addshadow //this should work I think, but it does nothing
    22.             #include "UnityCG.cginc"
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.             };
    29.             struct v2f
    30.             {
    31.                 float4 vertex : SV_POSITION;
    32.             };
    34.   float4 _Color;
    36.             v2f vert (appdata_full  v)
    37.             {
    38.                 v2f o;
    39. += v.normal*0.019;
    40.                 o.vertex = UnityObjectToClipPos(v.vertex);
    41.                 return o;
    42.             }
    44.             fixed4 frag (v2f i) : SV_Target
    45.             {
    46.                 return _Color;
    47.             }
    48.             ENDCG
    49.         }
    50.     }
    51. //FallBack "Diffuse" //this also causes it to use the diffuse's other passes (for shadows and stuff)
    52. }
    All it does is create an outline when adding it on top of a normally rendered object.
    The problem is that it doesn't seem to write depth for post effects (like depth of field), even though it is rendered correctly depth-wise, so it seems it does render to the depth buffer correctly.
    Which makes no sense to me. Do post effects use a different depth buffer?

    I tried to add #pragma addshadow, to make it create the correct shadowpasses (which I don't actually need, but I hoped it would also create the correct depth), but that doesn't seem to make any difference, in fact, even without it, it seems to write the correct depth (for normal rendering, not for post effects)

    Does any one know what the problem could be?
  2. bgolus


    Dec 7, 2012
    The addshadow thing is only for Surface shaders and would be appended to the #pragma surf line. But this is not a Surface shader, and you do not what to use one as those are explicitly for lit shaders and not unlit shaders. There are plenty of examples of "unlit Surface shaders" out there ... please don't use them!

    The thing is post processing does not use the depth buffer. It uses the camera depth texture, which is generated by rendering the shadow caster pass of all opaque objects in the scene. Ideally the data in the camera depth texture and the depth buffer match after the scene has been rendered, but for various reasons Unity needs the depth texture before the scene is rendered, so they are separate things. Your shader does not have a shadowcaster pass, thus it does not get rendered into the camera depth texture. If you add a shadowcaster pass, which using FallBack "Diffuse" would do, your objects will now also cast shadows, so be mindful of that. You may need to disable shadow casting on your renderer components as there's no way to set a shader to render to the depth texture but not render to the shadow maps.

    Instead of using FallBack "Diffuse" you can also try:
    FallBack "Legacy Shaders/VertexLit"
    UsePass "Legacy Shaders/VertexLit/ShadowCaster"

    UsePass is placed inside the SubShader { }, so one } above where you have FallBack line.
    andrewpey and Steven-1 like this.
  3. Steven-1


    Sep 11, 2010
    Ah ok, thank you, most helpfull.
    I actually vaguely recall knowing about this (at least partially), but I haven't written any shaders in a while and apparently forgot a lot. Thanks for the info.

    The problem with using the FallBack to make it use the shadowcaster pass of that shader, is that it doesn't render the correct shape then, as it doesn't do the vertex modifications in that pass as it does in the normal pass. (at least that's what it appears to do)

    I get the same result with the VertexLit shader as with the diffuse shader (hence why I commented ouy that line),
    so I suppose I should write a ShadowCaster pass in my shader which does the exact some vertex displacement, right?
  4. Steven-1


    Sep 11, 2010
    yup, that worked. I wrote the following:
    Code (CSharp):
    1. Pass
    2.         {
    3.             Name "ShadowCaster"
    4.             Tags { "LightMode" = "ShadowCaster" }
    6.             CGPROGRAM
    7.             #pragma vertex vert
    8.             #pragma fragment frag
    10.             #include "UnityCG.cginc"
    12.             struct appdata
    13.             {
    14.                 float4 vertex : POSITION;
    15.             };
    17.             struct v2f
    18.             {
    19.                 float4 vertex : SV_POSITION;
    20.             };
    22.             v2f vert (appdata_base v)
    23.             {
    24.                 v2f o;
    25.        += v.normal*0.019;
    26.                 o.vertex = UnityObjectToClipPos(v.vertex);
    27.                 return o;
    28.             }
    30.             fixed4 frag (v2f i) : SV_Target
    31.             {
    32.                 SHADOW_CASTER_FRAGMENT(i)
    33.             }
    34.             ENDCG
    35.         }
    and that works.
    Thanks for the help bgolus!
  5. ZackMcracken


    Dec 13, 2020
    I had the same problem with my objects not rendering to the depth texture and fixed it but surface normals are still not showing up.
  6. bgolus


    Dec 7, 2012
    is a whole extra level of “fun”.

    If you’re using the built in forward rendering path, the depth normal texture is rendered using a replacement shader pass.
    You need to make a copy of this shader and add your own pass to it using a custom
    that your shader uses. Then assign your modified version of the shader to be used instead of the built in one in the project’s Graphics settings.
  7. Iil-liI


    Apr 12, 2018
    bgolus, I am writing my lighting system and have spent a lot of time on the forum. I always see your answers and most of all you write even more than the official representatives of Unity Technology and close all questions. I just want to use this moment to thank you for this :)
    andrewpey likes this.