1
- use std:: mem:: swap;
1
+ use std:: { mem:: swap, u32 } ;
2
2
3
3
use itertools:: Itertools ;
4
4
use rayon:: slice:: ParallelSliceMut ;
@@ -7,10 +7,12 @@ use crate::{physics::NormalizedCollisionPair, vector2::Vector2};
7
7
8
8
#[ derive( Default , Clone ) ]
9
9
pub struct Bvh {
10
- nodes : Vec < Node > ,
10
+ node_aabbs : Vec < AABB > ,
11
+ node_tags : Vec < NodeTag > ,
12
+ node_leaf_indices : Vec < u32 > ,
13
+ node_tree_left : Vec < NodeId > ,
14
+ node_tree_right : Vec < NodeId > ,
11
15
object_aabbs : Vec < AABB > ,
12
- object_positions : Vec < Vector2 < f64 > > ,
13
- object_radii : Vec < f64 > ,
14
16
}
15
17
16
18
impl Bvh {
@@ -32,16 +34,21 @@ impl Bvh {
32
34
} ) ;
33
35
}
34
36
items. par_sort_unstable_by_key ( |item| item. morton_code ) ;
35
- let mut nodes = Vec :: with_capacity ( positions. len ( ) * 2 ) ;
37
+
38
+ let mut node_aabbs = Vec :: default ( ) ;
39
+ let mut node_tags = Vec :: default ( ) ;
40
+ let mut node_leaf_indices = Vec :: default ( ) ;
41
+ let mut node_tree_left = Vec :: default ( ) ;
42
+ let mut node_tree_right = Vec :: default ( ) ;
36
43
for item in & items {
37
- nodes. push ( Node {
38
- aabb : object_aabbs[ item. object_index ] ,
39
- kind : NodeKind :: Leaf ( u32:: try_from ( item. object_index ) . unwrap ( ) ) ,
40
- } ) ;
44
+ node_aabbs. push ( object_aabbs[ item. object_index ] ) ;
45
+ node_tags. push ( NodeTag :: Leaf ) ;
46
+ node_leaf_indices. push ( u32:: try_from ( item. object_index ) . unwrap ( ) ) ;
47
+ node_tree_left. push ( NodeId :: INVALID ) ;
48
+ node_tree_right. push ( NodeId :: INVALID ) ;
41
49
}
42
- let mut combine_area = ( 0 ..nodes. len ( ) )
43
- . map ( |i| NodeId ( u32:: try_from ( i) . unwrap ( ) ) )
44
- . collect_vec ( ) ;
50
+
51
+ let mut combine_area = ( 0 ..node_aabbs. len ( ) ) . map ( |i| NodeId ( u32:: try_from ( i) . unwrap ( ) ) ) . collect_vec ( ) ;
45
52
let mut combine_area_tmp = Vec :: with_capacity ( combine_area. len ( ) . div_ceil ( 2 ) ) ;
46
53
let ( mut combine_area, mut combine_area_tmp) = ( & mut combine_area, & mut combine_area_tmp) ;
47
54
while combine_area. len ( ) > 1 {
@@ -52,8 +59,8 @@ impl Bvh {
52
59
} else {
53
60
let left = chunk[ 0 ] ;
54
61
let right = chunk[ 1 ] ;
55
- let left_aabb = nodes [ usize:: try_from ( left. 0 ) . unwrap ( ) ] . aabb ;
56
- let right_aabb = nodes [ usize:: try_from ( right. 0 ) . unwrap ( ) ] . aabb ;
62
+ let left_aabb = node_aabbs [ usize:: try_from ( left. 0 ) . unwrap ( ) ] ;
63
+ let right_aabb = node_aabbs [ usize:: try_from ( right. 0 ) . unwrap ( ) ] ;
57
64
let aabb = AABB {
58
65
topleft : Vector2 :: new (
59
66
left_aabb. topleft . x . min ( right_aabb. topleft . x ) ,
@@ -64,45 +71,76 @@ impl Bvh {
64
71
left_aabb. bottomright . y . max ( right_aabb. bottomright . y ) ,
65
72
) ,
66
73
} ;
67
- let node_id = NodeId ( u32:: try_from ( nodes. len ( ) ) . unwrap ( ) ) ;
68
- nodes. push ( Node {
69
- aabb,
70
- kind : NodeKind :: Tree { left, right } ,
71
- } ) ;
74
+ let node_id = NodeId ( u32:: try_from ( node_aabbs. len ( ) ) . unwrap ( ) ) ;
75
+ node_aabbs. push ( aabb) ;
76
+ node_tags. push ( NodeTag :: Tree ) ;
77
+ node_leaf_indices. push ( u32:: MAX ) ;
78
+ node_tree_left. push ( left) ;
79
+ node_tree_right. push ( right) ;
72
80
node_id
73
81
} ;
74
82
combine_area_tmp. push ( node_id) ;
75
83
}
76
84
swap ( & mut combine_area, & mut combine_area_tmp) ;
77
85
}
78
86
Bvh {
87
+ node_aabbs,
88
+ node_tags,
89
+ node_leaf_indices,
90
+ node_tree_left,
91
+ node_tree_right,
79
92
object_aabbs,
80
- object_positions : positions. to_vec ( ) ,
81
- object_radii : radii. to_vec ( ) ,
82
- nodes,
83
93
}
84
94
}
85
95
86
- pub fn find_intersections ( & self , object_index : usize , candidates : & mut Vec < NormalizedCollisionPair > ) {
87
- if !self . nodes . is_empty ( ) {
88
- self . find_intersections_with ( object_index, candidates) ;
89
- }
96
+ pub fn node_aabbs ( & self ) -> & [ AABB ] {
97
+ & self . node_aabbs
98
+ }
99
+
100
+ pub fn node_tags ( & self ) -> & [ NodeTag ] {
101
+ & self . node_tags
102
+ }
103
+
104
+ pub fn node_leaf_indices ( & self ) -> & [ u32 ] {
105
+ & self . node_leaf_indices
106
+ }
107
+
108
+ pub fn node_tree_left ( & self ) -> & [ NodeId ] {
109
+ & self . node_tree_left
90
110
}
91
111
92
- pub fn nodes ( & self ) -> & [ Node ] {
93
- & self . nodes
112
+ pub fn node_tree_right ( & self ) -> & [ NodeId ] {
113
+ & self . node_tree_right
94
114
}
95
115
96
116
pub fn root ( & self ) -> NodeId {
97
- let id = self . nodes . len ( ) . checked_sub ( 1 ) . unwrap ( ) ;
117
+ let id = self . node_aabbs . len ( ) . checked_sub ( 1 ) . unwrap ( ) ;
98
118
NodeId ( u32:: try_from ( id) . unwrap ( ) )
99
119
}
100
120
101
121
pub fn object_aabbs ( & self ) -> & [ AABB ] {
102
122
& self . object_aabbs
103
123
}
104
124
105
- fn find_intersections_with ( & self , object1_index : usize , candidates : & mut Vec < NormalizedCollisionPair > ) {
125
+ pub fn find_intersections (
126
+ & self ,
127
+ object_index : usize ,
128
+ positions : & [ Vector2 < f64 > ] ,
129
+ radii : & [ f64 ] ,
130
+ candidates : & mut Vec < NormalizedCollisionPair > ,
131
+ ) {
132
+ if !self . node_aabbs . is_empty ( ) {
133
+ self . find_intersections_with ( object_index, positions, radii, candidates) ;
134
+ }
135
+ }
136
+
137
+ fn find_intersections_with (
138
+ & self ,
139
+ object1_index : usize ,
140
+ positions : & [ Vector2 < f64 > ] ,
141
+ radii : & [ f64 ] ,
142
+ candidates : & mut Vec < NormalizedCollisionPair > ,
143
+ ) {
106
144
const STACK_SIZE : usize = 16 ;
107
145
let mut stack = [ NodeId ( 0 ) ; STACK_SIZE ] ;
108
146
let mut sp = 0 ;
@@ -113,27 +151,29 @@ impl Bvh {
113
151
sp -= 1 ;
114
152
let node_id = stack[ sp] ;
115
153
let object_aabb = self . object_aabbs [ object1_index] ;
116
- let Node { aabb, kind, .. } = & self . nodes [ usize:: try_from ( node_id. 0 ) . unwrap ( ) ] ;
117
- if object_aabb. intersects ( aabb) {
118
- match * kind {
119
- NodeKind :: Leaf ( object2_index) => {
120
- let object2_index = usize:: try_from ( object2_index) . unwrap ( ) ;
154
+ let node_id = usize:: try_from ( node_id. 0 ) . unwrap ( ) ;
155
+ let aabb = self . node_aabbs [ node_id] ;
156
+ if object_aabb. intersects ( & aabb) {
157
+ let tag = self . node_tags [ node_id] ;
158
+ match tag {
159
+ NodeTag :: Leaf => {
160
+ let object2_index = usize:: try_from ( self . node_leaf_indices [ node_id] ) . unwrap ( ) ;
121
161
if object2_index != object1_index {
122
- let object1_position = self . object_positions [ object1_index] ;
123
- let object2_position = self . object_positions [ object2_index] ;
124
- let object1_radius = self . object_radii [ object1_index] ;
125
- let object2_radius = self . object_radii [ object2_index] ;
162
+ let object1_position = positions [ object1_index] ;
163
+ let object2_position = positions [ object2_index] ;
164
+ let object1_radius = radii [ object1_index] ;
165
+ let object2_radius = radii [ object2_index] ;
126
166
let distance_squared = ( object1_position - object2_position) . magnitude_squared ( ) ;
127
167
let collision_distance = object1_radius + object2_radius;
128
168
if distance_squared < collision_distance * collision_distance {
129
169
candidates. push ( NormalizedCollisionPair :: new ( object1_index, object2_index) ) ;
130
170
}
131
171
}
132
172
}
133
- NodeKind :: Tree { left , right } => {
134
- stack[ sp] = left ;
173
+ NodeTag :: Tree => {
174
+ stack[ sp] = self . node_tree_left [ node_id ] ;
135
175
sp += 1 ;
136
- stack[ sp] = right ;
176
+ stack[ sp] = self . node_tree_right [ node_id ] ;
137
177
sp += 1 ;
138
178
}
139
179
}
@@ -180,6 +220,17 @@ impl AABB {
180
220
#[ derive( Default , Debug , Clone , Copy ) ]
181
221
pub struct NodeId ( u32 ) ;
182
222
223
+ impl NodeId {
224
+ const INVALID : Self = Self ( u32:: MAX ) ;
225
+ }
226
+
227
+ #[ repr( C ) ]
228
+ #[ derive( Clone , Copy ) ]
229
+ pub enum NodeTag {
230
+ Leaf ,
231
+ Tree ,
232
+ }
233
+
183
234
#[ repr( C ) ]
184
235
#[ derive( Clone , Copy ) ]
185
236
pub struct Node {
0 commit comments