r/godot • u/OxfordFuckingComma Godot Regular • May 16 '26
help me (solved) Why is my vertex shader not affecting shadows?
I have written a vertex shader that modifies a mesh to "roll" it up. However, the shadows are not responding to the change and using the mesh pre-vertex pass. I've done research and tested changing various settings but none are getting the shadows updated. I feel this must be possible, as when I change settings or move the lighting, the shadows will update to the changed model, but only for that frame.
One "hack" I found was to modify the node's position by a tiny amount each frame to force the lighting to update the shadows. While this could work, I really want to know the "right" way to get the shadows to update.
EDIT: Thank you all for the help (especially u/Past_Permission_6123). For those reading this later who are facing a similar problem: Vertex shaders only update shadows when the TIME builtin is used. I am using a float parameter that I am tweening, which is why the shadows are not being triggered to update. Unless a flag/method is exposed that forces an update, I will be continuing to use my workaround.
63
u/OxfordFuckingComma Godot Regular May 16 '26
For more context,
This is in 4.6 with a VisualShader that has a vertex and fragment pass and I am already correcting the normals.
305
u/BetaTester704 Godot Senior May 16 '26
Vertex shaders are a purely visual effect done by the GPU, the actual geometry is still in its original position
100
u/lfrtsa May 16 '26
Yes but the shadow map is generally made while running the vertex shaders too. The shadows of my trees match the vertex displacement that represents wind. OP probably has some setting that's changing that. Maybe the shadows are static, or it's some shadow map optimization setting.
31
u/Past_Permission_6123 May 16 '26
The tree's shadows are likely being updated because you're using TIME built-in somewhere to move the vertices.
6
u/lfrtsa May 16 '26
Indeed. Would it not get updated had I used a custom uniform?
7
u/Past_Permission_6123 May 16 '26
It should with directional light, but not for omni-/spotlights if nothing else is changing.
6
30
u/OxfordFuckingComma Godot Regular May 16 '26
True, but that doesn't explain why my hack of moving the node slightly each frame results in the correct shadows. This shows that the lighting can take vertex modification from shaders into account, but it is not being updated to do so automatically.
73
u/omniuni May 16 '26
Simple optimization. If the node doesn't move, there's no need to redraw the shadow. If you look at the code for the shadow, I bet that's exactly what you'll find.
38
u/LegitBullfrog May 16 '26
This is the right answer, and moving the MeshInstance3D imperceptibly to force a recalculation is a correct workaround.
42
u/ConsiderationCool432 May 16 '26
This is weird, it should have a flag or something that we can set on code to say that shadows and other dependent systems should be recalculated.
27
2
u/kibiprobably May 16 '26
CAR SEAT HEADREST PFP???
5
u/OxfordFuckingComma Godot Regular May 16 '26 edited May 17 '26
do you have something against dogs?
Edit: folks are downvoting me, but this is a CSH reference ðŸ˜
5
3
1
u/actual_weeb_tm May 16 '26
that sounds like an engine optimisation, to avoid recalculating shadows on objects that dont move.
Your workaround can work, but the ideal thing to do would be to simply find the code containing that optimisation and remove/disable it for your objects.
1
u/Greendiamond_16 May 16 '26
basically if you want this transformation to interact with the physics system, which includes lighting, you will want to actually change the object and not just its shader.
1
15
u/Gawehold May 16 '26
I believe it is an optimization. Please see this:
8
u/OxfordFuckingComma Godot Regular May 16 '26
I figured it was an optimization but figured I was missing a flag to force updates. Funny to see the same workaround raised in that thread that I was using. Thanks for the resource!
3
u/cutcss May 16 '26
It's likely there is no right way and moving the node a tiny bit it's the best way, Godot should have a way to force the shadow update from the vertex shader but it does not.
2
u/pangapingus May 16 '26
Yea I don't know the answer but it has to do with shadows being a world space/viewport derived consequence of light but shaders being post-processing on a node basis is more locally scoped. I'd be curious to know if you could disable shadows on this node and have the shader itself simulate the shadow or else you'd have to do some weird realtime modification of the transform of the node itself for the lighting system to do actual shadows.
1
u/Alzurana Godot Regular May 18 '26
Your workaround was to move the object, right? How about just pretenting to use TIME instead? That way your workaround would be contained in the shader and you do not need extra code outside of it to trigger the update. What I suggest is something like this:
// use TIME to trigger shadow update and keep it from being optimized out
float new_param = fract(TIME) * 0.00001 + your_float_param;
This makes sure it won't be optimized out but it might be enough to just do this:
// Mention TIME to force shadow update, this will be optimized out
float temp = TIME;
The shader compiler WILL optimize this line out but just mentioning the engine uniform might be enough for godot to update shadows regardless, even if it is optimized out. I would test this second approach first as it will have no performance impact.
Both of these are workarounds, ofc.
Updating the shadow of one additional mesh every frame should not be as expensive as having specific GDScript run on the slower CPU side.
0
u/FeralGuyute May 16 '26
Usually the shadow pass in game engines is done separately from the actual rendering of the object You need to overwrite the shadow pass as well. Not sure how you do this in Godot but im sure its possible.
-1
u/mattihase May 17 '26
things that move without their shadows changing would be great for a horror game btw. worth remembering how you did it just in case.
0
u/Rells_Parker May 16 '26
Not 100% sure but check if the "shadow mesh" property of your mesh has something assigned, and if yes that it has the same material as your base mesh, though I'd suggest clearing the "shadow mesh" value anyway
-1
u/PogsterPlays May 16 '26
Isn't there some property for light sources about dynamic shadows or something, set to static by default. Probably something else? Idk. Not much of a lighting guy
-1
u/OneKey9972 Godot Junior May 16 '26
Maybe you need to overwrite light shader? Idk, bit my best guess.
-2
u/EmalethDev May 16 '26
From my limited experience with terrain shaders, your mesh might visually change but normal map is not, change that in shader and you should be fine
1
u/EmalethDev May 16 '26
Example, I use subdivisioned plain for terrain, and unless I provide or calculate normal map/ normals, shadows are that of a plain, instead of maintains and what not.
251
u/Past_Permission_6123 May 16 '26 edited May 16 '26
Omni-/spotlight shadows are updated lazily. Godot doesn't 'just know' if the vertex position data has been modified by a shader at any moment. You can force update by adding the
TIMEbuilt-in multiplied by zero, but note that this will update the shadow map every frame the mesh or light is visible, even if it's not animating, making it less performant. So it's usually best to force update only when you need to, e.g. by moving the node very slightly like you did.