diff options
| author | Hunter Kvalevog <hunter@kvog.sh> | 2025-11-20 15:37:28 -0600 |
|---|---|---|
| committer | Hunter Kvalevog <hunter@kvog.sh> | 2025-11-21 20:49:11 -0600 |
| commit | 2890cf45c1ad62bf8496f15dfb4796f9c71c02eb (patch) | |
| tree | 1b677376e962fb446588858f2a24cd3196b6bd3c /shaders/vfog.glsl | |
| parent | 8a077ca7c421dcea92c9485aa284c6e636f2ddad (diff) | |
shaders
Diffstat (limited to 'shaders/vfog.glsl')
| -rw-r--r-- | shaders/vfog.glsl | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/shaders/vfog.glsl b/shaders/vfog.glsl new file mode 100644 index 0000000..f638b27 --- /dev/null +++ b/shaders/vfog.glsl @@ -0,0 +1,131 @@ +#version 330 core + +// -------------------------------------------------------------------------------- +// Volumetric fog +// +// @model cube +// @uniform int u_mode 0 0 2 +// @uniform int u_steps 8 1 64 +// @uniform float u_sigma 4.0f +// +// SPDX-License-Identifier: 0BSD +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// Uniforms +// -------------------------------------------------------------------------------- +uniform float u_time; +uniform vec3 u_cam; +uniform int u_mode; +uniform int u_steps; +uniform float u_sigma; + +// -------------------------------------------------------------------------------- +// Vertex outputs +// -------------------------------------------------------------------------------- +in vec3 v_p; +in vec2 v_t; +in vec3 v_n; + +// -------------------------------------------------------------------------------- +// Fragment outputs +// -------------------------------------------------------------------------------- +out vec4 f_c; + +// ----------------------------------------------------------------------------- +// Ray-AABB intersection +// ref: https://tavianator.com/2022/ray_box_boundary.html +// ----------------------------------------------------------------------------- +bool intersect(vec3 ro, vec3 rd, vec3 bbmin, vec3 bbmax, out float t0, out float t1) +{ + vec3 inv = 1.0f / rd; + vec3 ta = (bbmin - ro) * inv; + vec3 tb = (bbmax - ro) * inv; + vec3 tmin = min(ta, tb); + vec3 tmax = max(ta, tb); + t0 = max(max(tmin.x, tmin.y), tmin.z); + t1 = min(min(tmax.x, tmax.y), tmax.z); + return t1 >= max(t0, 0.0f); +} + +// ----------------------------------------------------------------------------- +// Mode 0: Basic volumetric fog +// ----------------------------------------------------------------------------- +float sample_basic(vec3 pos) +{ + return 1.0; +} + +// ----------------------------------------------------------------------------- +// Mode 1: Fade along y axis +// ----------------------------------------------------------------------------- +float sample_vfade(vec3 pos) +{ + return 1.0f - pos.y; +} + +// ----------------------------------------------------------------------------- +// Mode 2: Some waves +// ----------------------------------------------------------------------------- +float sample_waves(vec3 pos) +{ + // Fractal sum + // ref: https://thebookofshaders.com/13/ + float h = 0.75f; // baseline + + // Big waves + h += 0.08f * sin(pos.x * 2.0f + u_time); + h += 0.08f * cos(pos.z * 2.0f + u_time * -1.1f); + + // Medium waves + h += 0.05f * sin(pos.x * 5.0f + u_time * 1.7f); + h += 0.05f * cos(pos.z * 4.0f + u_time * -2.0f); + + // Small but choppy waves + h += 0.03f * sin(pos.x * 12.0f + u_time * 3.3f); + h += 0.03f * cos(pos.z * 11.0f + u_time * -2.5f); + + return float(pos.y < h); +} + +// -------------------------------------------------------------------------------- +// Entry point +// -------------------------------------------------------------------------------- +void main() +{ + vec3 bbmin = vec3(-1.0f); + vec3 bbmax = vec3( 1.0f); + + vec3 ro = u_cam; + vec3 rd = normalize(v_p - ro); + + float t0 = 0.0f; + float t1 = 0.0f; + if (!intersect(ro, rd, bbmin, bbmax, t0, t1)) { + f_c = vec4(0.0f, 0.0f, 0.0f, 0.0f); + return; + } + + // Clamp entry point in front of camera + float t_enter = max(t0, 0.0f); + float t_exit = t1; + float t_len = max(0.0f, t_exit - t_enter); + + float density = 0; + for (int i = 0; i < u_steps; ++i) { + float t = mix(t_enter, t_exit, (float(i) + 0.5f) / float(u_steps)); + vec3 p = ro + rd * t; + switch (u_mode) { + case 0: { density += sample_basic(p); } break; + case 1: { density += sample_vfade(p); } break; + case 2: { density += sample_waves(p); } break; + } + } + density /= float(u_steps); + + // Beer-Lambert attenuation + // ref: https://en.wikipedia.org/wiki/Beer%E2%80%93Lambert_law + float a = 1.0f - exp(-u_sigma * t_len * density); + + f_c = vec4(vec3(1.0f), a); +}
\ No newline at end of file |