1use crate::core::error::*;
2use crate::core::geometry::*;
3use crate::core::interaction::*;
4use crate::core::param_set::*;
5use crate::core::primitive::*;
6use crate::core::profile::*;
7use crate::core::shape::*;
8
9use std::sync::Arc;
10
11#[derive(Clone, Copy, Debug)]
13enum KDAccelNode {
14 Leaf {
15 primitive_indices_offset: usize,
16 n_primitives: usize,
17 },
18 Interior {
19 axis: u8,
20 split: Float,
21 above_child: usize,
22 },
23}
24
25impl KDAccelNode {
26 fn init_leaf(prim_nums: &[usize], primitive_indices: &mut Vec<usize>) -> Self {
27 let primitive_indices_offset = primitive_indices.len();
28 let n_primitives = prim_nums.len();
29 for i in 0..prim_nums.len() {
30 primitive_indices.push(prim_nums[i]);
31 }
32 KDAccelNode::Leaf {
33 primitive_indices_offset,
34 n_primitives,
35 }
36 }
37 fn init_interior(axis: u8, split: Float, above_child: usize) -> Self {
38 KDAccelNode::Interior {
39 axis,
40 split,
41 above_child,
42 }
43 }
44}
45
46#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
47enum EdgeType {
48 Start,
49 End,
50}
51
52impl Default for EdgeType {
53 fn default() -> Self {
54 EdgeType::Start
55 }
56}
57
58#[derive(Clone, Copy, Default, Debug)]
59struct BoundEdge {
60 t: Float,
61 prim_num: usize,
62 edge_type: EdgeType,
63}
64
65struct KDTreeBuilder {
66 pub isect_cost: i32,
67 pub traversal_cost: i32,
68 pub max_prims: usize,
69 pub empty_bonus: Float,
70}
71
72impl KDTreeBuilder {
73 pub fn build_tree(
74 &mut self,
75 node_bounds: &Bounds3f,
76 all_prim_bounds: &[Bounds3f],
77 prim_nums: &[usize],
78 nodes: &mut Vec<KDAccelNode>,
79 primitive_indices: &mut Vec<usize>,
80 depth: i32,
81 bad_refines: u32,
82 ) -> usize {
83 let node_num = nodes.len();
84 let n_primitives = prim_nums.len();
86 if n_primitives <= self.max_prims || depth == 0 {
87 nodes.push(KDAccelNode::init_leaf(prim_nums, primitive_indices));
88 return node_num;
89 }
90
91 if let Some((best_axis, t_split, primes0, primes1, bad_refines)) =
93 self.choose_split_axis(node_bounds, all_prim_bounds, prim_nums, bad_refines)
94 {
95 assert!(best_axis < 3);
96
97 let mut bounds0 = node_bounds.clone();
99 let mut bounds1 = node_bounds.clone();
100 bounds0.max[best_axis] = t_split;
101 bounds1.min[best_axis] = t_split;
102 nodes.push(KDAccelNode::init_interior(best_axis as u8, t_split, 0)); let left_index = self.build_tree(
105 &bounds0,
106 all_prim_bounds,
107 &primes0,
108 nodes,
109 primitive_indices,
110 depth - 1,
111 bad_refines,
112 );
113 let right_index = self.build_tree(
114 &bounds1,
115 all_prim_bounds,
116 &primes1,
117 nodes,
118 primitive_indices,
119 depth - 1,
120 bad_refines,
121 );
122 assert_eq!(node_num + 1, left_index);
123 nodes[node_num] = KDAccelNode::init_interior(best_axis as u8, t_split, right_index);
124 } else {
125 nodes.push(KDAccelNode::init_leaf(prim_nums, primitive_indices));
126 }
127 return node_num;
128 }
129
130 fn choose_split_axis(
131 &self,
132 node_bounds: &Bounds3f,
133 all_prim_bounds: &[Bounds3f],
134 prim_nums: &[usize],
135 bad_refines: u32,
136 ) -> Option<(usize, Float, Vec<usize>, Vec<usize>, u32)> {
137 let n_primitives = prim_nums.len();
138
139 let mut best_axis: i32 = -1;
141 let mut best_offset: i64 = -1;
142 let mut best_cost = Float::INFINITY;
143 let old_cost = self.isect_cost as Float * n_primitives as Float;
144 let total_sa = node_bounds.surface_area();
145 let inv_total_sa = 1.0 / total_sa;
146 let traversal_cost = self.traversal_cost as Float;
147 let isect_cost = self.isect_cost as Float;
148 let empty_bonus = self.empty_bonus;
149 let d = node_bounds.max - node_bounds.min;
150
151 let mut edges = vec![vec![BoundEdge::default(); 2 * n_primitives]; 3];
153
154 let mut axis = node_bounds.maximum_extent();
156 let mut retries = 0;
157 loop {
158 for i in 0..n_primitives {
160 let pn = prim_nums[i];
161 let bounds = &all_prim_bounds[pn];
162 edges[axis][2 * i + 0] = BoundEdge {
163 t: bounds.min[axis],
164 prim_num: pn,
165 edge_type: EdgeType::Start,
166 };
167 edges[axis][2 * i + 1] = BoundEdge {
168 t: bounds.max[axis],
169 prim_num: pn,
170 edge_type: EdgeType::End,
171 };
172 }
173
174 edges[axis].sort_by(|a, b| {
176 if a.t == b.t {
177 return a.edge_type.partial_cmp(&b.edge_type).unwrap();
178 } else {
179 return a.t.partial_cmp(&b.t).unwrap();
180 }
181 });
182
183 let n_edges = 2 * n_primitives;
184
185 let mut n_below = 0;
187 let mut n_above = n_primitives;
188 for i in 0..n_edges {
189 if edges[axis][i].edge_type == EdgeType::End {
190 n_above -= 1;
191 }
192 let edge_t = edges[axis][i].t;
193 if edge_t > node_bounds.min[axis] && edge_t < node_bounds.max[axis] {
194 let other_axis0 = (axis + 1) % 3;
196 let other_axis1 = (axis + 2) % 3;
197 let below_sa = 2.0
198 * (d[other_axis0] * d[other_axis1]
199 + (edge_t - node_bounds.min[axis]) * (d[other_axis0] + d[other_axis1]));
200 let above_sa = 2.0
201 * (d[other_axis0] * d[other_axis1]
202 + (node_bounds.max[axis] - edge_t) * (d[other_axis0] + d[other_axis1]));
203 let p_below = below_sa * inv_total_sa;
204 let p_above = above_sa * inv_total_sa;
205 let eb = if n_above == 0 || n_below == 0 {
206 empty_bonus
207 } else {
208 0.0
209 };
210 let cost = traversal_cost
211 * isect_cost
212 * (1.0 - eb)
213 * (p_below * n_below as Float + p_above * n_above as Float);
214 if cost < best_cost {
215 best_cost = cost;
216 best_axis = axis as i32;
217 best_offset = i as i64;
218 }
219 }
220 if edges[axis][i].edge_type == EdgeType::Start {
221 n_below += 1;
222 }
223 }
224
225 if best_axis < 0 && retries < 2 {
227 retries += 1;
228 axis = (axis + 1) % 3;
229 continue;
230 }
231 break;
232 }
233
234 let mut bad_refines = bad_refines;
235 if best_cost > old_cost {
236 bad_refines += 1;
237 }
238 if (best_cost > 4.0 * old_cost && n_primitives < 16) || bad_refines == 3 {
239 return None;
240 }
241
242 if best_axis >= 0 && best_offset >= 0 {
243 let best_axis = best_axis as usize;
244 let best_offset = best_offset as usize;
245 let t_split = edges[best_axis][best_offset].t;
246
247 let mut primes0 = Vec::new();
249 let mut primes1 = Vec::new();
250 for i in 0..best_offset {
251 if edges[best_axis][i].edge_type == EdgeType::Start {
252 primes0.push(edges[best_axis][i].prim_num);
253 }
254 }
255 for i in (best_offset + 1)..(2 * n_primitives) {
256 if edges[best_axis][i].edge_type == EdgeType::End {
257 primes1.push(edges[best_axis][i].prim_num);
258 }
259 }
260
261 let length0 = primes0.len();
262 let length1 = primes1.len();
263 if length0 == 0 || length1 == 0 {
264 return None;
265 }
266
267 return Some((best_axis, t_split, primes0, primes1, bad_refines));
268 } else {
269 return None;
270 }
271 }
272}
273
274pub struct KDTreeAccel {
275 primitives: Vec<Arc<dyn Primitive>>,
276 primitive_indices: Vec<usize>,
277 nodes: Vec<KDAccelNode>,
278 bounds: Bounds3f,
279}
280
281impl KDTreeAccel {
282 pub fn new(
283 prims: &[Arc<dyn Primitive>],
284 isect_cost: i32,
285 traversal_cost: i32,
286 empty_bonus: Float,
287 max_primes: i32,
288 max_depth: i32,
289 ) -> Self {
290 let _p = ProfilePhase::new(Prof::AccelConstruction);
292
293 let primitives = prims.to_vec();
294
295 let max_depth = if max_depth <= 0 {
296 (8.0 + 1.3 * (prims.len() as f32).log2()).round() as i32
297 } else {
298 max_depth
299 };
300
301 let mut bounds = prims[0].world_bound();
303 let mut prim_bounds: Vec<Bounds3f> = Vec::with_capacity(primitives.len());
304 for prim in primitives.iter() {
305 let b = prim.world_bound();
306 bounds = Bounds3f::union(&bounds, &b);
307 prim_bounds.push(b);
308 }
309
310 let mut prim_nums = vec![0; primitives.len()];
312 for i in 0..primitives.len() {
313 prim_nums[i] = i;
314 }
315
316 let mut builder = KDTreeBuilder {
318 isect_cost,
319 traversal_cost,
320 max_prims: max_primes as usize,
321 empty_bonus,
322 };
323 let mut nodes = Vec::new();
324 let mut primitive_indices = Vec::new();
325 let root_index = builder.build_tree(
326 &bounds,
327 &prim_bounds,
328 &mut prim_nums,
329 &mut nodes,
330 &mut primitive_indices,
331 max_depth,
332 0,
333 );
334 assert!(root_index == 0);
335 return KDTreeAccel {
336 primitives,
337 primitive_indices,
338 nodes,
339 bounds,
340 };
341 }
342}
343
344type KDTodo = (usize, Float, Float);
345
346#[inline]
348fn safe_recip(x: Float) -> Float {
349 if x != 0.0 {
350 return Float::recip(x);
351 } else {
352 return 0.0; }
354}
355
356impl Primitive for KDTreeAccel {
357 fn world_bound(&self) -> Bounds3f {
358 return self.bounds;
359 }
360 fn intersect(&self, r: &Ray) -> Option<SurfaceInteraction> {
361 let _p = ProfilePhase::new(Prof::AccelIntersect);
362
363 let (t_min, t_max) = self.bounds.intersect_p(r)?;
365
366 let mut isect = None;
367 let inv_dir = [safe_recip(r.d.x), safe_recip(r.d.y), safe_recip(r.d.z)];
369 const MAX_TODO: usize = 64;
370 let mut todo: [KDTodo; MAX_TODO] = [(0, 0.0, 0.0); MAX_TODO];
371 let mut todo_pos: i32 = 0;
372 todo[todo_pos as usize] = (0, t_min, t_max);
373 while todo_pos >= 0 {
374 let (node_num, t_min, t_max) = todo[todo_pos as usize];
375 todo_pos -= 1;
376 let node = &self.nodes[node_num];
377 if r.t_max.get() < t_min {
379 break;
380 }
381 match node {
382 KDAccelNode::Interior {
383 axis,
384 split,
385 above_child,
386 } => {
387 let split = *split;
391 let axis = *axis as usize;
392 let above_child = *above_child as usize;
393 let t_plane = (split - r.o[axis]) * inv_dir[axis];
394 let below_first = r.o[axis] < split || (r.o[axis] == split && r.d[axis] <= 0.0);
395 let (first_index, second_index) = if below_first {
396 (node_num + 1, above_child)
397 } else {
398 (above_child, node_num + 1)
399 };
400
401 if t_plane > t_max || t_plane < 0.0 {
403 todo_pos += 1;
404 todo[todo_pos as usize] = (first_index, t_min, t_max);
405 } else if t_plane < t_min {
406 todo_pos += 1;
407 todo[todo_pos as usize] = (second_index, t_min, t_max);
408 } else {
409 todo_pos += 1;
410 todo[todo_pos as usize] = (second_index, t_plane, t_max);
411 todo_pos += 1;
412 todo[todo_pos as usize] = (first_index, t_min, t_plane);
413 }
414 }
415 KDAccelNode::Leaf {
416 primitive_indices_offset,
417 n_primitives,
418 } => {
419 let primitive_indices_offset = *primitive_indices_offset;
421 let n_primitives = *n_primitives;
422 for i in 0..n_primitives {
423 let index = self.primitive_indices[primitive_indices_offset + i];
424 let prim = &self.primitives[index];
425 if let Some(mut isect_n) = prim.intersect(r) {
426 if prim.is_geometric() {
427 isect_n.primitive = Some(Arc::downgrade(prim));
428 }
429 isect = Some(isect_n);
430 }
431 }
432 }
433 }
434 }
435 return isect;
436 }
437
438 fn intersect_p(&self, r: &Ray) -> bool {
439 let _p = ProfilePhase::new(Prof::AccelIntersectP);
440
441 let (t_min, t_max) = if let Some((t_min, t_max)) = self.bounds.intersect_p(r) {
443 (t_min, t_max)
444 } else {
445 return false;
446 };
447
448 let inv_dir = [safe_recip(r.d.x), safe_recip(r.d.y), safe_recip(r.d.z)];
450 const MAX_TODO: usize = 64;
451 let mut todo: [KDTodo; MAX_TODO] = [(0, 0.0, 0.0); MAX_TODO];
452 let mut todo_pos: i32 = 0;
453 todo[todo_pos as usize] = (0, t_min, t_max);
454 while todo_pos >= 0 {
455 let (node_num, t_min, t_max) = todo[todo_pos as usize];
456 todo_pos -= 1;
457 let node = &self.nodes[node_num];
458 if r.t_max.get() < t_min {
460 break;
461 }
462 match node {
463 KDAccelNode::Interior {
464 split,
465 axis,
466 above_child,
467 } => {
468 let split = *split;
472 let axis = *axis as usize;
473 let above_child = *above_child as usize;
474 let t_plane = (split - r.o[axis]) * inv_dir[axis];
475 let below_first = r.o[axis] < split || (r.o[axis] == split && r.d[axis] <= 0.0);
476 let (first_index, second_index) = if below_first {
477 (node_num + 1, above_child)
478 } else {
479 (above_child, node_num + 1)
480 };
481
482 if t_plane > t_max || t_plane < 0.0 {
484 todo_pos += 1;
485 todo[todo_pos as usize] = (first_index, t_min, t_max);
486 } else if t_plane < t_min {
487 todo_pos += 1;
488 todo[todo_pos as usize] = (second_index, t_min, t_max);
489 } else {
490 todo_pos += 1;
491 todo[todo_pos as usize] = (second_index, t_plane, t_max);
492 todo_pos += 1;
493 todo[todo_pos as usize] = (first_index, t_min, t_plane);
494 }
495 }
496 KDAccelNode::Leaf {
497 primitive_indices_offset,
498 n_primitives,
499 } => {
500 let primitive_indices_offset = *primitive_indices_offset;
503 let n_primitives = *n_primitives;
504 for i in 0..n_primitives {
505 let index = self.primitive_indices[primitive_indices_offset + i];
506 if self.primitives[index].intersect_p(r) {
507 return true;
508 }
509 }
510 }
511 }
512 }
513 return false;
514 }
515}
516
517impl Aggregate for KDTreeAccel {}
518
519pub fn create_kdtree_accelerator(
520 prims: &[Arc<dyn Primitive>],
521 params: &ParamSet,
522) -> Result<Arc<dyn Primitive>, PbrtError> {
523 let isect_cost = params.find_one_int("intersectcost", 80);
524 let trav_cost = params.find_one_int("traversalcost", 1);
525 let empty_bonus = params.find_one_float("emptybonus", 0.5);
526 let max_primes = params.find_one_int("maxprims", 1);
527 let max_depth = params.find_one_int("maxdepth", -1);
528 return Ok(Arc::new(KDTreeAccel::new(
529 prims,
530 isect_cost,
531 trav_cost,
532 empty_bonus,
533 max_primes,
534 max_depth,
535 )));
536}