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

Transparent Shader that blocks light as an opaque shader would

Discussion in 'Shaders' started by Xoduz, Mar 6, 2015.

  1. Xoduz

    Xoduz

    Joined:
    Apr 6, 2013
    Posts:
    135
    In Unity 4 I applied the following shader (originally from Answers, slightly modified) to objects that came between the player character and the main camera in order to make said object transparent - without affecting the lighting/shadows on either side of the object.

    Code (CSharp):
    1. Shader "Transparent/DiffuseWithShadow" {
    2.     Properties {
    3.         _Color ("Main Color", Color) = (1,1,1,1)
    4.         _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    5.     }
    6.     SubShader {
    7.         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
    8.         UsePass "VertexLit/SHADOWCOLLECTOR"  
    9.         UsePass "VertexLit/SHADOWCASTER"  
    10.         LOD 200
    11.         Blend SrcAlpha OneMinusSrcAlpha
    12.  
    13.         CGPROGRAM
    14.         #pragma surface surf Lambert addshadow
    15.  
    16.         sampler2D _MainTex;
    17.         fixed4 _Color;
    18.    
    19.         struct Input {
    20.             float2 uv_MainTex;
    21.         };
    22.    
    23.         void surf (Input IN, inout SurfaceOutput o) {
    24.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    25.             o.Albedo = c.rgb;
    26.             o.Alpha = c.a;
    27.         }
    28.         ENDCG
    29.     }
    30.    
    31.     Fallback "Transparent/VertexLit"
    32. }
    However in Unity 5 the shader doesn't work the same way. Objects still go transparent, but they also allow light (and shadows) to pass through, which is not ideal. Is there any way I could get the shader working the same way in Unity 5?

    From what I've picked up from other threads in this subforum, I'm assuming the "Blend" line is really supposed to go into a Pass block, but I'm not sure how to modify this shader to achieve that, as I'm not well versed in shader programming. If anyone could give me a helping hand with this it would be appreciated.

    I've attached two screenshots showing the difference in how the shader works in Unity 4 and Unity 5.
    shader_unity4.jpg shader_unity5.jpg
     
  2. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Can upload a sample scene using just cubes to show the effect working in 4, I can't quite get a repro working with just what's posted above, I think it's probably something simple by the looks of things.
     
  3. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Actually, can you try changing this:

    #pragma surface surf Lambert addshadow

    ToL

    #pragma surface surf Lambert alpha:blend addshadow

    It might be the fix, but just a guess.
     
  4. Xoduz

    Xoduz

    Joined:
    Apr 6, 2013
    Posts:
    135
    I've attached a sample scene to this post.

    In Unity 4, the cube and the area in between the two walls in the scene will only be affected by the point light in between the walls, even if the wall closest to the camera is set to use the custom "DiffuseWithShadow" shader.

    In Unity 5, the cube and area in between the walls is affected by both lights.

    The difference between how it works and how it should ideally work in Unity 5 can be seen by switching the shader on the wall closest to the camera between the standard shader and the included custom shader. Ideally, the custom shader should affect light and shadow in the same way as the standard shader does.
     

    Attached Files:

    Last edited: Mar 8, 2015
  5. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Cool, I won't get a chance to look tonight I don't think but I'll get back to you in the morning.
     
  6. Xoduz

    Xoduz

    Joined:
    Apr 6, 2013
    Posts:
    135
    I tried #pragma surface surf Lambert alpha:blend addshadow, though by itself not much changed. However when I tried this and commented out the UsePass "VertexLit/SHADOWCOLLECTOR" line at the same time, I almost got what I wanted, with the exception of the transparent wall now being too much affected by lightsources. The brighter the light shining on it, the harder it is to see through it (because it reflects the light?). Hm.
     
  7. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    I think it should be easy enough to fix, but I've not got Unity 4 on this machine, leave it with me and I'll let you know by tomorrow.
     
    Xoduz likes this.
  8. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Here you go, on mine it doesn't update the shadows instantly, switching emulation to Shader Model 3.0 and back gets it to re-do the shadows and you should see it working then:


    Code (CSharp):
    1. Shader "Transparent/DiffuseWithShadow"
    2. {
    3. Properties {
    4.     _Color ("Main Color", Color) = (1,1,1,1)
    5.     _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
    6. }
    7.  
    8. SubShader {
    9.     Tags {"Queue"="Transparent-1" "IgnoreProjector"="True" "RenderType"="Transparent"}
    10.     LOD 200
    11.    
    12. CGPROGRAM
    13. #pragma surface surf Lambert alpha:blend addshadow
    14.  
    15. sampler2D _MainTex;
    16. fixed4 _Color;
    17.  
    18. struct Input {
    19.     float2 uv_MainTex;
    20. };
    21.  
    22. void surf (Input IN, inout SurfaceOutput o) {
    23.     fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    24.     o.Albedo = c.rgb;
    25.     o.Alpha = c.a;
    26. }
    27. ENDCG
    28.  
    29.  
    30.  
    31.     // Pass to render object as a shadow caster
    32.     Pass {
    33.         Name "ShadowCaster"
    34.         Tags { "LightMode" = "ShadowCaster" }
    35.        
    36. CGPROGRAM
    37. #pragma vertex vert
    38. #pragma fragment frag
    39. #pragma multi_compile_shadowcaster
    40. #include "UnityCG.cginc"
    41.  
    42. struct v2f {
    43.     V2F_SHADOW_CASTER;
    44. };
    45.  
    46. v2f vert( appdata_base v )
    47. {
    48.     v2f o;
    49.     TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    50.     return o;
    51. }
    52.  
    53. float4 frag( v2f i ) : SV_Target
    54. {
    55.     SHADOW_CASTER_FRAGMENT(i)
    56. }
    57. ENDCG
    58.  
    59.     }
    60.  
    61.  
    62. }
    63.  
    64. }
    65.  
     
  9. Xoduz

    Xoduz

    Joined:
    Apr 6, 2013
    Posts:
    135
    Thank you, that seems to be a step (or leap) in the right direction :) I seem to be having some issues with it, though.
    • Whenever I apply the transparent shader to a wall to make it transparent, it appears to be random whether objects behind the the wall are affected by lights from the other side of that wall. Sometimes they are, sometimes they're not. Shadows from shadowcasting objects also pass through the walls in those cases.
    • Directional lights and spot lights always seem to affect objects behind transparent walls, no matter what?
    Including two screenshots. First seems to work as intended, second does not. Taken in same play session, just by moving camera to re-apply the transparent shader to the wall when they obscure the player:
    : shader_working.jpg shader_notworking.jpg
     
  10. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Hmmm, this might be a bug. Let me have a bit more of a look, it's either because we need to write to the depth buffer and maybe change the queue, or it is just a bug. I'll come back to you soon.
     
  11. DemeDev

    DemeDev

    Joined:
    Oct 18, 2017
    Posts:
    7
    I found a solution that worked for me. It's very simple.
    1. Duplicate your transparent wall (you can make it child of your original wall).
    2. Remove the new wall's collider because you just want the mesh.
    3. Now in the mesh renderer turn cast shadows to "shadows only", it will make the new wall invisible but it will block the light and shadows.
    The original wall will keep transparent and will work as before.

    I know it's 2021 but I had this problem today and I spent like 1-2 hours finding a solution. I hope it works for you.
     
    minoaimino and lichehorde like this.
  12. lichehorde

    lichehorde

    Joined:
    Feb 10, 2013
    Posts:
    1
    Thanks! This helped me out. :) For others who arrive here, bullet point #3 is referring to the original MeshRenderer, not the duplicated one from bullet point #1.