Skip to content

Commit 830c5fd

Browse files
authored
fix(geometry): handle when ray direction is 0 (#924)
Fixes #909
1 parent 7d5d641 commit 830c5fd

File tree

5 files changed

+44
-14
lines changed

5 files changed

+44
-14
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/geometry/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ ordered-float = { workspace = true }
1313

1414
[dev-dependencies]
1515
approx = { workspace = true }
16+
itertools = { workspace = true }
1617
rand = { workspace = true }
1718
tango-bench = { workspace = true }
1819

crates/geometry/src/ray.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use std::ops::Mul;
22

33
use glam::{IVec3, Vec3};
44

5+
const fn nan_as_inf(value: f32) -> f32 {
6+
if value.is_nan() { f32::INFINITY } else { value }
7+
}
8+
59
#[derive(Debug, Clone, Copy)]
610
pub struct Ray {
711
origin: Vec3,
@@ -34,8 +38,9 @@ impl Ray {
3438
}
3539

3640
#[must_use]
41+
#[inline]
3742
pub fn new(origin: Vec3, direction: Vec3) -> Self {
38-
let inv_direction = Vec3::new(1.0 / direction.x, 1.0 / direction.y, 1.0 / direction.z);
43+
let inv_direction = direction.map(f32::recip).map(nan_as_inf);
3944

4045
Self {
4146
origin,
@@ -58,6 +63,7 @@ impl Ray {
5863

5964
/// Efficiently traverse through grid cells that the ray intersects using the Amanatides and Woo algorithm.
6065
/// Returns an iterator over the grid cells ([`IVec3`]) that the ray passes through.
66+
#[inline]
6167
pub fn voxel_traversal(&self, bounds_min: IVec3, bounds_max: IVec3) -> VoxelTraversal {
6268
let current_pos = self.origin.as_ivec3();
6369

@@ -88,17 +94,8 @@ impl Ray {
8894
);
8995

9096
// Calculate t_max and t_delta using precomputed inv_direction
91-
let t_max = Vec3::new(
92-
next_boundary.x * self.inv_direction.x.abs(),
93-
next_boundary.y * self.inv_direction.y.abs(),
94-
next_boundary.z * self.inv_direction.z.abs(),
95-
);
96-
97-
let t_delta = Vec3::new(
98-
self.inv_direction.x.abs(),
99-
self.inv_direction.y.abs(),
100-
self.inv_direction.z.abs(),
101-
);
97+
let t_max = (next_boundary * self.inv_direction.abs()).map(nan_as_inf);
98+
let t_delta = self.inv_direction.abs();
10299

103100
VoxelTraversal {
104101
current_pos,
@@ -159,3 +156,36 @@ impl Iterator for VoxelTraversal {
159156
Some(current)
160157
}
161158
}
159+
160+
#[cfg(test)]
161+
mod tests {
162+
use itertools::Itertools;
163+
164+
use super::*;
165+
166+
#[test]
167+
fn test_traverse_axis_aligned_ray() {
168+
static DIRECTIONS: [IVec3; 6] = [
169+
IVec3::new(-1, 0, 0),
170+
IVec3::new(1, 0, 0),
171+
IVec3::new(0, -1, 0),
172+
IVec3::new(0, 1, 0),
173+
IVec3::new(0, 0, -1),
174+
IVec3::new(0, 0, 1),
175+
];
176+
177+
static ORIGIN: IVec3 = IVec3::new(-1, 0, 1);
178+
179+
for direction in DIRECTIONS {
180+
let ray = Ray::new(ORIGIN.as_vec3(), direction.as_vec3());
181+
let voxels = ray
182+
.voxel_traversal(IVec3::MIN, IVec3::MAX)
183+
.take(10)
184+
.collect::<Vec<_>>();
185+
assert_eq!(voxels[0], ORIGIN);
186+
for (a, b) in voxels.iter().tuple_windows() {
187+
assert_eq!(b - a, direction);
188+
}
189+
}
190+
}
191+
}

crates/hyperion/tests/collision.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use hyperion::{
1414
};
1515

1616
#[test]
17-
#[ignore = "this test takes a SUPER long time to run due to https://github.com/hyperion-mc/hyperion/issues/909"]
1817
fn test_get_first_collision() {
1918
/// Function to spawn arrows at different angles
2019
fn spawn_arrow(world: &mut World, position: Vec3, direction: Vec3, owner: Owner) -> Entity {

crates/hyperion/tests/entity.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use serial_test::serial;
1313

1414
#[test]
1515
#[serial]
16-
#[ignore = "this test takes a SUPER long time to run due to https://github.com/hyperion-mc/hyperion/issues/909"]
1716
fn arrow() {
1817
let mut app = App::new();
1918
app.add_plugins(HyperionCore);

0 commit comments

Comments
 (0)