Halloween is around the corner and I may have something to help you decorating, if you have a spare projector to aim at some bushes or a spare display to hide behind something translucent.
I hereby release this video under the CC0 license, which means you can use it any way you like.
The video was created using a self-written shader inside Godot Engine on public domain silhouette pictures from Pixabay, which were converted to a signed distance field texture by my good old sdfgen (which was my first Rust-lang project by the way).
This is how it looks projected onto a bush.
Thanks to all the awesome artists, who release assets under free licenses. These are the artworks used in the video.
- https://pixabay.com/vectors/halloween-jack-o-lantern-silhouette-5644533
- https://pixabay.com/vectors/evil-fear-jack-o-lantern-1801297
- https://pixabay.com/vectors/witch-woman-silhouette-hansel-4072544
- https://cdn.pixabay.com/photo/2016/03/31/21/34/zombies-1296507__480.png
- https://pixabay.com/vectors/cat-halloween-silhouette-puss-1775543
- https://pixabay.com/vectors/silhouette-house-halloween-bats-3834100
- https://pixabay.com/vectors/frankenstein-creature-halloween-156488
This is the shader source code.
shader_type canvas_item;
const float BRIGHTNESS_DST = 0.002;
const float TIME_DST = 0.2;
const float TIME_MULTIPLIER = 0.1;
const vec4 COLOR_INNER = vec4(1.0, 1.0, 1.0, 1.0);
const vec4 COLOR_OUTER = vec4(0.0, 0.0, 0.0, 1.0);
uniform sampler2D noise;
float gradient(float x, float dst) {
if (x < (0.5 - dst)) {
return 0.0;
} else if (x > (0.5 + dst)) {
return 1.0;
}
return (x-(0.5 - dst)) / (2.0 * dst);
}
vec2 offset(int id) {
int y = id / 3;
int x = id % 3;
return vec2(float(x) * 0.25, float(y) * 0.25);
}
void fragment() {
int id = int(TIME * TIME_MULTIPLIER) % 9;
int nextid = (id + 1) % 9;
float subtimeRaw = fract(TIME * TIME_MULTIPLIER);
float subtime = gradient(subtimeRaw, TIME_DST);
float t1 = texture(TEXTURE, UV * vec2(0.25, 0.25) + offset(id)).r;
float t2 = texture(TEXTURE, UV * vec2(0.25, 0.25) + offset(nextid)).r;
float triag = 1.0 - abs(2.0 * subtime - 1.0);
float noiseF = ((texture(noise, UV + (vec2(0.0,1.0) * (TIME * TIME_MULTIPLIER * 2.0))).r) - 0.5) * (triag * 0.5 + 0.5) * 0.1;
float brightness = gradient(mix(t1, t2, subtime) + noiseF, mix(BRIGHTNESS_DST, 0.01, triag));
COLOR = mix(COLOR_INNER, COLOR_OUTER, brightness);
}
The input “TEXTURE” is nine 1024x1024 signed distance fields arranged in a 3x3 grid in the top left of a 4096x4096 texture. The input “noise” is a standard noise texture provided by the Godot engine.
I hope you like the video and find a good use for it. Happy Halloween!