diff --git a/engine/physics/src/physics.rs b/engine/physics/src/physics.rs index 8644cb3..96bc0fa 100644 --- a/engine/physics/src/physics.rs +++ b/engine/physics/src/physics.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap,HashSet}; +use crate::model::DirectedEdge; use crate::model::{self as model_physics,PhysicsMesh,PhysicsMeshTransform,TransformedMesh,MeshQuery,PhysicsMeshId,PhysicsSubmeshId}; use strafesnet_common::bvh; use strafesnet_common::map; @@ -980,6 +981,34 @@ impl PhysicsContext<'_>{ } } impl PhysicsData{ + pub fn trace_ray(&self,ray:strafesnet_common::ray::Ray)->Option<ModelId>{ + let (_time,convex_mesh_id)=self.bvh.sample_ray(&ray,Time::ZERO,Time::MAX/4,|&model,ray|{ + let mesh=self.models.mesh(model); + // brute force trace every face + mesh.faces().filter_map(|face_id|{ + let (n,d)=mesh.face_nd(face_id); + // trace ray onto face + // n.(o+d*t)==n.p + // n.o + n.d * t == n.p + // t == (n.p - n.o)/n.d + let nd=n.dot(ray.direction); + if nd.is_zero(){ + return None; + } + let t=(d-n.dot(ray.origin))/nd; + // check if point of intersection is behind face edges + // *2 because average of 2 vertices + let p=ray.extrapolate(t)*2; + mesh.face_edges(face_id).iter().all(|&directed_edge_id|{ + let edge_n=mesh.directed_edge_n(directed_edge_id); + let cross_n=edge_n.cross(n); + let &[vert0,vert1]=mesh.edge_verts(directed_edge_id.as_undirected()).as_ref(); + cross_n.dot(p)<cross_n.dot(mesh.vert(vert0)+mesh.vert(vert1)) + }).then(||t) + }).min().map(Into::into) + })?; + Some(convex_mesh_id.model_id.into()) + } /// use with caution, this is the only non-instruction way to mess with physics pub fn generate_models(&mut self,map:&map::CompleteMap){ let mut modes=map.modes.clone().denormalize();