Search Unity

Writing to depth buffer with custom shader

Discussion in 'Shaders' started by Duney, Dec 16, 2013.

  1. Duney

    Duney

    Joined:
    Aug 19, 2013
    Posts:
    170
    I am currently trying to sample the _CameraDepthTexture and it all seems to be okay (although there seems to be several ways of actually doing it), however I have noticed that when an object has one of my custom shaders on the material, the object does not seem to be written to the depth buffer. This means I am unable to sample that pixel from the depth buffer and gain its world position.

    So I was wondering whether there was something I needed to do in a vertex/fragment shader that means the object should still write to the depth buffer. I have tried to take a look around and found the documentation on ZWrite:
    which sounds like by default my shader should be writing to the depth buffer. When using one of the built-in surface shaders the depth seems to work fine.

    $depthproblem.png
     
  2. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    Is there a specific reason you are using the depth texture to get the world position of a pixel? You could also just get the world position by doing:

    Code (csharp):
    1. o.wpos = mul(_Object2World, v.vertex);
    Not really applicable for screen effects of course :)

    The images you posted are pretty small so I can't really see what's going on. But perhaps you have other geometry on top that blocks what is underneath from that view?
     
  3. Duney

    Duney

    Joined:
    Aug 19, 2013
    Posts:
    170
    Just tried deferred lighting for the rendering path and it now shows the depth from custom shaders although I'm not entirely sure why?
    And I am using it to create some custom shadow effects for certain objects within the game.
     
  4. WhiskyJoe

    WhiskyJoe

    Joined:
    Aug 21, 2012
    Posts:
    143
    Well, for deferred rendering it needs to have the depth buffer to properly do its lighting, so it's probably forcing an option on somewhere where it seems to be off for you.

    Question is, where ;)
     
  5. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    Do you have "RenderType" tag declared in your custom shader?
     
  6. Duney

    Duney

    Joined:
    Aug 19, 2013
    Posts:
    170
    It's set to opaque, but I think it was the same regardless.
     
  7. aubergine

    aubergine

    Joined:
    Sep 12, 2009
    Posts:
    2,878
    Its hard to tell without seeing your custom shader code.
     
  8. Duney

    Duney

    Joined:
    Aug 19, 2013
    Posts:
    170
    Here's the code from the shader. It's pretty standard so I'm not sure why it wouldn't be writing to the depth buffer.

    Code (csharp):
    1.  
    2. Shader "Custom Shader" {
    3.     Properties {
    4.         _Color ("Texture Colour", Color) = (1.0, 1.0, 1.0, 1.0)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _DetailTex ("Detail Texture", 2D) = "gray" {}
    7.         _DecalTex ("Decal Texture", 2D) = "black" {}
    8.        
    9.         _DecalStr ("Decal Strength", float) = 1.0
    10.         _Rotation ("Decal Rotation", float) = 0.0
    11.     }
    12.     SubShader {
    13.         Pass {
    14.             //ZWrite On
    15.             Tags { "RenderType"="Opaque" }
    16.             LOD 200
    17.            
    18.             CGPROGRAM
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.            
    22.             #include "UnityCG.cginc"
    23.    
    24.             sampler2D _MainTex;
    25.             sampler _DetailTex;
    26.             sampler _DecalTex;
    27.            
    28.             float4 _MainTex_ST;
    29.             float4 _DetailTex_ST;
    30.             float4 _DecalTex_ST;
    31.            
    32.             float _DecalStr;
    33.             fixed4 _Color;
    34.             float _Rotation;
    35.                        
    36.             struct vertexOutput {
    37.                 float4 vertexPos : POSITION;
    38.                 float2 texCoords : TEXCOORD0;
    39.                 float2 decalTexCoords : TEXCOORD1;
    40.                 float4 worldPos : TEXCOORD2;
    41.                 float3 normalDir : TEXCOORD3;
    42.                 //float3 viewDir : TEXCOORD4;
    43.             };
    44.    
    45.             vertexOutput vert (appdata_base vIn)
    46.             {
    47.                 vertexOutput vOut;
    48.                 vOut.texCoords = vIn.texcoord;
    49.                
    50.                 // Angle to rotate the decal by
    51.                 vIn.texcoord.xy -=0.5;
    52.                 float s = sin ( radians( _Rotation ) );
    53.                 float c = cos ( radians( _Rotation ) );
    54.                
    55.                 float2x2 rotationMatrix = float2x2( c, -s, s, c );
    56.                 rotationMatrix *= 0.5;
    57.                 rotationMatrix += 0.5;
    58.                 rotationMatrix = (rotationMatrix * 2) - 1;
    59.                 vOut.decalTexCoords.xy = mul ( vIn.texcoord.xy, rotationMatrix );
    60.                 vOut.decalTexCoords.xy += 0.5;
    61.                
    62.                 vOut.worldPos = mul( _Object2World, vIn.vertex );
    63.                 vOut.normalDir = normalize( mul( float4( vIn.normal, 0.0 ), _World2Object ).xyz );
    64.                 vOut.vertexPos = mul( UNITY_MATRIX_MVP, vIn.vertex );
    65.                 return vOut;
    66.             }
    67.            
    68.             // Variables for lighting
    69.             float3 _LightPos;
    70.             fixed4 _LightColour;
    71.             half _LightIntensity;
    72.            
    73.             fixed4 frag ( vertexOutput fIn ) : COLOR
    74.             {
    75.                 // General Lighting Calculations -------------------------------------------------------------
    76.                 float3 lightDir = normalize( _LightPos - fIn.worldPos.xyz );
    77.                
    78.                 fixed3 diffuseLighting = _LightColour * saturate( dot ( normalize(fIn.normalDir), lightDir ) ) * _LightIntensity;
    79.                 // Texture Mapping ---------------------------------------------------------------------------
    80.                 // Sample the main texture
    81.                 fixed4 mainTex = tex2D(_MainTex, fIn.texCoords * _MainTex_ST.xy + _MainTex_ST.zw  ) * _Color;
    82.                
    83.                 // Sample the detail map texture
    84.                 fixed4 detailTex = tex2D(_DetailTex, fIn.texCoords * _DetailTex_ST.xy + _DetailTex_ST.zw  );
    85.                
    86.                 // Sample the decal texture -- Offset the tiling methods by set amounts to centre the decal
    87.                 fixed4 decalTex = tex2D(_DecalTex, fIn.decalTexCoords * float2(_DecalTex_ST.x * 3.0, _DecalTex_ST.y * 3.0) + float2(  _DecalTex_ST.z - 1.0f, _DecalTex_ST.w -1.0f )  );
    88.                
    89.                 //Test whether other areas of the decal are 0 (using < or > for floating point tests)
    90.                 if (decalTex.a > 0.001f)
    91.                 {
    92.                     // If there not then were sampling the decal, lerp between main texture and decal
    93.                     mainTex.xyz = lerp( mainTex.xyz, decalTex.xyz, _DecalStr );
    94.                 }
    95.    
    96.                 mainTex.xyz *= (detailTex.xyz * 2.0f) * + diffuseLighting;
    97.                 mainTex.xyz *= mainTex.a;
    98.                                
    99.                 return mainTex;
    100.             }
    101.             ENDCG
    102.         }
    103.        
    104.        
    105.     }
    106.     FallBack "Diffuse"
    107. }
    108.  
     
  9. deram_scholzara

    deram_scholzara

    Joined:
    Aug 26, 2005
    Posts:
    1,043
    Would be really nice if this got answered - I'm running into basically the same issue. Vertex/Fragment shaders do not seem to zwrite, which breaks a lot of effects that use the depth buffer.

    Edit: I think I may have found the issue. Apparently the tags need to go inside the SubShader block, but not inside the Pass block. So if you change your shader to this, it should work:
    Code (csharp):
    1.  
    2. Shader "Custom Shader" {
    3.     Properties {
    4.         _Color ("Texture Colour", Color) = (1.0, 1.0, 1.0, 1.0)
    5.         _MainTex ("Base (RGB)", 2D) = "white" {}
    6.         _DetailTex ("Detail Texture", 2D) = "gray" {}
    7.         _DecalTex ("Decal Texture", 2D) = "black" {}
    8.        
    9.         _DecalStr ("Decal Strength", float) = 1.0
    10.         _Rotation ("Decal Rotation", float) = 0.0
    11.     }
    12.     SubShader {
    13.         Tags { "RenderType"="Opaque" }
    14.         LOD 200
    15.        
    16.         Pass {
    17.             CGPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.            
    21.             #include "UnityCG.cginc"
    22.    
    23.             sampler2D _MainTex;
    24.             sampler _DetailTex;
    25.             sampler _DecalTex;
    26.            
    27.             float4 _MainTex_ST;
    28.             float4 _DetailTex_ST;
    29.             float4 _DecalTex_ST;
    30.            
    31.             float _DecalStr;
    32.             fixed4 _Color;
    33.             float _Rotation;
    34.                        
    35.             struct vertexOutput {
    36.                 float4 vertexPos : POSITION;
    37.                 float2 texCoords : TEXCOORD0;
    38.                 float2 decalTexCoords : TEXCOORD1;
    39.                 float4 worldPos : TEXCOORD2;
    40.                 float3 normalDir : TEXCOORD3;
    41.                 //float3 viewDir : TEXCOORD4;
    42.             };
    43.    
    44.             vertexOutput vert (appdata_base vIn)
    45.             {
    46.                 vertexOutput vOut;
    47.                 vOut.texCoords = vIn.texcoord;
    48.                
    49.                 // Angle to rotate the decal by
    50.                 vIn.texcoord.xy -=0.5;
    51.                 float s = sin ( radians( _Rotation ) );
    52.                 float c = cos ( radians( _Rotation ) );
    53.                
    54.                 float2x2 rotationMatrix = float2x2( c, -s, s, c );
    55.                 rotationMatrix *= 0.5;
    56.                 rotationMatrix += 0.5;
    57.                 rotationMatrix = (rotationMatrix * 2) - 1;
    58.                 vOut.decalTexCoords.xy = mul ( vIn.texcoord.xy, rotationMatrix );
    59.                 vOut.decalTexCoords.xy += 0.5;
    60.                
    61.                 vOut.worldPos = mul( _Object2World, vIn.vertex );
    62.                 vOut.normalDir = normalize( mul( float4( vIn.normal, 0.0 ), _World2Object ).xyz );
    63.                 vOut.vertexPos = mul( UNITY_MATRIX_MVP, vIn.vertex );
    64.                 return vOut;
    65.             }
    66.            
    67.             // Variables for lighting
    68.             float3 _LightPos;
    69.             fixed4 _LightColour;
    70.             half _LightIntensity;
    71.            
    72.             fixed4 frag ( vertexOutput fIn ) : COLOR
    73.             {
    74.                 // General Lighting Calculations -------------------------------------------------------------
    75.                 float3 lightDir = normalize( _LightPos - fIn.worldPos.xyz );
    76.                
    77.                 fixed3 diffuseLighting = _LightColour * saturate( dot ( normalize(fIn.normalDir), lightDir ) ) * _LightIntensity;
    78.                 // Texture Mapping ---------------------------------------------------------------------------
    79.                 // Sample the main texture
    80.                 fixed4 mainTex = tex2D(_MainTex, fIn.texCoords * _MainTex_ST.xy + _MainTex_ST.zw  ) * _Color;
    81.                
    82.                 // Sample the detail map texture
    83.                 fixed4 detailTex = tex2D(_DetailTex, fIn.texCoords * _DetailTex_ST.xy + _DetailTex_ST.zw  );
    84.                
    85.                 // Sample the decal texture -- Offset the tiling methods by set amounts to centre the decal
    86.                 fixed4 decalTex = tex2D(_DecalTex, fIn.decalTexCoords * float2(_DecalTex_ST.x * 3.0, _DecalTex_ST.y * 3.0) + float2(  _DecalTex_ST.z - 1.0f, _DecalTex_ST.w -1.0f )  );
    87.                
    88.                 //Test whether other areas of the decal are 0 (using < or > for floating point tests)
    89.                 if (decalTex.a > 0.001f)
    90.                 {
    91.                     // If there not then were sampling the decal, lerp between main texture and decal
    92.                     mainTex.xyz = lerp( mainTex.xyz, decalTex.xyz, _DecalStr );
    93.                 }
    94.    
    95.                 mainTex.xyz *= (detailTex.xyz * 2.0f) * + diffuseLighting;
    96.                 mainTex.xyz *= mainTex.a;
    97.                                
    98.                 return mainTex;
    99.             }
    100.             ENDCG
    101.         }
    102.        
    103.        
    104.     }
    105.     FallBack "Diffuse"
    106. }
    107.  
     
  10. OlliQueck

    OlliQueck

    Joined:
    Apr 11, 2013
    Posts:
    49
    any progress on this issue? I'm working on a similar thing. Getting Custom shadows in a post processing shader/ image effect but im stuck with he same problem. Simple standard shader writes to Z buffer, self-made vertex&frag shader does'nt :/ deram_scholzar's suggestion doesn't make a difference

    tried that http://docs.unity3d.com/Manual/SL-DepthTextures.html
    but no difference in depth buffer
     
    Last edited: May 21, 2015
  11. OlliQueck

    OlliQueck

    Joined:
    Apr 11, 2013
    Posts:
    49
    got it. if you're writing a fragment shader and want it to write to depth buffer dont forget the "Fallback "Diffuse" at the end... sounds weird but it makes the difference
     
  12. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Lol you're right, thats weird. Though, that does not solve my problem:(

    I'm doing something like a custom terrain (actually just to debug a erosion simulation), which is simply a plane, and the vertices are offsetted in the vertex shader. Now, I want to get the water depth (another offsetted plane above the terrain). But the underlying terrain does not write to the depth buffer (Actually it does, but not the offset is not considered unfortunately)! I probably could manually do back in the fragment shader (see this thread), but that seems complicated. I mean, the shader has to write the depth anyways behind the scenes, so, is there a better way?
     
  13. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    Don't suppose anyone has found a solution to this?...

    I've got the same issue - doing some animation in a vertex shader, and want a working depth/normal pass for SSAO (and I'm stuck with forward rendering for now)
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Getting the proper results to appear in the _CameraDepthTexture is fairly straightforward. If you're using a surface shader it's as easy as appending "addshadow" to the #pragma surface line. If you're doing a vertex / frag shader you'll need to add a custom shadow caster pass. There's a basic shadow caster pass in Unity's Vertex Fragment Shader Examples page.

    Here's the copy/paste of the relevant section:
    Code (CSharp):
    1.         // shadow caster rendering pass, implemented manually
    2.         // using macros from UnityCG.cginc
    3.         Pass
    4.         {
    5.             Tags {"LightMode"="ShadowCaster"}
    6.  
    7.             CGPROGRAM
    8.             #pragma vertex vert
    9.             #pragma fragment frag
    10.             #pragma multi_compile_shadowcaster
    11.             #include "UnityCG.cginc"
    12.  
    13.             struct v2f {
    14.                 V2F_SHADOW_CASTER;
    15.             };
    16.  
    17.             v2f vert(appdata_base v)
    18.             {
    19.                 v2f o;
    20.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    21.                 return o;
    22.             }
    23.  
    24.             float4 frag(v2f i) : SV_Target
    25.             {
    26.                 SHADOW_CASTER_FRAGMENT(i)
    27.             }
    28.             ENDCG
    29.         }
    That TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) looks scary, but it's basically just taking the v.vertex and doing the usual mul(UNITY_MATRIX_MVP, v.vertex), with a couple extra things for shadow maps. All you need to do is do your custom vertex modifications prior to that macro and it will all work.

    Example:
    Code (CSharp):
    1.             v2f vert(appdata_base v)
    2.             {
    3.                 float4 worldPos = mul(_Object2World, v.vertex);
    4.                 // do stuff to worldPos.xyz
    5.                 v.vertex = mul(_World2Object, worldPos);
    6.                 v2f o;
    7.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    8.                 return o;
    9.             }
    At this point you're probably wondering what a shadow caster has to do with the depth. In forward rendering Unity doesn't use the depth from the camera after it's rendered the scene, but instead does a pre-pass rendering the entire view using those shadow caster shader passes and saves that as the _CameraDepthTexture, then it renders the camera view you actually see. This is why having ZWrite on or off on the main shader doesn't seem to have any effect on what shows up in the depth texture, and why any custom vertex manipulations seem to do nothing. The Fallback line is where the shadow caster for most shaders comes from; if your shader doesn't have a shadow caster pass it'll use the one the Fallback shader uses instead.

    Updating the depth / normals texture is a little more annoying, but basically you need a similar custom shader. Instead of using a special pass in your shader Unity uses the older replacement shader system to create the _CameraDepthNormalsTexture. The replacement shader in question is the Internal-DepthNormalsTexture.shader which you have to replace with your own shader with a new pass appended to it. Then your custom shader needs to have a custom "RenderType" tag and a matching "RenderType" shader in the Internal-DepthNormalsTexture.shader.

    In Unity 5.3 and prior I don't remember if you can get away with just adding a new Internal-DepthNormalsTexture.shader file into your assets folder or if you have to actually replace the one in the actual editor folder. If you're using Unity 5.4 the graphics settings have an easy way to override this.

    edit: Minor note about deferred for completeness sake. In the deferred the _CameraDepthTexture does come from the deferred camera's depth pass, and the _CameraDepthNormalsTexture comes from the deferred normals and camera depth. However any forward rendered objects that you want to appear in the depth will use the same Shadow Caster pass to "inject" themselves into the deferred camera's depth. They do not inject into the normals, and there is no way to fix this without actually using a deferred shader! This means fully forward rendered objects when using the deferred rendering path cannot work properly with any effect that needs the camera normals! The only solution is to render the object twice!
     
    Last edited: Jul 26, 2016
  15. Deleted User

    Deleted User

    Guest

    bgolus when you say: "All you need to do is do your custom vertex modifications prior to that macro and it will all work.", you mean that the vertex shader of the shadow casting pass has to do the same transformations as the regular vertex shader? In my case the project is a GPGPU simulation where the positions are read from a texture in the vertex shader, so if I understand correctly I have to have similar logic in the shadow casting part so my particles are properly positioned in the depth texture? Thanks!
     
  16. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yes, correct - the same modifications are required for proper depth that you do in your normal vertex shader.
     
  17. Deleted User

    Deleted User

    Guest

    Thanks! So I did all of that, basically following something similar to what the Disk shader in this project does:
    https://github.com/keijiro/Pcx

    However, still not a correct depth texture. Anything else I might be missing, like maybe a project-level setting, or a CPU-side thing? Thanks!
     
  18. Deleted User

    Deleted User

    Guest

    Or do I need to do anything special on the script side to make sure each pass is drawn?
     
  19. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    @johanismael sorry, not much of an expert. Long time ago since I messed with that, I think in the end I simply resorted to a surface shader because (if I'm correct) I still had some kind of troubles. Not ideal in your case though:/
     
  20. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    I'm using a surface shader but I can't get it to write to the _CameraDepthTexture using either "addshadow" or "fullforwardshadows". Here's the relevant section of code using the latter:

    Code (CSharp):
    1.         Tags { "Queue"="Transparent" "RenderType"="Transparent" "DisableBatching"="True" }
    2.         LOD 200
    3.         CGPROGRAM
    4.         #pragma surface surf Standard fullforwardshadows vertex:vert alpha:fade
    I had thought it might be because I was changing the vertices for a billboard effect, but disabling that code didn't solve the problem.
     
  21. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Only objects using the opaque queue range (Geometry or AlphaTest, 0 through 2500) will render to the depth texture.
     
  22. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    I switched it to queue "Geometry" and am using a renderqueue of 2500 for the material, but it still doesn't write to the depth texture.
     
  23. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    You also cannot use the alpha:fade or any other alpha option (apart from keepalpha) and addshadow together. The shadow caster pass will simply not be generated if the alpha option exists. The work around for that would be to use a fallback like:
    Fallback "Legacy Shaders/Transparent/Cutout/VertexLit"

    But understand that any transparent shader that writes to the depth texture will cause graphical anomalies as the depth texture will no longer be accurate for the content on screen. Any place where there's a transparent surface technically has more than one depth represented, but the depth texture can only store one depth per pixel. On the PC or console this will cause issues like shadows not being cast onto objects you expect them to be cast on when there is a transparent depth texture writing surface over it, as only the closest object will receive shadows. Any post processing effects that use the depth will also have similar problems, and stuff like depth of field may have sharp depth discontinuities around depth texture writing transparent objects.
     
    HonoraryBob likes this.
  24. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    Using Fallback "Legacy Shaders/Transparent/Cutout/VertexLit" partially solved the problem; but since I'm billboarding by rotating the vertices in the vertex shader, the quad's profile in the CameraDepthTexture is the original unrotated form; and since I clip pixels based on the alpha channel, the depth texture doesn't reflect this either. Farther above you had explained how to solve the first problem in a vert-frag shader, but I'm using a surface shader so I'm not sure how to solve it; likewise for the second problem.
     
  25. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214

    Is there any way to make a custom version of the standard cutout shader that allows fading around the edges (rather than the sharp cutout effect) while still writing to the CameraDepthTexture? I succeeded in doing the first part but not the second. Here's the code I'm using (which creates a nice soft-edge effect but produces a solid block in the CameraDepthTexture rather than a pixel-by-pixel pattern):

    Code (CSharp):
    1.  Shader "Standard-Cutout-SmoothEdges"
    2. {
    3.      Properties
    4.      {
    5.          _Color ("Main Color", Color) = (1,1,1,1)
    6.          _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    7.          _AlphaCutoff ("Alpha cutoff", Range(0,1)) = 0.5
    8.    
    9.        
    10.      }
    11.      SubShader
    12.      {
    13.          Tags {"Queue"="Geometry" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
    14.          LOD 300
    15.        
    16.          CGPROGRAM
    17.          #pragma surface surf Lambert alpha:fade
    18.          sampler2D _MainTex;
    19.          fixed4 _Color;
    20.          float _AlphaCutoff;
    21.          struct Input
    22.          {
    23.              float2 uv_MainTex;
    24.          };
    25.          void surf (Input IN, inout SurfaceOutput o)
    26.          {
    27.              fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    28.              clip (c.a - _AlphaCutoff);            
    29.              o.Albedo = c.rgb;
    30.              o.Alpha = c.a;
    31.                                
    32.                        
    33.          }
    34.          ENDCG
    35.      }
    36.      Fallback "Legacy Shaders/VertexLit"
    37. }
     
  26. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    I mean, sure. Just use the Standard shader as the fallback! ... except that won't work easily for ... reasons.

    The short version is the Standard shader uses a lot of keyword enabled options, and by default the shadow caster is no different than the Legacy VertexLit shader. The way Fallback and UsePass works, any keywords defined in the base .shader file are ignored (since Fallback and UsePass exist outside of CGPROGRAM blocks where those are defined), so you'd have to set those keywords manually via a custom material inspector, or with a couple of [Toggle] properties you remember to keep enabled, or manually setting the keywords by hand.

    Alternatively, and much more sanely, you could just copy the ShadowCaster pass from the Standard shader and the #define lines you need. All of the Standard shadow caster's actual code is in a cginc file, so the pass definition itself is very small.
    Code (CSharp):
    1.         // ------------------------------------------------------------------
    2.         //  Shadow rendering pass
    3.         Pass {
    4.             Name "ShadowCaster"
    5.             Tags { "LightMode" = "ShadowCaster" }
    6.  
    7.             ZWrite On ZTest LEqual
    8.  
    9.             CGPROGRAM
    10.             #pragma target 2.0
    11.  
    12.             #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    13.             #pragma shader_feature _METALLICGLOSSMAP
    14.             #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
    15.             #pragma skip_variants SHADOWS_SOFT
    16.             #pragma multi_compile_shadowcaster
    17.  
    18.             #pragma vertex vertShadowCaster
    19.             #pragma fragment fragShadowCaster
    20.  
    21.             #include "UnityStandardShadow.cginc"
    22.  
    23.             ENDCG
    24.         }
    Replace all three of the #pragma shader_feature lines with:
    Code (csharp):
    1. #define _ALPHABLEND_ON 1
    And you're done.
     
    HonoraryBob likes this.
  27. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214

    Thank you. I had beaten my head against the wall so long on this. It seems to work with maybe only some anomalies at mid-distances.
     
  28. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    There are a few other issues you'll have.

    Because this object is part of the opaque queue range, it'll sort front to back, so overlapping objects will be sorted badly unless you manually sort them yourself by set the sortingOrder on the renderer components.

    It'll also disappear entirely "behind" the skybox if there are no other opaque objects behind these objects. This is because Unity's sky box relies on opaque objects writing to the depth buffer, and you generally don't want to "z write" to the depth buffer when rendering transparencies. Note, the depth buffer and camera depth texture are totally separate things when using forward rendering. The camera depth texture usually matches the depth buffer, but in this case it won't due to you rendering a dithered pattern to the depth texture and nothing to the depth buffer.

    Other transparent objects won't sort properly with your objects. Your objects always be "behind" them since all other transparencies are being rendered afterward, and thus render on top. The depth buffer exists to handle sorting like this for opaques, but you don't have that luxury here.


    Honestly my suggestion would be to go about this another way. Specifically keep your shader using the normal transparent queue, and inject your objects into the depth texture using command buffers rather than relying on the built in systems to do the same.
     
  29. Samhayne

    Samhayne

    Joined:
    Jun 15, 2009
    Posts:
    45
    I didn't fully get it yet.

    Is it a bad thing to drop a
    Code (CSharp):
    1. FallBack "Mobile/Diffuse"
    or
    Code (CSharp):
    1. FallBack "Diffuse"
    line add the end to make the shader write to the depth buffer or is it ok?

    Or is it better to add the lines, bgolus mentioned in Posting #14?


    For my case I'd only need it to render foam around objects touching water.
     
  30. miloszecket

    miloszecket

    Joined:
    Feb 4, 2019
    Posts:
    7
    I'm trying to do this, but I'm using dynamically tessellated geometry. How do I go about implementing this?
     
  31. miloszecket

    miloszecket

    Joined:
    Feb 4, 2019
    Posts:
    7
    How would I create this custom shader? (and if it matters, I'm attempting to add tessellated and displaced geometry to the depth buffer)
     
  32. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Long time since I last messed with it. I think I went for a surface shader in the end for simplicities sake. AFAIK there I just did;
    Code (csharp):
    1. #pragma surface surf Lambert addshadow
    2. #pragma vertex vert
    and the modifications you'd do in the vertex shader are applies to the shadow pass as well.
    As for a standard vertex/fragment shader, I believe you just need to do the same vertex transformation in a custom shadow pass (assuming you're using forward renderer).