xfy 5fa2621e6a fix(shaders): use #define_import_path + namespaced imports
The whole-file #import "file.wgsl" form (without ::) does not reliably
bring functions into scope in naga_oil/Bevy 0.19 — the renderer was
failing at runtime with 'no definition in scope for identifier:
ray_direction' (and rot_x, deriv, etc.), producing a blank screen despite
'cargo build' passing (shaders aren't compile-checked at build time).

Fix: add #define_import_path to each module file and import symbols
explicitly via namespace::name (the canonical Bevy pattern from the
shader_material_2d example). Verified the full shader pipeline compiles
and runs at runtime with zero WGSL errors.

This was a pre-existing bug masked by incomplete runtime verification in
earlier tasks; it is NOT specific to Task 15's grid work. All earlier
visual features (shadow, Doppler disk, Einstein halo, stars, planets,
grid) now actually render.
2026-07-13 09:51:08 +08:00

51 lines
2.0 KiB
WebGPU Shading Language

#define_import_path singularity::planets
struct SphereData {
center: vec4<f32>, // xyz = center, w = radius
color: vec4<f32>, // xyz = color, w = emissive flag (u32 reinterpreted; we just check > 0.5)
};
// The storage binding is declared here as part of the planets module; it lives
// in the material's bind group (group 2 = #{MATERIAL_BIND_GROUP}).
@group(#{MATERIAL_BIND_GROUP}) @binding(3) var<storage, read> planets: array<SphereData>;
// Test the segment prev->cur against all planets. Returns hit color & alpha,
// or (0,0,0,0) if no hit. `dir` is the ray direction (for shading).
fn planet_hit(prev: vec3<f32>, cur: vec3<f32>, dir: vec3<f32>) -> vec4<f32> {
var nearest_t = 1e9;
var nearest_col = vec3<f32>(0.0);
var found = false;
for (var i: u32 = 0u; i < uniforms.planet_count; i = i + 1u) {
let s = planets[i];
let center = s.center.xyz;
let radius = s.center.w;
// Ray-sphere intersection for the segment.
let seg = cur - prev;
let oc = prev - center;
let a = dot(seg, seg);
let b = 2.0 * dot(oc, seg);
let c = dot(oc, oc) - radius * radius;
let disc = b * b - 4.0 * a * c;
if (disc < 0.0) { continue; }
let sq = sqrt(disc);
var t = (-b - sq) / (2.0 * a);
if (t < 0.0) { t = (-b + sq) / (2.0 * a); }
if (t >= 0.0 && t <= 1.0 && t < nearest_t) {
nearest_t = t;
let hit_pos = prev + seg * t;
let n = normalize(hit_pos - center);
// Lambert shading from a fixed light direction.
let light_dir = normalize(vec3<f32>(0.5, 0.8, 0.3));
let ndl = max(dot(n, light_dir), 0.0);
var col = s.color.xyz * (0.2 + 0.8 * ndl);
if (s.color.w > 0.5) { col = s.color.xyz; } // emissive
nearest_col = col;
found = true;
}
}
if (found) {
return vec4<f32>(nearest_col, 0.95);
}
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
}