@@ -42,11 +42,20 @@ impl Ray {
42
42
self . origin + self . direction * t
43
43
}
44
44
45
- /// Efficiently traverse through grid cells that the ray intersects.
45
+ /// Efficiently traverse through grid cells that the ray intersects using an optimized DDA algorithm .
46
46
/// Returns an iterator over the grid cells ([`IVec3`]) that the ray passes through.
47
47
pub fn voxel_traversal ( & self , bounds_min : IVec3 , bounds_max : IVec3 ) -> VoxelTraversal {
48
- // Convert ray origin to grid coordinates
49
- let current_pos = self . origin . floor ( ) . as_ivec3 ( ) ;
48
+ // Convert ray origin to grid coordinates and handle negative coordinates correctly
49
+ #[ allow( clippy:: cast_possible_truncation) ]
50
+ let current_pos = if self . origin . x < 0.0 || self . origin . y < 0.0 || self . origin . z < 0.0 {
51
+ IVec3 :: new (
52
+ self . origin . x . floor ( ) as i32 ,
53
+ self . origin . y . floor ( ) as i32 ,
54
+ self . origin . z . floor ( ) as i32 ,
55
+ )
56
+ } else {
57
+ self . origin . as_ivec3 ( )
58
+ } ;
50
59
51
60
// Calculate step direction for each axis
52
61
let step = IVec3 :: new (
@@ -73,42 +82,56 @@ impl Ray {
73
82
} ,
74
83
) ;
75
84
76
- // Calculate initial t_max values (distance to next voxel boundary for each axis)
77
- let next_voxel = current_pos + step;
85
+ // Calculate t_max - distance to next voxel boundary for each axis
78
86
let t_max = Vec3 :: new (
79
87
if self . direction . x == 0.0 {
80
88
f32:: INFINITY
81
89
} else {
82
- ( ( next_voxel. x as f32 ) - self . origin . x ) * self . inv_direction . x
90
+ let next_x = if self . direction . x > 0.0 {
91
+ current_pos. x as f32 + 1.0 - self . origin . x
92
+ } else {
93
+ self . origin . x - current_pos. x as f32
94
+ } ;
95
+ next_x * self . inv_direction . x . abs ( )
83
96
} ,
84
97
if self . direction . y == 0.0 {
85
98
f32:: INFINITY
86
99
} else {
87
- ( ( next_voxel. y as f32 ) - self . origin . y ) * self . inv_direction . y
100
+ let next_y = if self . direction . y > 0.0 {
101
+ current_pos. y as f32 + 1.0 - self . origin . y
102
+ } else {
103
+ self . origin . y - current_pos. y as f32
104
+ } ;
105
+ next_y * self . inv_direction . y . abs ( )
88
106
} ,
89
107
if self . direction . z == 0.0 {
90
108
f32:: INFINITY
91
109
} else {
92
- ( ( next_voxel. z as f32 ) - self . origin . z ) * self . inv_direction . z
110
+ let next_z = if self . direction . z > 0.0 {
111
+ current_pos. z as f32 + 1.0 - self . origin . z
112
+ } else {
113
+ self . origin . z - current_pos. z as f32
114
+ } ;
115
+ next_z * self . inv_direction . z . abs ( )
93
116
} ,
94
117
) ;
95
118
96
- // Calculate t_delta values ( distance between voxel boundaries)
119
+ // Calculate t_delta - distance between voxel boundaries
97
120
let t_delta = Vec3 :: new (
98
121
if self . direction . x == 0.0 {
99
122
f32:: INFINITY
100
123
} else {
101
- step . x as f32 * self . inv_direction . x
124
+ self . inv_direction . x . abs ( )
102
125
} ,
103
126
if self . direction . y == 0.0 {
104
127
f32:: INFINITY
105
128
} else {
106
- step . y as f32 * self . inv_direction . y
129
+ self . inv_direction . y . abs ( )
107
130
} ,
108
131
if self . direction . z == 0.0 {
109
132
f32:: INFINITY
110
133
} else {
111
- step . z as f32 * self . inv_direction . z
134
+ self . inv_direction . z . abs ( )
112
135
} ,
113
136
) ;
114
137
0 commit comments