physics mesh builder rewrite

This commit is contained in:
Quaternions 2024-02-07 20:52:32 -08:00
parent 96085a3076
commit f412874317

View File

@ -1,5 +1,6 @@
use std::borrow::{Borrow,Cow}; use std::borrow::{Borrow,Cow};
use strafesnet_common::model; use std::collections::{HashSet,HashMap};
use strafesnet_common::model::{self,PolygonIter};
use strafesnet_common::zeroes; use strafesnet_common::zeroes;
use strafesnet_common::integer::{self,Planar64,Planar64Vec3}; use strafesnet_common::integer::{self,Planar64,Planar64Vec3};
@ -56,6 +57,7 @@ pub enum FEV<F,E:DirectedEdge,V>{
} }
//use Unit32 #[repr(C)] for map files //use Unit32 #[repr(C)] for map files
#[derive(Clone,Hash,Eq,PartialEq)]
struct Face{ struct Face{
normal:Planar64Vec3, normal:Planar64Vec3,
dot:Planar64, dot:Planar64,
@ -188,21 +190,28 @@ impl PhysicsMesh{
pub fn unit_cylinder()->Self{ pub fn unit_cylinder()->Self{
Self::unit_cube() Self::unit_cube()
} }
pub fn mesh_data(&self)->&PhysicsMeshData{ #[inline]
pub const fn mesh_data(&self)->&PhysicsMeshData{
&self.data &self.data
} }
pub fn complete_mesh(&self)->&PhysicsMeshTopology{ #[inline]
pub const fn complete_mesh(&self)->&PhysicsMeshTopology{
&self.submeshes[0] &self.submeshes[0]
} }
pub fn submeshes(&self)->&[PhysicsMeshTopology]{ #[inline]
if self.submeshes.len()==1{ pub const fn complete_mesh_view(&self)->PhysicsMeshView{
//the complete mesh is already a convex mesh PhysicsMeshView{
&self.submeshes[0..0] data:&self.data,
}else{ topology:self.complete_mesh(),
&self.submeshes[1..]
} }
} }
pub fn submesh_view(&self,submesh_id:PhysicsSubmeshId)->PhysicsMeshView{ #[inline]
pub const fn submeshes(&self)->&[PhysicsMeshTopology]{
//the complete mesh is already a convex mesh when len()==1, len()==2 is invalid but will still work
&self.submeshes[self.submeshes.len().saturating_sub(1).min(1)..]
}
#[inline]
pub const fn submesh_view(&self,submesh_id:PhysicsSubmeshId)->PhysicsMeshView{
PhysicsMeshView{ PhysicsMeshView{
data:&self.data, data:&self.data,
topology:&self.submeshes()[submesh_id.get() as usize], topology:&self.submeshes()[submesh_id.get() as usize],
@ -219,13 +228,13 @@ impl PhysicsMesh{
//mesh builder code //mesh builder code
#[derive(Default,Clone)] #[derive(Default,Clone)]
struct VertRefGuy{ struct VertRefGuy{
edges:std::collections::HashSet<SubmeshDirectedEdgeId>, edges:HashSet<SubmeshDirectedEdgeId>,
faces:std::collections::HashSet<SubmeshFaceId>, faces:HashSet<SubmeshFaceId>,
} }
#[derive(Clone,Hash,Eq,PartialEq)] #[derive(Clone,Hash,Eq,PartialEq)]
struct EdgeRefVerts([SubmeshVertId;2]); struct EdgeRefVerts([SubmeshVertId;2]);
impl EdgeRefVerts{ impl EdgeRefVerts{
fn new(v0:SubmeshVertId,v1:SubmeshVertId)->(Self,bool){ const fn new(v0:SubmeshVertId,v1:SubmeshVertId)->(Self,bool){
(if v0.0<v1.0{ (if v0.0<v1.0{
Self([v0,v1]) Self([v0,v1])
}else{ }else{
@ -235,10 +244,10 @@ impl EdgeRefVerts{
} }
struct EdgeRefFaces([SubmeshFaceId;2]); struct EdgeRefFaces([SubmeshFaceId;2]);
impl EdgeRefFaces{ impl EdgeRefFaces{
fn new()->Self{ const fn new()->Self{
Self([SubmeshFaceId(0);2]) Self([SubmeshFaceId(0);2])
} }
fn push(&mut self,i:usize,face_id:SubmeshFaceId){ const fn push(&mut self,i:usize,face_id:SubmeshFaceId){
self.0[i]=face_id; self.0[i]=face_id;
} }
} }
@ -246,88 +255,126 @@ struct FaceRefEdges(Vec<SubmeshDirectedEdgeId>);
#[derive(Default)] #[derive(Default)]
struct EdgePool{ struct EdgePool{
edge_guys:Vec<(EdgeRefVerts,EdgeRefFaces)>, edge_guys:Vec<(EdgeRefVerts,EdgeRefFaces)>,
edge_id_from_guy:std::collections::HashMap<EdgeRefVerts,usize>, edge_id_from_guy:HashMap<EdgeRefVerts,SubmeshEdgeId>,
} }
impl EdgePool{ impl EdgePool{
fn push(&mut self,edge_ref_verts:EdgeRefVerts)->(&mut EdgeRefFaces,SubmeshEdgeId){ fn push(&mut self,edge_ref_verts:EdgeRefVerts)->(&mut EdgeRefFaces,SubmeshEdgeId){
let edge_id=if let Some(&edge_id)=self.edge_id_from_guy.get(&edge_ref_verts){ let edge_id=if let Some(&edge_id)=self.edge_id_from_guy.get(&edge_ref_verts){
edge_id edge_id
}else{ }else{
let edge_id=self.edge_guys.len(); let edge_id=SubmeshEdgeId::new(self.edge_guys.len() as u32);
self.edge_guys.push((edge_ref_verts.clone(),EdgeRefFaces::new())); self.edge_guys.push((edge_ref_verts.clone(),EdgeRefFaces::new()));
self.edge_id_from_guy.insert(edge_ref_verts,edge_id); self.edge_id_from_guy.insert(edge_ref_verts,edge_id);
edge_id edge_id
}; };
(&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id)}.1,SubmeshEdgeId::new(edge_id as u32)) (&mut unsafe{self.edge_guys.get_unchecked_mut(edge_id.get() as usize)}.1,edge_id)
} }
} }
impl From<&model::Mesh> for PhysicsMesh{ impl From<&model::Mesh> for PhysicsMesh{
fn from(indexed_model:&model::Mesh)->Self{ fn from(mesh:&model::Mesh)->Self{
assert!(indexed_model.unique_pos.len()!=0,"Mesh cannot have 0 vertices"); assert!(mesh.unique_pos.len()!=0,"Mesh cannot have 0 vertices");
let verts=indexed_model.unique_pos.iter().map(|v|Vert(v.clone())).collect(); let verts=mesh.unique_pos.into_iter().map(Vert).collect();
let mut vert_ref_guys=vec![VertRefGuy::default();indexed_model.unique_pos.len()];
let mut edge_pool=EdgePool::default();
let mut face_i=0;
let mut faces=Vec::new(); let mut faces=Vec::new();
let mut face_ref_guys=Vec::new(); let mut face_id_from_face=HashMap::new();
for group in &indexed_model.polygon_groups{for poly_vertices in group.polys(){ let submeshes=mesh.physics_groups.iter().enumerate().map(|(submesh_id,physics_group)|{
let face_id=SubmeshFaceId::new(face_i); //construct submesh
//one face per poly let mut submesh_faces=Vec::new();//these contain a map from submeshId->meshId
let mut normal=Planar64Vec3::ZERO; let mut submesh_verts=Vec::new();
let len=poly_vertices.len(); let mut submesh_vert_id_from_mesh_vert_id=HashMap::<MeshVertId,SubmeshVertId>::new();
let face_edges=poly_vertices.iter().enumerate().map(|(i,&vert_id)|{ //lazy closure
let vert0_id=indexed_model.unique_vertices[vert_id.get() as usize].pos.get() as usize; let get_submesh_vert_id=|vert_id:MeshVertId|{
let vert1_id=indexed_model.unique_vertices[poly_vertices[(i+1)%len].get() as usize].pos.get() as usize; if let Some(&submesh_vert_id)=submesh_vert_id_from_mesh_vert_id.get(&vert_id){
//https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method) submesh_vert_id
let v0=indexed_model.unique_pos[vert0_id]; }else{
let v1=indexed_model.unique_pos[vert1_id]; let submesh_vert_id=SubmeshVertId::new(vert_id.get() as u32);
normal+=Planar64Vec3::new( submesh_vert_id_from_mesh_vert_id.insert(vert_id,submesh_vert_id);
(v0.y()-v1.y())*(v0.z()+v1.z()), submesh_vert_id
(v0.z()-v1.z())*(v0.x()+v1.x()), }
(v0.x()-v1.x())*(v0.y()+v1.y()), };
); let mut edge_pool=EdgePool::default();
//get/create edge and push face into it let mut vert_ref_guys=vec![VertRefGuy::default();mesh.unique_pos.len()];
let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(SubmeshVertId::new(vert0_id as u32),SubmeshVertId::new(vert1_id as u32)); let mut face_ref_guys=Vec::new();
let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts); let submesh_id=PhysicsSubmeshId::new(submesh_id as u32);
//polygon vertices as assumed to be listed clockwise for polygon_group_id in &physics_group.groups{
//populate the edge face on the left or right depending on how the edge vertices got sorted let polygon_group=mesh.polygon_groups[polygon_group_id.get() as usize];
edge_ref_faces.push(!is_sorted as usize,face_id); for poly_vertices in polygon_group.polys(){
//index edges & face into vertices let submesh_face_id=SubmeshFaceId::new(submesh_faces.len() as u32);
{ //one face per poly
let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(vert0_id)}; let mut normal=Planar64Vec3::ZERO;
vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted)); let len=poly_vertices.len();
vert_ref_guy.faces.insert(face_id); let face_edges=poly_vertices.into_iter().enumerate().map(|(i,vert_id)|{
unsafe{vert_ref_guys.get_unchecked_mut(vert1_id)}.edges.insert(edge_id.as_directed(!is_sorted)); let vert0_id=MeshVertId::new(mesh.unique_vertices[vert_id.get() as usize].pos.get() as u32);
let vert1_id=MeshVertId::new(mesh.unique_vertices[poly_vertices[(i+1)%len].get() as usize].pos.get() as u32);
//index submesh verts
let submesh_vert0_id=get_submesh_vert_id(vert0_id);
let submesh_vert1_id=get_submesh_vert_id(vert1_id);
//https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal (Newell's Method)
let v0=mesh.unique_pos[vert0_id.get() as usize];
let v1=mesh.unique_pos[vert1_id.get() as usize];
normal+=Planar64Vec3::new(
(v0.y()-v1.y())*(v0.z()+v1.z()),
(v0.z()-v1.z())*(v0.x()+v1.x()),
(v0.x()-v1.x())*(v0.y()+v1.y()),
);
//get/create edge and push face into it
let (edge_ref_verts,is_sorted)=EdgeRefVerts::new(submesh_vert0_id,submesh_vert1_id);
let (edge_ref_faces,edge_id)=edge_pool.push(edge_ref_verts);
//polygon vertices as assumed to be listed clockwise
//populate the edge face on the left or right depending on how the edge vertices got sorted
edge_ref_faces.push(!is_sorted as usize,submesh_face_id);
//index edges & face into vertices
{
let vert_ref_guy=unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert0_id.get() as usize)};
vert_ref_guy.edges.insert(edge_id.as_directed(is_sorted));
vert_ref_guy.faces.insert(submesh_face_id);
unsafe{vert_ref_guys.get_unchecked_mut(submesh_vert1_id.get() as usize)}.edges.insert(edge_id.as_directed(!is_sorted));
}
//return directed_edge_id
edge_id.as_directed(is_sorted)
}).collect();
//choose precision loss randomly idk
normal=normal/len as i64;
let mut dot=Planar64::ZERO;
for &v in poly_vertices{
dot+=normal.dot(mesh.unique_pos[mesh.unique_vertices[v.get() as usize].pos.get() as usize]);
}
let face=Face{normal,dot:dot/len as i64};
let face_id=match face_id_from_face.get(&face){
Some(&face_id)=>face_id,
None=>{
let face_id=MeshFaceId::new(faces.len() as u32);
face_id_from_face.insert(face,face_id);
faces.push(face);
face_id
}
};
submesh_faces.push(face_id);
face_ref_guys.push(FaceRefEdges(face_edges));
} }
//return directed_edge_id
edge_id.as_directed(is_sorted)
}).collect();
//choose precision loss randomly idk
normal=normal/len as i64;
let mut dot=Planar64::ZERO;
for &v in poly_vertices{
dot+=normal.dot(indexed_model.unique_pos[indexed_model.unique_vertices[v.get() as usize].pos.get() as usize]);
} }
faces.push(Face{normal,dot:dot/len as i64}); PhysicsMeshTopology{
face_ref_guys.push(FaceRefEdges(face_edges)); faces:submesh_faces,
face_i+=1; verts:submesh_verts,
}} face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{
//conceivably faces, edges, and vertices exist now FaceRefs{edges:face_ref_guy.0}
}).collect(),
edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)|
EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0}
).collect(),
vert_topology:vert_ref_guys.into_iter().map(|vert_ref_guy|
VertRefs{
edges:vert_ref_guy.edges.into_iter().collect(),
faces:vert_ref_guy.faces.into_iter().collect(),
}
).collect(),
}
}).collect();
Self{ Self{
faces, data:PhysicsMeshData{
verts, faces,
face_topology:face_ref_guys.into_iter().map(|face_ref_guy|{ verts,
FaceRefs{edges:face_ref_guy.0} },
}).collect(), submeshes,
edge_topology:edge_pool.edge_guys.into_iter().map(|(edge_ref_verts,edge_ref_faces)|
EdgeRefs{faces:edge_ref_faces.0,verts:edge_ref_verts.0}
).collect(),
vert_topology:vert_ref_guys.into_iter().map(|vert_ref_guy|
VertRefs{
edges:vert_ref_guy.edges.into_iter().collect(),
faces:vert_ref_guy.faces.into_iter().collect(),
}
).collect(),
} }
} }
} }