From 053bab9e248407d2d91c4a53e13484889f97edae Mon Sep 17 00:00:00 2001 From: Quaternions Date: Mon, 30 Oct 2023 22:11:54 -0700 Subject: [PATCH] wip: physics work --- src/face_crawler.rs | 4 +- src/model_physics.rs | 52 +++++++++++-- src/physics.rs | 179 +++++++++++++++++++------------------------ 3 files changed, 124 insertions(+), 111 deletions(-) diff --git a/src/face_crawler.rs b/src/face_crawler.rs index f9e75e3..3929767 100644 --- a/src/face_crawler.rs +++ b/src/face_crawler.rs @@ -109,10 +109,10 @@ pub fn predict_collision(mesh:&impl MeshQuery,relat } } -pub fn predict_collision_end(mesh:&impl MeshQuery,relative_body:&Body,time_limit:Time,c:&crate::physics::RelativeCollision)->Option<(F,Time)>{ +pub fn predict_collision_end(mesh:&impl MeshQuery,relative_body:&Body,time_limit:Time,c:&crate::physics::ContactCollision)->Option<(F,Time)>{ //imagine the mesh without the collision face //no algorithm needed, there is only one state and three cases (Face,Edge,None) //determine when it passes an edge ("sliding off" case) or if it leaves the surface directly - //the state can be constructed from the RelativeCollision directly + //the state can be constructed from the ContactCollision directly None } diff --git a/src/model_physics.rs b/src/model_physics.rs index 9646e00..78576cb 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -1,11 +1,11 @@ use crate::integer::{Planar64,Planar64Vec3}; use std::borrow::Cow; -#[derive(Clone,Copy)] +#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct VertId(usize); -#[derive(Clone,Copy)] +#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct EdgeId(usize); -#[derive(Clone,Copy)] +#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] pub struct FaceId(usize); //Vertex <-> Edge <-> Face -> Collide @@ -115,6 +115,42 @@ impl MeshQuery for PhysicsMesh{ } } +pub struct VirtualMesh<'a>{ + mesh:&'a PhysicsMesh, + transform:&'a crate::integer::Planar64Affine3, + normal_transform:&'a crate::integer::Planar64Mat3, + normal_determinant:Planar64, +} +impl MeshQuery for VirtualMesh<'_>{ + fn closest_fev(&self,point:Planar64Vec3)->FEV{ + //put some genius code right here + todo!() + } + fn face_nd(&self,face_id:FaceId)->(Planar64Vec3,Planar64){ + let (n,d)=self.mesh.face_nd(face_id); + (self.normal_transform*n,self.normal_determinant*d) + } + fn vert(&self,vert_id:VertId)->Planar64Vec3{ + self.transform.transform_point3(self.mesh.vert(vert_id)) + } + #[inline] + fn face_edges(&self,face_id:FaceId)->Cow>{ + self.mesh.face_edges(face_id) + } + #[inline] + fn edge_faces(&self,edge_id:EdgeId)->Cow<[FaceId;2]>{ + self.mesh.edge_faces(edge_id) + } + #[inline] + fn edge_verts(&self,edge_id:EdgeId)->Cow<[(VertId,FaceId);2]>{ + self.mesh.edge_verts(edge_id) + } + #[inline] + fn vert_edges(&self,vert_id:VertId)->Cow>{ + self.mesh.vert_edges(vert_id) + } +} + //Note that a face on a minkowski mesh refers to a pair of fevs on the meshes it's summed from //(face,vertex) //(edge,edge) @@ -128,20 +164,20 @@ enum MinkowskiEdge{ VertEdge(VertId,EdgeId), EdgeVert(EdgeId,VertId), } -#[derive(Clone,Copy)] -enum MinkowskiFace{ +#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)] +pub enum MinkowskiFace{ FaceVert(FaceId,VertId), EdgeEdge(EdgeId,EdgeId), VertFace(VertId,FaceId), } pub struct MinkowskiMesh<'a>{ - mesh0:&'a PhysicsMesh, - mesh1:&'a PhysicsMesh, + mesh0:&'a VirtualMesh<'a>, + mesh1:&'a VirtualMesh<'a>, } impl MinkowskiMesh<'_>{ - pub fn minkowski_sum<'a>(mesh0:&'a PhysicsMesh,mesh1:&'a PhysicsMesh)->MinkowskiMesh<'a>{ + pub fn minkowski_sum<'a>(mesh0:&'a VirtualMesh,mesh1:&'a VirtualMesh)->MinkowskiMesh<'a>{ MinkowskiMesh{ mesh0, mesh1, diff --git a/src/physics.rs b/src/physics.rs index 28b2c2c..be486aa 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,11 +1,12 @@ -use crate::{instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction}, zeroes::zeroes2}; - +use crate::zeroes::zeroes2; +use crate::instruction::{InstructionEmitter,InstructionConsumer,TimedInstruction}; use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64,Ratio64Vec2}; +use crate::model_physics::{PhysicsMesh,VirtualMesh,MinkowskiMesh}; #[derive(Debug)] pub enum PhysicsInstruction { - CollisionStart(RelativeCollision), - CollisionEnd(RelativeCollision), + CollisionStart(Collision), + CollisionEnd(Collision), StrafeTick, ReachWalkTargetVelocity, // Water, @@ -154,6 +155,7 @@ impl Default for Modes{ } } +#[derive(Default)] struct PhysicsModels{ models:Vec, model_id_from_wormhole_id:std::collections::HashMap::, @@ -163,8 +165,8 @@ impl PhysicsModels{ self.models.clear(); self.model_id_from_wormhole_id.clear(); } - fn get(&self,i:usize)->Option<&PhysicsModel>{ - self.models.get(i) + fn get(&self,model_id:usize)->Option<&PhysicsModel>{ + self.models.get(model_id) } fn get_wormhole_model(&self,wormhole_id:u32)->Option<&PhysicsModel>{ self.models.get(*self.model_id_from_wormhole_id.get(&wormhole_id)?) @@ -175,14 +177,6 @@ impl PhysicsModels{ model_id } } -impl Default for PhysicsModels{ - fn default() -> Self { - Self{ - models:Vec::new(), - model_id_from_wormhole_id:std::collections::HashMap::new(), - } - } -} #[derive(Clone)] pub struct PhysicsCamera{ @@ -592,7 +586,7 @@ pub struct PhysicsState{ pub next_mouse:MouseState,//Where is the mouse headed next controls:u32, move_state:MoveState, - //all models + meshes:Vec, models:PhysicsModels, bvh:crate::bvh::BvhNode, @@ -613,10 +607,6 @@ impl PhysicsOutputState{ } } -//pretend to be using what we want to eventually do -type TreyMeshFace = crate::aabb::AabbFace; -type TreyMesh = crate::aabb::Aabb; - enum PhysicsCollisionAttributes{ Contact{//track whether you are contacting the object contacting:crate::model::ContactingAttributes, @@ -628,113 +618,94 @@ enum PhysicsCollisionAttributes{ }, } -pub struct PhysicsModel { +pub struct PhysicsModel{ //A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es //in this iteration, all it needs is extents. - mesh: TreyMesh, - transform:crate::integer::Planar64Affine3, + mesh_id:usize, attributes:PhysicsCollisionAttributes, + transform:crate::integer::Planar64Affine3, + normal_transform:crate::integer::Planar64Mat3, } -impl PhysicsModel { - fn from_model_transform_attributes(model:&crate::model::IndexedModel,transform:&crate::integer::Planar64Affine3,attributes:PhysicsCollisionAttributes)->Self{ - let mut aabb=TreyMesh::default(); - for indexed_vertex in &model.unique_vertices { - aabb.grow(transform.transform_point3(model.unique_pos[indexed_vertex.pos as usize])); - } +impl PhysicsModel{ + fn new(mesh_id:usize,transform:crate::integer::Planar64Affine3,attributes:PhysicsCollisionAttributes)->Self{ Self{ - mesh:aabb, + mesh_id, attributes, - transform:transform.clone(), + transform, + normal_transform:transform.matrix3.inverse().transpose(), } } - pub fn from_model(model:&crate::model::IndexedModel,instance:&crate::model::ModelInstance) -> Option { + pub fn from_model(mesh_id:usize,instance:&crate::model::ModelInstance) -> Option { match &instance.attributes{ - crate::model::CollisionAttributes::Contact{contacting,general}=>Some(PhysicsModel::from_model_transform_attributes(model,&instance.transform,PhysicsCollisionAttributes::Contact{contacting:contacting.clone(),general:general.clone()})), - crate::model::CollisionAttributes::Intersect{intersecting,general}=>Some(PhysicsModel::from_model_transform_attributes(model,&instance.transform,PhysicsCollisionAttributes::Intersect{intersecting:intersecting.clone(),general:general.clone()})), + crate::model::CollisionAttributes::Contact{contacting,general}=>Some(PhysicsModel::new(mesh_id,instance.transform.clone(),PhysicsCollisionAttributes::Contact{contacting:contacting.clone(),general:general.clone()})), + crate::model::CollisionAttributes::Intersect{intersecting,general}=>Some(PhysicsModel::new(mesh_id,instance.transform.clone(),PhysicsCollisionAttributes::Intersect{intersecting:intersecting.clone(),general:general.clone()})), crate::model::CollisionAttributes::Decoration=>None, } } - pub fn unit_vertices(&self) -> [Planar64Vec3;8] { - TreyMesh::unit_vertices() - } - pub fn mesh(&self) -> &TreyMesh { - return &self.mesh; - } - // pub fn face_mesh(&self,face:TreyMeshFace)->TreyMesh{ - // self.mesh.face(face) - // } - pub fn face_normal(&self,face:TreyMeshFace) -> Planar64Vec3 { - TreyMesh::normal(face)//this is wrong for scale + pub fn mesh<'a>(&self,meshes:&Vec)->VirtualMesh<'a>{ + VirtualMesh{ + mesh:&meshes[self.mesh_id], + transform:&self.transform, + normal_transform:&self.normal_transform, + normal_determinant:self.normal_transform.determinant(), + } } } -//need non-face (full model) variant for CanCollide false objects -//OR have a separate list from contacts for model intersection #[derive(Debug,Clone,Eq,Hash,PartialEq)] -pub struct RelativeCollision { - face:TreyMeshFace,//just an id - model:usize,//using id to avoid lifetimes +struct ContactCollision{ + face_id:crate::model_physics::MinkowskiFace, + model_id:usize,//using id to avoid lifetimes } - -impl RelativeCollision { - fn model<'a>(&self,models:&'a PhysicsModels)->Option<&'a PhysicsModel>{ - models.get(self.model) - } - // pub fn mesh(&self,models:&Vec) -> TreyMesh { - // return self.model(models).unwrap().face_mesh(self.face).clone() - // } - fn normal(&self,models:&PhysicsModels) -> Planar64Vec3 { - return self.model(models).unwrap().face_normal(self.face) - } +#[derive(Debug,Clone,Eq,Hash,PartialEq)] +struct IntersectCollision{ + model_id:usize, } - +#[derive(Debug,Clone,Eq,Hash,PartialEq)] +enum Collision{ + Contact(ContactCollision), + Intersect(IntersectCollision), +} +#[derive(Default)] struct TouchingState{ - contacts:std::collections::HashMap::, - intersects:std::collections::HashMap::, + contacts:std::collections::HashSet::, + intersects:std::collections::HashSet::, } impl TouchingState{ fn clear(&mut self){ self.contacts.clear(); self.intersects.clear(); } - fn insert_contact(&mut self,model_id:usize,collision:RelativeCollision)->Option{ - self.contacts.insert(model_id,collision) - } - fn remove_contact(&mut self,model_id:usize)->Option{ - self.contacts.remove(&model_id) - } - fn insert_intersect(&mut self,model_id:usize,collision:RelativeCollision)->Option{ - self.intersects.insert(model_id,collision) - } - fn remove_intersect(&mut self,model_id:usize)->Option{ - self.intersects.remove(&model_id) - } - fn constrain_velocity(&self,models:&PhysicsModels,velocity:&mut Planar64Vec3){ - for (_,contact) in &self.contacts { - let n=contact.normal(models); - let d=velocity.dot(n); - if dbool{ + match collision{ + Collision::Contact(collision)=>self.contacts.insert(collision), + Collision::Intersect(collision)=>self.intersects.insert(collision), } } + fn remove(&mut self,collision:&Collision)->bool{ + match collision{ + Collision::Contact(collision)=>self.contacts.remove(collision), + Collision::Intersect(collision)=>self.intersects.remove(collision), + } + } + fn get_acceleration(&self,gravity:Planar64Vec3)->Planar64Vec3{ + //accelerators + //water + //contact constrain? + todo!() + } + fn constrain_velocity(&self,meshes:&Vec,models:&PhysicsModels,velocity:&mut Planar64Vec3){ + for contact in &self.contacts{ + //trey push solve + } + todo!() + } fn constrain_acceleration(&self,models:&PhysicsModels,acceleration:&mut Planar64Vec3){ - for (_,contact) in &self.contacts { - let n=contact.normal(models); - let d=acceleration.dot(n); - if d Self { - Self{ - contacts: std::collections::HashMap::new(), - intersects: std::collections::HashMap::new(), + for contact in &self.contacts{ + //trey push solve } + todo!() } } @@ -803,6 +774,7 @@ impl Default for PhysicsState{ style:StyleModifiers::default(), touching:TouchingState::default(), models:PhysicsModels::default(), + meshes:Vec::new(), bvh:crate::bvh::BvhNode::default(), move_state: MoveState::Air, camera:PhysicsCamera::default(), @@ -844,9 +816,11 @@ impl PhysicsState { let mut starts=Vec::new(); let mut spawns=Vec::new(); for model in &indexed_models.models{ - //make aabb and run vertices to get realistic bounds + let mesh_id=self.meshes.len(); + let mut make_mesh=false; for model_instance in &model.instances{ - if let Some(model_physics)=PhysicsModel::from_model(model,model_instance){ + if let Some(model_physics)=PhysicsModel::from_model(mesh_id,model_instance){ + make_mesh=true; let model_id=self.models.push(model_physics); for attr in &model_instance.temp_indexing{ match attr{ @@ -857,8 +831,11 @@ impl PhysicsState { } } } + if make_mesh{ + self.meshes.push(PhysicsMesh::from_model(model)); + } } - self.bvh=crate::bvh::generate_bvh(self.models.models.iter().map(|m|m.mesh().clone()).collect()); + self.bvh=crate::bvh::generate_bvh(self.models.aabb_list(&self.meshes)); //I don't wanna write structs for temporary structures //this code builds ModeDescriptions from the unsorted lists at the top of the function starts.sort_by_key(|tup|tup.1.mode_id); @@ -1000,7 +977,7 @@ impl PhysicsState { } aabb } - fn predict_collision_end(&self,time:Time,time_limit:Time,collision_data:&RelativeCollision) -> Option> { + fn predict_collision_end(&self,time:Time,time_limit:Time,collision_data:&ContactCollision) -> Option> { //must treat cancollide false objects differently: you may not exit through the same face you entered. //RelativeCollsion must reference the full model instead of a particular face //this is Ctrl+C Ctrl+V of predict_collision_start but with v=-v before the calc and t=-t after the calc @@ -1264,7 +1241,7 @@ impl PhysicsState { if let Some(face)=best_face{ return Some(TimedInstruction{ time: best_time, - instruction:PhysicsInstruction::CollisionStart(RelativeCollision{ + instruction:PhysicsInstruction::CollisionStart(ContactCollision{ face, model:model_id })