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

Writing depth value in fragment program

Discussion in 'Shaders' started by tomaszek, Nov 5, 2010.

  1. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Hi,

    I've got problem with writing depth in fragment program. All fragment programs I saw for ShaderLab write only color, but it seems to be possible to output depth too (as I see in HLSL/Cg forums). I've been digging the forum for hours but I still got no idea how to do it. Was trying shader from attachment, but compiler throws such error:

    Shader error in 'TestShader': D3D shader assembly failed with: (8): error X2022: scalar registers cannot be masked
    Shader Assembly: ps_2_0
    ; 4 ALU
    def c0, 0.00000000, 0, 0, 0
    dcl t0
    frc r1, t0
    mov r0.z, c0.x

    Any idea how to make it working ?
     

    Attached Files:

  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    The texture you write to in the fragment program is only a color buffer so writing depth will not work I guess.
    Unity 3 renders the depth and normal buffer in a different pass (given you enable the camera to render a depth texture) than the color, but you can potentially access this one.
     
  3. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Thank you, fast and competent reply as usual by dreamora :).

    I've just analysed compiled version of simple surface shader. Indeed - as far as I see there is only color buffer written. I will have to sort things another way aquiring information from depth texture. The problem is - I want this shader (grass shader) to work on terrains which are usually queued as "geometry-100". So I'd need to write my material later as it will be alpha masked "transparent". Are there any known drawbacks when shifting terrain material later in render queue ? Dangerous side effects to be aware of ?
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    likely totally non working depth sorting actually.
    It already runs at its edge of usability as you might find out with some PostFX actually.
     
  5. duke

    duke

    Joined:
    Jan 10, 2007
    Posts:
    763
    Has this been addressed in 3.4?
     
  6. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Just a note for those wanting to write to depth in D3D9 shader and getting the 'D3D shader assembly failed with: (36): error X2022: scalar registers cannot be masked' error.

    Although this bug still remains, the problem is with the cg compiler, something that has been known since 2008 (according to this old cg thread on nvidia forums). So either its never been fixed or Unity is using a pretty old version of cg?

    Thankfully it appears from initial testing this issue can be solved by changing the compiled shader code from
    Code (csharp):
    1. mov oDepth.z, r0.z
    to
    Code (csharp):
    1. mov oDepth, r0.z
    I.e. removing the .z mask, which since its on a scalar doesn't work and hence the error.

    To change the compiled code simply create your shader normally, ignoring the error. Once finished select the shader and click 'open compiled shader' button in the inspector. Now copy the entire contents of the compiled shader and paste it into a new shader file. Look through the code and replace the lines causing the bug as above, then save the shader.

    It does mean that your original shaderlab/cg shader will never compile or be usable in d3d9 environment so don't use it or include it in your builds! However your fixed 'compiled' version should work fine. At least it does for me in the editor and as a window build.
     
  7. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Good to know it's possible. Works in OpenGL/GLSL and D3D9 after NoiseCrime's fix, but still there are suspicious messages in compiled code:

    1. for mobile profiles:

    /* NOTE: GLSL optimization failed
    0:32(15): error: `gl_FragDepth' undeclared
    0:32(15): error: type mismatch
    */

    so can't say if works for mobile

    2. error about flash export incompatibility

    Shader warning in 'TestShader': register type 9 not supported in AGAL (compiling for flash) at line 5

    Anyway - it's big step further and could be useful, however I dropped the idea using this feature completelt for performance reasons (writing into depth buffer is told to be slow, but honestly I've never tested it since I couldn't do it well in Unity).
     
  8. Noisecrime

    Noisecrime

    Joined:
    Apr 7, 2010
    Posts:
    2,051
    Good point about Mobile ( where writing to depth buffer is not supported as far as I understand) and Flash.

    As for performance, seems fine to me (Windows). I guess it could be slower than normal rendering since the gpu has no idea what depth you are going to set, so normal optimisations (e.g. early outs) can't be done. However its not likely that you'd use this frequently for many objects, more likely as in my case, you'd want to use it once per frame to populate the depth buffer with specific values.
     
    Last edited: Apr 16, 2012
  9. Aras

    Aras

    Unity Technologies

    Joined:
    Nov 7, 2005
    Posts:
    4,770
    We can't do much about mobile here. In OpenGL ES 2.0, writing to the fragment depth is not possible. There is just no way to do it.


    Again, not much we can do. In Stage3D's AGAL shader language, writing to fragment depth is not possible.

    To not produce any warnings, add "#pragma exclude_renderers gles flash" to the shader code.
     
  10. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,369
    The "X2022: scalar registers cannot be masked' bug is fixed in Unity 4.2. The shader should be like this by the way:

    Code (csharp):
    1.  
    2. Shader "TestShader" {
    3. SubShader {
    4.     Pass {
    5.         Fog { Mode Off }
    6.         CGPROGRAM        
    7.             #pragma exclude_renderers gles flash
    8.             #pragma vertex vert
    9.             #pragma fragment frag
    10.            
    11.             // vertex input: position, UV
    12.             struct appdata {
    13.                 float4 vertex : POSITION;
    14.                 float4 texcoord : TEXCOORD0;
    15.             };
    16.            
    17.             struct v2f {
    18.                 float4 pos : POSITION;
    19.                 float4 uv : TEXCOORD0;
    20.             };
    21.            
    22.             v2f vert (appdata v) {
    23.                 v2f o;
    24.                 o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    25.                 o.uv = float4( v.texcoord.xy, 0, 0 );
    26.                 return o;
    27.             }
    28.            
    29.             struct C2E2f_Output {
    30.                 float4 col:COLOR;
    31.                 float dep:DEPTH;
    32.             };     
    33.            
    34.             C2E2f_Output frag( v2f i ) {
    35.            
    36.                 C2E2f_Output o;
    37.                 half4 c = frac( i.uv );
    38.                 o.col=c; // this is not iteresting
    39.                 o.dep=0; // this is what I want to output into Z-buffer (0 value is just an example)
    40.                 return o;
    41.             }
    42.         ENDCG
    43.         }
    44.     }
    45. }
    46.  
     
    Last edited: Jul 23, 2013
  11. BenC

    BenC

    Joined:
    Jul 24, 2013
    Posts:
    3
    Has anyone used this successfully in DX11?

    Depth output from a pixel shader works fine for me in DX9 mode (after upgrading to 4.2 to fix the mask issue described above), but if I put the renderer into DX11 mode the depth output seems to be ignored - I just get the regular geometry depth...
     
  12. KingOfColly

    KingOfColly

    Joined:
    May 25, 2013
    Posts:
    15
    Anyone made any progress with this?

    I'm having the same problem with my shader when trying to implement a logarithmic depth buffer ('Use Direct3D 11' enabled in Player settings). Using the log calc gives the same output as depth = 0 and depth = 1. Like it ignores the value I set (or more likely I'm doing it wrong!). This is on PC by the way (Win7 x64)

    Code (csharp):
    1.  
    2. Shader "Custom/LogDepth"
    3. {
    4.     Properties
    5.     {
    6.         _MainTex ("Base (RGB)", 2D) = "white" {}
    7.     }
    8.    
    9.     SubShader
    10.     {
    11.         Pass
    12.         {
    13.             Tags { "RenderType"="Opaque" }
    14.            
    15.             CGPROGRAM
    16.             #pragma target 4.0
    17.             #pragma vertex vert
    18.             #pragma fragment frag
    19.             #include "UnityCG.cginc"
    20.                
    21.             sampler2D _MainTex;
    22.             float4 _MainTex_ST;
    23.             float c = 1.0;
    24.             float far = 1000000.0;
    25.            
    26.             struct v2f
    27.             {
    28.                 float4 position : POSITION;
    29.                 float2 uv : TEXCOORD0;
    30.             };
    31.            
    32.             struct fragOut
    33.             {
    34.                 half4 color : COLOR;
    35.                 float depth : DEPTH;
    36.             };
    37.                    
    38.             v2f vert(appdata_base v)
    39.             {
    40.                 v2f o;
    41.                
    42.                 o.position = mul(UNITY_MATRIX_MVP, v.vertex);
    43.                 o.uv = v.texcoord;
    44.                
    45.                 return o;
    46.             }
    47.    
    48.             fragOut frag(in v2f i)
    49.             {  
    50.                 fragOut o;
    51.            
    52.                 o.color = tex2D(_MainTex, i.uv);
    53.                 o.depth = (log(c * i.position.z + 1) / log(c * far + 1) * i.position.w);
    54.                 //o.depth = 0;
    55.                 //o.depth = 1;
    56.                
    57.                 return o;
    58.             }
    59.             ENDCG
    60.         }
    61.     }
    62.    
    63.     FallBack "Diffuse"
    64. }
    65.  
     
    Last edited: Dec 8, 2013
  13. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Finally I found the solution - simply we can't use old semantics with DX11 (DEPTH) - we need to use (SV_Depth as pixel function output and SV_Target instead of COLOR, in case of new deferred we've got indexed SV_Target0 to SV_Target3 semantics for MRT output).

    Tom
     
  14. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    Hi Tom,
    could you quickly give an example please ? new to shaders and a bit confused.
    tried this and couldn't make it work, nothing in zbuffer.
    thanks a lot
    Victor

    Code (CSharp):
    1.          float4 _MainTex_ST;
    2.         float4 _Color;
    3.         sampler2D _MainTex;
    4.         half _Dist;
    5.         float c = 1.0;
    6.         float far = 1000000.0;
    7.  
    8.    
    9.          struct v2f {
    10.               float4 pos : SV_POSITION;
    11.               fixed4 color : COLOR;
    12.               float3 norm : NORMAL;
    13.               float2 uv : TEXCOORD0;
    14.            };
    15.  
    16.         struct fragOut
    17.         {
    18.             half4 color : SV_Target ;
    19.             float depth : SV_Depth ;
    20.         };
    21.  
    22.           v2f vert (appdata_full v)
    23.           {
    24.               v2f o;
    25.             o.norm = v.normal.xyz;
    26.             o.pos = mul (UNITY_MATRIX_MVP, v.vertex );
    27.             o.uv = TRANSFORM_TEX(v.texcoord.xy,_MainTex);
    28.             //assign color and alpha
    29.             o.color.xyz = _Color.xyz;
    30.             o.color.w = 1;
    31.             return o;
    32.         }
    33.    
    34.         fragOut frag (in v2f i)
    35.         {
    36.             fragOut o;
    37.             fixed4 tex = _Color * tex2D (_MainTex, i.uv);
    38.             o.color = tex;
    39.             o.depth = (log(c * i.pos.z + 1) / log(c * far + 1) * i.pos.w);
    40.             o.color.rgb=  o.depth; //
    41.             return o;
    42.           }
     
  15. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Something like this:

    Code (csharp):
    1.  
    2. struct fragOut
    3. {
    4.    half4 color : SV_Target;
    5.    float depth : SV_Depth;
    6. };
    7.  
    Tom
     
  16. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    still have nothing...well...thanks anyway
     
  17. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    I don't know if above example still works, anyway, as a hint:

    Code (csharp):
    1.  
    2.     float depthWithOffset = i.eyeDepth*(1+rayLength/distance(i.posWorld.xyz, _WorldSpaceCameraPos)); // Z-DEPTH perspective correction
    3.      o.depth = (1.0 - depthWithOffset * _ZBufferParams.w) / (depthWithOffset * _ZBufferParams.z);
    4.  
    in vertex function use COMPUTE_EYEDEPTH(vertexFunctionOutputStruct.eyeDepth);

    the eyeDepth value is passed to fragment function as i.eyeDepth above. You also need to pass world position (posWorld) to frag function. With rayLength variable you can offset resultant depth back and forth in world units. When rayDepth=0 we've got not modified depth. Such formula works fine in my shaders, although determining rayDepth (depth offset in world units) may be very tricky when you try to make computations in, for example, tangent space.

    Tom
     
    antislash likes this.
  18. UnityGuillaume

    UnityGuillaume

    Unity Technologies

    Joined:
    Mar 16, 2015
    Posts:
    123
  19. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    hi Tom
    your hint looks fine for perspective correction( wich i was also looking for, i'm thankful)
    i'm really noobish, but what i don't get is where and how do you write to zbuffer.
    i will use your code as i am trying fo get a very simple fog working (thus persp correction);
    what i would really love is write a damn depth to the z buffer so i could write my semi-transparent shader pixels to zbuffer.
    i think i must have a look at unity foliage code or so.
    thanks very much
    victor
     
  20. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    i wish a unity god of code could provide a simple example of a shader that whrites what i want to zbuffer ;)
     
    ModLunar likes this.
  21. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Unity transform it into platform dependent code. For DX( it will be COLOR/DEPTH semantics. For openGL it will write into gl_Depth in fragment progam (via GLSL optimizer which is supposed to move from HLSL to GLSL code - with curvy luck must admit but most of time it makes its job)

    Tom
     
  22. Zicandar

    Zicandar

    Joined:
    Feb 10, 2014
    Posts:
    388
    If you don't actually want a different value then what the vertexes would normally be at...
    Then most of this thread is just a waste of time AND Performance!
    Just add a ZWrite On where you have blend modes ect...
    (It will write to z buffer, but NOT to the copy of the z-buffer unity keeps after all opaque objects are drawn in deferred / and it will also not affect in forward mode the "depth" buffer that is readable as that is once again a copy of things, but in this case a separate pass is used to draw Opaque objects only...)
     
  23. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    I can't tell what exactly antislash want to achieve exactly, because writing into depth indeed can impact performance because of missing GPU depth buffer culling optimizations when we write into it. So - offsetting depth with some constant value (use Offset keyword in shader then) or managing depth writing in general (ZWrite keyword) is not what I mean when it comes to modifying depth buffer. Below example explain it:



    It's how to make low poly mesh looking extemely high poly w/o tesellation (which would be difficult to displace in this particular case). Note that these disks intersect each other and cast / receive proper shadows

    Here is a working example (works on DX9, DX11 and openGL on my Win7 machine). Place on any object in forward lighting and look what happen using depth offset slider. Of course this shader is only a sketch to present the idea. Look for // DEPTH WRITE TWEAK comments to see where I modified surface shader output.

    Code (csharp):
    1.  
    2. Shader "Custom/DepthWrite" {
    3.    Properties {
    4.      _Color ("Color", Color) = (1,1,1,1)
    5.      _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.      _Glossiness ("Smoothness", Range(0,1)) = 0.5
    7.      _Metallic ("Metallic", Range(0,1)) = 0.0
    8.      _DepthOffset ("_DepthOffset", Range(-1,1)) = 0  // DEPTH WRITE TWEAK
    9.    }
    10.    SubShader {
    11.      Tags { "RenderType"="Opaque" }
    12.      LOD 200
    13.  
    14.  
    15.    // ------------------------------------------------------------
    16.    // Surface shader code generated out of a CGPROGRAM block:
    17.  
    18.  
    19.    // ---- forward rendering base pass:
    20.    Pass {
    21.      Name "FORWARD"
    22.      Tags { "LightMode" = "ForwardBase" }
    23.  
    24. CGPROGRAM
    25. // compile directives
    26. #pragma vertex vert_surf
    27. #pragma fragment frag_surf
    28. #pragma target 3.0
    29. #pragma multi_compile_fog
    30. #pragma multi_compile_fwdbase
    31. #include "HLSLSupport.cginc"
    32. #include "UnityShaderVariables.cginc"
    33. // Surface shader code generated based on:
    34. // writes to per-pixel normal: no
    35. // writes to emission: no
    36. // needs world space reflection vector: no
    37. // needs world space normal vector: no
    38. // needs screen space position: no
    39. // needs world space position: no
    40. // needs view direction: no
    41. // needs world space view direction: no
    42. // needs world space position for lighting: YES
    43. // needs world space view direction for lighting: YES
    44. // needs world space view direction for lightmaps: no
    45. // needs vertex color: no
    46. // passes tangent-to-world matrix to pixel shader: no
    47. // reads from normal: no
    48. // 1 texcoords actually used
    49. //  float2 _MainTex
    50. #define UNITY_PASS_FORWARDBASE
    51. #include "UnityCG.cginc"
    52. #include "Lighting.cginc"
    53. #include "UnityPBSLighting.cginc"
    54. #include "AutoLight.cginc"
    55.  
    56. #define INTERNAL_DATA
    57. #define WorldReflectionVector(data,normal) data.worldRefl
    58. #define WorldNormalVector(data,normal) normal
    59.  
    60.      // Physically based Standard lighting model, and enable shadows on all light types
    61.      //#pragma surface surf Standard fullforwardshadows
    62.  
    63.      // Use shader model 3.0 target, to get nicer looking lighting
    64.      //#pragma target 3.0
    65.  
    66.      sampler2D _MainTex;
    67.      float _DepthOffset;  // DEPTH WRITE TWEAK
    68.  
    69.      struct Input {
    70.        float2 uv_MainTex;
    71.      };
    72.  
    73.      half _Glossiness;
    74.      half _Metallic;
    75.      fixed4 _Color;
    76.  
    77.      void surf (Input IN, inout SurfaceOutputStandard o) {
    78.        // Albedo comes from a texture tinted by color
    79.        fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    80.        o.Albedo = c.rgb;
    81.        // Metallic and smoothness come from slider variables
    82.        o.Metallic = _Metallic;
    83.        o.Smoothness = _Glossiness;
    84.        o.Alpha = c.a;
    85.      }
    86.  
    87.  
    88. // vertex-to-fragment interpolation data
    89. // no lightmaps:
    90. #ifdef LIGHTMAP_OFF
    91. struct v2f_surf {
    92.   float4 pos : SV_POSITION;
    93.   float2 pack0 : TEXCOORD0; // _MainTex
    94.   half3 worldNormal : TEXCOORD1;
    95.   float4 worldPos : TEXCOORD2; // DEPTH WRITE TWEAK (added .w component to encode eyeDepth)
    96.   #if UNITY_SHOULD_SAMPLE_SH
    97.   half3 sh : TEXCOORD3; // SH
    98.   #endif
    99.   SHADOW_COORDS(4)
    100.   UNITY_FOG_COORDS(5)
    101.   #if SHADER_TARGET >= 30
    102.   float4 lmap : TEXCOORD6;
    103.   #endif
    104. };
    105. #endif
    106. // with lightmaps:
    107. #ifndef LIGHTMAP_OFF
    108. struct v2f_surf {
    109.   float4 pos : SV_POSITION;
    110.   float2 pack0 : TEXCOORD0; // _MainTex
    111.   half3 worldNormal : TEXCOORD1;
    112.   float4 worldPos : TEXCOORD2; // DEPTH WRITE TWEAK (added .w component to encode eyeDepth)
    113.   float4 lmap : TEXCOORD3;
    114.   SHADOW_COORDS(4)
    115.   UNITY_FOG_COORDS(5)
    116.   #ifdef DIRLIGHTMAP_COMBINED
    117.   fixed3 tSpace0 : TEXCOORD6;
    118.   fixed3 tSpace1 : TEXCOORD7;
    119.   fixed3 tSpace2 : TEXCOORD8;
    120.   #endif
    121. };
    122. #endif
    123. float4 _MainTex_ST;
    124.  
    125. // vertex shader
    126. v2f_surf vert_surf (appdata_full v) {
    127.   v2f_surf o;
    128.   UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
    129.   o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    130.   o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    131.   float3 worldPos = mul(_Object2World, v.vertex).xyz;
    132.   fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    133.   #if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
    134.   fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    135.   fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    136.   #endif
    137.   #if !defined(LIGHTMAP_OFF) && defined(DIRLIGHTMAP_COMBINED)
    138.   o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
    139.   o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
    140.   o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
    141.   #endif
    142.   o.worldPos.xyz = worldPos; // DEPTH WRITE TWEAK (set .xyz channels)
    143.   COMPUTE_EYEDEPTH(o.worldPos.w); // DEPTH WRITE TWEAK
    144.   o.worldNormal = worldNormal;
    145.   #ifndef DYNAMICLIGHTMAP_OFF
    146.   o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
    147.   #endif
    148.   #ifndef LIGHTMAP_OFF
    149.   o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    150.   #endif
    151.  
    152.   // SH/ambient and vertex lights
    153.   #ifdef LIGHTMAP_OFF
    154.   #if UNITY_SHOULD_SAMPLE_SH
    155.   #if UNITY_SAMPLE_FULL_SH_PER_PIXEL
    156.   o.sh = 0;
    157.   #elif (SHADER_TARGET < 30)
    158.   o.sh = ShadeSH9 (float4(worldNormal,1.0));
    159.   #else
    160.   o.sh = ShadeSH3Order (half4(worldNormal, 1.0));
    161.   #endif
    162.   // Add approximated illumination from non-important point lights
    163.   #ifdef VERTEXLIGHT_ON
    164.   o.sh += Shade4PointLights (
    165.   unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
    166.   unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
    167.   unity_4LightAtten0, worldPos, worldNormal);
    168.   #endif
    169.   #endif
    170.   #endif // LIGHTMAP_OFF
    171.  
    172.   TRANSFER_SHADOW(o); // pass shadow coordinates to pixel shader
    173.   UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
    174.   return o;
    175. }
    176.  
    177. // fragment shader
    178. //fixed4 frag_surf (v2f_surf IN) : SV_Target {
    179. void frag_surf (v2f_surf IN, out fixed4 outColor:SV_Target, out float outDepth : SV_Depth) { // DEPTH WRITE TWEAK
    180.   // prepare and unpack data
    181.   Input surfIN;
    182.   UNITY_INITIALIZE_OUTPUT(Input,surfIN);
    183.   surfIN.uv_MainTex = IN.pack0.xy;
    184.   float3 worldPos = IN.worldPos.xyz; // DEPTH WRITE TWEAK (take actual worldPos part explicitly using xyz swizzling mask)
    185.   #ifndef USING_DIRECTIONAL_LIGHT
    186.   fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
    187.   #else
    188.   fixed3 lightDir = _WorldSpaceLightPos0.xyz;
    189.   #endif
    190.   fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
    191.   #ifdef UNITY_COMPILER_HLSL
    192.   SurfaceOutputStandard o = (SurfaceOutputStandard)0;
    193.   #else
    194.   SurfaceOutputStandard o;
    195.   #endif
    196.   o.Albedo = 0.0;
    197.   o.Emission = 0.0;
    198.   o.Alpha = 0.0;
    199.   o.Occlusion = 1.0;
    200.   fixed3 normalWorldVertex = fixed3(0,0,1);
    201.   o.Normal = IN.worldNormal;
    202.   normalWorldVertex = IN.worldNormal;
    203.  
    204.   // call surface function
    205.   surf (surfIN, o);
    206.  
    207.   // compute lighting & shadowing factor
    208.   UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
    209.   fixed4 c = 0;
    210.  
    211.   // Setup lighting environment
    212.   UnityGI gi;
    213.   UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
    214.   gi.indirect.diffuse = 0;
    215.   gi.indirect.specular = 0;
    216.   #if !defined(LIGHTMAP_ON)
    217.   gi.light.color = _LightColor0.rgb;
    218.   gi.light.dir = lightDir;
    219.   gi.light.ndotl = LambertTerm (o.Normal, gi.light.dir);
    220.   #endif
    221.   // Call GI (lightmaps/SH/reflections) lighting function
    222.   UnityGIInput giInput;
    223.   UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
    224.   giInput.light = gi.light;
    225.   giInput.worldPos = worldPos;
    226.   giInput.worldViewDir = worldViewDir;
    227.   giInput.atten = atten;
    228.   #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
    229.   giInput.lightmapUV = IN.lmap;
    230.   #else
    231.   giInput.lightmapUV = 0.0;
    232.   #endif
    233.   #if UNITY_SHOULD_SAMPLE_SH
    234.   giInput.ambient = IN.sh;
    235.   #else
    236.   giInput.ambient.rgb = 0.0;
    237.   #endif
    238.   giInput.probeHDR[0] = unity_SpecCube0_HDR;
    239.   giInput.probeHDR[1] = unity_SpecCube1_HDR;
    240.   #if UNITY_SPECCUBE_BLENDING || UNITY_SPECCUBE_BOX_PROJECTION
    241.   giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
    242.   #endif
    243.   #if UNITY_SPECCUBE_BOX_PROJECTION
    244.   giInput.boxMax[0] = unity_SpecCube0_BoxMax;
    245.   giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
    246.   giInput.boxMax[1] = unity_SpecCube1_BoxMax;
    247.   giInput.boxMin[1] = unity_SpecCube1_BoxMin;
    248.   giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
    249.   #endif
    250.   LightingStandard_GI(o, giInput, gi);
    251.  
    252.   // realtime lighting: call lighting function
    253.   c += LightingStandard (o, worldViewDir, gi);
    254.   UNITY_APPLY_FOG(IN.fogCoord, c); // apply fog
    255.   UNITY_OPAQUE_ALPHA(c.a);
    256.  
    257.   // DEPTH WRITE TWEAK
    258.   //return c;
    259.   outColor=c;
    260.   float depthWithOffset=IN.worldPos.w+_DepthOffset;
    261.   outDepth=(1.0 - depthWithOffset * _ZBufferParams.w) / (depthWithOffset * _ZBufferParams.z);
    262. }
    263.  
    264. ENDCG
    265.  
    266. }
    267.  
    268.    }
    269.    FallBack "Diffuse"
    270. }
    271.  
    This is ripped default surface shader with one pass only (works in forward for one light then).

    ATB, Tom

    P.S. This nice screenshot above is shader from my incoming shader package - "UBER - standard shader ultra" (these shaders, besides of various parallax techniques have a lot of new features as well).
     
  24. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    nice one Tom.

    what i want to do is : have multiple CG passes in a surface shader vith vertes displacement, eg to achieve a mossy surface, on small vegetation scattered over another surface and write each displaced pixel accordingly to zbuffer so effects like fog can affect them correctly.
     
  25. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    If you base on multiple passes for verts (like classic fur approach) you don't need to write into depth. Multiple passes ("shells") will be displaced in depth buffer accordingly, but use alpha cutout shading then rather than transparent to solve sorting issues.

    Tom
     
  26. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    hi tom, i start from a surface shader, maybe it's a bit different?
    i use
    Tags { "Queue"="AlphaTest+50" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
    LOD 200
    Blend SrcAlpha OneMinusSrcAlpha
    ZWrite On
    ZTest LEqual
    and
    #pragma surface surf StandardSpecular fullforwardshadows alphatest:_Cutoff vertex:vert addshadow

    but atm, onlythe "base" geometry is taken in account when using global fog ie
     
  27. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    You won't have multiple passes to "extrude" for example grass strands. It will have only one pass per each lighting scenarion (+shadow caster / depth pass).

    Global fog is more complex issue - in forward it needs to have depth computed in separate buffer. Transparent objects are rendered always in forward (no matter the camera lighting path used).

    Tom
     
  28. antislash

    antislash

    Joined:
    Apr 23, 2015
    Posts:
    646
    thanks a lot tom, i'll do my homework
     
  29. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Hi Tom,
    First, thanks so much for UBER, it's simply superior:)

    I've some problems myself with depth, I'm offsetting a plane with a heightmap (terrain-like) with a customised Standard shader, but it seems depth is not written for the offsetted vertices:(
    Is there something easy&fast I can do to fix it? Like tell the ZWrite to call the vertex program and take those vertex positions to write? A ZWrite Prepass?

    Screenshot6.jpg
    The depth is visualized here, the plane shouldn't be in the ZBuffer, but the mesh you see outlined should, which is the plane modified in the vertex shader. The ZTesting seems to work though, that's what's bugging me. Doesn't need ZTesting the Z Buffer?

    I'm not very experienced in shader programming, but I attempted to fix it by writing manually to the ZBuffer for the offsetted vertices. Basically I pass both vertex and scene depth to the fragment shader where I decide what to write to the buffer.

    This is the depth debugged in grayscale as the mesh receives it, divided by 1000 to bring them into an acceptable range:
    Screenshot7.jpg

    Code (csharp):
    1. struct DepthWriteFragOut
    2. {
    3.     half4 col : SV_Target;
    4.     #if defined(_HEIGHTOFFSET)
    5.     half depth : SV_Depth;
    6.     #endif
    7. };
    8.  
    9. // In the end of the fragment function:
    10. DepthWriteFragOut o;
    11. o.col = col;
    12. #if defined(_HEIGHTOFFSET)
    13. float objDepth = i.screenPos.z;
    14. float sceneDepth = LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPos)).r);//(_ProjectionParams.z - _ProjectionParams.y);
    15.  
    16. if (sceneDepth > objDepth)
    17. {
    18.     o.depth = objDepth/(_ProjectionParams.z - _ProjectionParams.y);
    19.     o.col = half4 ((half3)(objDepth/1000), 1);
    20. }
    21. else
    22. {
    23.     o.depth = sceneDepth;
    24.     o.col = half4 ((half3)(sceneDepth/1000), 1);
    25. }
    26. #endif
    27. return o;
    That is the part where I decide what to write in the fragment program. So, when writing these grayscale values to the buffer it should basically work. But the result of the code above looks exactly as without writing to the depth buffer, strangely:(

    I suppose it has something to do with the limitation described here, where ZWriting from fragment shaders is not supported due to DirectX11 having native depth texture capabilities. But, how did you do it in UBER then? Any way I can write those vertex modifications to the depth buffer properly?

    Thanks,
    Seneral
     
  30. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    If everything you need is to modify vertex positions in vert() function then you need no special rocket science here like computing the depth offset in fragment program and writing into depth buffer. Simply I can tell from your DepthWriteFragOut o; part is that your shader is:

    1. not surface shader (we can't manage direct output structure there AFAIK)
    2. it is forward shader

    In your case you probably need to modify depth buffer for sake of some postFX, am I right ? In such case you'd need to know that forward shaders use "shadow caster" passes to make it. modify this pass then or look into internal-dpeth shader which renders forward objects. If your shader doesn't have replacement tag and you don't have the same replacement tag in internal-depth shader, default unity's pass (just opaque w/o vertex modifications) is used.

    So - in your case, if you don't really need to modify what's written into depth buffer at per pixel level, but only by modifying vertices in vert() function, above hints should lead you into solution - either proper shadow caster pass definition in your shader (which modify vertices the same way you do in your regular pass) or tweaking/customizing internal-depth shader used by Unity to "grab" depths in forward rendering path.

    Tom
     
  31. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Actually, the shader is the Standard shader, where I just added a shader_feature:) That means there are shadowcaster passes, but there's also a deferred version I will need to modify accordingly (does this have a shadowcaster pass?)...
    Looking at the replacement tags might work, though I don't know if I can modify the Standard shader as much without breaking something:) But I'm delighted it's easier than what I've made so far, thanks!
     
  32. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Wow, thank you so much, it works with the shadow pass:)
    Screenshot10.jpg
    In UnityStandardShadow.cginc, First we need to make the HeightMap avaiable. So, add #include UnityStandardInput.cginc at the top and comment out all duplicate variables found in the file. Then, in vertShadowCaster, add these at the end:
    Code (csharp):
    1.  
    2.     #if defined(_HEIGHTOFFSET) // --HEIGHTOFFSETFEATURE--
    3.     v.vertex.y += tex2Dlod (_HeightMap, float4 (v.uv0.xy, 0.0, 0.0)).r * _Height;
    4.     opos = mul(UNITY_MATRIX_MVP, v.vertex);
    5.     #endif
    6.  
    Of course, we need to add the _HEIGHTOFFSET shader_feature in both LOD (300 & 150) Shadow passes. Don't know if that works in deferred though...
     
  33. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    In forward (and in deferred for shaders that renders at the end in forward) - shadow caster pass is used for both:
    1. preparing depth texture (Unity need this for sake of shadow _collecting_)
    2. for actual shadow casting - this means the pass is fired "from the light" perspective to preapre shadow maps (which are basically depth textures)

    In deferred shadow caster pass is used for shadow casting only (to prepare shadow maps). Depth buffer is made "on the fly" while deferred objects appear in g-buffers. Depth values are not needed on early stage in deferred (for shadows because shadows are solved by separate shader pass - that's why we can't just turn off shadow collecting per object because it's solved in screen space).

    So - when you've got working shadow caster pass made in standard shader, you just put the same vertex displacement in vert function for deferred - look into UnityStandardCore.cginc - there are forward and deferred (with meta - for realtime GI) passes decalred - just locate deferred vert function (the name of function you can find by #pragma vertex from .shader deferred part) and put your displacement there the same way you did in shadow caster. That's it - should "just work"

    ATB, Tom
     
  34. Seneral

    Seneral

    Joined:
    Jun 2, 2014
    Posts:
    1,206
    Yeah already did that, it does work, finally:D Thanks!
     
  35. spkim921

    spkim921

    Joined:
    Mar 30, 2017
    Posts:
    2
    I am working on getting depth from screen I used the shader which was implement from other people. I am new in depth Shader. Would you mind sharing the code or what is wrong on this code?

    Code (CSharp):
    1. Shader "DepthShader" {
    2.     SubShader{ // Unity chooses the subshader that fits the GPU best
    3.         Pass{ // some shaders require multiple passes
    4.         ZWrite On
    5.         CGPROGRAM // here begins the part in Unity's Cg
    6.  
    7. #pragma vertex vert
    8. #pragma fragment frag
    9. #include "UnityCG.cginc"
    10.         struct v2f
    11.     {
    12.         float4 position : POSITION;
    13.         float4 projPos : TEXCOORD1;
    14.     };
    15.  
    16.     v2f vert(float4 vertexPos : POSITION)
    17.     {
    18.         v2f OUT;
    19.         OUT.position = mul(UNITY_MATRIX_MVP, vertexPos);
    20.         OUT.projPos = ComputeScreenPos(OUT.position);
    21.         return OUT;
    22.     }
    23.  
    24.     //camera depth texture here
    25.     uniform sampler2D _CameraDepthTexture; //Depth Texture
    26.     void frag(v2f IN, out float4 color:COLOR, out float depth : DEPTH) // fragment shader
    27.     {
    28.         color = float4(0);
    29.         // use eye depth for actual z...
    30.         depth = LinearEyeDepth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(IN.projPos)).r);
    31.  
    32.         //or this for depth in between [0,1]
    33.         //depth = Linear01Depth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(IN.projPos)).r);
    34.     }
    35.  
    36.     ENDCG // here ends the part in Cg
    37.     }
    38.     }
    39. }
    My result is look like below pink. Do I need add component in CAMERA?

     

    Attached Files:

  36. tomaszek

    tomaszek

    Joined:
    Jun 18, 2009
    Posts:
    3,862
    Pink means rather that your shader can't compile due to errors. Correct semapntic for depth is not DEPTH any longer. Try SV_Depth for depth and SV_Target instead of COLOR. I haven't copied your shader to see what's wrong though (might try after Easter). I'm not sure what's the purpose of the shader. Sometimes things can be solved without writing into depth which is kind of "last resort" solution as it blocks most of GPU optimization (think - shaders begin to work slow).

    Tom
     
  37. Megabyteceer

    Megabyteceer

    Joined:
    Mar 23, 2018
    Posts:
    1
    This fragment works for me:
    ```
    void frag (v2f i, out half4 color:SV_Target, out float depth : SV_Depth)
    {
    color = tex2D(_MainTex, i.uv);
    depth = color.a;
    }
    ```
     
    bobbaluba likes this.
  38. chenzhizhao

    chenzhizhao

    Joined:
    Oct 24, 2019
    Posts:
    1
    it's 2020, opengles 3.0 should have gl_fragDepth, it's it possible to do this on mobile phones?
     
  39. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Possible? Yes.

    Super duper slow? Also yes.
     
    Radivarig likes this.