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

Help with shadows in shader that moves vertices

Discussion in 'Shaders' started by InfiniteMonkey, May 1, 2019.

  1. InfiniteMonkey

    InfiniteMonkey

    Joined:
    Oct 8, 2016
    Posts:
    19
    The situation is this : I'm rendering some low-poly clouds in my game, and I got everything working, but I was doing all the work on the CPU. I'm trying to move it all to the GPU and I've got everything working EXCEPT the shadow rendering. You can see the CPU-driven version at https://twitter.com/BalancingMonkey/status/1117924968770097152.

    The way I was doing it was with a single cloud *mesh* that I replaced all the vertex data every frame. That mesh was then attached to two *meshrenderers*, one with a small custom shader that coloured the clouds (and cast no shadows), and a second one that was set to ShadowOnly and used the Standard shader with Rendering Mode set to Fade and Albedo set to (1,1,1,0.7). This way, I got solid clouds, but the shadows themselves were not as solid as the shadows cast by other objects.

    The process I'm using now is to set up the mesh once, with each cloud 'cell' being full size. Then I've still got the two meshrenderers with shaders. This time the 'cloud' shader does the work in the vert program to position the vertices of each cloud cell in order to give the effect I want. The 'cloudshadow' shader is doing the same vertex repositioning.

    The two problems I have are (1) the shadows are dark - I'm not setting things right to have the Fade + Alpha = 0.7 semi-dark shadows and (2) for cloud cells that are smaller than full size, the shadows are positioning/moving quite differently to the cell itself. You can see an example of the bug below - the problem is where the shadows zip across the world when I make their associated cells shrink in place:



    The 'cloud' shader code is:
    Code (CSharp):
    1. Shader "Clouds"
    2. {
    3.     Properties
    4.     {
    5.     }
    6.     SubShader
    7.     {
    8.         Tags { "RenderType"="Opaque"}
    9.         LOD 200
    10.  
    11.         CGPROGRAM
    12.         // Physically based Standard lighting model, and enable shadows on all light types
    13.         #pragma surface surf Standard vertex:vert fullforwardshadows addshadow
    14.  
    15.         // Use shader model 3.0 target, to get nicer looking lighting
    16.         #pragma target 3.0
    17.  
    18.         struct Input
    19.         {
    20.             fixed4 color : COLOR;
    21.         };
    22.  
    23.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    24.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    25.         // #pragma instancing_options assumeuniformscaling
    26.         UNITY_INSTANCING_BUFFER_START(Props)
    27.             // put more per-instance properties here
    28.         UNITY_INSTANCING_BUFFER_END(Props)
    29.      
    30.         void vert (inout appdata_full v)
    31.         {
    32.             // BLAH BLAH BLAH ALL CULMINATING IN:
    33.             v.vertex = ......;
    34.  
    35.             UNITY_TRANSFER_DEPTH(v);
    36.         }
    37.  
    38.         void surf (Input IN, inout SurfaceOutputStandard o)
    39.         {
    40.             o.Albedo = fixed3(1,1,1);
    41.         }
    42.         ENDCG
    43.     }
    44.     FallBack "Standard"
    45. }
    46.  
    And the 'cloudshadow' shader is:
    Code (CSharp):
    1. Shader "CloudShadows"
    2. {
    3.    Properties
    4.     {
    5.     }
    6.     SubShader
    7.     {
    8.         Tags { "Queue"="Transparent" "RenderType"="Transparent"}
    9.         LOD 200
    10.  
    11.         CGPROGRAM
    12.         // Physically based Standard lighting model, and enable shadows on all light types
    13.         #pragma surface surf Standard vertex:vert fullforwardshadows addshadow
    14.  
    15.         // Use shader model 3.0 target, to get nicer looking lighting
    16.         #pragma target 3.0
    17.  
    18.         struct Input
    19.         {
    20.             fixed4 color : COLOR;
    21.         };
    22.  
    23.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    24.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    25.         // #pragma instancing_options assumeuniformscaling
    26.         UNITY_INSTANCING_BUFFER_START(Props)
    27.             // put more per-instance properties here
    28.         UNITY_INSTANCING_BUFFER_END(Props)
    29.  
    30.         void vert (inout appdata_full v)
    31.         {
    32.             // BLAH BLAH BLAH ALL CULMINATING IN:
    33.             v.vertex = ......;
    34.         }
    35.  
    36.         void surf (Input IN, inout SurfaceOutputStandard o)
    37.         {
    38.             o.Albedo = fixed3(1,1,1);
    39.             o.Alpha =  0.7;
    40.         }
    41.         ENDCG
    42.     }
    43.     FallBack "Standard"
    44. }
    45.  
    Note that I've removed the specifics of the vertex transformation just for simplicity - I'd hope the details of it aren't needed, but I can supply them if necessary.

    A few more notes:
    1) At the moment the 'cloud' renderer is set to Shadows : Off and the 'cloudshadow' renderer to ShadowOnly. If I disable the cloudshadow objects and set the 'cloud' renderer to Shadows : On I get the same effect with the shadows moving wrong, so it's not unique to the cloudshadow shader

    2) I use a similar process of positioning the vertices for the ground tiles too, and the shadows seem to behave themselves for that. the cloud shader is based on the ground shader, so I'm not sure what the issue is :(

    Obviously I'm a bit clueless about all this. Any help would be greatly appreciated!
     
    Last edited: May 1, 2019
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Surface shaders don’t have built in support for semi-transparent shadows. You can hack it by using an alpha tested shader, but it’ll be much simpler to write a custom shadow caster pass like shown here:
    http://catlikecoding.com/unity/tutorials/rendering/part-12/

    You don’t need everything from that shader, just the main bits of using the
    _DitherMaskLOD texture and VPOS. I think you can have a shader file with only the shadow caster pass and it’ll work fine. You could also put those lines in a Surface Shader and see if that works. I seem to remember some bug with Surface Shaders and generated shadow passes using VPOS though...

    As for the shadows moving, presumably your shader is scaling the v.vertex.xyz. If the mesh is being batched, then the mesh’s 0,0,0 is at the center of the world, and it is going to be scaled down to that point rather than to its game object pivot. For what you have already, it might be fixed by enabling instancing on the material. With a custom vertex fragment shadow caster shader you’d have to do the work to make that shader instanced. Catlike coding has a tutorial on that too. Alternatively you can try adding the DisableBatching tag.
     
  3. InfiniteMonkey

    InfiniteMonkey

    Joined:
    Oct 8, 2016
    Posts:
    19
    Thanks for that. the shadow dithering tutorials look like just what I need.

    Unfortunately the game object pivot is already at the 0,0,0 for the clouds, and enabling instancing/disabling batching doesn't appear to do anything :( I've had to revert to my old code for now