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

67 lines
2.4 KiB
GLSL

#version 450 core
#include "common.glsl"
// Half-resolution ray march through height fog. Each step samples the sun
// shadow map and canopy cookie, producing physically shadowed light shafts
// (god rays). Output: rgb = in-scattered light, a = transmittance.
in vec2 vUV;
layout(binding = 0) uniform sampler2D uDepth;
layout(location = 0) out vec4 fragColor;
float phaseHG(float c, float g) {
float g2 = g * g;
return (1.0 - g2) / (4.0 * PI * pow(1.0 + g2 - 2.0 * g * c, 1.5));
}
float fogDensity(vec3 p) {
float h = exp(-max(p.y - uFogParams.y, 0.0) * uFogParams.x);
vec3 drift = vec3(uWind.x, 0.05, uWind.y) * uTime * 0.35;
float n = vnoise3(p * 0.16 + drift) * 0.65 + vnoise3(p * 0.45 - drift * 1.7) * 0.35;
n = mix(1.0, smoothstep(0.2, 0.8, n) * 1.8, uFogParams.z);
return uFogColor.w * h * n;
}
void main() {
float d = texture(uDepth, vUV).r;
vec3 wp = worldFromDepth(vUV, d);
vec3 ro = uCamPos.xyz;
vec3 rd = wp - ro;
float dist = length(rd);
rd /= dist;
dist = min(dist, uFogParams2.y);
int steps = int(uFogParams2.z);
float stepLen = dist / float(steps);
float jitter = ign(gl_FragCoord.xy);
float cosT = dot(rd, uSunDir.xyz);
// Dual lobe: strong forward scattering + a little back/side so shafts
// still read when looking away from the sun. Normalized: isotropic = 1.
float phase = (0.75 * phaseHG(cosT, uFogParams.w) + 0.25 * phaseHG(cosT, -0.25)) * 4.0 * PI;
vec3 sunL = uSunColor.rgb * uSunDir.w * uFogParams2.x * phase;
vec3 ambL = uFogColor.rgb * uSkyZenith.w;
vec3 scatter = vec3(0.0);
float T = 1.0;
for (int i = 0; i < steps; ++i) {
vec3 p = ro + rd * ((float(i) + jitter) * stepLen);
float dens = fogDensity(p);
if (dens < 1e-5) continue;
// Sparse beam mask: most sun scattering happens inside distinct shafts.
float vis = sunShadowFast(p) * shaftCookie(p);
vec3 S = (sunL * vis + ambL) * dens;
for (int l = 0; l < uLightCount.y; ++l) { // warm haze around fires
vec3 dl = uLightPos[l].xyz - p;
float r = uLightPos[l].w;
float att = max(1.0 - dot(dl, dl) / (r * r), 0.0);
att *= att;
S += uLightColor[l].rgb * att * att * dens * 0.35;
}
float Ts = exp(-dens * stepLen);
scatter += T * S * (1.0 - Ts) / dens; // energy-conserving step integral
T *= Ts;
if (T < 0.01) break;
}
fragColor = vec4(scatter, T);
}