use super::triangle::Triangle;
use crate::bvh::bin_resource::*;
use crate::bvh::bvh::QuantizedBvh4;
use crate::traits::ComputeAabb3;
use crate::Aabb3;
pub struct QuantizedBvhMesh {
bvh: QuantizedBvh4<u32>,
}
pub trait QueryTriangle {
fn query_triangle(&self, visit: impl FnMut(u32, &Triangle));
}
impl QueryTriangle for Vec<(Triangle, u32)> {
fn query_triangle(&self, mut visit: impl FnMut(u32, &Triangle)) {
for (triangle, index) in self {
visit(*index, triangle);
}
}
}
impl QuantizedBvhMesh {
pub fn new<T>(triangles: &T, encode_scale: f32) -> Self
where
T: QueryTriangle,
{
let mut aabbs = vec![];
triangles.query_triangle(
#[inline]
|id, triangle| {
let aabb = triangle.compute_aabb();
aabbs.push((aabb, id));
},
);
Self {
bvh: QuantizedBvh4::new_with_aabbs(
&aabbs,
encode_scale,
&mut BinAuxiliaryResource::default(),
),
}
}
#[inline]
pub fn find_overlaps(&self, aabb: &Aabb3, mut visit: impl FnMut(u32)) {
self.bvh.aabb_query(
aabb,
#[inline]
|_, triangle_index| {
visit(triangle_index);
true
},
);
}
#[cfg(test)]
#[inline]
#[must_use]
fn bvh(&self) -> &QuantizedBvh4<u32> {
&self.bvh
}
}
#[cfg(test)]
mod tests {
use std::io::BufReader;
use glam_det::{Point3, Vec3};
use tobj::LoadError;
use super::*;
#[test]
fn test_mesh_overlaps() {
let _ = env_logger::builder().is_test(true).try_init();
let file_input = include_bytes!("../../tests/reduced_bunny.obj");
let mut buf = BufReader::new(file_input.as_slice());
let (models, _) = tobj::load_obj_buf(&mut buf, &tobj::LoadOptions::default(), |_| {
Err(LoadError::ReadError)
})
.expect("failed to load object");
let mut triangles: Vec<(Triangle, u32)> = vec![];
if let Some(model) = models.first() {
let indices = &model.mesh.indices;
let positions = &model.mesh.positions;
for face in 0..indices.len() / 3 {
let v0 = indices[face * 3] as usize;
let v1 = indices[face * 3 + 1] as usize;
let v2 = indices[face * 3 + 2] as usize;
let p0 = Point3::new(
positions[v0 * 3],
positions[v0 * 3 + 1],
positions[v0 * 3 + 2],
);
let p1 = Point3::new(
positions[v1 * 3],
positions[v1 * 3 + 1],
positions[v1 * 3 + 2],
);
let p2 = Point3::new(
positions[v2 * 3],
positions[v2 * 3 + 1],
positions[v2 * 3 + 2],
);
triangles.push((Triangle::new(p0, p1, p2), face as u32));
}
let bvh_mesh = QuantizedBvhMesh::new(&triangles, 1000.0);
let query_aabb_position = Point3::new(-1.639, 1.882, 0.862);
let query_aabb_size = Vec3::new(0.1, 0.17, 0.2);
let query_aabb = Aabb3::new(
query_aabb_position - query_aabb_size * 0.5,
query_aabb_position + query_aabb_size * 0.5,
);
let mut brute_force_results: Vec<u32> = Vec::new();
let mut bvh_results: Vec<u32> = Vec::new();
for (triangle, index) in &triangles {
let aabb = triangle.compute_aabb();
if aabb.overlap_test(&query_aabb) {
brute_force_results.push(*index);
}
}
bvh_mesh.find_overlaps(&query_aabb, |leaf| {
bvh_results.push(leaf);
});
for leaf_index in &brute_force_results {
assert!(bvh_results.contains(leaf_index));
}
let mut leaves: Vec<u32> = Vec::new();
bvh_mesh.bvh().traverse_leaves(|triangle_index| {
leaves.push(triangle_index);
});
leaves.sort_unstable();
for (index, triangle_index) in leaves.iter().enumerate() {
assert_eq!(*triangle_index, index as u32);
}
}
}
}