Search Unity

Shadow catcher or Matte shadow shader

Discussion in 'VR' started by behram, Jul 1, 2016.

  1. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Hello,
    Is anyone using a Shadow Catcher shader in any of their Hololens projects ?
    Since Mixed Reality is being supported by Unity I have a feeling more people will ask for such functionality.Especially those of us coming from VFX.

    The image below illustrates what I'm trying to describe:
    http://www.roadtovr.com/wp-content/uploads/2015/01/hololens-vid-0.jpg

    The image might be an artistic impression and a Post Processed render. Those shadows really ground / Anchor the hologram onto the table.

    A video in blender that illustrates the process:


    Can we have a shader that only renders shadows being cast on it (ideally a plane) and renders everything else transparent ?

    Thank you,
    b
     

    Attached Files:

    Last edited: Dec 22, 2016
  2. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    Hi behram,

    Unity has built in support for shadows. There are 2 parts involved in getting shadows to render. You need a shadow caster like the holographic rocket in your picture. You also need a shadow receiver. You probably want the spatial mesh to be a shadow receiver in your case.

    All holograms must have a MeshRenderer component in order to be rendered. If you want a hologram to be a shadow caster, you must make sure it's "Cast Shadows" property is set to "On" like so,



    Next, you need to cast the shadow onto something. So on your spatial mesh, you need to make sure the "receive shadows" property is set to true like so,



    Once you have done this, you will get something like the following if you are using the standard shader on your ground mesh.



    Since the HoloLens uses an additive display, the color black is basically transparent. So you may need to play with the actual color of your shadow otherwise you may not see it. Here is a shader, that I put together, that allows you to adjust the shadow color of your shadow receiver. Just create a material and set it to use the following shader. Then apply the material to your ground object.

    Code (CSharp):
    1. Shader "Unlit/VertColorWithShadow"
    2. {
    3.     Properties
    4.     {
    5.         _MainColor("Main Color", COLOR) = (0,0,0,1)
    6.         _ShadowColor("Shadow Color", COLOR) = (1,0,0,1)
    7.     }
    8.  
    9.     SubShader
    10.     {
    11.         Tags { "RenderType"="Opaque" }
    12.         LOD 100
    13.  
    14.         Pass
    15.         {
    16.             Tags {"LightMode" = "ForwardBase"}
    17.  
    18.             CGPROGRAM
    19.             #pragma multi_compile_fwdbase
    20.             #pragma vertex vert
    21.             #pragma fragment frag
    22.  
    23.             #include "UnityCG.cginc"
    24.             #include "AutoLight.cginc"
    25.  
    26.             float4 _MainColor;
    27.             float4 _ShadowColor;
    28.  
    29.             struct appdata
    30.             {
    31.                 float4 vertex : POSITION;
    32.             };
    33.  
    34.             struct v2f
    35.             {
    36.                 float4 pos : SV_POSITION;
    37.                 float4 mainColor : COLOR;
    38.                 LIGHTING_COORDS(1,2)
    39.             };
    40.          
    41.             v2f vert (appdata v)
    42.             {
    43.                 v2f o;
    44.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    45.                 o.mainColor = _MainColor;
    46.  
    47.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    48.  
    49.                 return o;
    50.             }
    51.          
    52.             fixed4 frag (v2f i) : SV_Target
    53.             {
    54.                 fixed atten = 1.0 - LIGHT_ATTENUATION(i);
    55.                 fixed3 shadowColor = atten * _ShadowColor.rgb;
    56.                 fixed4 finalColor = i.mainColor + fixed4(shadowColor, 1.0);
    57.  
    58.                 return finalColor;
    59.             }
    60.             ENDCG
    61.         }
    62.  
    63.         // Pass to render object as a shadow caster
    64.         Pass
    65.         {
    66.             Name "ShadowCaster"
    67.             Tags { "LightMode" = "ShadowCaster" }
    68.      
    69.             ZWrite On ZTest LEqual Cull Off
    70.  
    71.             CGPROGRAM
    72.             #pragma vertex vert
    73.             #pragma fragment frag
    74.             #pragma multi_compile_shadowcaster
    75.             #include "UnityCG.cginc"
    76.  
    77.             struct v2f {
    78.                 V2F_SHADOW_CASTER;
    79.             };
    80.  
    81.             v2f vert( appdata_base v )
    82.             {
    83.                 v2f o;
    84.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    85.                 return o;
    86.             }
    87.  
    88.             float4 frag( v2f i ) : SV_Target
    89.             {
    90.                 return float4(1.0, 1.0, 1.0, 1.0);
    91.             }
    92.             ENDCG
    93.         }
    94.     }
    95. }
    96.  
    Depending on your settings, you will get something like this

     
    Nick_Counter and behram like this.
  3. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Thanks Brandon,
    The shader works in the viewport (pic attached) but not on the device.
    I am using the AstroMan asset in the Model Explorer example scene and a simple 3D plane object right below the model.

    Note:
    There is a default script on the Astroman ( SetRendererSettings ) which iterates through child objects and switches off MeshRenderer cast & receive shadow settings. So I have commented out those lines just in case.

    Ok I will have to learn how to attach a shader to the Spatial Mesh that is generated at runtime. Let me look around the forums and docs and get back if I still cant hack this.

    fwiw thebanjomatic from the MS forums also pointed me to this Doc:
    https://developer.microsoft.com/en-us/windows/holographic/designing_for_mixed_reality

    I'm sharing this post / shader with the Unity community in general. because if it works...it's a indispensable utility to have.
    Thanks for creating it.
    Cheers,
    b
     

    Attached Files:

  4. ivodopiviz

    ivodopiviz

    Joined:
    Nov 8, 2014
    Posts:
    1
    Sorry for bringing up an old project, but I'm in trying to get working a similar scheme but without using Hololens. What would I need to change to get this working in a normal scene?

    The idea is to get the shadows casted over a 2D object but using a 3D invisible plane as reference for the perspective.

    Thanks in advance!
     
  5. smoluck

    smoluck

    Joined:
    Mar 8, 2016
    Posts:
    25
    Hi, i'm using Hololens since a few days, and i can say that the Shader gaved by
    BrandonFogerty works well under Hololens. Except that my shadows should be close to white.... sounds weird. With that additive display tech, it's not totally impossible to represent shadows or reable text, because all the black values inside the display will be completely wipe out like an Alpha.

    that's really making me crying, because the first advertising (commercial) video presentation just show off things and graphics that you can't get in reality (mixed Reality by the fact)
     
  6. cvasquez-coiron

    cvasquez-coiron

    Joined:
    Nov 10, 2014
    Posts:
    22
    Hi Brandon,
    Thank you very much for sharing this shader.
    It works perfectly fine in the Hololens device look-through AR display.
    BUT when I record a video using the "Take Video" option on Microsoft HoloLens tool, the Plain object is shown below the shadow... What would you recommend to do to be able to record a video using this shadow caster?

    Thank you very much!