// Common functions for Signed Distance Field (SDF) raymarching. // These functions require the user to define a `df(vec3) -> 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) -> vec3 { let eps = vec2(NORM_OFF, 0.0); var nor: vec3; 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, rd: vec3, 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, ld: vec3, 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; }