Compare commits

...

15 Commits

Author SHA1 Message Date
686bf5d712 print moooore 2023-11-30 18:56:21 -08:00
b2f781ac14 pip 2023-11-30 18:56:21 -08:00
1f636116c0 jkwenfjnwef 2023-11-30 18:56:21 -08:00
086b47c406 prin 2023-11-30 18:56:21 -08:00
aa0e03bc0c a 2023-11-30 18:56:21 -08:00
481a37e0f4 debug 2023-11-30 18:56:21 -08:00
cdfa4db1c9 crazy debug generic restrictions 2023-11-30 18:56:21 -08:00
136c77c65c debug 2023-11-30 18:56:21 -08:00
a7299c423f debug crap 2023-11-30 18:56:21 -08:00
abaf0b2939 debug 2023-11-30 18:56:21 -08:00
8e27c404a3 big platforms fail 2023-11-30 18:56:15 -08:00
62216c3c47 x11 mode has different sens 2023-11-30 18:56:15 -08:00
78b436741c more test 2023-11-30 18:56:15 -08:00
d8f57eb9fa use inverse_times_det 2023-11-30 17:19:56 -08:00
36a61b50a8 inverse_times_det 2023-11-30 17:17:03 -08:00
5 changed files with 116 additions and 19 deletions

View File

