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>
33 lines
1.3 KiB
WebGPU Shading Language
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;
|
|
}
|