indicatrix 0.2.2

A physically-based spectral gemstone renderer that turns GemCAD-style cutting schedules into rendered output.
Documentation
// Physics review, Task 2 (facet edge rounding): `shading_normal_near_edge` Tier 2
// kernel -- driven by `renderer::gpu::shading_normal_check`. A standalone file with its
// own `planes` binding (bound to the SAME real 57-facet Standard Round Brilliant plane
// set `intersect_polyhedron.wgsl`/`polyhedron_check` use), mirroring that file's own
// pattern for a function whose only extra input beyond scalars/vectors is the
// polyhedron's plane list. A direct, unmodified line-for-line translation of
// `optics::raytracer::shading_normal_near_edge` -- the SAME translation
// `shaders/spectral_transport.wgsl`'s megakernel-local copy is (both read `planes` via
// their own file's binding, so neither can share a `transport_physics.wgsl` function
// for it -- see that file's own doc comment for why a binding-touching function stays
// per-file).

struct FacetPlane {
    normal: vec3<f32>,
    d: f32,
}

struct ShadingNormalCase {
    hit_point: vec3<f32>,
    hit_facet_idx: u32,
    hit_normal: vec3<f32>,
    rounding_radius: f32,
}

@group(0) @binding(0) var<storage, read> planes: array<FacetPlane>;
@group(0) @binding(1) var<storage, read> cases: array<ShadingNormalCase>;
@group(0) @binding(2) var<storage, read_write> out_normals: array<f32>;

fn normalize_or_zero(v: vec3<f32>) -> vec3<f32> {
    let l2 = dot(v, v);
    if (l2 > 1e-30) {
        return v / sqrt(l2);
    }
    return vec3<f32>(0.0, 0.0, 0.0);
}

// optics::raytracer::shading_normal_near_edge
fn shading_normal_near_edge(hit_point: vec3<f32>, hit_facet_idx: u32, hit_normal: vec3<f32>, rounding_radius: f32) -> vec3<f32> {
    if (rounding_radius <= 0.0) {
        return hit_normal;
    }
    var nearest_dist: f32 = 1e30;
    var nearest_normal = hit_normal;
    let num_planes = arrayLength(&planes);
    for (var i: u32 = 0u; i < num_planes; i = i + 1u) {
        if (i == hit_facet_idx) {
            continue;
        }
        let p = planes[i];
        let dist = -(p.d + dot(p.normal, hit_point));
        if (dist < nearest_dist) {
            nearest_dist = dist;
            nearest_normal = p.normal;
        }
    }
    if (nearest_dist >= rounding_radius) {
        return hit_normal;
    }
    let t = clamp(1.0 - nearest_dist / rounding_radius, 0.0, 1.0);
    let smooth_t = t * t * fma(-2.0, t, 3.0);
    let bisector = normalize_or_zero(hit_normal + nearest_normal);
    return normalize_or_zero(hit_normal * (1.0 - smooth_t) + bisector * smooth_t);
}

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
    let idx = gid.x;
    if (idx >= arrayLength(&cases)) {
        return;
    }
    let c = cases[idx];
    let n = shading_normal_near_edge(c.hit_point, c.hit_facet_idx, c.hit_normal, c.rounding_radius);
    out_normals[idx * 3u + 0u] = n.x;
    out_normals[idx * 3u + 1u] = n.y;
    out_normals[idx * 3u + 2u] = n.z;
}