mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-12 22:53:27 +00:00
Adds documentation for ray-triangle intersection
Documents the `omath::collision::Ray` and `LineTracer` types, detailing their purpose, usage, and API. Includes a description of the Möller–Trumbore algorithm and provides usage examples for segment-triangle and infinite ray intersection tests. Relates to feature/docs
This commit is contained in:
171
docs/collision/line_tracer.md
Normal file
171
docs/collision/line_tracer.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# `omath::collision::Ray` & `LineTracer` — Ray–Triangle intersection (Möller–Trumbore)
|
||||
|
||||
> Headers: your project’s `ray.hpp` (includes `omath/linear_algebra/triangle.hpp`, `omath/linear_algebra/vector3.hpp`)
|
||||
> Namespace: `omath::collision`
|
||||
> Depends on: `omath::Vector3<float>`, `omath::Triangle<Vector3<float>>`
|
||||
> Algorithm: **Möller–Trumbore** ray–triangle intersection (no allocation)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
These types provide a minimal, fast path to test and compute intersections between a **ray or line segment** and a **single triangle**:
|
||||
|
||||
* `Ray` — start/end points plus a flag to treat the ray as **infinite** (half-line) or a **finite segment**.
|
||||
* `LineTracer` — static helpers:
|
||||
|
||||
* `can_trace_line(ray, triangle)` → `true` if they intersect.
|
||||
* `get_ray_hit_point(ray, triangle)` → the hit point (precondition: intersection exists).
|
||||
|
||||
---
|
||||
|
||||
## `Ray`
|
||||
|
||||
```cpp
|
||||
class Ray {
|
||||
public:
|
||||
omath::Vector3<float> start; // ray origin
|
||||
omath::Vector3<float> end; // end point (for finite segment) or a point along the direction
|
||||
bool infinite_length = false;
|
||||
|
||||
[[nodiscard]] omath::Vector3<float> direction_vector() const noexcept;
|
||||
[[nodiscard]] omath::Vector3<float> direction_vector_normalized() const noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
### Semantics
|
||||
|
||||
* **Direction**: `direction_vector() == end - start`.
|
||||
The normalized variant returns a unit vector (or `{0,0,0}` if the direction length is zero).
|
||||
* **Extent**:
|
||||
|
||||
* `infinite_length == true` → treat as a **semi-infinite ray** from `start` along `direction`.
|
||||
* `infinite_length == false` → treat as a **closed segment** from `start` to `end`.
|
||||
|
||||
> Tip: For an infinite ray that points along some vector `d`, set `end = start + d`.
|
||||
|
||||
---
|
||||
|
||||
## `LineTracer`
|
||||
|
||||
```cpp
|
||||
class LineTracer {
|
||||
public:
|
||||
LineTracer() = delete;
|
||||
|
||||
[[nodiscard]]
|
||||
static bool can_trace_line(
|
||||
const Ray& ray,
|
||||
const omath::Triangle<omath::Vector3<float>>& triangle
|
||||
) noexcept;
|
||||
|
||||
// Möller–Trumbore intersection
|
||||
[[nodiscard]]
|
||||
static omath::Vector3<float> get_ray_hit_point(
|
||||
const Ray& ray,
|
||||
const omath::Triangle<omath::Vector3<float>>& triangle
|
||||
) noexcept;
|
||||
};
|
||||
```
|
||||
|
||||
### Behavior & contract
|
||||
|
||||
* **Intersection test**: `can_trace_line` returns `true` iff the ray/segment intersects the triangle (within the ray’s extent).
|
||||
* **Hit point**: `get_ray_hit_point` **assumes** there is an intersection.
|
||||
Call **only after** `can_trace_line(...) == true`. Otherwise the result is unspecified.
|
||||
* **Triangle winding**: Standard Möller–Trumbore works with either winding; no backface culling is implied here.
|
||||
* **Degenerate inputs**: A zero-length ray or degenerate triangle yields **no hit** under typical Möller–Trumbore tolerances.
|
||||
|
||||
---
|
||||
|
||||
## Quick examples
|
||||
|
||||
### 1) Segment vs triangle
|
||||
|
||||
```cpp
|
||||
using omath::Vector3;
|
||||
using omath::Triangle;
|
||||
using omath::collision::Ray;
|
||||
using omath::collision::LineTracer;
|
||||
|
||||
Triangle<Vector3<float>> tri(
|
||||
Vector3<float>{0, 0, 0},
|
||||
Vector3<float>{1, 0, 0},
|
||||
Vector3<float>{0, 1, 0}
|
||||
);
|
||||
|
||||
Ray seg;
|
||||
seg.start = {0.25f, 0.25f, 1.0f};
|
||||
seg.end = {0.25f, 0.25f,-1.0f};
|
||||
seg.infinite_length = false; // finite segment
|
||||
|
||||
if (LineTracer::can_trace_line(seg, tri)) {
|
||||
Vector3<float> hit = LineTracer::get_ray_hit_point(seg, tri);
|
||||
// use hit
|
||||
}
|
||||
```
|
||||
|
||||
### 2) Infinite ray
|
||||
|
||||
```cpp
|
||||
Ray ray;
|
||||
ray.start = {0.5f, 0.5f, 1.0f};
|
||||
ray.end = ray.start + Vector3<float>{0, 0, -1}; // direction only
|
||||
ray.infinite_length = true;
|
||||
|
||||
bool hit = LineTracer::can_trace_line(ray, tri);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Notes & edge cases
|
||||
|
||||
* **Normalization**: `direction_vector_normalized()` returns `{0,0,0}` for a zero-length direction (safe, but unusable for tracing).
|
||||
* **Precision**: The underlying algorithm uses EPS thresholds to reject nearly parallel cases; results near edges can be sensitive to floating-point error. If you need robust edge inclusion/exclusion, document and enforce a policy (e.g., inclusive barycentric range with small epsilon).
|
||||
* **Hit location**: The point returned by `get_ray_hit_point` lies **on the triangle plane** and within its area by construction (when `can_trace_line` is `true`).
|
||||
|
||||
---
|
||||
|
||||
## API summary
|
||||
|
||||
```cpp
|
||||
namespace omath::collision {
|
||||
|
||||
class Ray {
|
||||
public:
|
||||
Vector3<float> start, end;
|
||||
bool infinite_length = false;
|
||||
|
||||
[[nodiscard]] Vector3<float> direction_vector() const noexcept;
|
||||
[[nodiscard]] Vector3<float> direction_vector_normalized() const noexcept;
|
||||
};
|
||||
|
||||
class LineTracer {
|
||||
public:
|
||||
LineTracer() = delete;
|
||||
|
||||
[[nodiscard]] static bool can_trace_line(
|
||||
const Ray&,
|
||||
const omath::Triangle<omath::Vector3<float>>&
|
||||
) noexcept;
|
||||
|
||||
[[nodiscard]] static Vector3<float> get_ray_hit_point(
|
||||
const Ray&,
|
||||
const omath::Triangle<omath::Vector3<float>>&
|
||||
) noexcept; // precondition: can_trace_line(...) == true
|
||||
};
|
||||
|
||||
} // namespace omath::collision
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation hints (if you extend it)
|
||||
|
||||
* Expose a variant that returns **barycentric coordinates** `(u, v, w)` alongside the hit point to support texture lookup or edge tests.
|
||||
* Provide an overload returning `std::optional<Vector3<float>>` (or `expected`) for safer one-shot queries without a separate test call.
|
||||
* If you need backface culling, add a flag or dedicated function (reject hits where the signed distance is negative with respect to triangle normal).
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 31 Oct 2025*
|
||||
Reference in New Issue
Block a user