3-D SDF — sphere trace, WebGL2
A signed distance field — a sphere orbiting on a unit circle, smooth-unioned with a static box — sphere-traced in a WebGL2 fragment shader (64 iterations max, ε = 1e-3). Normals via central differences, simple diffuse + rim shading. The receipt prices the shader at iterations × pixels × ~20 f32 ops × 32 bit-ops; μ is the gap between TDP envelope and Landauer floor at GPU throughput.
view the kernel that wrote this receipt crates/mathground-view/src/sdf3d.rs
//! 3-D SDF — sphere-trace fragment shader shipped as a static GLSL ES 3.0
//! string. The Rust side counts iterations × pixels to derive a bit-op
//! estimate; the GPU does the actual work.
//!
//! Scene: smooth-union of a moving sphere and a static box. V-class L0-closed
//! given the same uniforms.
pub const VERTEX_SRC: &str = r#"#version 300 es
in vec2 a_pos;
out vec2 v_uv;
void main() {
gl_Position = vec4(a_pos, 0.0, 1.0);
v_uv = a_pos;
}
"#;
pub const FRAGMENT_SRC: &str = r#"#version 300 es
precision highp float;
in vec2 v_uv;
uniform float u_time;
uniform vec2 u_resolution;
out vec4 frag;
float sdSphere(vec3 p, float r) { return length(p) - r; }
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}
float scene(vec3 p) {
vec3 sp = vec3(0.7 * sin(u_time), 0.0, 0.7 * cos(u_time));
float s = sdSphere(p - sp, 0.45);
float b = sdBox(p, vec3(0.40));
return smin(s, b, 0.30);
}
vec3 normal(vec3 p) {
float e = 0.0008;
return normalize(vec3(
scene(p + vec3(e, 0.0, 0.0)) - scene(p - vec3(e, 0.0, 0.0)),
scene(p + vec3(0.0, e, 0.0)) - scene(p - vec3(0.0, e, 0.0)),
scene(p + vec3(0.0, 0.0, e)) - scene(p - vec3(0.0, 0.0, e))
));
}
void main() {
vec2 uv = v_uv;
uv.x *= u_resolution.x / u_resolution.y;
vec3 ro = vec3(0.0, 0.0, -2.5);
vec3 rd = normalize(vec3(uv, 1.2));
float t = 0.0;
bool hit = false;
for (int i = 0; i < 64; i++) {
vec3 p = ro + rd * t;
float d = scene(p);
if (d < 0.001) { hit = true; break; }
t += d;
if (t > 10.0) break;
}
if (!hit) { frag = vec4(0.03, 0.05, 0.08, 1.0); return; }
vec3 p = ro + rd * t;
vec3 n = normal(p);
vec3 l = normalize(vec3(0.7, 0.7, -0.5));
float diff = max(dot(n, l), 0.0);
float rim = pow(1.0 - max(dot(n, -rd), 0.0), 2.0);
vec3 col = mix(vec3(0.18, 0.55, 0.85), vec3(0.95, 0.55, 0.18), 0.5 + 0.5 * sin(u_time * 0.5));
col = col * (0.18 + 0.82 * diff) + vec3(0.4, 0.8, 1.0) * rim * 0.35;
frag = vec4(col, 1.0);
}
"#;
/// Estimate the bit-ops cost for one frame at `width × height` pixels.
/// Conservative: 64 march iterations × ~20 f32 ops × 32 bit-ops per pixel.
pub fn estimate_bit_ops_per_pixel() -> u64 {
64 * 20 * 32
}
pub fn estimate_bit_ops_per_frame(w: u32, h: u32) -> u64 {
(w as u64) * (h as u64) * estimate_bit_ops_per_pixel()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn shaders_are_non_empty() {
assert!(VERTEX_SRC.contains("a_pos"));
assert!(FRAGMENT_SRC.contains("scene"));
assert!(FRAGMENT_SRC.contains("smin"));
}
#[test]
fn cost_scales_with_area() {
let a = estimate_bit_ops_per_frame(100, 100);
let b = estimate_bit_ops_per_frame(200, 100);
assert_eq!(b, 2 * a);
}
}
This is the exact Rust file compiled into the WASM module the page just loaded. Every line that runs on your device is here. The receipt is a function of this code, not a bespoke benchmark.