feat(webgpu-rt): any-hit + AABB (procedural) geometry support #14
4 changed files with 66 additions and 15 deletions
feat(webgpu-rt): add intersection stage, procedural hit group, AABB BLAS API
Extends the cross-backend RT type surface for procedural geometry + any-hit on the WebGPU path: - RTShaderGroupType::ProceduralHitGroup + RTShaderGroup::intersectionShader (mirror VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR). - WebGPURTStage::Intersection for AABB intersection shaders. - Mesh::BuildProcedural(span<RTAabb>, opaque) — the WebGPU analog of a VK_GEOMETRY_TYPE_AABBS_KHR geometry. - wgpuRegisterMeshBLAS gains geomType / opaqueFlag / primCount. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
commit
321fe596a7
|
|
@ -87,6 +87,17 @@ export namespace Crafter {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(BVHNode) == 32);
|
static_assert(sizeof(BVHNode) == 32);
|
||||||
|
|
||||||
|
// One procedural primitive's axis-aligned bounding box, in object
|
||||||
|
// space. The analog of VkAabbPositionsKHR — the BLAS stores these
|
||||||
|
// instead of triangles and an intersection shader (registered in the
|
||||||
|
// hit group as a ProceduralHitGroup) reports the actual surface hit
|
||||||
|
// for each AABB the ray enters.
|
||||||
|
struct RTAabb {
|
||||||
|
float min[3];
|
||||||
|
float max[3];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(RTAabb) == 24);
|
||||||
|
|
||||||
class Mesh {
|
class Mesh {
|
||||||
public:
|
public:
|
||||||
// BLAS "handle": opaque identity that goes into
|
// BLAS "handle": opaque identity that goes into
|
||||||
|
|
@ -119,6 +130,19 @@ export namespace Crafter {
|
||||||
// as `vertexAttribs : array<u32>` with a per-mesh u32-word offset.
|
// as `vertexAttribs : array<u32>` with a per-mesh u32-word offset.
|
||||||
void Build(const ::Crafter::CompressedMeshAsset& asset,
|
void Build(const ::Crafter::CompressedMeshAsset& asset,
|
||||||
WebGPUCommandEncoderRef cmd = 0);
|
WebGPUCommandEncoderRef cmd = 0);
|
||||||
|
|
||||||
|
// Build an AABB (procedural) BLAS from a list of object-space boxes
|
||||||
|
// — the WebGPU analog of a VK_GEOMETRY_TYPE_AABBS_KHR geometry. The
|
||||||
|
// hit group bound to instances of this mesh must be a
|
||||||
|
// ProceduralHitGroup carrying an intersection shader; that shader is
|
||||||
|
// invoked for each box the ray enters and reports the surface hit.
|
||||||
|
// `opaque` is the geometry's opaque bit: pass false to let any-hit
|
||||||
|
// shaders run (the default for procedural geometry, which is usually
|
||||||
|
// transparent / volumetric). The `cmd` parameter is unused on
|
||||||
|
// WebGPU — kept for API symmetry with the triangle path.
|
||||||
|
void BuildProcedural(std::span<const RTAabb> aabbs,
|
||||||
|
bool opaque = false,
|
||||||
|
WebGPUCommandEncoderRef cmd = 0);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|
||||||
|
|
|
||||||
|
|
@ -60,18 +60,26 @@ export namespace Crafter {
|
||||||
inline constexpr std::uint8_t kRTGeometryInstanceForceOpaque = 0x4;
|
inline constexpr std::uint8_t kRTGeometryInstanceForceOpaque = 0x4;
|
||||||
inline constexpr std::uint8_t kRTGeometryInstanceForceNoOpaque = 0x8;
|
inline constexpr std::uint8_t kRTGeometryInstanceForceNoOpaque = 0x8;
|
||||||
|
|
||||||
// Hit-group identification. Matches VkRayTracingShaderGroupTypeKHR for
|
// Hit-group identification. Matches VkRayTracingShaderGroupTypeKHR.
|
||||||
// the two types we actually support (general + triangles-hit).
|
// General — raygen / miss / callable
|
||||||
|
// TrianglesHitGroup — closest-hit/any-hit over triangle geometry
|
||||||
|
// ProceduralHitGroup — closest-hit/any-hit + an intersection shader
|
||||||
|
// over AABB (VK_GEOMETRY_TYPE_AABBS_KHR) geometry
|
||||||
enum class RTShaderGroupType : std::uint8_t {
|
enum class RTShaderGroupType : std::uint8_t {
|
||||||
General = 0, // raygen / miss / callable
|
General = 0, // raygen / miss / callable
|
||||||
TrianglesHitGroup = 1,
|
TrianglesHitGroup = 1,
|
||||||
|
ProceduralHitGroup = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cross-backend description of one entry in the shader-group array
|
// Cross-backend description of one entry in the shader-group array
|
||||||
// passed to PipelineRT::Init. Mirrors the meaningful subset of
|
// passed to PipelineRT::Init. Mirrors the meaningful subset of
|
||||||
// VkRayTracingShaderGroupCreateInfoKHR: per group, the type and the
|
// VkRayTracingShaderGroupCreateInfoKHR: per group, the type and the
|
||||||
// indices (into the SBT's shader array) for general / closestHit /
|
// indices (into the SBT's shader array) for general / closestHit /
|
||||||
// anyHit, with kRTShaderUnused == VK_SHADER_UNUSED_KHR for "none".
|
// anyHit / intersection, with kRTShaderUnused == VK_SHADER_UNUSED_KHR
|
||||||
|
// for "none". `intersectionShader` is only consulted for
|
||||||
|
// ProceduralHitGroup; it names the shader run for each AABB the ray
|
||||||
|
// enters (the analog of VkRayTracingShaderGroupCreateInfoKHR::
|
||||||
|
// intersectionShader).
|
||||||
inline constexpr std::uint32_t kRTShaderUnused = 0xFFFFFFFFu;
|
inline constexpr std::uint32_t kRTShaderUnused = 0xFFFFFFFFu;
|
||||||
|
|
||||||
struct RTShaderGroup {
|
struct RTShaderGroup {
|
||||||
|
|
@ -79,5 +87,6 @@ export namespace Crafter {
|
||||||
std::uint32_t generalShader = kRTShaderUnused;
|
std::uint32_t generalShader = kRTShaderUnused;
|
||||||
std::uint32_t closestHitShader = kRTShaderUnused;
|
std::uint32_t closestHitShader = kRTShaderUnused;
|
||||||
std::uint32_t anyHitShader = kRTShaderUnused;
|
std::uint32_t anyHitShader = kRTShaderUnused;
|
||||||
|
std::uint32_t intersectionShader = kRTShaderUnused;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ export namespace Crafter {
|
||||||
// buffer through unchanged. Signature:
|
// buffer through unchanged. Signature:
|
||||||
// fn <entryFn>(coord: vec2<u32>, hdr: vec4<f32>) -> vec4<f32>
|
// fn <entryFn>(coord: vec2<u32>, hdr: vec4<f32>) -> vec4<f32>
|
||||||
Resolve = 4,
|
Resolve = 4,
|
||||||
|
// Intersection shader for AABB (procedural) geometry. Run for each
|
||||||
|
// AABB primitive the ray enters during TRACE; reports whether the
|
||||||
|
// procedural surface is hit and at what distance. Signature:
|
||||||
|
// fn <entryFn>(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
|
||||||
|
// primitiveId: u32) -> IntersectionResult
|
||||||
|
// `ray` is in object space. IntersectionResult{ hit, t, attribs,
|
||||||
|
// hitKind } is declared by the library prelude.
|
||||||
|
Intersection = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
// One WGSL shader source + the function name PipelineRTWebGPU should
|
// One WGSL shader source + the function name PipelineRTWebGPU should
|
||||||
|
|
@ -35,6 +43,9 @@ export namespace Crafter {
|
||||||
// ClosestHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>)
|
// ClosestHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>)
|
||||||
// AnyHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>) -> u32
|
// AnyHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>) -> u32
|
||||||
// returns RT_ANYHIT_ACCEPT / RT_ANYHIT_IGNORE / RT_ANYHIT_END_SEARCH.
|
// returns RT_ANYHIT_ACCEPT / RT_ANYHIT_IGNORE / RT_ANYHIT_END_SEARCH.
|
||||||
|
// Intersection: fn <entryFn>(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
|
||||||
|
// primitiveId: u32) -> IntersectionResult
|
||||||
|
// IntersectionResult{ hit: bool, t: f32, attribs: vec2<f32>, hitKind: u32 }.
|
||||||
//
|
//
|
||||||
// `RayDesc`, `HitInfo`, the `RT_*` flag/return constants, the `tlas` /
|
// `RayDesc`, `HitInfo`, the `RT_*` flag/return constants, the `tlas` /
|
||||||
// BLAS / mesh-record bindings, and the `traceRay` function are all
|
// BLAS / mesh-record bindings, and the `traceRay` function are all
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,12 @@ namespace Crafter::WebGPU {
|
||||||
// that gets appended to a global attribs heap and exposed to RT
|
// that gets appended to a global attribs heap and exposed to RT
|
||||||
// closest-hit shaders as `vertexAttribs : array<u32>` at
|
// closest-hit shaders as `vertexAttribs : array<u32>` at
|
||||||
// @group(1) @binding(7). Pass (nullptr, 0) for positions-only meshes.
|
// @group(1) @binding(7). Pass (nullptr, 0) for positions-only meshes.
|
||||||
|
// `geomType` selects the primitive kind: 0 = triangles (the
|
||||||
|
// verticesPtr/indicesPtr streams), 1 = AABBs (VK_GEOMETRY_TYPE_AABBS) —
|
||||||
|
// then verticesPtr holds 2 vec3 per primitive [min, max], indexCount is
|
||||||
|
// 0, and an intersection shader supplies the hit. `opaqueFlag` is the
|
||||||
|
// geometry's opaque bit (0 lets any-hit run). `primCount` is the
|
||||||
|
// triangle / AABB primitive count.
|
||||||
__attribute__((import_module("env"), import_name("wgpuRegisterMeshBLAS")))
|
__attribute__((import_module("env"), import_name("wgpuRegisterMeshBLAS")))
|
||||||
extern "C" std::uint32_t wgpuRegisterMeshBLAS(
|
extern "C" std::uint32_t wgpuRegisterMeshBLAS(
|
||||||
float minX, float minY, float minZ,
|
float minX, float minY, float minZ,
|
||||||
|
|
@ -175,7 +181,8 @@ namespace Crafter::WebGPU {
|
||||||
const void* indicesPtr, std::int32_t indexCount,
|
const void* indicesPtr, std::int32_t indexCount,
|
||||||
const void* bvhNodesPtr, std::int32_t bvhNodeCount,
|
const void* bvhNodesPtr, std::int32_t bvhNodeCount,
|
||||||
const void* primRemapPtr, std::int32_t primRemapCount,
|
const void* primRemapPtr, std::int32_t primRemapCount,
|
||||||
const void* attribsPtr, std::int32_t attribsByteCount);
|
const void* attribsPtr, std::int32_t attribsByteCount,
|
||||||
|
std::int32_t geomType, std::int32_t opaqueFlag, std::int32_t primCount);
|
||||||
|
|
||||||
// RT pipeline build. The library composes WGSL by concatenating the
|
// RT pipeline build. The library composes WGSL by concatenating the
|
||||||
// traversal library, generated hit-group switches, and the user-
|
// traversal library, generated hit-group switches, and the user-
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue