forked from StrafesNET/strafe-client
deduplicate models
This commit is contained in:
parent
7e1cf7041a
commit
747f628f04
174
src/main.rs
174
src/main.rs
@ -230,7 +230,7 @@ impl GlobalState{
|
|||||||
Some(ModelGraphicsInstance{
|
Some(ModelGraphicsInstance{
|
||||||
transform: instance.transform.into(),
|
transform: instance.transform.into(),
|
||||||
normal_transform: Into::<glam::Mat3>::into(instance.transform.matrix3).inverse().transpose(),
|
normal_transform: Into::<glam::Mat3>::into(instance.transform.matrix3).inverse().transpose(),
|
||||||
color: instance.color,
|
color:model_graphics::ModelGraphicsColor4::from(instance.color),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
@ -262,9 +262,174 @@ impl GlobalState{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//check every model to see if it's using the same (texture,color) but has few instances, if it is combine it into one model
|
||||||
|
//1. collect unique instances of texture and color, note model id
|
||||||
|
//2. for each model id, check if removing it from the pool decreases both the model count and instance count by more than one
|
||||||
|
//3. transpose all models that stay in the set
|
||||||
|
|
||||||
|
//best plan: benchmark set_bind_group, set_vertex_buffer, set_index_buffer and draw_indexed
|
||||||
|
//check if the estimated render performance is better by transposing multiple model instances into one model instance
|
||||||
|
|
||||||
|
//for now: just deduplicate single models...
|
||||||
|
let mut deduplicated_models=Vec::with_capacity(indexed_models_len);//use indexed_models_len because the list will likely get smaller instead of bigger
|
||||||
|
let mut unique_texture_color=std::collections::HashMap::new();//texture->color->vec![(model_id,instance_id)]
|
||||||
|
for (model_id,model) in unique_texture_models.iter().enumerate(){
|
||||||
|
//for now: filter out models with more than one instance
|
||||||
|
if 1<model.instances.len(){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//populate hashmap
|
||||||
|
let unique_color=if let Some(unique_color)=unique_texture_color.get_mut(&model.texture){
|
||||||
|
unique_color
|
||||||
|
}else{
|
||||||
|
//make new hashmap
|
||||||
|
let unique_color=std::collections::HashMap::new();
|
||||||
|
unique_texture_color.insert(model.texture,unique_color);
|
||||||
|
unique_texture_color.get_mut(&model.texture).unwrap()
|
||||||
|
};
|
||||||
|
//separate instances by color
|
||||||
|
for (instance_id,instance) in model.instances.iter().enumerate(){
|
||||||
|
let model_instance_list=if let Some(model_instance_list)=unique_color.get_mut(&instance.color){
|
||||||
|
model_instance_list
|
||||||
|
}else{
|
||||||
|
//make new hashmap
|
||||||
|
let model_instance_list=Vec::new();
|
||||||
|
unique_color.insert(instance.color.clone(),model_instance_list);
|
||||||
|
unique_color.get_mut(&instance.color).unwrap()
|
||||||
|
};
|
||||||
|
//add model instance to list
|
||||||
|
model_instance_list.push((model_id,instance_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//populate a hashset of models selected for transposition
|
||||||
|
//construct transposed models
|
||||||
|
let mut selected_model_instances=std::collections::HashSet::new();
|
||||||
|
for (texture,unique_color) in unique_texture_color.into_iter(){
|
||||||
|
for (color,model_instance_list) in unique_color.into_iter(){
|
||||||
|
//world transforming one model does not meet the definition of deduplicaiton
|
||||||
|
if 1<model_instance_list.len(){
|
||||||
|
//create model
|
||||||
|
let mut unique_pos=Vec::new();
|
||||||
|
let mut pos_id_from=std::collections::HashMap::new();
|
||||||
|
let mut unique_tex=Vec::new();
|
||||||
|
let mut tex_id_from=std::collections::HashMap::new();
|
||||||
|
let mut unique_normal=Vec::new();
|
||||||
|
let mut normal_id_from=std::collections::HashMap::new();
|
||||||
|
let mut unique_color=Vec::new();
|
||||||
|
let mut color_id_from=std::collections::HashMap::new();
|
||||||
|
let mut unique_vertices=Vec::new();
|
||||||
|
let mut vertex_id_from=std::collections::HashMap::new();
|
||||||
|
|
||||||
|
let mut polys=Vec::new();
|
||||||
|
//transform instance vertices
|
||||||
|
for (model_id,instance_id) in model_instance_list.into_iter(){
|
||||||
|
//populate hashset to prevent these models from being copied
|
||||||
|
selected_model_instances.insert(model_id);
|
||||||
|
//there is only one instance per model
|
||||||
|
let model=&unique_texture_models[model_id];
|
||||||
|
let instance=&model.instances[instance_id];
|
||||||
|
//just hash word slices LOL
|
||||||
|
let map_pos_id:Vec<u32>=model.unique_pos.iter().map(|untransformed_pos|{
|
||||||
|
let pos=instance.transform.transform_point3(glam::Vec3::from_array(untransformed_pos.clone())).to_array();
|
||||||
|
let h=pos.map(|v|bytemuck::cast::<f32,u32>(v));
|
||||||
|
(if let Some(&pos_id)=pos_id_from.get(&h){
|
||||||
|
pos_id
|
||||||
|
}else{
|
||||||
|
let pos_id=unique_pos.len();
|
||||||
|
unique_pos.push(pos.clone());
|
||||||
|
pos_id_from.insert(h,pos_id);
|
||||||
|
pos_id
|
||||||
|
}) as u32
|
||||||
|
}).collect();
|
||||||
|
let map_tex_id:Vec<u32>=model.unique_tex.iter().map(|tex|{
|
||||||
|
let h=tex.map(|v|bytemuck::cast::<f32,u32>(v));
|
||||||
|
(if let Some(&tex_id)=tex_id_from.get(&h){
|
||||||
|
tex_id
|
||||||
|
}else{
|
||||||
|
let tex_id=unique_tex.len();
|
||||||
|
unique_tex.push(tex.clone());
|
||||||
|
tex_id_from.insert(h,tex_id);
|
||||||
|
tex_id
|
||||||
|
}) as u32
|
||||||
|
}).collect();
|
||||||
|
let map_normal_id:Vec<u32>=model.unique_normal.iter().map(|untransformed_normal|{
|
||||||
|
let normal=(instance.normal_transform*glam::Vec3::from_array(untransformed_normal.clone())).to_array();
|
||||||
|
let h=normal.map(|v|bytemuck::cast::<f32,u32>(v));
|
||||||
|
(if let Some(&normal_id)=normal_id_from.get(&h){
|
||||||
|
normal_id
|
||||||
|
}else{
|
||||||
|
let normal_id=unique_normal.len();
|
||||||
|
unique_normal.push(normal.clone());
|
||||||
|
normal_id_from.insert(h,normal_id);
|
||||||
|
normal_id
|
||||||
|
}) as u32
|
||||||
|
}).collect();
|
||||||
|
let map_color_id:Vec<u32>=model.unique_color.iter().map(|color|{
|
||||||
|
let h=color.map(|v|bytemuck::cast::<f32,u32>(v));
|
||||||
|
(if let Some(&color_id)=color_id_from.get(&h){
|
||||||
|
color_id
|
||||||
|
}else{
|
||||||
|
let color_id=unique_color.len();
|
||||||
|
unique_color.push(color.clone());
|
||||||
|
color_id_from.insert(h,color_id);
|
||||||
|
color_id
|
||||||
|
}) as u32
|
||||||
|
}).collect();
|
||||||
|
//map the indexed vertices onto new indices
|
||||||
|
//creating the vertex map is slightly different because the vertices are directly hashable
|
||||||
|
let map_vertex_id:Vec<u32>=model.unique_vertices.iter().map(|unmapped_vertex|{
|
||||||
|
let vertex=model::IndexedVertex{
|
||||||
|
pos:map_pos_id[unmapped_vertex.pos as usize] as u32,
|
||||||
|
tex:map_tex_id[unmapped_vertex.tex as usize] as u32,
|
||||||
|
normal:map_normal_id[unmapped_vertex.normal as usize] as u32,
|
||||||
|
color:map_color_id[unmapped_vertex.color as usize] as u32,
|
||||||
|
};
|
||||||
|
(if let Some(&vertex_id)=vertex_id_from.get(&vertex){
|
||||||
|
vertex_id
|
||||||
|
}else{
|
||||||
|
let vertex_id=unique_vertices.len();
|
||||||
|
unique_vertices.push(vertex.clone());
|
||||||
|
vertex_id_from.insert(vertex,vertex_id);
|
||||||
|
vertex_id
|
||||||
|
}) as u32
|
||||||
|
}).collect();
|
||||||
|
for group in &model.groups{
|
||||||
|
for poly in &group.polys{
|
||||||
|
polys.push(model::IndexedPolygon{vertices:poly.vertices.iter().map(|&vertex_id|map_vertex_id[vertex_id as usize]).collect()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//push model into dedup
|
||||||
|
deduplicated_models.push(model_graphics::IndexedModelGraphicsSingleTexture{
|
||||||
|
unique_pos,
|
||||||
|
unique_tex,
|
||||||
|
unique_normal,
|
||||||
|
unique_color,
|
||||||
|
unique_vertices,
|
||||||
|
texture,
|
||||||
|
groups:vec![model_graphics::IndexedGroupFixedTexture{
|
||||||
|
polys
|
||||||
|
}],
|
||||||
|
instances:vec![model_graphics::ModelGraphicsInstance{
|
||||||
|
transform:glam::Mat4::IDENTITY,
|
||||||
|
normal_transform:glam::Mat3::IDENTITY,
|
||||||
|
color
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fill untouched models
|
||||||
|
for (model_id,model) in unique_texture_models.into_iter().enumerate(){
|
||||||
|
if !selected_model_instances.contains(&model_id){
|
||||||
|
deduplicated_models.push(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//de-index models
|
//de-index models
|
||||||
let mut models=Vec::with_capacity(unique_texture_models.len());
|
let deduplicated_models_len=deduplicated_models.len();
|
||||||
for model in unique_texture_models.into_iter(){
|
let mut models=Vec::with_capacity(deduplicated_models_len);
|
||||||
|
for model in deduplicated_models.into_iter(){
|
||||||
let mut vertices = Vec::new();
|
let mut vertices = Vec::new();
|
||||||
let mut index_from_vertex = std::collections::HashMap::new();//::<IndexedVertex,usize>
|
let mut index_from_vertex = std::collections::HashMap::new();//::<IndexedVertex,usize>
|
||||||
let mut entities = Vec::new();
|
let mut entities = Vec::new();
|
||||||
@ -372,6 +537,7 @@ impl GlobalState{
|
|||||||
println!("Texture References={}",num_textures);
|
println!("Texture References={}",num_textures);
|
||||||
println!("Textures Loaded={}",texture_views.len());
|
println!("Textures Loaded={}",texture_views.len());
|
||||||
println!("Indexed Models={}",indexed_models_len);
|
println!("Indexed Models={}",indexed_models_len);
|
||||||
|
println!("Deduplicated Models={}",deduplicated_models_len);
|
||||||
println!("Graphics Objects: {}",self.graphics.models.len());
|
println!("Graphics Objects: {}",self.graphics.models.len());
|
||||||
println!("Graphics Instances: {}",instance_count);
|
println!("Graphics Instances: {}",instance_count);
|
||||||
}
|
}
|
||||||
@ -393,7 +559,7 @@ fn get_instances_buffer_data(instances:&[ModelGraphicsInstance]) -> Vec<f32> {
|
|||||||
raw.extend_from_slice(AsRef::<[f32; 3]>::as_ref(&mi.normal_transform.z_axis));
|
raw.extend_from_slice(AsRef::<[f32; 3]>::as_ref(&mi.normal_transform.z_axis));
|
||||||
raw.extend_from_slice(&[0.0]);
|
raw.extend_from_slice(&[0.0]);
|
||||||
//color
|
//color
|
||||||
raw.extend_from_slice(AsRef::<[f32; 4]>::as_ref(&mi.color));
|
raw.extend_from_slice(AsRef::<[f32; 4]>::as_ref(&mi.color.get()));
|
||||||
raw.append(&mut v);
|
raw.append(&mut v);
|
||||||
}
|
}
|
||||||
raw
|
raw
|
||||||
|
@ -27,9 +27,29 @@ pub struct ModelGraphicsSingleTexture{
|
|||||||
pub entities: Vec<Vec<u16>>,
|
pub entities: Vec<Vec<u16>>,
|
||||||
pub texture: Option<u32>,
|
pub texture: Option<u32>,
|
||||||
}
|
}
|
||||||
|
#[derive(Clone,PartialEq)]
|
||||||
|
pub struct ModelGraphicsColor4(glam::Vec4);
|
||||||
|
impl ModelGraphicsColor4{
|
||||||
|
pub const fn get(&self)->glam::Vec4{
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<glam::Vec4> for ModelGraphicsColor4{
|
||||||
|
fn from(value:glam::Vec4)->Self{
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl std::hash::Hash for ModelGraphicsColor4{
|
||||||
|
fn hash<H: std::hash::Hasher>(&self,state:&mut H) {
|
||||||
|
for &f in self.0.as_ref(){
|
||||||
|
bytemuck::cast::<f32,u32>(f).hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for ModelGraphicsColor4{}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ModelGraphicsInstance{
|
pub struct ModelGraphicsInstance{
|
||||||
pub transform:glam::Mat4,
|
pub transform:glam::Mat4,
|
||||||
pub normal_transform:glam::Mat3,
|
pub normal_transform:glam::Mat3,
|
||||||
pub color:glam::Vec4,
|
pub color:ModelGraphicsColor4,
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user