Search Unity

Moving a vertice after applying lights and shadows.

Discussion in 'Shaders' started by NecroToad, Jun 8, 2020.

  1. NecroToad

    NecroToad

    Joined:
    Oct 27, 2014
    Posts:
    8
    Hi guys, first of all this is my first post on the forum, I hope everything is right!

    I'm just starting learning shaders and a have a question that I can't find an answer for: it's possible to compute lighting and shadows before moving my vertices in a vertex shader, in a way that when I move the vertices the lighting and shadows applied on the faces move with them?

    Here is a example:




    iI it possible to do such a thing or does anyone have a clue or an example about it?
    Thank you very much.
     
  2. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    This is definitely possible. What you would want to do is only apply the vertex offset to the output clip-space position whilst leaving all other outputs as they were without the offset;

    Code (CSharp):
    1. struct v2f
    2. {
    3.     float4 pos : SV_POSITION;
    4.     float2 uv : TEXCOORD0;
    5.     float3 worldPos : TEXCOORD1;
    6.     float3 worldNorm : TEXCOORD2;
    7. };
    8.  
    9. v2f vert (appdata_full v)
    10. {
    11.     v2f o;
    12.     //Pass all your outputs like normal
    13.     o.uv = v.texcoord;
    14.     o.worldPos = mul (unity_ObjectToWorld, float4 (v.vertex.xyz, 1)).xyz;
    15.     o.worldNorm = UnityObjectToWorldNormal (v.normal);
    16.     //Apply the offset only on the output clip-pos
    17.     o.pos = UnityWorldToClipPos (o.worldPos + float3 (sin (o.worldPos.y), 0, 0));
    18.     return o;
    19. }
    Shadows are a bit trickier because Unity abstracts away all control, and for directional lights will end up being sampled in screen space, so you would need to rewrite a chunk of the shadow sampling code in the same vein as the above.
     
  3. NecroToad

    NecroToad

    Joined:
    Oct 27, 2014
    Posts:
    8
    Thank you very much, I'll give it a try.
    About the shadows and directional light, do you have any tips on how/where can I learn that? I don't need all the complexity that Unity allows, I'm planning to have only one shadow caster which is a spot light.

    Also, is it possible to have a post effect in my camera that can do this vertex effect to all vertices that it sees so that I don't need to have apply this shader to all my mesh's materials?
     
  4. Namey5

    Namey5

    Joined:
    Jul 5, 2013
    Posts:
    188
    All shadow sampling code is defined in "AutoLight.cginc" which you can find by downloading the builtin shaders from the Unity website. From there, it's just a matter of following back through the calls to see how functions expand. From the looks of it you could just run the vertex function like normal without displacement, then add the displacement at the end like so;

    Code (CSharp):
    1. #include "AutoLight.cginc"
    2.  
    3. ...
    4.  
    5. struct v2f
    6. {
    7.     float4 pos : SV_POSITION;
    8.     float2 uv : TEXCOORD0;
    9.     float3 worldPos : TEXCOORD1;
    10.     float3 worldNorm : TEXCOORD2;
    11.     SHADOW_COORDS(3)
    12. };
    13.    
    14. v2f vert (appdata_full v)
    15. {
    16.     v2f o;
    17.     //Pass all your outputs like normal (including clip-pos)
    18.     o.pos = UnityObjectToClipPos (v.vertex);
    19.     o.uv = v.texcoord;
    20.     o.worldPos = mul (unity_ObjectToWorld, float4 (v.vertex.xyz, 1)).xyz;
    21.     o.worldNorm = UnityObjectToWorldNormal (v.normal);
    22.     //Calculate shadow coords now
    23.     TRANSFER_SHADOW(o)
    24.     //Then displace the position after
    25.     o.pos = UnityWorldToClipPos (o.worldPos + float3 (sin (o.worldPos.y), 0, 0));
    26.     return o;
    27. }
    28.  
    29. half4 frag (v2f i) : SV_Target
    30. {
    31.     //Sample shadows
    32.     return SHADOW_ATTENUATION(i);
    33. }
    As far as a post effect, probably not. You can reconstruct the scene's world-space position using depth information in post and displace that way, but that would only work in a few situations (and edges would struggle). As an alternative you could use replacement shaders, although that would be equivalent to just setting every object in your scene to the same material.
     
  5. NecroToad

    NecroToad

    Joined:
    Oct 27, 2014
    Posts:
    8
    Thank you once more Namey5.
    This has helped me a lot. I'm still testing the things you said and trying to learn from them.
    I don't have any more questions, the things you said gave me a great starting point, thanks for your time!