Compare commits

...

2 Commits
luauu ... bb2

Author SHA1 Message Date
6c3f20eb53 how 2025-10-17 15:55:19 +01:00
15736b60ce wip 2025-10-17 15:55:14 +01:00

View File

@@ -272,62 +272,64 @@ fn generate_bvh_node<T>(boxen:Vec<(T,Aabb)>,force:bool)->BvhNode<T>{
sort_x.sort_by_key(|&(_,c)|c);
sort_y.sort_by_key(|&(_,c)|c);
sort_z.sort_by_key(|&(_,c)|c);
let h=n/2;
let (_,median_x)=sort_x[h];
let (_,median_y)=sort_y[h];
let (_,median_z)=sort_z[h];
//locate a run of values equal to the median
//partition point gives the first index for which the predicate evaluates to false
let first_index_eq_median_x=sort_x.partition_point(|&(_,x)|x<median_x);
let first_index_eq_median_y=sort_y.partition_point(|&(_,y)|y<median_y);
let first_index_eq_median_z=sort_z.partition_point(|&(_,z)|z<median_z);
let first_index_gt_median_x=sort_x.partition_point(|&(_,x)|x<=median_x);
let first_index_gt_median_y=sort_y.partition_point(|&(_,y)|y<=median_y);
let first_index_gt_median_z=sort_z.partition_point(|&(_,z)|z<=median_z);
//pick which side median value copies go into such that both sides are as balanced as possible based on distance from n/2
let partition_point_x=if n.abs_diff(2*first_index_eq_median_x)<n.abs_diff(2*first_index_gt_median_x){first_index_eq_median_x}else{first_index_gt_median_x};
let partition_point_y=if n.abs_diff(2*first_index_eq_median_y)<n.abs_diff(2*first_index_gt_median_y){first_index_eq_median_y}else{first_index_gt_median_y};
let partition_point_z=if n.abs_diff(2*first_index_eq_median_z)<n.abs_diff(2*first_index_gt_median_z){first_index_eq_median_z}else{first_index_gt_median_z};
//this ids which octant the boxen is put in
let mut octant=vec![0;n];
for &(i,_) in &sort_x[partition_point_x..]{
octant[i]+=1<<0;
}
for &(i,_) in &sort_y[partition_point_y..]{
octant[i]+=1<<1;
}
for &(i,_) in &sort_z[partition_point_z..]{
octant[i]+=1<<2;
}
//generate lists for unique octant values
let mut list_list=Vec::with_capacity(8);
let mut octant_list=Vec::with_capacity(8);
for (i,(data,aabb)) in boxen.into_iter().enumerate(){
let octant_id=octant[i];
let list_id=if let Some(list_id)=octant_list.iter().position(|&id|id==octant_id){
list_id
}else{
let list_id=list_list.len();
octant_list.push(octant_id);
list_list.push(Vec::new());
list_id
};
list_list[list_id].push((data,aabb));
}
if list_list.len()==1{
generate_bvh_node(list_list.remove(0),true)
}else{
let mut aabb=Aabb::default();
BvhNode{
content:RecursiveContent::Branch(
list_list.into_iter().map(|b|{
let node=generate_bvh_node(b,false);
aabb.join(&node.aabb);
node
}).collect()
),
aabb,
let mut reverse_acumulated_aabbs=vec![fixed_wide::fixed::Fixed::ZERO;n];
fn get_min_area<T>(
boxen:&[(T,Aabb)],
sorted_list:&[(usize,Planar64)],
reverse_acumulated_aabbs:&mut Vec<fixed_wide::fixed::Fixed<2,64>>,
best_area:&mut fixed_wide::fixed::Fixed<2,64>,
)->Option<usize>{
let mut accumulated_aabb=Aabb::default();
// create an array of aabbs which accumulates box aabbs from the end of the list
for (i,&(index,_)) in sorted_list.iter().enumerate().rev(){
accumulated_aabb.join(&boxen[index].1);
reverse_acumulated_aabbs[i]=accumulated_aabb.area_weight();
}
// iterate the list forwards and calculate the total area
// if the boxes were split at this index
accumulated_aabb=Aabb::default();
let mut best_index=None;
for (i,&(index,_)) in sorted_list.iter().enumerate(){
accumulated_aabb.join(&boxen[index].1);
let area=accumulated_aabb.area_weight()+reverse_acumulated_aabbs[i];
if area<*best_area{
*best_area=area;
best_index=Some(i);
}
}
best_index
}
let mut best_area=fixed_wide::fixed::Fixed::MAX;
let mut best_index=0;
let mut best_list=Vec::new();
if let Some(index_x)=get_min_area(&boxen,&sort_x,&mut reverse_acumulated_aabbs,&mut best_area){
best_index=index_x;
best_list=sort_x;
}
if let Some(index_y)=get_min_area(&boxen,&sort_y,&mut reverse_acumulated_aabbs,&mut best_area){
best_index=index_y;
best_list=sort_y;
}
if let Some(index_z)=get_min_area(&boxen,&sort_z,&mut reverse_acumulated_aabbs,&mut best_area){
best_index=index_z;
best_list=sort_z;
}
// need to split boxen into two according to best_list and best_index
let mut second=Vec::with_capacity(best_index);
boxen.retain(|i|);
let second=best_list.split_off(best_index);
let mut aabb=Aabb::default();
BvhNode{
content:RecursiveContent::Branch(
[best_list,second].map(|b|{
let node=generate_bvh_node(b,false);
aabb.join(&node.aabb);
node
}).collect()
),
aabb,
}
}
}