Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Dithering transparency shader with shadow

Discussion in 'Shaders' started by Zaq, Mar 10, 2022.

  1. Zaq

    Zaq

    Joined:
    Jan 13, 2014
    Posts:
    2
    This is a shader created by ocias but the shadow does not dither with the object. Any idea how to make it works? Thanks!
    Code (CSharp):
    1. // Standard shader with stipple transparency
    2. // by Alex Ocias - https://ocias.com
    3.  
    4. // based on an article by Digital Rune: https://www.digitalrune.com/Blog/Post/1743/Screen-Door-Transparency
    5.  
    6. Shader "Ocias/Standard (Stipple Transparency)" {
    7.     Properties{
    8.         _Color("Color", Color) = (1,1,1,1)
    9.         _ShadowColor("ShadowColor", Color) = (1,1,1,1)
    10.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    11.         _BumpMap("Bumpmap", 2D) = "bump" {}
    12.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    13.         _Metallic("Metallic", Range(0,1)) = 0.5
    14.         _Transparency("Transparency", Range(0,1)) = 1.0
    15.     }
    16.         SubShader{
    17.             Tags { "RenderType" = "Opaque" }
    18.             LOD 100
    19.  
    20.             CGPROGRAM
    21.             // Physically based Standard lighting model, and enable shadows on all light types
    22.             #pragma surface surf Standard fullforwardshadows addshadow
    23.  
    24.             // Use shader model 3.0 target, to get nicer looking lighting
    25.             #pragma target 3.0
    26.  
    27.             sampler2D _MainTex;
    28.             sampler2D _BumpMap;
    29.  
    30.             struct Input {
    31.                 float2 uv_MainTex;
    32.                 float2 uv_BumpMap;
    33.                 float4 screenPos;
    34.             };
    35.  
    36.             half _Glossiness;
    37.             half _Metallic;
    38.             half _Transparency;
    39.             fixed4 _Color;
    40.             fixed4 _ShadowColor;
    41.  
    42.             void surf(Input IN, inout SurfaceOutputStandard o) {
    43.                 // Albedo comes from a texture tinted by color
    44.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    45.                 o.Albedo = c.rgb;
    46.                 // Metallic and smoothness come from slider variables
    47.                 o.Metallic = _Metallic;
    48.                 o.Smoothness = _Glossiness;
    49.                 o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    50.                 o.Alpha = c.a;
    51.  
    52.                 // Screen-door transparency: Discard pixel if below threshold.
    53.                 float4x4 thresholdMatrix =
    54.                 {  1.0 / 17.0,  9.0 / 17.0,  3.0 / 17.0, 11.0 / 17.0,
    55.                   13.0 / 17.0,  5.0 / 17.0, 15.0 / 17.0,  7.0 / 17.0,
    56.                    4.0 / 17.0, 12.0 / 17.0,  2.0 / 17.0, 10.0 / 17.0,
    57.                   16.0 / 17.0,  8.0 / 17.0, 14.0 / 17.0,  6.0 / 17.0
    58.                 };
    59.                 float4x4 _RowAccess = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
    60.                 float2 pos = IN.screenPos.xy / IN.screenPos.w;
    61.                 pos *= _ScreenParams.xy; // pixel position
    62.                 clip(_Transparency - thresholdMatrix[fmod(pos.x, 4)] * _RowAccess[fmod(pos.y, 4)]);
    63.             }
    64.             ENDCG
    65.         }
    66.  
    67.         FallBack "Diffuse"
    68. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    There's a long standing bug with Surface Shaders that the screenPos is not set for the shadow caster pass, and it is instead set to all zeros. The only work around for this is to not use the built in screenPos and instead calculate it yourself with a custom vertex function.

    Code (csharp):
    1. #pragma surface surf Standard fullforwardshadows addshadow vertex:vert
    2.  
    3. struct Input {
    4.   float2 uv_MainTex;
    5.   // float2 uv_BumpMap; // you probably shouldn't use this unless you actually require a separate scale and offset for your bump texture, just reuse uv_MainTex for the normal map
    6.   float4 myScreenPos; // can't be called screenPos
    7. };
    8.  
    9. void vert (inout appdata_full v, out Input o)
    10. {
    11.   o.myScreenPos = ComputeScreenPos(UnityObjectToClipPos(v.vertex));
    12. }
    13.  
    14. // in the surf function
    15. float2 pos = IN.myScreenPos.xy / IN.myScreenPos.w;
     
    ruzgames likes this.
  3. sirleto

    sirleto

    Joined:
    Sep 9, 2019
    Posts:
    112
    funnily enough in unity 2021.3.5f1 i get the shadow dithered properly.

    (once i edited line 62 in OPs shader to not only use _Transparency but also the textures alpha channel)

    maybe i didnt understand the problem at hand? can you explain it to me bgolus? dont want to waste your time, just curious to learn what i am missing here.
     
  4. R4s3tsu

    R4s3tsu

    Joined:
    Mar 21, 2020
    Posts:
    12
    What about not surface shaders? I working on some and had the same problem, actually I never had this in ASE shader Editor, I guess because it's using ase_screenPos name. But when I'm trying to make custom shader, the problem appeared, and cannot figure out how to avoid, even if I use custom name.
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    I know this was asked a long time ago, but the original shader here does not have dithered shadows, or a dithered camera depth texture due to the
    screenPos
    value being broken, as stated above.

    This means the above shader, with the modification to like 62, looks like this:
    upload_2023-2-14_16-1-14.png
    Notice the shadow is a solid circle, and that you can't even see the shadow "thru" the object.

    With the suggested fix you get a properly dithered shadow, and you can see the shadow through the object.
    upload_2023-2-14_16-1-5.png

    For non-surface shaders, the "solution" is kind of the same... you need to pass the screen position from the vertex shader to the fragment shader and the code to do so is basically exactly the same as the example I posted in terms of the main steps.

    What you might be missing is you also need to actually write a custom shadow caster pass. You can't just throw an
    addshadow
    in there someplace as if you're writing a vertex fragment shader you're explicitly not making use of Unity's shader generation code, which is what Surface Shaders are.
     
    sirleto likes this.