From 987582b2fad144e1409d0bf041a5623aad97c255 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Sun, 15 Dec 2024 13:20:37 +1300 Subject: [PATCH 1/8] add docs --- README.md | 3 + etc/ray_tracing.md | 150 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 etc/ray_tracing.md diff --git a/README.md b/README.md index 00728076af..70bfe1efce 100644 --- a/README.md +++ b/README.md @@ -251,3 +251,6 @@ wgpu uses the coordinate systems of D3D and Metal: | Render | Texture | | --------------------------------------------------- | ----------------------------------------------------- | | ![render_coordinates](./etc/render_coordinates.png) | ![texture_coordinates](./etc/texture_coordinates.png) | + +## Ray Tracing Extensions +See [the ray tracing documentation](./etc/ray_tracing.md). \ No newline at end of file diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md new file mode 100644 index 0000000000..a294264b3f --- /dev/null +++ b/etc/ray_tracing.md @@ -0,0 +1,150 @@ +## Ray Tracing Extensions +`wgpu` supports an experimental version of ray tracing which is subject to change. The extensions allow for acceleration structures to be created and built (with +`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE` enabled) and interacted with in shaders. Currently `naga` only supports ray queries +(accessible with `Features::EXPERIMENTAL_RAY_QUERY` enabled in wgpu). + +**Note**: The features documented here may have major bugs in them and are expected to be subject +to breaking changes, suggestions for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/1040). +Large changes may mean that this documentation may be out of date. + + +### `wgpu`'s raytracing API: +The documentation and specific details of the functions and structures provided +can be found with their definitions. +A `Blas` can be created with `device.create_blas`. +A `Tlas` can be created with `device.create_tlas`. + +Unless one is planning on using the unsafe (not recommended for beginners) building API a `Tlas` should be put inside +a `TlasPackage`. After that a reference to the `Tlas` can be retrieved by calling `TlasPackage::tlas`, +this reference can be placed in a bind group to be used in a shader. A reference to a `Blas` can +be used to create `TlasInstance` alongside a transformation matrix, a custom index +(this can be any data that should be given to the shader on a hit) which only the first 24 +bits may be set, and a mask to filter hits in the shader. + +A `Blas` must be built in either the same build as any `Tlas` it is used to build or an earlier build call. +Before a `Tlas` is used in a shader it must +- have been built +- have all `Blas`es that it was last built with to have last been built in either the same build as + this `Tlas` or an earlier build call. + +### `naga`'s raytracing API: +`naga` supports ray queries (also known as inline raytracing) only. Ray tracing pipelines are currently unsupported. +Naming is mostly taken from vulkan. + +Function definitions: + +`rayQueryInitialize(rq: ptr, acceleration_structure: acceleration_structure, ray_desc: RayDesc)` +- Initializes the `ray_query` to check where (if anywhere) the ray defined by `ray_desc` hits in `acceleration_structure` + +`rayQueryProceed(rq: ptr) -> bool` +- Traces the ray in the initialized ray_query (partially) through the scene. +- Returns true if a triangle that was hit by the ray was in a `Blas` that is not marked as opaque. +- Returns false if all triangles that were hit by the ray were in `Blas`es that were marked as opaque. +- The hit is considered `Candidate` if this function returns true, and the hit is considered `Committed` if + this function returns false. + +`rayQueryGetCommittedIntersection(rq: ptr) -> RayIntersection` +- Returns intersection details about a hit considered `Committed`. + +`rayQueryGetCandidateIntersection(rq: ptr) -> RayIntersection` +- Returns intersection details about a hit considered `Candidate`. + +Structure definitions: +````wgsl +struct RayDesc { + flags: u32, + cull_mask: u32, + t_min: f32, + t_max: f32, + origin: vec3, + dir: vec3, +} +```` +- `flags`: contains flags to use for this ray (e.g. consider all `Blas`es opaque) +- `cull_mask`: if the bitwise and of this and any `TlasInstance`'s `mask` is not zero then the object inside + the `Blas` contained within that `TlasInstance` may be hit. +- `t_min`: only points on the ray whose t is greater than this may be hit. +- `t_max`: only points on the ray whose t is less than this may be hit. +- `origin`: the origin of the ray. +- `dir`: the direction of the ray, t is calculated as the length down the ray divided by the length of `dir`. + +````wgsl +struct RayIntersection { + kind: u32, + t: f32, + instance_custom_index: u32, + instance_id: u32, + sbt_record_offset: u32, + geometry_index: u32, + primitive_index: u32, + barycentrics: vec2, + front_face: bool, + object_to_world: mat4x3, + world_to_object: mat4x3, +} +```` +- `kind`: the kind of the hit, no other member of this structure is useful if this is equal + to constant `RAY_QUERY_INTERSECTION_NONE`. +- `t`: see `RayDesc::dir` for calculations. +- `instance_custom_index`: corresponds to `instance.custom_index` where `instance` is the `TlasInstance` + that the intersected object was contained in. +- `instance_id`: the index into the `TlasPackage` to get the `TlasInstance` that the hit object is in +- `sbt_record_offset`: the offset into the shader binding table. Currently, this value is always 0. +- `geometry_index`: the index into the `Blas`'s build descriptor (e.g. if `BlasBuildEntry::geometry` is + `BlasGeometries::TriangleGeometries` then it is the index into that contained vector). +- `primitive_index`: the object hit's index into the provided buffer (e.g. if the object is a triangle + then this is the triangle index) +- `barycentrics`: two of the barycentric coordinates, the third can be calculated (only useful if this is a triangle). +- `front_face`: whether the hit face is the front (only useful if this is a triangle). +- `object_to_world`: matrix for converting from object-space to world-space +- `world_to_object`: matrix for converting from world-space to object-space + +Constant definitions: + +`const FORCE_OPAQUE = 0x1;` +- When `RayDesc::flags` contains this flag all `Blas`es as being marked as opaque. + +`const FORCE_NO_OPAQUE = 0x2;` +- When `RayDesc::flags` contains this flag all `Blas`es as being not marked as opaque. + +`const TERMINATE_ON_FIRST_HIT = 0x4;` +- When `RayDesc::flags` contains this flag instead of searching for the closest hit return the first hit. + +`const SKIP_CLOSEST_HIT_SHADER = 0x8;` +- Unused: implemented for raytracing pipelines. + +`const CULL_BACK_FACING = 0x10;` +- When `RayDesc::flags` contains this flag if `RayIntersection::front_face` is false do not return a hit. + +`const CULL_FRONT_FACING = 0x20;` +- When `RayDesc::flags` contains this flag if `RayIntersection::front_face` is true do not return a hit. + +`const CULL_OPAQUE = 0x40;` +- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is marked as opaque do not return a + hit. + +`const CULL_NO_OPAQUE = 0x80;` +- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is not marked as opaque do not return + a hit. + +`const SKIP_TRIANGLES = 0x100;` +- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is a triangle containing blas do not + return a hit. + +`const SKIP_AABBS = 0x200;` +- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is a AABB containing blas do not + return a hit. + +`const RAY_QUERY_INTERSECTION_NONE = 0;` +- If `RayIntersection::kind` is equal to this the ray hit nothing. + +`const RAY_QUERY_INTERSECTION_TRIANGLE = 1;` +- If `RayIntersection::kind` is equal to this the ray hit a triangle. + +`const RAY_QUERY_INTERSECTION_GENERATED = 2;` +- If `RayIntersection::kind` is equal to this the ray hit a custom object, this will only happen in a committed + intersection if a ray which intersected a bounding box for a custom object which was then committed. + +`const RAY_QUERY_INTERSECTION_AABB = 3;` +- If `RayIntersection::kind` is equal to this the ray hit a AABB, this will only happen in a candidate intersection if + the ray intersects the bounding box for a custom object. \ No newline at end of file From 1f31e6be2caae4ce4c5a76b775cb616d0b406aac Mon Sep 17 00:00:00 2001 From: Vecvec Date: Sun, 15 Dec 2024 13:25:17 +1300 Subject: [PATCH 2/8] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6810ee3173..94e37d79ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ By @ErichDonGubler in [#6456](https://github.com/gfx-rs/wgpu/pull/6456), [#6148] #### General +- Add unified documentation for ray-tracing. By @Vecvec in [#6747](https://github.com/gfx-rs/wgpu/pull/6747) - Return submission index in `map_async` and `on_submitted_work_done` to track down completion of async callbacks. By @eliemichel in [#6360](https://github.com/gfx-rs/wgpu/pull/6360). - Move raytracing alignments into HAL instead of in core. By @Vecvec in [#6563](https://github.com/gfx-rs/wgpu/pull/6563). - Allow for statically linking DXC rather than including separate `.dll` files. By @DouglasDwyer in [#6574](https://github.com/gfx-rs/wgpu/pull/6574). From c7933ad835c107151b67346d74bb411f29fe6329 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Mon, 16 Dec 2024 13:27:45 +1300 Subject: [PATCH 3/8] Add more details to the docs --- etc/ray_tracing.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md index a294264b3f..a3db6372a0 100644 --- a/etc/ray_tracing.md +++ b/etc/ray_tracing.md @@ -42,6 +42,12 @@ Function definitions: - Returns false if all triangles that were hit by the ray were in `Blas`es that were marked as opaque. - The hit is considered `Candidate` if this function returns true, and the hit is considered `Committed` if this function returns false. +- A `Candidate` intersection interrupts the ray traversal. +- A `Candidate` intersection may happen anywhere along the ray, it should not be relied on to give the closest hit. A +`Candidate` intersection is to allow the user themselves to decide if that intersection is valid*. If one wants to get +the closest hit a `Committed` intersection should be used. +- Calling this function multiple times will cause the ray traversal to continue if it was interrupted by a `Candidate` +intersection. `rayQueryGetCommittedIntersection(rq: ptr) -> RayIntersection` - Returns intersection details about a hit considered `Committed`. @@ -49,6 +55,8 @@ Function definitions: `rayQueryGetCandidateIntersection(rq: ptr) -> RayIntersection` - Returns intersection details about a hit considered `Candidate`. +*The API to commit a candidate intersection is not yet implemented but would be possible to be user implemented. + Structure definitions: ````wgsl struct RayDesc { From 80244c6e48b7b6e242c0d7dd36e99e8199676a10 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Mon, 16 Dec 2024 15:47:44 +1300 Subject: [PATCH 4/8] note matrices need to be transposed --- etc/ray_tracing.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md index a3db6372a0..7e64d439d7 100644 --- a/etc/ray_tracing.md +++ b/etc/ray_tracing.md @@ -104,8 +104,10 @@ struct RayIntersection { then this is the triangle index) - `barycentrics`: two of the barycentric coordinates, the third can be calculated (only useful if this is a triangle). - `front_face`: whether the hit face is the front (only useful if this is a triangle). -- `object_to_world`: matrix for converting from object-space to world-space -- `world_to_object`: matrix for converting from world-space to object-space +- `object_to_world`: matrix for converting from object-space to world-space* +- `world_to_object`: matrix for converting from world-space to object-space* + +*These matrices need to be transposed currently otherwise they will not work properly. Constant definitions: From bc30f07a9eec8046ca9bd1d05ce70688df009489 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Mon, 16 Dec 2024 15:57:02 +1300 Subject: [PATCH 5/8] note undefined behaviour --- etc/ray_tracing.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md index 7e64d439d7..22e233f165 100644 --- a/etc/ray_tracing.md +++ b/etc/ray_tracing.md @@ -57,6 +57,17 @@ intersection. *The API to commit a candidate intersection is not yet implemented but would be possible to be user implemented. +Undefined behavior*: +- Calling `rayQueryGetCommittedIntersection` or `rayQueryGetCandidateIntersection` when `rayQueryProceed` has not been +called on this ray query since it was initialized (or if the ray query has not been previously initialized). +- Calling `rayQueryGetCommittedIntersection` when `rayQueryProceed`'s latest return on this ray query is considered + `Candidate`. +- Calling `rayQueryGetCandidateIntersection` when `rayQueryProceed`'s latest return on this ray query is considered + `Committed`. +- Calling `rayQueryProceed` when `rayQueryInitialize` has not previously been called on this ray query + +*this is only known undefined behaviour. + Structure definitions: ````wgsl struct RayDesc { From d4c47a16592b27cf0c8f1a0f8500c21fba482a20 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Mon, 16 Dec 2024 16:06:48 +1300 Subject: [PATCH 6/8] note this is not a ray tracing introduction --- etc/ray_tracing.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md index 22e233f165..99d8520147 100644 --- a/etc/ray_tracing.md +++ b/etc/ray_tracing.md @@ -7,6 +7,9 @@ to breaking changes, suggestions for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/1040). Large changes may mean that this documentation may be out of date. +***This is not*** an introduction to raytracing, and assumes basic prior knowledge, to look at the fundamentals look at +an [introduction](https://developer.nvidia.com/blog/introduction-nvidia-rtx-directx-ray-tracing/). + ### `wgpu`'s raytracing API: The documentation and specific details of the functions and structures provided From 08da9f56de06a936692e3738a3ae9ed5d6770d40 Mon Sep 17 00:00:00 2001 From: Vecvec Date: Mon, 16 Dec 2024 18:48:12 +1300 Subject: [PATCH 7/8] note undefined behavior will be worked around later --- etc/ray_tracing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md index 99d8520147..49b8a31ded 100644 --- a/etc/ray_tracing.md +++ b/etc/ray_tracing.md @@ -69,7 +69,7 @@ called on this ray query since it was initialized (or if the ray query has not b `Committed`. - Calling `rayQueryProceed` when `rayQueryInitialize` has not previously been called on this ray query -*this is only known undefined behaviour. +*this is only known undefined behaviour, and will be worked around in the future. Structure definitions: ````wgsl From 6e2c70c5cff2b1c3b28c20f64774090c49c15cd9 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Mon, 16 Dec 2024 14:51:00 -0500 Subject: [PATCH 8/8] Style and Location --- README.md | 14 ++- etc/ray_tracing.md | 174 ------------------------------------ etc/specs/ray_tracing.md | 186 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 178 deletions(-) delete mode 100644 etc/ray_tracing.md create mode 100644 etc/specs/ray_tracing.md diff --git a/README.md b/README.md index 70bfe1efce..6d75945128 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,15 @@ We have the Matrix space [![Matrix Space](https://img.shields.io/static/v1?label We have a [wiki](https://github.com/gfx-rs/wgpu/wiki) that serves as a knowledge base. +## Extension Specifications + +While the core of wgpu is based on the WebGPU standard, we also support extensions that allow for features that the standard does not have yet. +For high-level documentation on how to use these extensions, see the individual specifications: + +🧪EXPERIMENTAL🧪 APIs are subject to change and may allow undefined behavior if used incorrectly. + +- 🧪EXPERIMENTAL🧪 [Ray Tracing](./etc/specs/ray_tracing.md). + ## Supported Platforms | API | Windows | Linux/Android | macOS/iOS | Web (wasm) | @@ -250,7 +259,4 @@ wgpu uses the coordinate systems of D3D and Metal: | Render | Texture | | --------------------------------------------------- | ----------------------------------------------------- | -| ![render_coordinates](./etc/render_coordinates.png) | ![texture_coordinates](./etc/texture_coordinates.png) | - -## Ray Tracing Extensions -See [the ray tracing documentation](./etc/ray_tracing.md). \ No newline at end of file +| ![render_coordinates](./etc/render_coordinates.png) | ![texture_coordinates](./etc/texture_coordinates.png) | \ No newline at end of file diff --git a/etc/ray_tracing.md b/etc/ray_tracing.md deleted file mode 100644 index 49b8a31ded..0000000000 --- a/etc/ray_tracing.md +++ /dev/null @@ -1,174 +0,0 @@ -## Ray Tracing Extensions -`wgpu` supports an experimental version of ray tracing which is subject to change. The extensions allow for acceleration structures to be created and built (with -`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE` enabled) and interacted with in shaders. Currently `naga` only supports ray queries -(accessible with `Features::EXPERIMENTAL_RAY_QUERY` enabled in wgpu). - -**Note**: The features documented here may have major bugs in them and are expected to be subject -to breaking changes, suggestions for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/1040). -Large changes may mean that this documentation may be out of date. - -***This is not*** an introduction to raytracing, and assumes basic prior knowledge, to look at the fundamentals look at -an [introduction](https://developer.nvidia.com/blog/introduction-nvidia-rtx-directx-ray-tracing/). - - -### `wgpu`'s raytracing API: -The documentation and specific details of the functions and structures provided -can be found with their definitions. -A `Blas` can be created with `device.create_blas`. -A `Tlas` can be created with `device.create_tlas`. - -Unless one is planning on using the unsafe (not recommended for beginners) building API a `Tlas` should be put inside -a `TlasPackage`. After that a reference to the `Tlas` can be retrieved by calling `TlasPackage::tlas`, -this reference can be placed in a bind group to be used in a shader. A reference to a `Blas` can -be used to create `TlasInstance` alongside a transformation matrix, a custom index -(this can be any data that should be given to the shader on a hit) which only the first 24 -bits may be set, and a mask to filter hits in the shader. - -A `Blas` must be built in either the same build as any `Tlas` it is used to build or an earlier build call. -Before a `Tlas` is used in a shader it must -- have been built -- have all `Blas`es that it was last built with to have last been built in either the same build as - this `Tlas` or an earlier build call. - -### `naga`'s raytracing API: -`naga` supports ray queries (also known as inline raytracing) only. Ray tracing pipelines are currently unsupported. -Naming is mostly taken from vulkan. - -Function definitions: - -`rayQueryInitialize(rq: ptr, acceleration_structure: acceleration_structure, ray_desc: RayDesc)` -- Initializes the `ray_query` to check where (if anywhere) the ray defined by `ray_desc` hits in `acceleration_structure` - -`rayQueryProceed(rq: ptr) -> bool` -- Traces the ray in the initialized ray_query (partially) through the scene. -- Returns true if a triangle that was hit by the ray was in a `Blas` that is not marked as opaque. -- Returns false if all triangles that were hit by the ray were in `Blas`es that were marked as opaque. -- The hit is considered `Candidate` if this function returns true, and the hit is considered `Committed` if - this function returns false. -- A `Candidate` intersection interrupts the ray traversal. -- A `Candidate` intersection may happen anywhere along the ray, it should not be relied on to give the closest hit. A -`Candidate` intersection is to allow the user themselves to decide if that intersection is valid*. If one wants to get -the closest hit a `Committed` intersection should be used. -- Calling this function multiple times will cause the ray traversal to continue if it was interrupted by a `Candidate` -intersection. - -`rayQueryGetCommittedIntersection(rq: ptr) -> RayIntersection` -- Returns intersection details about a hit considered `Committed`. - -`rayQueryGetCandidateIntersection(rq: ptr) -> RayIntersection` -- Returns intersection details about a hit considered `Candidate`. - -*The API to commit a candidate intersection is not yet implemented but would be possible to be user implemented. - -Undefined behavior*: -- Calling `rayQueryGetCommittedIntersection` or `rayQueryGetCandidateIntersection` when `rayQueryProceed` has not been -called on this ray query since it was initialized (or if the ray query has not been previously initialized). -- Calling `rayQueryGetCommittedIntersection` when `rayQueryProceed`'s latest return on this ray query is considered - `Candidate`. -- Calling `rayQueryGetCandidateIntersection` when `rayQueryProceed`'s latest return on this ray query is considered - `Committed`. -- Calling `rayQueryProceed` when `rayQueryInitialize` has not previously been called on this ray query - -*this is only known undefined behaviour, and will be worked around in the future. - -Structure definitions: -````wgsl -struct RayDesc { - flags: u32, - cull_mask: u32, - t_min: f32, - t_max: f32, - origin: vec3, - dir: vec3, -} -```` -- `flags`: contains flags to use for this ray (e.g. consider all `Blas`es opaque) -- `cull_mask`: if the bitwise and of this and any `TlasInstance`'s `mask` is not zero then the object inside - the `Blas` contained within that `TlasInstance` may be hit. -- `t_min`: only points on the ray whose t is greater than this may be hit. -- `t_max`: only points on the ray whose t is less than this may be hit. -- `origin`: the origin of the ray. -- `dir`: the direction of the ray, t is calculated as the length down the ray divided by the length of `dir`. - -````wgsl -struct RayIntersection { - kind: u32, - t: f32, - instance_custom_index: u32, - instance_id: u32, - sbt_record_offset: u32, - geometry_index: u32, - primitive_index: u32, - barycentrics: vec2, - front_face: bool, - object_to_world: mat4x3, - world_to_object: mat4x3, -} -```` -- `kind`: the kind of the hit, no other member of this structure is useful if this is equal - to constant `RAY_QUERY_INTERSECTION_NONE`. -- `t`: see `RayDesc::dir` for calculations. -- `instance_custom_index`: corresponds to `instance.custom_index` where `instance` is the `TlasInstance` - that the intersected object was contained in. -- `instance_id`: the index into the `TlasPackage` to get the `TlasInstance` that the hit object is in -- `sbt_record_offset`: the offset into the shader binding table. Currently, this value is always 0. -- `geometry_index`: the index into the `Blas`'s build descriptor (e.g. if `BlasBuildEntry::geometry` is - `BlasGeometries::TriangleGeometries` then it is the index into that contained vector). -- `primitive_index`: the object hit's index into the provided buffer (e.g. if the object is a triangle - then this is the triangle index) -- `barycentrics`: two of the barycentric coordinates, the third can be calculated (only useful if this is a triangle). -- `front_face`: whether the hit face is the front (only useful if this is a triangle). -- `object_to_world`: matrix for converting from object-space to world-space* -- `world_to_object`: matrix for converting from world-space to object-space* - -*These matrices need to be transposed currently otherwise they will not work properly. - -Constant definitions: - -`const FORCE_OPAQUE = 0x1;` -- When `RayDesc::flags` contains this flag all `Blas`es as being marked as opaque. - -`const FORCE_NO_OPAQUE = 0x2;` -- When `RayDesc::flags` contains this flag all `Blas`es as being not marked as opaque. - -`const TERMINATE_ON_FIRST_HIT = 0x4;` -- When `RayDesc::flags` contains this flag instead of searching for the closest hit return the first hit. - -`const SKIP_CLOSEST_HIT_SHADER = 0x8;` -- Unused: implemented for raytracing pipelines. - -`const CULL_BACK_FACING = 0x10;` -- When `RayDesc::flags` contains this flag if `RayIntersection::front_face` is false do not return a hit. - -`const CULL_FRONT_FACING = 0x20;` -- When `RayDesc::flags` contains this flag if `RayIntersection::front_face` is true do not return a hit. - -`const CULL_OPAQUE = 0x40;` -- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is marked as opaque do not return a - hit. - -`const CULL_NO_OPAQUE = 0x80;` -- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is not marked as opaque do not return - a hit. - -`const SKIP_TRIANGLES = 0x100;` -- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is a triangle containing blas do not - return a hit. - -`const SKIP_AABBS = 0x200;` -- When `RayDesc::flags` contains this flag if the `Blas` a intersection is checking is a AABB containing blas do not - return a hit. - -`const RAY_QUERY_INTERSECTION_NONE = 0;` -- If `RayIntersection::kind` is equal to this the ray hit nothing. - -`const RAY_QUERY_INTERSECTION_TRIANGLE = 1;` -- If `RayIntersection::kind` is equal to this the ray hit a triangle. - -`const RAY_QUERY_INTERSECTION_GENERATED = 2;` -- If `RayIntersection::kind` is equal to this the ray hit a custom object, this will only happen in a committed - intersection if a ray which intersected a bounding box for a custom object which was then committed. - -`const RAY_QUERY_INTERSECTION_AABB = 3;` -- If `RayIntersection::kind` is equal to this the ray hit a AABB, this will only happen in a candidate intersection if - the ray intersects the bounding box for a custom object. \ No newline at end of file diff --git a/etc/specs/ray_tracing.md b/etc/specs/ray_tracing.md new file mode 100644 index 0000000000..b0b50fce56 --- /dev/null +++ b/etc/specs/ray_tracing.md @@ -0,0 +1,186 @@ +# Ray Tracing Extensions + +🧪Experimental🧪 + +`wgpu` supports an experimental version of ray tracing which is subject to change. The extensions allow for acceleration structures to be created and built (with +`Features::EXPERIMENTAL_RAY_TRACING_ACCELERATION_STRUCTURE` enabled) and interacted with in shaders. Currently `naga` only supports ray queries +(accessible with `Features::EXPERIMENTAL_RAY_QUERY` enabled in wgpu). + +**Note**: The features documented here may have major bugs in them and are expected to be subject +to breaking changes, suggestions for the API exposed by this should be posted on [the ray-tracing issue](https://github.com/gfx-rs/wgpu/issues/1040). +Large changes may mean that this documentation may be out of date. + +***This is not*** an introduction to raytracing, and assumes basic prior knowledge, to look at the fundamentals look at +an [introduction](https://developer.nvidia.com/blog/introduction-nvidia-rtx-directx-ray-tracing/). + +## `wgpu`'s raytracing API: + +The documentation and specific details of the functions and structures provided +can be found with their definitions. + +A [`Blas`] can be created with [`Device::create_blas`]. +A [`Tlas`] can be created with [`Device::create_tlas`]. + +Unless one is planning on using the unsafe building API (not recommended for beginners) a [`Tlas`] should be put inside +a [`TlasPackage`]. After that a reference to the [`Tlas`] can be retrieved by calling [`TlasPackage::tlas`]. +This reference can be placed in a bind group to be used in a shader. A reference to a [`Blas`] can +be used to create [`TlasInstance`] alongside a transformation matrix, a custom index +(this can be any data that should be given to the shader on a hit) which only the first 24 +bits may be set, and a mask to filter hits in the shader. + +A [`Blas`] must be built in either the same build as any [`Tlas`] it is used to build or an earlier build call. +Before a [`Tlas`] is used in a shader it must +- have been built +- have all [`Blas`]es that it was last built with to have last been built in either the same build as + this [`Tlas`] or an earlier build call. + +[`Device::create_blas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_blas +[`Device::create_tlas`]: https://wgpu.rs/doc/wgpu/struct.Device.html#method.create_tlas +[`Tlas`]: https://wgpu.rs/doc/wgpu/struct.Tlas.html +[`Blas`]: https://wgpu.rs/doc/wgpu/struct.Blas.html +[`TlasInstance`]: https://wgpu.rs/doc/wgpu/struct.TlasInstance.html +[`TlasPackage`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html +[`TlasPackage::tlas`]: https://wgpu.rs/doc/wgpu/struct.TlasPackage.html#method.tlas + +## `naga`'s raytracing API: + +`naga` supports ray queries (also known as inline raytracing) only. Ray tracing pipelines are currently unsupported. +Naming is mostly taken from vulkan. + +```wgsl +// - Initializes the `ray_query` to check where (if anywhere) the ray defined by `ray_desc` hits in `acceleration_structure +rayQueryInitialize(rq: ptr, acceleration_structure: acceleration_structure, ray_desc: RayDesc) + +// - Traces the ray in the initialized ray_query (partially) through the scene. +// - Returns true if a triangle that was hit by the ray was in a `Blas` that is not marked as opaque. +// - Returns false if all triangles that were hit by the ray were in `Blas`es that were marked as opaque. +// - The hit is considered `Candidate` if this function returns true, and the hit is considered `Committed` if +// this function returns false. +// - A `Candidate` intersection interrupts the ray traversal. +// - A `Candidate` intersection may happen anywhere along the ray, it should not be relied on to give the closest hit. A +// `Candidate` intersection is to allow the user themselves to decide if that intersection is valid*. If one wants to get +// the closest hit a `Committed` intersection should be used. +// - Calling this function multiple times will cause the ray traversal to continue if it was interrupted by a `Candidate` +// intersection. +rayQueryProceed(rq: ptr) -> bool` + +// - Returns intersection details about a hit considered `Committed`. +rayQueryGetCommittedIntersection(rq: ptr) -> RayIntersection + +// - Returns intersection details about a hit considered `Candidate`. +rayQueryGetCandidateIntersection(rq: ptr) -> RayIntersection +``` + +*The API to commit a candidate intersection is not yet implemented but would be possible to be user implemented. + +> [!CAUTION] +> +> ### ⚠️Undefined behavior ⚠️: +> - Calling `rayQueryGetCommittedIntersection` or `rayQueryGetCandidateIntersection` when `rayQueryProceed` has not been +> called on this ray query since it was initialized (or if the ray query has not been previously initialized). +> - Calling `rayQueryGetCommittedIntersection` when `rayQueryProceed`'s latest return on this ray query is considered +> `Candidate`. +> - Calling `rayQueryGetCandidateIntersection` when `rayQueryProceed`'s latest return on this ray query is considered +> `Committed`. +> - Calling `rayQueryProceed` when `rayQueryInitialize` has not previously been called on this ray query +> +> *this is only known undefined behaviour, and will be worked around in the future. + +```wgsl +struct RayDesc { + // Contains flags to use for this ray (e.g. consider all `Blas`es opaque) + flags: u32, + // If the bitwise and of this and any `TlasInstance`'s `mask` is not zero then the object inside + // the `Blas` contained within that `TlasInstance` may be hit. + cull_mask: u32, + // Only points on the ray whose t is greater than this may be hit. + t_min: f32, + // Only points on the ray whose t is less than this may be hit. + t_max: f32, + // The origin of the ray. + origin: vec3, + // The direction of the ray, t is calculated as the length down the ray divided by the length of `dir`. + dir: vec3, +} + +struct RayIntersection { + // the kind of the hit, no other member of this structure is useful if this is equal + // to constant `RAY_QUERY_INTERSECTION_NONE`. + kind: u32, + // Distance from starting point, measured in units of `RayDesc::dir`. + t: f32, + // Corresponds to `instance.custom_index` where `instance` is the `TlasInstance` + // that the intersected object was contained in. + instance_custom_index: u32, + // The index into the `TlasPackage` to get the `TlasInstance` that the hit object is in + instance_id: u32, + // The offset into the shader binding table. Currently, this value is always 0. + sbt_record_offset: u32, + // The index into the `Blas`'s build descriptor (e.g. if `BlasBuildEntry::geometry` is + // `BlasGeometries::TriangleGeometries` then it is the index into that contained vector). + geometry_index: u32, + // The object hit's index into the provided buffer (e.g. if the object is a triangle + // then this is the triangle index) + primitive_index: u32, + // Two of the barycentric coordinates, the third can be calculated (only useful if this is a triangle). + barycentrics: vec2, + // Whether the hit face is the front (only useful if this is a triangle). + front_face: bool, + // Matrix for converting from object-space to world-space. + // + // Bug: This matrix need to be transposed currently otherwise it will not work properly. + object_to_world: mat4x3, + // Matrix for converting from world-space to object-space + // + // Bug: This matrix need to be transposed currently otherwise it will not work properly. + world_to_object: mat4x3, +} + +/// -- Flags for `RayDesc::flags` -- + +// All `Blas`es are marked as opaque. +const FORCE_OPAQUE = 0x1; + +// All `Blas`es are marked as non-opaque. +const FORCE_NO_OPAQUE = 0x2; + +// Instead of searching for the closest hit return the first hit. +const TERMINATE_ON_FIRST_HIT = 0x4; + +// Unused: implemented for raytracing pipelines. +const SKIP_CLOSEST_HIT_SHADER = 0x8; + +// If `RayIntersection::front_face` is false do not return a hit. +const CULL_BACK_FACING = 0x10; + +// If `RayIntersection::front_face` is true do not return a hit. +const CULL_FRONT_FACING = 0x20; + +// If the `Blas` a intersection is checking is marked as opaque do not return a hit. +const CULL_OPAQUE = 0x40; + +// If the `Blas` a intersection is checking is not marked as opaque do not return a hit. +const CULL_NO_OPAQUE = 0x80; + +// If the `Blas` a intersection is checking contains triangles do not return a hit. +const SKIP_TRIANGLES = 0x100; + +// If the `Blas` a intersection is checking contains AABBs do not return a hit. +const SKIP_AABBS = 0x200; + +/// -- Constants for `RayIntersection::kind` -- + +// The ray hit nothing. +const RAY_QUERY_INTERSECTION_NONE = 0; + +// The ray hit a triangle. +const RAY_QUERY_INTERSECTION_TRIANGLE = 1; + +// The ray hit a custom object, this will only happen in a committed intersection +// if a ray which intersected a bounding box for a custom object which was then committed. +const RAY_QUERY_INTERSECTION_GENERATED = 2; + +// The ray hit a AABB, this will only happen in a candidate intersection +// if the ray intersects the bounding box for a custom object. +const RAY_QUERY_INTERSECTION_AABB = 3; +```