Compare commits
2 Commits
mesh-shade
...
bb2
| Author | SHA1 | Date | |
|---|---|---|---|
| 6c3f20eb53 | |||
| 15736b60ce |
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user