2D Cast shadow
This shader applies a dynamic shadow effect to 2D canvas items. The shadow’s direction can be controlled using the look_right
parameter. The shader works by stretching the x-coordinates of the vertices horizontally and then calculating a shadow effect in the fragment shader. This allows for flexible shadow positioning and can create a more realistic depth effect for 2D elements.
As this shader only casts the shadow (which is intentional), the correct positioning must be managed using the z-index to ensure proper layering and visual effects.
Why the need to orient the shadow? Because if you horizontally flip your sprite, you don’t want the shadow to disengage from the other shadows’ direction. By controlling the shadow orientation, you maintain a consistent and realistic shadow direction relative to other objects in your scene.
Shader code
shader_type canvas_item;
uniform bool look_right = true;
void vertex() {
VERTEX.x = VERTEX.x * { -1.0, 1.0 }[int(look_right)];
float xSkewRatio = step(UV.y, .5);
vec2 skewTransition = vec2(abs(VERTEX.x) * xSkewRatio, 0.0);
vec2 skewScale = vec2(VERTEX.x, (VERTEX.y + abs(VERTEX.y)) / 2.0);
VERTEX = skewScale;
VERTEX = VERTEX + skewTransition;
}
void fragment() {
COLOR = vec4(vec3(.0), .5 * COLOR.a);
}
Looks awesome!
I have two small questions:
Since the shader turns the sprite (or other node) into a shadow, I assume I have to duplicate my sprite and then apply the shader to the duplicate so that I have the character + the shadow. Is that correct?Any idea what could be causing this : link <– This is my sprite, then just the shadow, then both together. No clue what’s causing these 2 vertical and horizontal bars. I checked the sprite and it doesn’t have any invisible pixel. (Plus they would need to be outside the file canvas to appear so far)
You’re correct that the shadow shader should be applied to a duplicate of the sprite, not the original sprite itself.
I’ve also encountered those visual artifacts in certain scenarios. Upon reflection, I realized that my previous method of handling the transformation within the fragment shader wasn’t ideal. As a result, I’ve developed an improved version of the shader to address these issues
I’ve created an updated version of the shader that is both simpler and more efficient. However, it comes with an important change in behavior: when you flip your sprite horizontally, the shadow will maintain its original orientation. This means the shadow won’t flip with the sprite, which is different from how it worked before.
how can I change the direction of the shadow (aka rotate it)?
You can easily flip the rendering horizontally by changing “VERTEX = VERTEX + skewTransition;” to “VERTEX = VERTEX – skewTransition;”. I encourage you to experiment further to achieve the perfect result.
I want to use it for a top-down game and rotate the shadow based on the direction of the sun
Achieving more than 180° coverage is not feasible because this is entirely 2D and sprites lack depth.
However, by adjusting the skew to the left or right, you can create a reasonably decent shadow cast for a smaller coverage area. Unless your game is set in winter, this might cheat reality, but does it really matter?
Also, I assumed you already understand how look_right changed the rendering.