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

[Solved] Transparency issue with backside of double-sided shader

Discussion in 'Shaders' started by JonRurka, Apr 23, 2020.

  1. JonRurka

    JonRurka

    Joined:
    Nov 19, 2012
    Posts:
    35
    Hello, I'm creating procedurally generated grass for my terrain engine. I construct my mesh in a compute shader, and pass the vertex data to my grass shader. My shader looks alright from one side (the side with where the front faces are facing the camera), but from the other side, something strange is happening with the transparency. Any ideas as to what I'm not doing right for the reverse sides?

    Front side (Pretty!):


    Back side (Weird...):



    shader:
    Code (CSharp):
    1. Shader "Custom/PlantShader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture", 2D) = "gray" {}
    6.         _Ambience("Ambience", Float) = 1
    7.     }
    8.     SubShader
    9.     {
    10.         Tags{ "Queue" = "Transparent" "RenderType" = "TransparentCutout" }
    11.         Blend SrcAlpha OneMinusSrcAlpha
    12.         LOD 200
    13.         ZWrite Off
    14.  
    15.         Pass
    16.         {
    17.             Cull Off
    18.             CGPROGRAM
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.  
    22.            #pragma target 5.0
    23.             #include "UnityCG.cginc"
    24.             #include "Lighting.cginc"
    25.  
    26.            // make fog work
    27.            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight multi_compile_fog
    28.  
    29.            // shadow helper functions and macros
    30.            #include "AutoLight.cginc"
    31.  
    32.            struct VertexData {
    33.                float3 Vertex;
    34.                float2 UV;
    35.                float3 Normal;
    36.            };
    37.  
    38.            uniform StructuredBuffer<VertexData> _Vertex;
    39.  
    40.            float _Ambience;
    41.  
    42.            struct v2f
    43.            {
    44.                float2 uv : TEXCOORD0;
    45.                UNITY_FOG_COORDS(1)
    46.                SHADOW_COORDS(2) // put shadows data into TEXCOORD2
    47.                float4 pos : SV_POSITION;
    48.                fixed3 diff : COLOR0;
    49.                fixed3 ambient : COLOR1;
    50.                fixed3 diff_rev : COLOR2;
    51.                fixed3 ambient_rev : COLOR3;
    52.                float4 worldPos : TEXCOORD3;
    53.  
    54.                half3 worldNormal : NORMAL;
    55.                half3 worldNormal_rev : NORMAL1;
    56.            };
    57.  
    58.            sampler2D _MainTex;
    59.            float4 _MainTex_ST;
    60.  
    61.             v2f vert(uint id : SV_VertexID)
    62.             {
    63.                v2f o;
    64.  
    65.                float4 in_v = float4(_Vertex[id].Vertex, 1);
    66.  
    67.                o.pos = UnityObjectToClipPos(in_v);
    68.                o.uv = TRANSFORM_TEX(_Vertex[id].UV, _MainTex);
    69.                UNITY_TRANSFER_FOG(o, o.pos);
    70.  
    71.                o.worldPos = mul(unity_ObjectToWorld, in_v);
    72.  
    73.                half3 worldNorm = UnityObjectToWorldNormal(_Vertex[id].Normal);;
    74.              
    75.  
    76.                // diffuse and ambient lighting.
    77.                half nl = max(0, dot(-worldNorm, _WorldSpaceLightPos0.xyz));
    78.                o.diff = nl * _LightColor0.rgb;
    79.                o.ambient = ShadeSH9(half4(-worldNorm, 1)) + _Ambience;
    80.                o.worldNormal = -worldNorm;
    81.  
    82.  
    83.                nl = max(0, dot(worldNorm, _WorldSpaceLightPos0.xyz));
    84.                o.diff_rev = nl * _LightColor0.rgb;
    85.                o.ambient_rev = ShadeSH9(half4(worldNorm, 1)) + _Ambience;
    86.                o.worldNormal_rev = worldNorm;
    87.  
    88.                // compute shadows data
    89.                TRANSFER_SHADOW(o)
    90.  
    91.                return o;
    92.             }
    93.  
    94.             fixed4 frag(v2f i, half facing : VFACE) : SV_Target
    95.             {
    96.                // sample the texture
    97.                //fixed4 col = fixed4(0.5, 0.5, 0.5, 0.5);
    98.                fixed4 col = tex2D(_MainTex, i.uv);
    99.  
    100.                fixed3 diff = i.diff;
    101.                fixed3 ambient = i.ambient;
    102.                half3 normal = i.worldNormal;
    103.  
    104.                if (facing < 0.5) {
    105.                   normal = i.worldNormal_rev;
    106.                   diff = i.diff_rev;
    107.                   ambient = i.ambient_rev;
    108.                }
    109.  
    110.                // compute shadow attenuation (1.0 = fully lit, 0.0 = fully shadowed)
    111.                fixed shadow = SHADOW_ATTENUATION(i);
    112.                // darken light's illumination with shadow, keep ambient intact
    113.                fixed3 lighting = diff * shadow + ambient;
    114.                col.rgb *= lighting;
    115.  
    116.                // apply fog
    117.                //UNITY_APPLY_FOG(i.fogCoord, col);
    118.                return col;
    119.             }
    120.             ENDCG
    121.         }
    122.     }
    123. }
     
    Last edited: Apr 23, 2020
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Transparent meshes have to be sorted back to front to render correctly. That's how real time rendering ensures transparent objects render correctly.
    https://en.wikipedia.org/wiki/Painter's_algorithm

    The alternative would be to make your shader use alpha testing or alpha to coverage instead of transparency.
     
    JonRurka likes this.
  3. JonRurka

    JonRurka

    Joined:
    Nov 19, 2012
    Posts:
    35
    Switching to alpha testing and adding "AlphaToMask On" worked. Really like how it came out after applying post-process anti-aliasing:



    Thank you bgolus
     
  4. GiorgioK

    GiorgioK

    Joined:
    Oct 20, 2021
    Posts:
    34
    I understand that almost 2 years have passed since the last answer, but I want to ask a few questions to the author of the topic.
    1) What render pipeline are you using (BIRP / URP / HDRP) ?
    2) Now I have a similar problem with grass and rope foliage and your shader from the first post does not work for me at all!
    There are no compilation errors and the grass is completely transparent (I use BIRP).
    3) Does your grass from the last screenshot receive shadows from other objects? Does she cast a shadow?
    Can you show the final version of your shader for the two-sided grass here?