Crafter.Graphics/examples/RTVolume/intersection.wgsl
catbot 5dd1086f08 docs(webgpu-rt): add RTVolume example (procedural spheres + any-hit cut-out)
A 3x3x3 grid of AABB-geometry spheres rendered through an analytic
ray-sphere intersection shader, with an any-hit spherical-checkerboard
cut-out so the background shows through. Exercises both features end to
end on the WebGPU wavefront tracer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:09:30 +00:00

33 lines
1.3 KiB
WebGPU Shading Language

// RTVolume intersection shader (runs in TRACE, per AABB the ray enters).
// Analytic ray-sphere test: the unit box [-1,1]^3 is treated as the
// bounding volume of a sphere of radius 1 centred at the box centre. The
// ray is in object space and is NOT normalised (it is worldToObject *
// worldRay), so the returned t is directly comparable to the world-space
// ray parameter the tracer commits — solve the quadratic with the general
// a = dot(d,d) form rather than assuming |d| == 1.
fn intersection_main(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
primitiveId: u32) -> IntersectionResult {
var r: IntersectionResult;
r.hit = false;
let center = (aabbMin + aabbMax) * 0.5;
let radius = (aabbMax.x - aabbMin.x) * 0.5;
let oc = ray.origin - center;
let a = dot(ray.direction, ray.direction);
let b = 2.0 * dot(oc, ray.direction);
let c = dot(oc, oc) - radius * radius;
let disc = b * b - 4.0 * a * c;
if (disc < 0.0) { return r; }
let sq = sqrt(disc);
var t = (-b - sq) / (2.0 * a); // near root
if (t < ray.tMin) { t = (-b + sq) / (2.0 * a); } // fall back to far root
if (t < ray.tMin || t > ray.tMax) { return r; }
r.hit = true;
r.t = t;
r.attribs = vec2<f32>(0.0);
r.hitKind = 0u;
return r;
}