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

Is there a way to get the standard fade / transparent shader to recieve shadows?

Discussion in 'Shaders' started by NerdRageStudios, Jun 24, 2017.

  1. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    As the title suggests, I am trying to get the standard shader to recieve shadows on a transparent object, but this only works in cutout.

    Is there an easy way to achieve this? I tried to use some custom shaders to do this, but I also need to retain the normal mapping too.

    I'm not great with shaders, and was just hoping there might be an easy way to add the recieving of shadows to the standard shader code?
     
    makaka-org likes this.
  2. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,492
    I don't know enough but it must be the render queue, transparent are special beast as they F*** with depth buffer, therefore nothing that is rendered after them is rendering correctly (ie don't show through them), hence we render transparency after everything else has done it's thing. So maybe the shadow pass happen only with opaque shader or before the transparent queue.
     
  3. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    Hey thanks for the info :) I was just reading a long thread on this, and it seems its not trivial at all. Cast shadows seems to be the main pain point, but I only want to recieve, which I imagine must be considerably easier.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Casting shadows from transparent objects is supported by Unity, it's already a built in feature of the Standard shader for example.

    Receiving shadows is also quite easy to do, all of the code for it is already in the shaders, but Unity simply does not pass the required shadow map information to any material rendered in the transparent queues, so it's effectively impossible to have transparent shadow receivers.

    The closest to a "shader only" work around is to set the queue to something less than 2500, but this means the object will be sorted front to back instead of back to front which will look wrong if you have multiple of these objects overlapping. Also the way Unity handles directional light shadows means either the transparent object receives a shadow or the opaque surfaces behind it, but not both.

    The other "trick" is to render out your own shadow maps and use those instead. That can be expensive as then you're rendering shadow maps for the same stuff twice, so some people just entirely replace Unity's shadows and lighting with their own.

    More recently it's been possible to copy the shadow maps to another texture, and there's a round about way to get the other data needed. But this just means you don't have to render them yourself. You still effectively have to rewrite the existing shaders to make use of the data.

    All of these problems should hopefully be solved sometime in the next year or two when Unity finally releases their new renderer officially.
    https://github.com/Unity-Technologies/ScriptableRenderLoop
     
    RodrigoSeVeN likes this.
  5. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,492
    To expend on the shadow problem, basically shadow are created by rendering a depth buffer from the light perspective, then in the camera space we triangulate each rendered pixel to see if it's behind or not the light depth to create shadows.

    This has many implication, if you render transparent objects, they will write to the "light depth", hence objects behind them will have shadow despite being behind the transparent objects, in a way the transparent object will behave as if it is opaque BUT receive shadows.

    So you need to render:
    - light depth with only opaque,
    - then opaque,
    - then transparent.

    But transparent will not cast anything, don't expect transparent shadows. Also you might need a specific shader to handle transparency's shadow, because it shouldn't be opaque.

    But in the end, I think reflection would have done the same job, if you have a cubemap well place. But I haven't tried this.
     
    bgolus likes this.
  6. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    Thank you both for this information, its really helpful and I have had to do a lot of reading up on this. I've tried to adapt the shader to use opaque, but to be honest this is way above my level of comprehension, so I suspect I will have to try another way of doing this inside the art assets to at least come close to the level that I am hoping to achieve.

    Thanks for the help... at some point I am going to have to learn how to write shaders, i've tried following some tutorials online but I find it hard to find ones that explain the basics in an easy way, especially to someone who is new to the shader language
     
  7. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,539
    It appears to already be an exposed feature in Unity 2017.1, so even sooner than that I guess. It's primarily a matter of documentation and someone putting in the time to do it now. *wink wink* @tatoforever
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    A good start:
    http://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-in-unity3d/
    And then if you want to dig a bit deeper:
    http://catlikecoding.com/unity/tutorials/
    There are some official Unity video tutorials on writing very basic shaders, and many unofficial ones as well.

    The code as been viewable publicly since around 5.5, if not prior, and has worked since the 5.6 betas, though they keep changing their APIs so the latest version doesn't usually work with the public releases yet. But soon ...
     
  9. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    Hey @bgolus thanks for the links, I've just read them through and now that makes a lot more sense to me now, I wrote my own shader to try and get the effect I am after, as I believe that rendering to opaque might give me the effect i am after. It doesnt work of course, but I suspect that its my code, but I'll keep plugging on. thanks for the help :)
     
  10. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    I feel like I'm so close, but I cannot get this to work properly. Here is my shader code, I now have shadows, with normal mapping and transparency. However, when I try to render to opaque I get the following black weirdness showing up. I must be doing something dumb here, but I have no idea how to fix this...



    Code (CSharp):
    1. Shader "Custom/Sprite"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _BumpMap ("Normalmap", 2D) = "bump" {}
    7.         _BumpIntensity("NormalMap Intensity", Float) = 1
    8.         _Color ("Tint", Color) = (1,1,1,1)
    9.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags
    15.         {
    16.             "Queue"="Opaque"
    17.             "IgnoreProjector"="True"
    18.             "RenderType"="Transparent"
    19.             "PreviewType"="Plane"
    20.             "CanUseSpriteAtlas"="True"
    21.         }
    22.  
    23.         Cull Off
    24.         Lighting Off
    25.         ZWrite Off
    26.         Blend One OneMinusSrcAlpha
    27.  
    28.         CGPROGRAM
    29.         #pragma surface surf Lambert vertex:vert nofog keepalpha addshadow
    30.         #pragma multi_compile _ PIXELSNAP_ON
    31.  
    32.         sampler2D _MainTex;
    33.         sampler2D _BumpMap;
    34.         fixed4 _Color;
    35.         fixed _BumpIntensity;
    36.  
    37.         struct Input
    38.         {
    39.             float2 uv_MainTex;
    40.             float2 uv_BumpMap;
    41.             fixed4 color;
    42.         };
    43.        
    44.         void vert (inout appdata_full v, out Input o)
    45.         {
    46.             #if defined(PIXELSNAP_ON)
    47.             v.vertex = UnityPixelSnap (v.vertex);
    48.             #endif
    49.            
    50.             UNITY_INITIALIZE_OUTPUT(Input, o);
    51.             o.color = v.color * _Color;
    52.         }
    53.  
    54.         void surf (Input IN, inout SurfaceOutput o)
    55.         {
    56.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    57.             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    58.             _BumpIntensity = 1 / _BumpIntensity;
    59.             o.Normal.z = o.Normal.z * _BumpIntensity;
    60.             o.Albedo = c.rgb * c.a;
    61.             o.Alpha = c.a;
    62.         }
    63.         ENDCG
    64.     }
    65.  
    66. Fallback "Transparent/VertexLit"
    67. }
    68.  
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    You probably want to use alpha test, which you can implement either using the alphatest surface attribute, as mentioned here:
    https://docs.unity3d.com/Manual/SL-SurfaceShaders.html

    You'll want to define a _Cutoff property and then use alphatest:_Cutoff in the #pragma surface line instead of keepalpha.

    You'll also want to use "Queue"="AlphaTest" and Fallback "Transparent/Cutout/VertexLit"
     
    StenCG, MrThee and NerdRageStudios like this.
  12. NerdRageStudios

    NerdRageStudios

    Joined:
    Nov 1, 2013
    Posts:
    167
    Thanks so much for this, it worked a treat, finally I have the desired effect!

    For anyone else attempting something like this, here is the final shader code for transparent sprites, with normal maps to recieve shadows.

    Code (CSharp):
    1. Shader "Custom/Sprite"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _BumpMap ("Normalmap", 2D) = "bump" {}
    7.         _BumpIntensity("NormalMap Intensity", Float) = 1
    8.         _Cutoff("Alpha Cutoff", Range(0,1)) = 0.5
    9.         _Color ("Tint", Color) = (1,1,1,1)
    10.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    11.     }
    12.  
    13.     SubShader
    14.     {
    15.         Tags
    16.         {
    17.             "Queue"="AlphaTest"
    18.             "IgnoreProjector"="True"
    19.             "RenderType"="Transparent"
    20.             "PreviewType"="Plane"
    21.             "CanUseSpriteAtlas"="True"
    22.         }
    23.  
    24.         Cull Off
    25.         Lighting Off
    26.         ZWrite Off
    27.         Blend One OneMinusSrcAlpha
    28.  
    29.         CGPROGRAM
    30.         #pragma surface surf Lambert vertex:vert nofog alphatest:_Cutoff addshadow
    31.         #pragma multi_compile _ PIXELSNAP_ON
    32.  
    33.         sampler2D _MainTex;
    34.         sampler2D _BumpMap;
    35.         fixed4 _Color;
    36.         fixed _BumpIntensity;
    37.  
    38.         struct Input
    39.         {
    40.             float2 uv_MainTex;
    41.             float2 uv_BumpMap;
    42.             fixed4 color;
    43.         };
    44.        
    45.         void vert (inout appdata_full v, out Input o)
    46.         {
    47.             #if defined(PIXELSNAP_ON)
    48.             v.vertex = UnityPixelSnap (v.vertex);
    49.             #endif
    50.            
    51.             UNITY_INITIALIZE_OUTPUT(Input, o);
    52.             o.color = v.color * _Color;
    53.         }
    54.  
    55.         void surf (Input IN, inout SurfaceOutput o)
    56.         {
    57.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color;
    58.             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
    59.             _BumpIntensity = 1 / _BumpIntensity;
    60.             o.Normal.z = o.Normal.z * _BumpIntensity;
    61.             o.Normal = normalize((half3)o.Normal);
    62.             o.Albedo = c.rgb * c.a;
    63.             o.Alpha = c.a;
    64.         }
    65.         ENDCG
    66.     }
    67.  
    68. Fallback "Transparent/Cutout/VertexLit"
    69. }
    70.  
    Tada :

     
  13. unity_vhGUvHX085wnqw

    unity_vhGUvHX085wnqw

    Joined:
    Nov 10, 2017
    Posts:
    1
    Thank you very much NerdRageStudios, bravo !

    It's exactly the effect I need. :=)
     
    NerdRageStudios likes this.
  14. Mikhail94

    Mikhail94

    Joined:
    Dec 22, 2015
    Posts:
    35
  15. mradfo21

    mradfo21

    Joined:
    May 16, 2013
    Posts:
    194
    Alas, if only this worked on alpha fade and not just alpha test. It's crazy to think you'd want transparent objects and never want them to receive shadows
     
    DChap and CloudyVR like this.
  16. vlaslive

    vlaslive

    Joined:
    Oct 11, 2015
    Posts:
    1
  17. kartolina17

    kartolina17

    Joined:
    Nov 11, 2020
    Posts:
    2
    Thank you, how could this be changed so it will for spotlights as well?