Compare commits
12 Commits
luau-md-de
...
luau-md-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
2ca197431b
|
|||
|
13f93fb2f0
|
|||
|
ee72434a87
|
|||
|
8c783ed8ae
|
|||
|
d90c201a91
|
|||
|
2c6a373fd0
|
|||
|
733bfc1bbf
|
|||
|
695ed460fc
|
|||
|
9b308e5fb7
|
|||
|
971ecc6393
|
|||
|
89c86cc805
|
|||
|
4f09bb41db
|
@@ -17,6 +17,13 @@ enum Simplex1_3<Vert>{
|
||||
Simplex3(Simplex<3,Vert>),
|
||||
}
|
||||
impl<Vert> Simplex1_3<Vert>{
|
||||
fn len(&self)->usize{
|
||||
match self{
|
||||
Simplex1_3::Simplex1(_)=>1,
|
||||
Simplex1_3::Simplex2(_)=>2,
|
||||
Simplex1_3::Simplex3(_)=>3,
|
||||
}
|
||||
}
|
||||
fn push_front(self,v:Vert)->Simplex2_4<Vert>{
|
||||
match self{
|
||||
Simplex1_3::Simplex1([v0])=>Simplex2_4::Simplex2([v,v0]),
|
||||
@@ -241,6 +248,7 @@ fn reduce3<M:MeshQuery>(
|
||||
let p=-(p0+point);
|
||||
let mut u=p1-p0;
|
||||
let v=p2-p0;
|
||||
println!("p={p} u={u} v={v}");
|
||||
|
||||
// local uv = u:Cross(v)
|
||||
// local up = u:Cross(p)
|
||||
@@ -264,6 +272,7 @@ fn reduce3<M:MeshQuery>(
|
||||
}else{
|
||||
uv
|
||||
};
|
||||
println!("and we got here?? direction={direction:?}");
|
||||
|
||||
// return direction, a0, a1, b0, b1, c0, c1
|
||||
return Reduced{
|
||||
@@ -355,10 +364,6 @@ fn reduce4<M:MeshQuery>(
|
||||
let mut u=p1-p0;
|
||||
let mut v=p2-p0;
|
||||
let w=p3-p0;
|
||||
println!("p={p}");
|
||||
println!("u={u}");
|
||||
println!("v={v}");
|
||||
println!("w={w}");
|
||||
|
||||
// local uv = u:Cross(v)
|
||||
// local vw = v:Cross(w)
|
||||
@@ -376,9 +381,11 @@ fn reduce4<M:MeshQuery>(
|
||||
let uv_p=uv.dot(p);
|
||||
|
||||
// if pvw/uvw >= 0 and upw/uvw >= 0 and uvp/uvw >= 0 then
|
||||
if !pv_w.div_sign(uv_w).is_negative()
|
||||
&&!up_w.div_sign(uv_w).is_negative()
|
||||
&&!uv_p.div_sign(uv_w).is_negative(){
|
||||
let a=!pv_w.div_sign(uv_w).is_negative();
|
||||
let b=!up_w.div_sign(uv_w).is_negative();
|
||||
let c=!uv_p.div_sign(uv_w).is_negative();
|
||||
println!("a={a} b={b} c={c}");
|
||||
if a&&b&&c{
|
||||
// origin is contained, this is a positive detection
|
||||
// local direction = Vector3.new(0, 0, 0)
|
||||
// return direction, a0, a1, b0, b1, c0, c1, d0, d1
|
||||
@@ -406,6 +413,8 @@ fn reduce4<M:MeshQuery>(
|
||||
// b0, c0 = c0, d0
|
||||
// b1, c1 = c1, d1
|
||||
(v1,v2)=(v2,v3);
|
||||
}else{
|
||||
v2=v3;
|
||||
}
|
||||
}else{
|
||||
// elseif wuDist == minDist3 then
|
||||
@@ -418,6 +427,8 @@ fn reduce4<M:MeshQuery>(
|
||||
// before [a,b,c,d]
|
||||
(v1,v2)=(v3,v1);
|
||||
// after [a,d,b]
|
||||
}else{
|
||||
v2=v3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,23 +440,17 @@ fn reduce4<M:MeshQuery>(
|
||||
let pv=p.cross(v);
|
||||
let uv_up=uv.dot(up);
|
||||
let uv_pv=uv.dot(pv);
|
||||
println!("up={up}");
|
||||
println!("pv={pv}");
|
||||
println!("uv_up={uv_up}");
|
||||
println!("uv_pv={uv_pv}");
|
||||
|
||||
// if uv_up >= 0 and uv_pv >= 0 then
|
||||
if !uv_up.is_negative()&&!uv_pv.is_negative(){
|
||||
// local direction = uvw < 0 and uv or -uv
|
||||
// return direction, a0, a1, b0, b1, c0, c1
|
||||
if uv_w.is_negative(){
|
||||
println!("a");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(uv),
|
||||
simplex:Simplex1_3::Simplex3([v0,v1,v2]),
|
||||
});
|
||||
}else{
|
||||
println!("b");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(-uv),
|
||||
simplex:Simplex1_3::Simplex3([v0,v1,v2]),
|
||||
@@ -483,13 +488,11 @@ fn reduce4<M:MeshQuery>(
|
||||
// direction = uvw < 0 and uv or -uv
|
||||
// return direction, a0, a1, b0, b1
|
||||
if uv_w.is_negative(){
|
||||
println!("c");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(uv),
|
||||
simplex:Simplex1_3::Simplex2([v0,v1]),
|
||||
});
|
||||
}else{
|
||||
println!("d");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(-uv),
|
||||
simplex:Simplex1_3::Simplex2([v0,v1]),
|
||||
@@ -497,7 +500,6 @@ fn reduce4<M:MeshQuery>(
|
||||
}
|
||||
}
|
||||
|
||||
println!("e");
|
||||
// return direction, a0, a1, b0, b1
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir3(direction),
|
||||
@@ -511,13 +513,11 @@ fn reduce4<M:MeshQuery>(
|
||||
if dir==vec3::zero(){
|
||||
// direction = uvw < 0 and uv or -uv
|
||||
if uv_w.is_negative(){
|
||||
println!("f");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(uv),
|
||||
simplex:Simplex1_3::Simplex1([v0]),
|
||||
});
|
||||
}else{
|
||||
println!("g");
|
||||
return Reduce::Reduced(Reduced{
|
||||
dir:narrow_dir2(-uv),
|
||||
simplex:Simplex1_3::Simplex1([v0]),
|
||||
@@ -525,7 +525,6 @@ fn reduce4<M:MeshQuery>(
|
||||
}
|
||||
}
|
||||
|
||||
println!("h");
|
||||
// return direction, a0, a1
|
||||
Reduce::Reduced(Reduced{
|
||||
dir,
|
||||
@@ -553,6 +552,24 @@ impl<Vert> Simplex2_4<Vert>{
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_point(mesh:&MinkowskiMesh<'_>,point:Planar64Vec3)->bool{
|
||||
const ENABLE_FAST_FAIL:bool=true;
|
||||
// TODO: remove mesh negation
|
||||
minimum_difference::<ENABLE_FAST_FAIL,_,_>(&-mesh,point,
|
||||
// on_exact
|
||||
|is_intersecting,_simplex|{
|
||||
is_intersecting
|
||||
},
|
||||
// on_escape
|
||||
|_simplex|{
|
||||
// intersection is guaranteed at this point
|
||||
true
|
||||
},
|
||||
// fast_fail value
|
||||
||false
|
||||
)
|
||||
}
|
||||
|
||||
//infinity fev algorithm state transition
|
||||
#[derive(Debug)]
|
||||
enum Transition<Vert>{
|
||||
@@ -751,19 +768,16 @@ fn crawl_to_closest_fev<'a>(mesh:&MinkowskiMesh<'a>,simplex:Simplex<3,MinkowskiV
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InfiniteLoop;
|
||||
pub fn closest_fev_not_inside<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Vec3)->Result<Option<FEV<MinkowskiMesh<'a>>>,InfiniteLoop>{
|
||||
pub fn closest_fev_not_inside<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Vec3)->Option<FEV<MinkowskiMesh<'a>>>{
|
||||
println!("=== LUA ===");
|
||||
let (hits,_details)=crate::minimum_difference_lua::minimum_difference_details(mesh,point).unwrap();
|
||||
println!("=== RUST ===");
|
||||
let closest_fev_not_inside=closest_fev_not_inside_inner(mesh,point).unwrap();
|
||||
let closest_fev_not_inside=closest_fev_not_inside_inner(mesh,point);
|
||||
assert_eq!(hits,closest_fev_not_inside.is_none(),"algorithms disagree");
|
||||
Ok(closest_fev_not_inside)
|
||||
closest_fev_not_inside
|
||||
}
|
||||
|
||||
pub fn closest_fev_not_inside_inner<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Vec3)->Result<Option<FEV<MinkowskiMesh<'a>>>,InfiniteLoop>{
|
||||
fn closest_fev_not_inside_inner<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Vec3)->Option<FEV<MinkowskiMesh<'a>>>{
|
||||
const ENABLE_FAST_FAIL:bool=false;
|
||||
// TODO: remove mesh negation
|
||||
minimum_difference::<ENABLE_FAST_FAIL,_,_>(&-mesh,point,
|
||||
@@ -771,16 +785,20 @@ pub fn closest_fev_not_inside_inner<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Ve
|
||||
|is_intersecting,simplex|{
|
||||
println!("on_exact simplex={simplex:?}");
|
||||
if is_intersecting{
|
||||
return Ok(None);
|
||||
return None;
|
||||
}
|
||||
// Convert simplex to FEV
|
||||
// Vertices must be inverted since the mesh is inverted
|
||||
Ok(Some(match simplex{
|
||||
Some(match simplex{
|
||||
Simplex1_3::Simplex1([v0])=>FEV::Vert(-v0),
|
||||
Simplex1_3::Simplex2([v0,v1])=>{
|
||||
// invert
|
||||
let (v0,v1)=(-v0,-v1);
|
||||
crawl_to_closest_ev(mesh,[v0,v1],point).into()
|
||||
let ev=crawl_to_closest_ev(mesh,[v0,v1],point);
|
||||
if !matches!(ev,EV::Edge(_)){
|
||||
println!("I can't believe it's not an edge!");
|
||||
}
|
||||
ev.into()
|
||||
},
|
||||
Simplex1_3::Simplex3([v0,v1,v2])=>{
|
||||
// invert
|
||||
@@ -788,40 +806,23 @@ pub fn closest_fev_not_inside_inner<'a>(mesh:&MinkowskiMesh<'a>,point:Planar64Ve
|
||||
// Shimmy to the side until you find a face that contains the closest point
|
||||
// it's ALWAYS representable as a face, but this algorithm may
|
||||
// return E or V in edge cases but I don't think that will break the face crawler
|
||||
crawl_to_closest_fev(mesh,[v0,v1,v2],point)
|
||||
let fev=crawl_to_closest_fev(mesh,[v0,v1,v2],point);
|
||||
if !matches!(fev,FEV::Face(_)){
|
||||
println!("I can't believe it's not a face!");
|
||||
}
|
||||
fev
|
||||
},
|
||||
}))
|
||||
})
|
||||
},
|
||||
// on_escape
|
||||
|_simplex|{
|
||||
// intersection is guaranteed at this point
|
||||
// local norm, dist, u0, u1, v0, v1, w0, w1 = expand(queryP, queryQ, a0, a1, b0, b1, c0, c1, d0, d1, 1e-5)
|
||||
// let simplex=refine_to_exact(mesh,simplex);
|
||||
Ok(None)
|
||||
None
|
||||
},
|
||||
// fast_fail value is irrelevant and will never be returned!
|
||||
||unreachable!(),
|
||||
||Err(InfiniteLoop),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn contains_point(mesh:&MinkowskiMesh<'_>,point:Planar64Vec3)->bool{
|
||||
const ENABLE_FAST_FAIL:bool=true;
|
||||
// TODO: remove mesh negation
|
||||
minimum_difference::<ENABLE_FAST_FAIL,_,_>(&-mesh,point,
|
||||
// on_exact
|
||||
|is_intersecting,_simplex|{
|
||||
is_intersecting
|
||||
},
|
||||
// on_escape
|
||||
|_simplex|{
|
||||
// intersection is guaranteed at this point
|
||||
true
|
||||
},
|
||||
// fast_fail value
|
||||
||false,
|
||||
// infinite loop
|
||||
||false,
|
||||
||unreachable!()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -836,7 +837,6 @@ fn minimum_difference<const ENABLE_FAST_FAIL:bool,T,M:MeshQuery>(
|
||||
on_exact:impl FnOnce(bool,Simplex1_3<M::Vert>)->T,
|
||||
on_escape:impl FnOnce(Simplex<4,M::Vert>)->T,
|
||||
on_fast_fail:impl FnOnce()->T,
|
||||
on_infinite_loop:impl FnOnce()->T,
|
||||
)->T{
|
||||
// local initialAxis = queryQ() - queryP()
|
||||
// local new_point_p = queryP(initialAxis)
|
||||
@@ -855,8 +855,8 @@ fn minimum_difference<const ENABLE_FAST_FAIL:bool,T,M:MeshQuery>(
|
||||
|
||||
// exitRadius = testIntersection and 0 or exitRadius or 1/0
|
||||
// for _ = 1, 100 do
|
||||
for _ in 0..100{
|
||||
println!("direction={direction}");
|
||||
loop{
|
||||
println!("arity={} direction={direction}",simplex_small.len());
|
||||
|
||||
// new_point_p = queryP(-direction)
|
||||
// new_point_q = queryQ(direction)
|
||||
@@ -909,7 +909,6 @@ fn minimum_difference<const ENABLE_FAST_FAIL:bool,T,M:MeshQuery>(
|
||||
// next loop this will be a
|
||||
last_pos=next_pos;
|
||||
}
|
||||
on_infinite_loop()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -931,8 +930,7 @@ mod test{
|
||||
true
|
||||
},
|
||||
// fast_fail value
|
||||
||false,
|
||||
||false,
|
||||
||false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -670,14 +670,12 @@ impl MinkowskiMesh<'_>{
|
||||
mesh1,
|
||||
}
|
||||
}
|
||||
pub fn predict_collision_in(&self,relative_body:&Body,range:impl RangeBounds<Time>)->Result<Option<(MinkowskiFace,GigaTime)>,crate::minimum_difference::InfiniteLoop>{
|
||||
let Some(fev)=crate::minimum_difference::closest_fev_not_inside(self,relative_body.position)?else{
|
||||
return Ok(None);
|
||||
};
|
||||
pub fn predict_collision_in(&self,relative_body:&Body,range:impl RangeBounds<Time>)->Option<(MinkowskiFace,GigaTime)>{
|
||||
let fev=crate::minimum_difference::closest_fev_not_inside(self,relative_body.position)?;
|
||||
//continue forwards along the body parabola
|
||||
Ok(fev.crawl(self,relative_body,range.start_bound(),range.end_bound()).hit())
|
||||
fev.crawl(self,relative_body,range.start_bound(),range.end_bound()).hit()
|
||||
}
|
||||
pub fn predict_collision_out(&self,relative_body:&Body,range:impl RangeBounds<Time>)->Result<Option<(MinkowskiFace,GigaTime)>,crate::minimum_difference::InfiniteLoop>{
|
||||
pub fn predict_collision_out(&self,relative_body:&Body,range:impl RangeBounds<Time>)->Option<(MinkowskiFace,GigaTime)>{
|
||||
let (lower_bound,upper_bound)=(range.start_bound(),range.end_bound());
|
||||
// TODO: handle unbounded collision using infinity fev
|
||||
let time=match upper_bound{
|
||||
@@ -685,16 +683,14 @@ impl MinkowskiMesh<'_>{
|
||||
Bound::Excluded(&time)=>time,
|
||||
Bound::Unbounded=>unimplemented!("unbounded collision out"),
|
||||
};
|
||||
let Some(fev)=crate::minimum_difference::closest_fev_not_inside(self,relative_body.extrapolated_position(time))?else{
|
||||
return Ok(None);
|
||||
};
|
||||
let fev=crate::minimum_difference::closest_fev_not_inside(self,relative_body.extrapolated_position(time))?;
|
||||
// swap and negate bounds to do a time inversion
|
||||
let (lower_bound,upper_bound)=(upper_bound.map(|&t|-t),lower_bound.map(|&t|-t));
|
||||
let infinity_body=-relative_body;
|
||||
//continue backwards along the body parabola
|
||||
Ok(fev.crawl(self,&infinity_body,lower_bound.as_ref(),upper_bound.as_ref()).hit()
|
||||
fev.crawl(self,&infinity_body,lower_bound.as_ref(),upper_bound.as_ref()).hit()
|
||||
//no need to test -time<time_limit because of the first step
|
||||
.map(|(face,time)|(face,-time)))
|
||||
.map(|(face,time)|(face,-time))
|
||||
}
|
||||
pub fn predict_collision_face_out(&self,relative_body:&Body,range:impl RangeBounds<Time>,contact_face_id:MinkowskiFace)->Option<(MinkowskiDirectedEdge,GigaTime)>{
|
||||
// TODO: make better
|
||||
|
||||
@@ -828,7 +828,7 @@ impl TouchingState{
|
||||
}).collect();
|
||||
crate::push_solve::push_solve(&contacts,acceleration)
|
||||
}
|
||||
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,Time>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time)->Result<(),crate::minimum_difference::InfiniteLoop>{
|
||||
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,Time>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){
|
||||
// let relative_body=body.relative_to(&Body::ZERO);
|
||||
let relative_body=body;
|
||||
for (convex_mesh_id,face_id) in &self.contacts{
|
||||
@@ -849,7 +849,7 @@ impl TouchingState{
|
||||
//detect model collision in reverse
|
||||
let model_mesh=models.intersect_mesh(convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
|
||||
collector.collect(minkowski.predict_collision_out(&relative_body,start_time..collector.time())?.map(|(_face,time)|{
|
||||
collector.collect(minkowski.predict_collision_out(&relative_body,start_time..collector.time()).map(|(_face,time)|{
|
||||
TimedInstruction{
|
||||
time:relative_body.time+time.into(),
|
||||
instruction:InternalInstruction::CollisionEnd(
|
||||
@@ -859,7 +859,6 @@ impl TouchingState{
|
||||
}
|
||||
}));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1200,7 +1199,7 @@ impl<'a> PhysicsContext<'a>{
|
||||
collector.collect(state.next_move_instruction());
|
||||
|
||||
//check for collision ends
|
||||
state.touching.predict_collision_end(&mut collector,&data.models,&data.hitbox_mesh,&state.body,state.time).unwrap();
|
||||
state.touching.predict_collision_end(&mut collector,&data.models,&data.hitbox_mesh,&state.body,state.time);
|
||||
//check for collision starts
|
||||
let mut aabb=aabb::Aabb::default();
|
||||
state.body.grow_aabb(&mut aabb,state.time,collector.time());
|
||||
@@ -1215,17 +1214,17 @@ impl<'a> PhysicsContext<'a>{
|
||||
//no checks are needed because of the time limits.
|
||||
let model_mesh=data.models.mesh(*convex_mesh_id);
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
|
||||
let Ok(collision)=minkowski.predict_collision_in(relative_body,state.time..collector.time())else{
|
||||
println!("Infinite loop! body={relative_body}");
|
||||
return;
|
||||
};
|
||||
collector.collect(collision.map(|(face,dt)|TimedInstruction{
|
||||
time:relative_body.time+dt.into(),
|
||||
instruction:InternalInstruction::CollisionStart(
|
||||
Collision::new(*convex_mesh_id,face),
|
||||
dt
|
||||
collector.collect(minkowski.predict_collision_in(relative_body,state.time..collector.time())
|
||||
.map(|(face,dt)|
|
||||
TimedInstruction{
|
||||
time:relative_body.time+dt.into(),
|
||||
instruction:InternalInstruction::CollisionStart(
|
||||
Collision::new(*convex_mesh_id,face),
|
||||
dt
|
||||
)
|
||||
}
|
||||
)
|
||||
}));
|
||||
);
|
||||
});
|
||||
collector.take()
|
||||
}
|
||||
@@ -1973,7 +1972,7 @@ mod test{
|
||||
let hitbox_mesh=h1.transformed_mesh();
|
||||
let platform_mesh=h0.transformed_mesh();
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(platform_mesh,hitbox_mesh);
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO..Time::from_secs(10)).unwrap();
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO..Time::from_secs(10));
|
||||
assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
|
||||
}
|
||||
fn test_collision_rotated(relative_body:Body,expected_collision_time:Option<Time>){
|
||||
@@ -1991,7 +1990,7 @@ mod test{
|
||||
let hitbox_mesh=h1.transformed_mesh();
|
||||
let platform_mesh=h0.transformed_mesh();
|
||||
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(platform_mesh,hitbox_mesh);
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO..Time::from_secs(10)).unwrap();
|
||||
let collision=minkowski.predict_collision_in(&relative_body,Time::ZERO..Time::from_secs(10));
|
||||
assert_eq!(collision.map(|tup|relative_body.time+tup.1.into()),expected_collision_time,"Incorrect time of collision");
|
||||
}
|
||||
fn test_collision(relative_body:Body,expected_collision_time:Option<Time>){
|
||||
|
||||
@@ -121,9 +121,13 @@ fn test_scene_cylinder()->PhysicsData{
|
||||
let cube_face_description=CubeFaceDescription::new(Default::default(),RenderConfigId::new(0));
|
||||
let mesh=builder.push_mesh(strafesnet_rbx_loader::primitives::unit_cylinder(cube_face_description));
|
||||
// place one 5x5x5 cylinder.
|
||||
// log cylinder
|
||||
// transform=PhysicsMeshTransform { vertex: Planar64Affine3 { matrix3: Matrix { array: [[-0.00000469, 20.41880000, -0.00001730], [-3.71969533, -0.00000d38, -11.c3c43095], [-11.c3c41e7d, 0.00000000, 3.719690ac]] }, translation: Vector { array: [-908.de600000, 28f.e5240000, 24c.c4d80000] } }, normal: Matrix { array: [[-0.00002d857e4861a0, 147.71af629e398c1d05, -0.0000ead3c8730458], [-6f.147da83887600000, -0.0001ab1b4486f8fc, -23d.04a89b8def680000], [-23d.04aae32fa55a8280, 0.0000018177694d73, 6f.147e3a4136524bf8]] }, det: 2942.07be40fdd83c96df87d34320 }
|
||||
// wedge part
|
||||
// transform=PhysicsMeshTransform { vertex: Planar64Affine3 { matrix3: Matrix { array: [[-4.9ba5b000, 0.00000000, 0.00000000], [0.00000000, 3.85509c00, 0.00000000], [0.00000000, 0.00000000, -4.9ba5b000]] }, translation: Vector { array: [-781.30380000, 35b.dab40000, 11c.a4160000] } }, normal: Matrix { array: [[-10.3941970ff7400000, 0.0000000000000000, 0.0000000000000000], [0.0000000000000000, 15.3bcf8e5c59000000, 0.0000000000000000], [0.0000000000000000, 0.0000000000000000, -10.3941970ff7400000]] }, det: 4a.c2312159fcd9163c00000000 }
|
||||
builder.push_mesh_instance(mesh,Planar64Affine3::new(
|
||||
mat3::from_diagonal(vec3::int(5,5,5)>>1),
|
||||
vec3::int(0,-5,0)
|
||||
mat3::Matrix3::from_cols([vec3::raw_array([-0x4_9ba5b000, 0x0_00000000, 0x0_00000000]), vec3::raw_array([0x0_00000000, 0x3_85509c00, 0x0_00000000]), vec3::raw_array([0x0_00000000, 0x0_00000000, -0x4_9ba5b000])]),
|
||||
vec3::raw_array([-0x781_30380000, 0x35b_dab40000, 0x11c_a4160000])
|
||||
));
|
||||
builder.build()
|
||||
}
|
||||
@@ -131,9 +135,13 @@ fn test_scene_cylinder()->PhysicsData{
|
||||
#[test]
|
||||
fn test_minimum_difference(){
|
||||
let physics_data=test_scene_cylinder();
|
||||
// log cylinder
|
||||
// H p(-2329.436, 694.175, 587.190) v(0.000, -5.714, 0.000) a(0.000, -100.000, 0.000) t(56s+880000000ns)
|
||||
// wedge part
|
||||
// H p(-1920.041, 867.905, 284.639) v(0.000, -4.695, 0.000) a(0.000, -100.000, 0.000) t(119s+260000000ns)
|
||||
let body=strafesnet_physics::physics::Body::new(
|
||||
vec3::int(4,1,4)>>1,
|
||||
vec3::int(-1,-1,-2),
|
||||
vec3::try_from_f32_array([-1920.041, 867.905, 284.639]).unwrap(),
|
||||
vec3::try_from_f32_array([0.000, -4.695, 0.000]).unwrap(),
|
||||
vec3::int(0,-100,0),
|
||||
Time::ZERO,
|
||||
);
|
||||
|
||||
@@ -74,39 +74,3 @@ fn physics_bug_3()->Result<(),ReplayError>{
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Infinite loop! body=p(-1796.657, 677.618, 36.959) v(3.158, -53.650, -34.435) a(-0.000, -71.276, -45.248) t(288s+440000000ns)
|
||||
// Infinite loop! body=p(-2382.440, 160.150, -379.151) v(53.632, 35.779, 44.904) a(0.000, -100.000, 0.000) t(306s+675758543ns)
|
||||
// Infinite loop! body=p(-1798.724, 731.459, 68.784) v(-17.389, 0.000, -78.087) a(0.000, 0.000, 0.000) t(284s+006980061ns)
|
||||
// Infinite loop! body=p(-1796.657, 677.618, 36.959) v(3.158, -53.650, -34.435) a(-0.000, -71.276, -45.248) t(288s+440000000ns)
|
||||
// Infinite loop! body=p(-1797.504, 738.529, 74.864) v(-3.653, 0.000, -79.917) a(0.000, 0.000, 0.000) t(282s+709871336ns)
|
||||
// Infinite loop! body=p(-1797.569, 735.449, 71.859) v(23.726, -76.309, -3.747) a(0.000, 0.000, 0.000) t(283s+325193187ns)
|
||||
|
||||
#[test]
|
||||
fn physics_md_infinite_loop()->Result<(),ReplayError>{
|
||||
println!("loading map file..");
|
||||
let data=read_entire_file("../tools/bhop_maps/5692113331.snfm")?;
|
||||
let map=strafesnet_snf::read_map(data)?.into_complete_map()?;
|
||||
|
||||
// create recording
|
||||
println!("generating models..");
|
||||
let physics_data=PhysicsData::new(&map);
|
||||
println!("simulating...");
|
||||
|
||||
//teleport to bug
|
||||
use strafesnet_common::integer::{vec3,Time};
|
||||
let body=strafesnet_physics::physics::Body::new(
|
||||
vec3::try_from_f32_array([-1796.657, 677.618, 36.959]).unwrap(),
|
||||
vec3::try_from_f32_array([3.158, -53.650, -34.435]).unwrap(),
|
||||
vec3::int(0,-100,0),
|
||||
Time::ZERO,
|
||||
);
|
||||
let mut physics=PhysicsState::new_with_body(body);
|
||||
// wait one second to activate the bug
|
||||
PhysicsContext::run_input_instruction(&mut physics,&physics_data,strafesnet_common::instruction::TimedInstruction{
|
||||
time:Time::from_millis(500),
|
||||
instruction:strafesnet_common::physics::Instruction::Idle,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user