forked from StrafesNET/strafe-client
physics mesh builder rewrite
This commit is contained in:
parent
96085a3076
commit
f412874317
@ -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(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user