obvhs/bvh2/node.rs
1use bytemuck::{Pod, Zeroable};
2#[cfg(feature = "small_bvh2_node")]
3use glam::Vec3;
4
5use crate::aabb::Aabb;
6
7#[cfg(feature = "small_bvh2_node")]
8static_assertions::assert_eq_size!(Bvh2Node, Aabb);
9#[cfg(feature = "small_bvh2_node")]
10static_assertions::assert_eq_align!(Bvh2Node, Aabb);
11
12#[cfg(feature = "small_bvh2_node")]
13/// A node in the Bvh2, can be an inner node or leaf.
14#[derive(Default, Clone, Copy, Debug, Pod, Zeroable)]
15#[repr(C)]
16#[repr(align(16))]
17pub struct Bvh2Node {
18 /// The bounding box minimum coordinate for the primitive(s) contained in this node
19 pub min: Vec3,
20 /// Number of primitives contained in this node.
21 /// If prim_count is 0, this is a inner node.
22 /// If prim_count > 0 this node is a leaf node.
23 /// Note: CwBvh will clamp to max 3, Bvh2 will clamp to max 255
24 /// partial rebuilds uses u32::MAX to temporarily designate a subtree root.
25 pub prim_count: u32,
26 /// The bounding box maximum coordinate for the primitive(s) contained in this node
27 pub max: Vec3,
28 /// The index of the first child Aabb or primitive.
29 /// If this node is an inner node the first child will be at `nodes[first_index]`, and the second at `nodes[first_index + 1]`.
30 /// If this node is a leaf node the first index typically indexes into a primitive_indices list that contains the actual index of the primitive.
31 /// The reason for this mapping is that if multiple primitives are contained in this node, they need to have their indices layed out contiguously.
32 /// To avoid this indirection we have two options:
33 /// 1. Layout the primitives in the order of the primitive_indices mapping so that this can index directly into the primitive list.
34 /// 2. Only allow one primitive per node and write back the original mapping to the bvh node list.
35 pub first_index: u32,
36}
37
38#[cfg(not(feature = "small_bvh2_node"))]
39/// A node in the Bvh2, can be an inner node or leaf.
40#[derive(Default, Clone, Copy, Debug, Pod, Zeroable)]
41#[repr(C)]
42#[repr(align(16))]
43pub struct Bvh2Node {
44 /// The bounding box for the primitive(s) contained in this node
45 pub aabb: Aabb,
46 /// Number of primitives contained in this node.
47 /// If prim_count is 0, this is a inner node.
48 /// If prim_count > 0 this node is a leaf node.
49 /// Note: CwBvh will clamp to max 3, Bvh2 will clamp to max 255
50 /// partial rebuilds uses u32::MAX to temporarily designate a subtree root.
51 pub prim_count: u32,
52 /// The index of the first child Aabb or primitive.
53 /// If this node is an inner node the first child will be at `nodes[first_index]`, and the second at `nodes[first_index + 1]`.
54 /// If this node is a leaf node the first index typically indexes into a primitive_indices list that contains the actual index of the primitive.
55 /// The reason for this mapping is that if multiple primitives are contained in this node, they need to have their indices layed out contiguously.
56 /// To avoid this indirection we have two options:
57 /// 1. Layout the primitives in the order of the primitive_indices mapping so that this can index directly into the primitive list.
58 /// 2. Only allow one primitive per node and write back the original mapping to the bvh node list.
59 pub first_index: u32,
60 /// With the aabb, prim_count, and first_index, this struct was already padded out to 48 bytes. These meta fields
61 /// allow the user to access this otherwise unused space.
62 pub meta1: u32,
63 /// With the aabb, prim_count, and first_index, this struct was already padded out to 48 bytes. These meta fields
64 /// allow the user to access this otherwise unused space.
65 pub meta2: u32,
66}
67
68impl Bvh2Node {
69 #[cfg(feature = "small_bvh2_node")]
70 #[inline(always)]
71 pub fn new(aabb: Aabb, prim_count: u32, first_index: u32) -> Self {
72 let mut node: Bvh2Node = bytemuck::cast(aabb);
73 node.prim_count = prim_count;
74 node.first_index = first_index;
75 node
76 }
77
78 #[cfg(not(feature = "small_bvh2_node"))]
79 #[inline(always)]
80 pub fn new(aabb: Aabb, prim_count: u32, first_index: u32) -> Self {
81 Bvh2Node {
82 aabb,
83 prim_count,
84 first_index,
85 meta1: Default::default(),
86 meta2: Default::default(),
87 }
88 }
89
90 #[cfg(feature = "small_bvh2_node")]
91 #[inline(always)]
92 pub fn aabb(&self) -> &Aabb {
93 // Note(Lokathor): (from bytemuck::try_cast_ref()) everything with `align_of` and `size_of` will optimize away
94 // after monomorphization.
95 // Note(Griffin): checked asm and this appears to be correct. Test with:
96
97 // #[unsafe(no_mangle)] pub unsafe extern "C" fn aabb_shim(node: &Bvh2Node) -> &Aabb { node.aabb() }
98 // (use basic_bvh2 in black_box in basic_bvh2)
99 // cargo objdump --example basic_bvh2 --release --features small_bvh2_node -- -d --disassemble-symbols=aabb_shim -C
100
101 // 000000000003e260 <aabb_shim>:
102 // 3e260: 48 89 f8 movq %rdi, %rax
103 // 3e263: c3 retq
104
105 bytemuck::cast_ref(self)
106 }
107
108 #[cfg(not(feature = "small_bvh2_node"))]
109 #[inline(always)]
110 pub fn aabb(&self) -> &Aabb {
111 &self.aabb
112 }
113
114 #[cfg(feature = "small_bvh2_node")]
115 #[inline(always)]
116 pub fn set_aabb(&mut self, aabb: Aabb) {
117 self.min = aabb.min.into();
118 self.max = aabb.max.into();
119 }
120
121 #[cfg(not(feature = "small_bvh2_node"))]
122 #[inline(always)]
123 pub fn set_aabb(&mut self, aabb: Aabb) {
124 self.aabb = aabb;
125 }
126
127 #[inline(always)]
128 /// Also returns true for invalid nodes. If that matters in the context you are using this also check
129 /// Bvh2::is_invalid (used internally for partial BVH rebuilds)
130 pub fn is_leaf(&self) -> bool {
131 self.prim_count != 0
132 }
133
134 #[inline(always)]
135 /// Used internally for partial BVH rebuilds. Does not usually need to be checked. Currently, a bvh will only
136 /// temporarily contain any invalid nodes.
137 pub fn valid(&self) -> bool {
138 (self.prim_count & 0b10000000000000000000000000000000) == 0
139 }
140
141 #[inline(always)]
142 /// Used internally for partial BVH rebuilds.
143 pub fn set_invalid(&mut self) {
144 self.prim_count |= 0b10000000000000000000000000000000
145 }
146
147 #[inline(always)]
148 /// Used internally for partial BVH rebuilds.
149 pub fn set_valid(&mut self) {
150 self.prim_count &= 0b01111111111111111111111111111111
151 }
152
153 #[inline(always)]
154 pub fn is_left_sibling(node_id: usize) -> bool {
155 node_id % 2 == 1
156 }
157 #[inline(always)]
158 pub fn get_sibling_id(node_id: usize) -> usize {
159 if Self::is_left_sibling(node_id) {
160 node_id + 1
161 } else {
162 node_id - 1
163 }
164 }
165 #[inline(always)]
166 pub fn get_left_sibling_id(node_id: usize) -> usize {
167 if Self::is_left_sibling(node_id) {
168 node_id
169 } else {
170 node_id - 1
171 }
172 }
173 #[inline(always)]
174 pub fn get_right_sibling_id(node_id: usize) -> usize {
175 if Self::is_left_sibling(node_id) {
176 node_id + 1
177 } else {
178 node_id
179 }
180 }
181
182 #[inline(always)]
183 pub fn is_left_sibling32(node_id: u32) -> bool {
184 node_id % 2 == 1
185 }
186 #[inline(always)]
187 pub fn get_sibling_id32(node_id: u32) -> u32 {
188 if Self::is_left_sibling32(node_id) {
189 node_id + 1
190 } else {
191 node_id - 1
192 }
193 }
194 #[inline(always)]
195 pub fn get_left_sibling_id32(node_id: u32) -> u32 {
196 if Self::is_left_sibling32(node_id) {
197 node_id
198 } else {
199 node_id - 1
200 }
201 }
202 #[inline(always)]
203 pub fn get_right_sibling_id32(node_id: u32) -> u32 {
204 if Self::is_left_sibling32(node_id) {
205 node_id + 1
206 } else {
207 node_id
208 }
209 }
210 #[inline(always)]
211 pub fn make_inner(&mut self, first_index: u32) {
212 self.prim_count = 0;
213 self.first_index = first_index;
214 }
215}