From ce22f79c55e68f9fa496a47a528a6978b89e1261 Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 22 Mar 2026 20:28:48 +0100 Subject: feat(shaders): add ray_sphere snippet, use in gbuf_raster impostor --- cnn_v3/shaders/gbuf_raster.wgsl | 12 ++++-------- src/effects/shaders.cc | 1 + src/shaders/ray_sphere.wgsl | 21 +++++++++++++++++++++ workspaces/main/assets.txt | 1 + 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/shaders/ray_sphere.wgsl diff --git a/cnn_v3/shaders/gbuf_raster.wgsl b/cnn_v3/shaders/gbuf_raster.wgsl index fa2dfd5..aed0e72 100644 --- a/cnn_v3/shaders/gbuf_raster.wgsl +++ b/cnn_v3/shaders/gbuf_raster.wgsl @@ -5,6 +5,7 @@ #include "common_uniforms" #include "math/normal" +#include "ray_sphere" @group(0) @binding(0) var globals: GlobalUniforms; @group(0) @binding(1) var object_data: ObjectsBuffer; @@ -93,14 +94,9 @@ fn fs_main(in: VertexOutput) -> GBufOutput { let sphere_radius = length(obj.model[0].xyz); // uniform scale in col0 let cam_pos = globals.camera_pos_time.xyz; let rd = normalize(in.world_pos - cam_pos); - let oc = cam_pos - sphere_center; - let b = dot(oc, rd); - let c = dot(oc, oc) - sphere_radius * sphere_radius; - let disc = b * b - c; - if (disc < 0.0) { discard; } - let t = -b - sqrt(disc); - if (t < 0.0) { discard; } - let hit = cam_pos + rd * t; + let isect = ray_sphere_intersection(cam_pos, rd, sphere_center, sphere_radius); + if (!isect.hit) { discard; } + let hit = cam_pos + rd * isect.t; world_normal = normalize(hit - sphere_center); // Reproject hit point to get correct clip-space depth. let clip_hit = globals.view_proj * vec4f(hit, 1.0); diff --git a/src/effects/shaders.cc b/src/effects/shaders.cc index a6c1b64..8b625ee 100644 --- a/src/effects/shaders.cc +++ b/src/effects/shaders.cc @@ -51,6 +51,7 @@ void InitShaderComposer() { register_if_exists("ray_box", AssetId::ASSET_SHADER_RAY_BOX); register_if_exists("ray_triangle", AssetId::ASSET_SHADER_RAY_TRIANGLE); + register_if_exists("ray_sphere", AssetId::ASSET_SHADER_RAY_SPHERE); register_if_exists("debug/debug_print", AssetId::ASSET_SHADER_DEBUG_DEBUG_PRINT); diff --git a/src/shaders/ray_sphere.wgsl b/src/shaders/ray_sphere.wgsl new file mode 100644 index 0000000..659e144 --- /dev/null +++ b/src/shaders/ray_sphere.wgsl @@ -0,0 +1,21 @@ +// Ray-sphere intersection. +// ro: ray origin, rd: ray direction (must be normalized). +// center: sphere center, radius: sphere radius. +// Returns t of the nearest positive intersection, or -1.0 if no hit. + +struct RaySphereHit { + t: f32, // distance along ray to nearest hit (negative = miss) + hit: bool, +}; + +fn ray_sphere_intersection(ro: vec3f, rd: vec3f, + center: vec3f, radius: f32) -> RaySphereHit { + let oc = ro - center; + let b = dot(oc, rd); + let c = dot(oc, oc) - radius * radius; + let disc = b * b - c; + if (disc < 0.0) { return RaySphereHit(-1.0, false); } + let t = -b - sqrt(disc); + if (t < 0.0) { return RaySphereHit(-1.0, false); } + return RaySphereHit(t, true); +} diff --git a/workspaces/main/assets.txt b/workspaces/main/assets.txt index d436319..b96b4c4 100644 --- a/workspaces/main/assets.txt +++ b/workspaces/main/assets.txt @@ -38,6 +38,7 @@ SHADER_SDF_SHAPES, WGSL, ../../src/shaders/math/sdf_shapes.wgsl, "SDF Shapes (2D SHADER_LIGHTING, WGSL, ../../src/shaders/lighting.wgsl, "Lighting Snippet" SHADER_RAY_BOX, WGSL, ../../src/shaders/ray_box.wgsl, "Ray-Box Intersection Snippet" SHADER_RAY_TRIANGLE, WGSL, ../../src/shaders/ray_triangle.wgsl, "Ray-Triangle Intersection Snippet (Möller-Trumbore)" +SHADER_RAY_SPHERE, WGSL, ../../src/shaders/ray_sphere.wgsl, "Ray-Sphere Intersection Snippet" SHADER_MAIN, WGSL, shaders/main_shader.wgsl, "Main Heptagon Shader" SHADER_PARTICLE_COMPUTE, WGSL, ../../src/effects/particle_compute.wgsl, "Particle Compute Shader" SHADER_PARTICLE_RENDER, WGSL, ../../src/effects/particle_render.wgsl, "Particle Render Shader" -- cgit v1.2.3