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

vert/frag shader with shadows on offset vertices

Discussion in 'Shaders' started by CurlewStudios, Jun 29, 2018.

  1. CurlewStudios

    CurlewStudios

    Joined:
    May 22, 2016
    Posts:
    9
    I'm am writing an environment shader for my game. It uses an offset to the y-coordinate in the vertex function according to a heightmap to create some variation. However, this causes the environment to be displaced away from its shadows.

    It has previously added shadows by using

    Code (cg):
    1. SHADOW_COORDS(0)
    In the v2f struct

    Code (cg):
    1. TRANSFER_SHADOW(o)
    In the v2f function

    and.. in the fragment function:
    Code (cg):
    1. float atten = SHADOW_ATTENUATION(i);
    which was then multiplied over the other lighting.

    Lastly, the fallback was set to Standard.

    As I understand it I have to create a Shadowcaster and a Shadowreciever pass that use the same displacement as I do in my current pass, and remove the fallback shader. However, I couldn't find any examples of how to do it that wasn't over-complicated or just for surface shaders.

    Could anybody provide a simple example of how to create these passes with a world space vertex offset?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Only a shadow caster. The shadow receiver pass was removed in Unity 5.

    Unity's Vertex Fragment Shader Example page has a shader with a basic shadow caster pass.
    https://docs.unity3d.com/Manual/SL-VertexFragmentShaderExamples.html

    I'll copy the relevant bit here:
    Code (CSharp):
    1. Pass
    2.         {
    3.             Tags {"LightMode"="ShadowCaster"}
    4.  
    5.             CGPROGRAM
    6.             #pragma vertex vert
    7.             #pragma fragment frag
    8.             #pragma multi_compile_shadowcaster
    9.             #include "UnityCG.cginc"
    10.  
    11.             struct v2f {
    12.                 V2F_SHADOW_CASTER;
    13.             };
    14.  
    15.             v2f vert(appdata_base v)
    16.             {
    17.                 v2f o;
    18.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    19.                 return o;
    20.             }
    21.  
    22.             float4 frag(v2f i) : SV_Target
    23.             {
    24.                 SHADOW_CASTER_FRAGMENT(i)
    25.             }
    26.             ENDCG
    27.         }
    That's not doing any displacement, obviously, but it's trivial to add. Presumably your displacement looks something like this:

    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    float height = tex2Dlod(_HeightMap, float4(v.texcoord.xy, 0, 0)) * _HeightScale;
    worldPos.y += height;
    o.pos = mul(UNITY_MATRIX_VP, float4(worldPos, 1));


    To make that work with the shadow caster pass you just need to change one line.

    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    float height = tex2Dlod(_HeightMap, float4(v.texcoord.xy, 0, 0)) * _HeightScale;
    worldPos.y += height;
    v.vertex = mul(unity_WorldToObject, float4(worldPos, 1));


    Stick that before the TRANSFER_SHADOW_CASTER_NORMALOFFSET(o) in the shadow caster pass and you're done ... once you add the necessary uniform declaration for the height map and scale of course.
     
  3. CurlewStudios

    CurlewStudios

    Joined:
    May 22, 2016
    Posts:
    9
    Thank you bgolus! It worked out great.

    Another related question, after displacing the vertices, some of them now appear on the screen while the original was outside. This causes unity not to render the object even though it should be on screen after displacement.

    Is there a way to increese how big the culling box is (view frustrum?) so it keeps rendering them even when the original object (non-displaced) would be outside?

    I read somewhere that the solution was to disable this culling but that doesn't seem like a good idea..
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
  5. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    Code (CSharp):
    1. [code=CSharp]Shader "SimplestInstancedShader"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1, 1, 1, 1)
    6.         _heightMap("heightMap", 2D) = "white" {}
    7.     _MainTex("_MainTex", 2D) = "white" {}
    8.     }
    9.  
    10.         SubShader
    11.     {
    12.         Tags{ "Queue" = "Geometry""LightMode" = "ForwardBase" }
    13.         LOD 100
    14.  
    15.         Pass
    16.     {
    17.         CGPROGRAM
    18. #pragma vertex vert
    19. #pragma fragment frag
    20. #pragma multi_compile_instancing
    21.  
    22. #pragma multi_compile_fwdbase
    23. #pragma fragmentoption ARB_precision_hint_fastest
    24. #include "UnityCG.cginc"
    25. #include "AutoLight.cginc"
    26. #pragma multi_compile_shadowcaster
    27.         struct appdata
    28.     {
    29.         float4 vertex : POSITION;
    30.         float2 uv : TEXCOORD0;
    31.         UNITY_VERTEX_INPUT_INSTANCE_ID
    32.     };
    33.  
    34.     struct v2f
    35.     {
    36.         float4 pos : SV_POSITION;
    37.         float2 uv : TEXCOORD0;
    38.         LIGHTING_COORDS(4, 5)
    39.         UNITY_VERTEX_INPUT_INSTANCE_ID // necessary only if you want to access instanced properties in fragment Shader.
    40.     };
    41.  
    42.     UNITY_INSTANCING_BUFFER_START(Props)
    43.         UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
    44.         UNITY_INSTANCING_BUFFER_END(Props)
    45.         sampler2D _MainTex, _heightMap;
    46.         v2f vert(appdata v)
    47.     {
    48.         v2f o;
    49.  
    50.         UNITY_SETUP_INSTANCE_ID(v);
    51.         UNITY_TRANSFER_INSTANCE_ID(v, o); // necessary only if you want to access instanced properties in the fragment Shader.
    52.  
    53.      
    54.         float4 height = tex2Dlod(_heightMap, float4(v.uv, 0, 0));
    55.         v.vertex.y += height*5;
    56.         o.uv =v.uv;
    57.         o.pos = UnityObjectToClipPos(v.vertex);
    58.         TRANSFER_VERTEX_TO_FRAGMENT(o);
    59.         return o;
    60.     }
    61.  
    62.     fixed4 frag(v2f i) : SV_Target
    63.     {
    64.         UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader.
    65.     float attenuation = LIGHT_ATTENUATION(i);
    66.     fixed4 col = tex2D(_MainTex, i.uv);
    67.     return UNITY_ACCESS_INSTANCED_PROP(Props, _Color)*attenuation*col;
    68.     }
    69.         ENDCG
    70.     }
    71.  
    72.         Pass
    73.     {
    74.         Tags{ "LightMode" = "ShadowCaster" }
    75.  
    76.         CGPROGRAM
    77. #pragma vertex vert
    78. #pragma fragment frag
    79. #pragma multi_compile_shadowcaster
    80. #include "UnityCG.cginc"
    81.  
    82.         struct v2f {
    83.         V2F_SHADOW_CASTER;
    84.     };
    85.     sampler2D _MainTex, _heightMap;
    86.     v2f vert(appdata_base v)
    87.     {
    88.         v2f o;
    89.         float4 height = tex2Dlod(_heightMap, float4(v.texcoord.xy, 0, 0));
    90.         v.vertex.y += height * 5;
    91.  
    92.         o.pos = UnityObjectToClipPos(v.vertex);
    93.         TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    94.             return o;
    95.     }
    96.  
    97.     float4 frag(v2f i) : SV_Target
    98.     {
    99.         SHADOW_CASTER_FRAGMENT(i)
    100.     }
    101.         ENDCG
    102.     }
    103.     }
    104.  
    105.         Fallback "VertexLit"
    106. }
    [/code]
    not correct ,it seems still keep the old position
     

    Attached Files:

  6. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    Any way to fix this?