Files
Vibe-HD-2D/assets/shaders/particles.frag
Gabrieal Jimmy 2c99305fb0 init
2026-10-02 12:42:00 -05:00

57 lines
2.1 KiB
GLSL

#version 450 core
#include "common.glsl"
// Premultiplied output: glows and fire write alpha 0 (pure additive), sparks
// and smoke write coverage (alpha-blended). Blend func is ONE, ONE_MINUS_SRC_ALPHA.
in vec2 vUV;
in vec4 vColor;
flat in int vKind;
in vec2 vLifeSeed;
layout(location = 0) out vec4 fragColor;
void main() {
vec2 p = vUV * 2.0 - 1.0;
float r = length(p);
float life = vLifeSeed.x, seed = vLifeSeed.y;
if (vKind == 2) { // spark / droplet
float a = (1.0 - smoothstep(0.6, 1.0, r)) * vColor.a;
fragColor = vec4(vColor.rgb * a, a);
return;
}
if (vKind == 3) { // flame: teardrop eroded by scrolling noise, more as it ages
float taper = 1.0 + 0.7 * (p.y * 0.5 + 0.5);
float d = length(vec2(p.x * taper, p.y * 0.9 + 0.1));
vec2 q = vec2(p.x * 2.5, p.y * 2.0 - uTime * 3.5) + seed * 37.0;
float n = vnoise(q) * 0.6 + vnoise(q * 2.3 + 11.0) * 0.4;
float shape = 1.0 - smoothstep(0.45, 0.85, d + (n - 0.5) * (0.6 + 0.9 * life));
float core = 1.0 - smoothstep(0.0, 0.55, d);
float a = shape * vColor.a;
// Mostly additive, but each tongue also dims what is behind it a little,
// so flames stay saturated orange over bright daytime ground.
fragColor = vec4(vColor.rgb * a * (0.7 + 0.8 * core), a * 0.3);
return;
}
if (vKind == 4) { // ember
float core = exp(-r * r * 10.0);
fragColor = vec4(vColor.rgb * vColor.a * core, 0.0);
return;
}
if (vKind == 5) { // smoke puff
vec2 q = p * 1.6 + seed * 23.0 + vec2(0.0, -uTime * 0.3);
float n = vnoise(q) * 0.6 + vnoise(q * 2.1 + 5.0) * 0.4;
float a = (1.0 - smoothstep(0.2, 1.0, r + (n - 0.5) * 0.7)) * vColor.a;
fragColor = vec4(vColor.rgb * a, a);
return;
}
if (vKind == 6) { // fire glow halo
float g = exp(-r * r * 3.5) - 0.03;
fragColor = vec4(vColor.rgb * max(g, 0.0), 0.0);
return;
}
float core = 1.0 - smoothstep(0.0, 0.2, r);
float halo = exp(-r * r * 9.0) * 0.45;
fragColor = vec4(vColor.rgb * vColor.a * (core * 1.5 + halo), 0.0);
}