@@ -3,13 +3,16 @@ use crate::model_physics::{FEV,MeshQuery,DirectedEdge};
use crate::integer::{Time,Planar64};
use crate::zeroes::zeroes2;
enum Transition<F,E:DirectedEdge,V>{
#[derive(Debug)]
enum Transition<F,E:DirectedEdge,V>
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
Miss,
Next(FEV<F,E,V>,Time),
Hit(F,Time),
}
fn next_transition<F:Copy,E:Copy+DirectedEdge,V:Copy>(fev:&FEV<F,E,V>,time:Time,mesh:&impl MeshQuery<F,E,V>,body:&Body,time_limit:Time)->Transition<F,E,V>{
fn next_transition<F:Copy+std::fmt::Debug,E:Copy+DirectedEdge+std::fmt::Debug,V:Copy+std::fmt::Debug>(fev:&FEV<F,E,V>,time:Time,mesh:&impl MeshQuery<F,E,V>,body:&Body,time_limit:Time)->Transition<F,E,V>
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
//conflicting derivative means it crosses in the wrong direction.
//if the transition time is equal to an already tested transition, do not replace the current best.
let mut best_time=time_limit;
@@ -20,8 +23,10 @@ enum Transition<F,E:DirectedEdge,V>{
//n=face.normal d=face.dot
//n.a t^2+n.v t+n.p-d==0
let (n,d)=mesh.face_nd(face_id);
println!("Face n={} d={}",n,d);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
println!("dt={} low={} upp={} into={}",t-body.time,time<=t,t<best_time,n.dot(body.extrapolated_velocity(t))<Planar64::ZERO);
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Hit(face_id,t);
@@ -34,9 +39,11 @@ enum Transition<F,E:DirectedEdge,V>{
let n=n.cross(edge_n);
let verts=mesh.edge_verts(directed_edge_id.as_undirected());
let d=n.dot(mesh.vert(verts[0])+mesh.vert(verts[1]));
println!("Face Edge boundary_n={} boundary_d={}",n,d/2);
//WARNING: d is moved out of the *2 block because of adding two vertices!
for t in zeroes2(n.dot(body.position)*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
println!("dt={} low={} upp={} into={}",t-body.time,time<=t,t<best_time,n.dot(body.extrapolated_velocity(t))<Planar64::ZERO);
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
@@ -56,9 +63,11 @@ enum Transition<F,E:DirectedEdge,V>{
//edge_n gets parity from the order of edge_faces
let n=face_n.cross(edge_n)*((i as i64)*2-1);
let d=n.dot(vert_sum);
println!("Edge Face={:?} boundary_n={} boundary_d={}",edge_face_id,n,d/2);
//WARNING yada yada d *2
for t in zeroes2((n.dot(body.position))*2-d,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
println!("dt={} low={} upp={} into={}",t-body.time,time<=t,t<best_time,n.dot(body.extrapolated_velocity(t))<Planar64::ZERO);
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::<F,E,V>::Face(edge_face_id),t);
@@ -71,8 +80,10 @@ enum Transition<F,E:DirectedEdge,V>{
//vertex normal gets parity from vert index
let n=edge_n*(1-2*(i as i64));
let d=n.dot(mesh.vert(vert_id));
println!("Edge Vert boundary_n={} boundary_d={}",n,d);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
println!("dt={} low={} upp={} into={}",t-body.time,time<=t,t<best_time,n.dot(body.extrapolated_velocity(t))<Planar64::ZERO);
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::<F,E,V>::Vert(vert_id),t);
@@ -88,8 +99,10 @@ enum Transition<F,E:DirectedEdge,V>{
//edge is directed away from vertex, but we want the dot product to turn out negative
let n=-mesh.directed_edge_n(directed_edge_id);
let d=n.dot(mesh.vert(vert_id));
println!("Vert Edge={:?} boundary_n={} boundary_d={}",directed_edge_id,n,d);
for t in zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){
let t=body.time+Time::from(t);
println!("dt={} low={} upp={} into={}",t-body.time,time<=t,t<best_time,n.dot(body.extrapolated_velocity(t))<Planar64::ZERO);
if time<=t&&t<best_time&&n.dot(body.extrapolated_velocity(t))<Planar64::ZERO{
best_time=t;
best_transtition=Transition::Next(FEV::<F,E,V>::Edge(directed_edge_id.as_undirected()),t);
@@ -106,9 +119,19 @@ pub enum CrawlResult<F,E:DirectedEdge,V>{
Miss(FEV<F,E,V>),
Hit(F,Time),
}
pub fn crawl_fev<F:Copy,E:Copy+DirectedEdge,V:Copy>(mut fev:FEV<F,E,V>,mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,start_time:Time,time_limit:Time)->CrawlResult<F,E,V>{
pub fn crawl_fev<F:Copy+std::fmt::Debug,E:Copy+std::fmt::Debug+DirectedEdge,V:Copy+std::fmt::Debug>(mut fev:FEV<F,E,V>,mesh:&impl MeshQuery<F,E,V>,relative_body:&Body,start_time:Time,time_limit:Time)->CrawlResult<F,E,V>
where <E as DirectedEdge>::UndirectedEdge:std::fmt::Debug{
let mut time=start_time;
for _ in 0..20{
println!("@ fev={:?} time={}",fev,time);
match &fev{
&FEV::Face(face_id)=>{
let a=mesh.face_nd(face_id);
println!("face_n={}",a.0);
},
&FEV::Edge(edge_id)=>println!("edge_n={} verts={:?}",mesh.edge_n(edge_id),mesh.edge_verts(edge_id)),
&FEV::Vert(vert_id)=>println!("vert={}",mesh.vert(vert_id)),
}
match next_transition(&fev,time,mesh,relative_body,time_limit){
Transition::Miss=>return CrawlResult::Miss(fev),
Transition::Next(next_fev,next_time)=>(fev,time)=(next_fev,next_time),

View File

@@ -411,7 +411,7 @@ impl TryFrom<[f32;3]> for Unit32Vec3{
*/
///[-1.0,1.0] = [-2^32,2^32]
#[derive(Clone,Copy,Hash,Eq,Ord,PartialEq,PartialOrd)]
#[derive(Clone,Copy,Debug,Hash,Eq,Ord,PartialEq,PartialOrd)]
pub struct Planar64(i64);
impl Planar64{
pub const ZERO:Self=Self(0);
@@ -583,7 +583,7 @@ impl std::ops::Div<Planar64> for Planar64{
///[-1.0,1.0] = [-2^32,2^32]
#[derive(Clone,Copy,Default,Hash,Eq,PartialEq)]
#[derive(Clone,Copy,Debug,Default,Hash,Eq,PartialEq)]
pub struct Planar64Vec3(glam::I64Vec3);
impl Planar64Vec3{
pub const ZERO:Self=Planar64Vec3(glam::I64Vec3::ZERO);
@@ -907,6 +907,14 @@ impl Planar64Mat3{
}
}
#[inline]
pub const fn inverse_times_det(&self)->Self{
Self{
x_axis:Planar64Vec3::raw(((-(self.y_axis.0.z as i128*self.z_axis.0.y as i128)+self.y_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.z_axis.0.y as i128-self.x_axis.0.y as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.y_axis.0.y as i128)+self.x_axis.0.y as i128*self.y_axis.0.z as i128)>>32) as i64),
y_axis:Planar64Vec3::raw(((self.y_axis.0.z as i128*self.z_axis.0.x as i128-self.y_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((-(self.x_axis.0.z as i128*self.z_axis.0.x as i128)+self.x_axis.0.x as i128*self.z_axis.0.z as i128)>>32) as i64,((self.x_axis.0.z as i128*self.y_axis.0.x as i128-self.x_axis.0.x as i128*self.y_axis.0.z as i128)>>32) as i64),
z_axis:Planar64Vec3::raw(((-(self.y_axis.0.y as i128*self.z_axis.0.x as i128)+self.y_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((self.x_axis.0.y as i128*self.z_axis.0.x as i128-self.x_axis.0.x as i128*self.z_axis.0.y as i128)>>32) as i64,((-(self.x_axis.0.y as i128*self.y_axis.0.x as i128)+self.x_axis.0.x as i128*self.y_axis.0.y as i128)>>32) as i64),
}
}
#[inline]
pub const fn transpose(&self)->Self{
Self{
x_axis:Planar64Vec3::raw(self.x_axis.0.x,self.y_axis.0.x,self.z_axis.0.x),

View File

@@ -40,6 +40,7 @@ impl DirectedEdge for DirectedEdgeId{
pub struct FaceId(usize);
//Vertex <-> Edge <-> Face -> Collide
#[derive(Debug)]
pub enum FEV<F,E:DirectedEdge,V>{
Face(F),
Edge(E::UndirectedEdge),
@@ -47,10 +48,12 @@ pub enum FEV<F,E:DirectedEdge,V>{
}
//use Unit32 #[repr(C)] for map files
#[derive(Debug)]
struct Face{
normal:Planar64Vec3,
dot:Planar64,
}
#[derive(Debug)]
struct Vert(Planar64Vec3);
pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
fn edge_n(&self,edge_id:EDGE::UndirectedEdge)->Planar64Vec3{
@@ -69,18 +72,22 @@ pub trait MeshQuery<FACE:Clone,EDGE:Clone+DirectedEdge,VERT:Clone>{
fn vert_edges(&self,vert_id:VERT)->Cow<Vec<EDGE>>;
fn vert_faces(&self,vert_id:VERT)->Cow<Vec<FACE>>;
}
#[derive(Debug)]
struct FaceRefs{
edges:Vec<DirectedEdgeId>,
//verts:Vec<VertId>,
}
#[derive(Debug)]
struct EdgeRefs{
faces:[FaceId;2],//left, right
verts:[VertId;2],//bottom, top
}
#[derive(Debug)]
struct VertRefs{
faces:Vec<FaceId>,
edges:Vec<DirectedEdgeId>,
}
#[derive(Debug)]
pub struct PhysicsMesh{
faces:Vec<Face>,
verts:Vec<Vert>,
@@ -301,11 +308,11 @@ impl MeshQuery<FaceId,DirectedEdgeId,VertId> for TransformedMesh<'_>{
//(face,vertex)
//(edge,edge)
//(vertex,face)
#[derive(Clone,Copy)]
#[derive(Clone,Copy,Debug)]
pub enum MinkowskiVert{
VertVert(VertId,VertId),
}
#[derive(Clone,Copy)]
#[derive(Clone,Copy,Debug)]
pub enum MinkowskiEdge{
VertEdge(VertId,EdgeId),
EdgeVert(EdgeId,VertId),
@@ -320,7 +327,7 @@ impl UndirectedEdge for MinkowskiEdge{
}
}
}
#[derive(Clone,Copy)]
#[derive(Clone,Copy,Debug)]
pub enum MinkowskiDirectedEdge{
VertEdge(VertId,DirectedEdgeId),
EdgeVert(DirectedEdgeId,VertId),
@@ -341,7 +348,7 @@ impl DirectedEdge for MinkowskiDirectedEdge{
}
}
}
#[derive(Debug,Clone,Copy,Hash,Eq,PartialEq)]
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
pub enum MinkowskiFace{
VertFace(VertId,FaceId),
EdgeEdge(EdgeId,EdgeId,bool),
@@ -434,6 +441,7 @@ impl MinkowskiMesh<'_>{
}
/// This function drops a vertex down to an edge or a face if the path from infinity did not cross any vertex-edge boundaries but the point is supposed to have already crossed a boundary down from a vertex
fn infinity_fev(&self,infinity_dir:Planar64Vec3,point:Planar64Vec3)->FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>{
println!("infinity_fev dir={} point={}",infinity_dir,point);
//start on any vertex
//cross uncrossable vertex-edge boundaries until you find the closest vertex or edge
//cross edge-face boundary if it's uncrossable
@@ -441,17 +449,35 @@ impl MinkowskiMesh<'_>{
//if a vert is returned, it is the closest point to the infinity point
EV::Vert(vert_id)=>FEV::<MinkowskiFace,MinkowskiDirectedEdge,MinkowskiVert>::Vert(vert_id),
EV::Edge(edge_id)=>{
println!("fix edge edge_id={:?}",edge_id);
match edge_id{
MinkowskiEdge::VertEdge(v0,e1)=>{
println!("v0={}",self.mesh0.vert(v0));
for face_id1 in self.mesh1.edge_faces(e1).iter(){
println!("e1 face_n={}",self.mesh1.face_nd(*face_id1).0);
}
},
MinkowskiEdge::EdgeVert(e0,v1)=>{
println!("v1={}",self.mesh1.vert(v1));
for face_id0 in self.mesh0.edge_faces(e0).iter(){
println!("e0 face_n={}",self.mesh0.face_nd(*face_id0).0);
}
},
}
//cross to face if the boundary is not crossable and we are on the wrong side
let edge_n=self.edge_n(edge_id);
println!("edge_n={}",edge_n);
let vert_sum={
let &[v0,v1]=self.edge_verts(edge_id).borrow();
self.vert(v0)+self.vert(v1)
};
for (i,&face_id) in self.edge_faces(edge_id).iter().enumerate(){
let face_n=self.face_nd(face_id).0;
println!("face_id={:?} face_n={}",face_id,face_n);
//edge-face boundary nd, n facing out of the face towards the edge
let boundary_n=face_n.cross(edge_n)*(i as i64*2-1);
let boundary_d=boundary_n.dot(vert_sum);
println!("dot={} boundary_n={} boundary_d={} point_d={}",infinity_dir.dot(boundary_n),boundary_n,boundary_d,point.dot(boundary_n)*2);
// point.dot(boundary_n) is multiplied by two because vert_sum sums two vertices.
if infinity_dir.dot(boundary_n)==Planar64::ZERO&&point.dot(boundary_n)*2<=boundary_d{
//both faces cannot pass this condition, return early if one does.
@@ -477,6 +503,7 @@ impl MinkowskiMesh<'_>{
}
pub fn predict_collision_in(&self,relative_body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(MinkowskiFace,crate::integer::Time)>{
self.closest_fev_not_inside(relative_body.clone()).map_or(None,|fev|{
println!("@@@BEGIN REAL CRAWL@@@");
//continue forwards along the body parabola
match crate::face_crawler::crawl_fev(fev,self,relative_body,relative_body.time,time_limit){
crate::face_crawler::CrawlResult::Miss(_)=>None,
@@ -734,4 +761,4 @@ fn build_me_a_cube(){
let unit_cube=crate::primitives::unit_cube();
let mesh=PhysicsMesh::from(&unit_cube);
//println!("mesh={:?}",mesh);
}
}

View File

@@ -347,7 +347,7 @@ struct Hitbox{
impl Hitbox{
fn new(mesh:PhysicsMesh,transform:crate::integer::Planar64Affine3)->Self{
//calculate extents
let normal_transform=transform.matrix3.inverse().transpose();
let normal_transform=transform.matrix3.inverse_times_det().transpose();
let mut aabb=crate::aabb::Aabb::default();
for vert in mesh.verts(){
aabb.grow(transform.transform_point3(vert));
@@ -364,7 +364,7 @@ impl Hitbox{
halfsize:scale,
mesh,
transform:crate::integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(scale),Planar64Vec3::ZERO),
normal_transform:Planar64Mat3::from_diagonal(scale).inverse().transpose(),
normal_transform:Planar64Mat3::from_diagonal(scale).inverse_times_det().transpose(),
}
}
fn from_mesh_scale_offset(mesh:PhysicsMesh,scale:Planar64Vec3,offset:Planar64Vec3)->Self{
@@ -372,7 +372,7 @@ impl Hitbox{
halfsize:scale,
mesh,
transform:crate::integer::Planar64Affine3::new(Planar64Mat3::from_diagonal(scale),offset),
normal_transform:Planar64Mat3::from_diagonal(scale).inverse().transpose(),
normal_transform:Planar64Mat3::from_diagonal(scale).inverse_times_det().transpose(),
}
}
fn roblox()->Self{
@@ -783,7 +783,7 @@ pub struct PhysicsModel{
impl PhysicsModel{
pub fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{
let normal_transform=transform.matrix3.inverse().transpose();
let normal_transform=transform.matrix3.inverse_times_det().transpose();
Self{
mesh_id,
attr_id,
@@ -956,6 +956,7 @@ impl TouchingState{
//detect model collision in reverse
let model_mesh=models.mesh(intersect.model_id);
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
println!("### predict_collision_out id={} body={} time_limit={}",intersect.model_id,relative_body,collector.time());
collector.collect(minkowski.predict_collision_out(&relative_body,collector.time()).map(|(face,time)|{
TimedInstruction{
time,
@@ -1295,6 +1296,7 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
//no checks are needed because of the time limits.
let model_mesh=self.models.mesh(id);
let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(&model_mesh,&style_mesh);
println!("### predict_collision_in id={} body={} time_limit={}",id,relative_body,collector.time());
collector.collect(minkowski.predict_collision_in(&relative_body,collector.time())
//temp (?) code to avoid collision loops
.map_or(None,|(face,time)|if time==self.time{None}else{Some((face,time))})
@@ -1669,7 +1671,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
#[allow(dead_code)]
fn test_collision_axis_aligned(relative_body:Body,expected_collision_time:Option<Time>){
let h0=Hitbox::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::int(5,1,5)/2);
let h0=Hitbox::from_mesh_scale(PhysicsMesh::from(&crate::primitives::unit_cube()),Planar64Vec3::int(256,1,256)/2);
let h1=Hitbox::roblox();
let hitbox_mesh=h1.transformed_mesh();
let platform_mesh=h0.transformed_mesh();
@@ -1682,9 +1684,9 @@ fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time
let h0=Hitbox::new(PhysicsMesh::from(&crate::primitives::unit_cube()),
crate::integer::Planar64Affine3::new(
crate::integer::Planar64Mat3::from_cols(
Planar64Vec3::int(5,0,1)/2,
Planar64Vec3::int(256,0,1)/2,
Planar64Vec3::int(0,1,0)/2,
Planar64Vec3::int(-1,0,5)/2,
Planar64Vec3::int(-1,0,256)/2,
),
Planar64Vec3::ZERO,
)
@@ -1864,6 +1866,42 @@ fn test_collision_oblique(){
),Some(Time::from_secs(2)));
}
#[test]
fn test_collision_oblique_north(){
test_collision(Body::new(
Planar64Vec3::int(0,4,0),
Planar64Vec3::int(0,-1,-1),
Planar64Vec3::int(0,-1,0),
Time::ZERO
),Some(Time::from_nanos(732050807)));
}
#[test]
fn test_collision_oblique_east(){
test_collision(Body::new(
Planar64Vec3::int(0,4,0),
Planar64Vec3::int(1,-1,0),
Planar64Vec3::int(0,-1,0),
Time::ZERO
),Some(Time::from_nanos(732050807)));
}
#[test]
fn test_collision_oblique_south(){
test_collision(Body::new(
Planar64Vec3::int(0,4,0),
Planar64Vec3::int(0,-1,1),
Planar64Vec3::int(0,-1,0),
Time::ZERO
),Some(Time::from_nanos(732050807)));
}
#[test]
fn test_collision_oblique_west(){
test_collision(Body::new(
Planar64Vec3::int(0,4,0),
Planar64Vec3::int(-1,-1,0),
Planar64Vec3::int(0,-1,0),
Time::ZERO
),Some(Time::from_nanos(732050807)));
}
#[test]
fn zoom_hit_nothing(){
test_collision(Body::new(
Planar64Vec3::int(0,10,0),
@@ -1880,4 +1918,4 @@ fn already_inside_hit_nothing(){
Planar64Vec3::int(0,1,0),
Time::ZERO
),None);
}
}

View File

@@ -1,4 +1,5 @@
[camera]
sensitivity_x=98384
sensitivity_x=49192
#sensitivity_x=98384
fov_y=1.0
#fov_x_from_y_ratio=1.33333333333333333333333333333333