diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/shaders/math/color.wgsl | 27 | ||||
| -rw-r--r-- | common/shaders/math/utils.wgsl | 14 | ||||
| -rw-r--r-- | common/shaders/render/fullscreen_vs.wgsl | 10 | ||||
| -rw-r--r-- | common/shaders/render/raymarching.wgsl | 59 | ||||
| -rw-r--r-- | common/shaders/sdf_primitives.wgsl | 5 |
5 files changed, 115 insertions, 0 deletions
diff --git a/common/shaders/math/color.wgsl b/common/shaders/math/color.wgsl new file mode 100644 index 0000000..b63c915 --- /dev/null +++ b/common/shaders/math/color.wgsl @@ -0,0 +1,27 @@ +// Common color space and tone mapping functions. + +// sRGB to Linear approximation +// Note: Assumes input is in sRGB color space. +fn sRGB(t: vec3<f32>) -> vec3<f32> { + return mix(1.055 * pow(t, vec3<f32>(1.0/2.4)) - 0.055, 12.92 * t, step(t, vec3<f32>(0.0031308))); +} + +// ACES Filmic Tone Mapping (Approximate) +// A common tone mapping algorithm used in games and film. +fn aces_approx(v_in: vec3<f32>) -> vec3<f32> { + var v = max(v_in, vec3<f32>(0.0)); + v *= 0.6; + let a = 2.51; + let b = 0.03; + let c = 2.43; + let d = 0.59; + let e = 0.14; + return clamp((v * (a * v + b)) / (v * (c * v + d) + e), vec3<f32>(0.0), vec3<f32>(1.0)); +} + +// HSV to RGB conversion +const hsv2rgb_K = vec4<f32>(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); +fn hsv2rgb(c: vec3<f32>) -> vec3<f32> { + let p = abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www); + return c.z * mix(hsv2rgb_K.xxx, clamp(p - hsv2rgb_K.xxx, vec3<f32>(0.0), vec3<f32>(1.0)), c.y); +} diff --git a/common/shaders/math/utils.wgsl b/common/shaders/math/utils.wgsl new file mode 100644 index 0000000..85f0bdf --- /dev/null +++ b/common/shaders/math/utils.wgsl @@ -0,0 +1,14 @@ +// General-purpose math utility functions. + +// Returns a 2x2 rotation matrix. +fn rot(a: f32) -> mat2x2<f32> { + let c = cos(a); + let s = sin(a); + return mat2x2<f32>(c, s, -s, c); +} + +// Fast approximation of tanh. +fn tanh_approx(x: f32) -> f32 { + let x2 = x * x; + return clamp(x * (27.0 + x2) / (27.0 + 9.0 * x2), -1.0, 1.0); +} diff --git a/common/shaders/render/fullscreen_vs.wgsl b/common/shaders/render/fullscreen_vs.wgsl new file mode 100644 index 0000000..a68604b --- /dev/null +++ b/common/shaders/render/fullscreen_vs.wgsl @@ -0,0 +1,10 @@ +// Common vertex shader for fullscreen post-processing effects. +// Draws a single triangle that covers the entire screen. +@vertex fn vs_main(@builtin(vertex_index) i: u32) -> @builtin(position) vec4<f32> { + var pos = array<vec2<f32>, 3>( + vec2<f32>(-1, -1), + vec2<f32>(3, -1), + vec2<f32>(-1, 3) + ); + return vec4<f32>(pos[i], 0.0, 1.0); +} diff --git a/common/shaders/render/raymarching.wgsl b/common/shaders/render/raymarching.wgsl new file mode 100644 index 0000000..5a86840 --- /dev/null +++ b/common/shaders/render/raymarching.wgsl @@ -0,0 +1,59 @@ +// Common functions for Signed Distance Field (SDF) raymarching. +// These functions require the user to define a `df(vec3<f32>) -> f32` function +// which represents the scene's distance field. + +const TOLERANCE: f32 = 0.0005; +const MAX_RAY_LENGTH: f32 = 20.0; +const MAX_RAY_MARCHES: i32 = 80; +const NORM_OFF: f32 = 0.005; + +// Computes the surface normal of the distance field at a point `pos`. +fn normal(pos: vec3<f32>) -> vec3<f32> { + let eps = vec2<f32>(NORM_OFF, 0.0); + var nor: vec3<f32>; + nor.x = df(pos + eps.xyy) - df(pos - eps.xyy); + nor.y = df(pos + eps.yxy) - df(pos - eps.yxy); + nor.z = df(pos + eps.yyx) - df(pos - eps.yyx); + return normalize(nor); +} + +// Performs the raymarching operation. +// Returns the distance along the ray to the surface, or MAX_RAY_LENGTH if no surface is hit. +fn rayMarch(ro: vec3<f32>, rd: vec3<f32>, initt: f32) -> f32 { + var t = initt; + for (var i = 0; i < MAX_RAY_MARCHES; i++) { + if (t > MAX_RAY_LENGTH) { + t = MAX_RAY_LENGTH; + break; + } + let d = df(ro + rd * t); + if (d < TOLERANCE) { + break; + } + t += d; + } + return t; +} + +// Computes a soft shadow for a given point. +fn shadow(lp: vec3<f32>, ld: vec3<f32>, mint: f32, maxt: f32) -> f32 { + let ds = 1.0 - 0.4; + var t = mint; + var nd = 1e6; + let soff = 0.05; + let smul = 1.5; + let MAX_SHD_MARCHES = 20; + + for (var i = 0; i < MAX_SHD_MARCHES; i++) { + let p = lp + ld * t; + let d = df(p); + if (d < TOLERANCE || t >= maxt) { + let sd = 1.0 - exp(-smul * max(t / maxt - soff, 0.0)); + return select(mix(sd, 1.0, smoothstep(0.0, 0.025, nd)), sd, t >= maxt); + } + nd = min(nd, d); + t += ds * d; + } + let sd = 1.0 - exp(-smul * max(t / maxt - soff, 0.0)); + return sd; +} diff --git a/common/shaders/sdf_primitives.wgsl b/common/shaders/sdf_primitives.wgsl index 31bbe2d..407fb29 100644 --- a/common/shaders/sdf_primitives.wgsl +++ b/common/shaders/sdf_primitives.wgsl @@ -12,3 +12,8 @@ fn sdTorus(p: vec3<f32>, t: vec2<f32>) -> f32 { fn sdPlane(p: vec3<f32>, n: vec3<f32>, h: f32) -> f32 { return dot(p, n) + h; } + +fn sdBox2D(p: vec2<f32>, b: vec2<f32>) -> f32 { + let d = abs(p) - b; + return length(max(d, vec2<f32>(0.0))) + min(max(d.x, d.y), 0.0); +} |
