From 285cf2f973c9d8cfb8767edfdfb6ac4e4b37f295 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Jun 2019 17:13:30 +0100 Subject: [PATCH 01/16] Added proper 3D collisions --- common/src/sys/phys.rs | 53 ++++++++++++++++++++++++++++++------- voxygen/src/scene/camera.rs | 2 +- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 44dfdeecd3..8744899ab4 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -168,16 +168,49 @@ impl<'a> System<'a> for Sys { vel.0 = integrate_forces(dt.0, vel.0, friction); // Basic collision with terrain - let mut i = 0.0; - while terrain - .get(pos.0.map(|e| e.floor() as i32)) - .map(|vox| !vox.is_empty()) - .unwrap_or(false) - && i < 6000.0 * dt.0 - { - pos.0.z += 0.0025; - vel.0.z = 0.0; - i += 1.0; + + // Iterate through nearby blocks, prioritise closer ones + let near_iter = [0, -1, 1].into_iter() + .map(move |i| [0, -1, 1].into_iter() + .map(move |j| [0, 1, -1, 2].into_iter() + .map(move |k| (*i, *j, *k)))) + .flatten() + .flatten(); + + // For every nearby block... + for (i, j, k) in near_iter { + let block_pos = pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k); + + // ...check to see whether it is solid... + if terrain + .get(block_pos) + .map(|vox| !vox.is_empty()) + .unwrap_or(false) + { + // ...and calculate bounding boxes for both the player's body and the block. + let this_body_aabb = Aabb { min: pos.0 + Vec3::new(-0.4, -0.4, 1.0), max: pos.0 + Vec3::new(0.4, 0.4, 2.0) }; + let other_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; + + // If the bounding boxes collide, resolve the collision + if this_body_aabb.collides_with_aabb(other_aabb) { + let dir = this_body_aabb.collision_vector_with_aabb(other_aabb); + + let max_axis = dir.map(|e| e.abs()).reduce_partial_min(); + let resolve_dir = dir.map(|e| if e.abs() == max_axis { e } else { 0.0 }); + + pos.0 -= resolve_dir; + vel.0 = vel.0.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); + } + + // Now, calculate a binding box for the player's feet... + let this_feet_aabb = Aabb { min: pos.0 + Vec3::new(-0.3, -0.3, 0.0), max: pos.0 + Vec3::new(0.3, 0.3, 1.0) }; + + // ...if it collides with the block, snap the player to the top of it... + if this_feet_aabb.collides_with_aabb(other_aabb) { + pos.0.z -= this_feet_aabb.collision_vector_with_aabb(other_aabb).z; + vel.0.z = vel.0.z.max(0.0); + } + } } } } diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 40d5193a1e..6a520b36bf 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -6,7 +6,7 @@ use vek::*; const NEAR_PLANE: f32 = 0.1; const FAR_PLANE: f32 = 10000.0; -const INTERP_TIME: f32 = 0.05; +const INTERP_TIME: f32 = 0.025; pub struct Camera { tgt_focus: Vec3, From 7a1359961cd4a2fc60f0712e5f2e3e8aee0dc685 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Jun 2019 19:57:44 +0100 Subject: [PATCH 02/16] Removed block-hopping, fixed collisions --- common/src/sys/phys.rs | 81 ++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 8744899ab4..87fdbfbb02 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -145,18 +145,6 @@ impl<'a> System<'a> for Sys { // Movement pos.0 += vel.0 * dt.0; - // Update OnGround component - if terrain - .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) - .map(|vox| !vox.is_empty()) - .unwrap_or(false) - && vel.0.z <= 0.0 - { - on_grounds.insert(entity, OnGround); - } else { - on_grounds.remove(entity); - } - // Integrate forces // Friction is assumed to be a constant dependent on location let friction = 50.0 @@ -170,14 +158,37 @@ impl<'a> System<'a> for Sys { // Basic collision with terrain // Iterate through nearby blocks, prioritise closer ones - let near_iter = [0, -1, 1].into_iter() - .map(move |i| [0, -1, 1].into_iter() - .map(move |j| [0, 1, -1, 2].into_iter() - .map(move |k| (*i, *j, *k)))) + let near_iter = [0, -1, 1, -2, 2, 3].into_iter() + .map(move |k| [0, -1, 1, -2, 2].into_iter() + .map(move |j| [0, -1, 1, -2, 2].into_iter() + .map(move |i| (*i, *j, *k)))) .flatten() .flatten(); + /* + let collision_with = |pos: Vec3, near_iter| { + for (i, j, k) in near_iter { + let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k); + + let this_aabb = Aabb { min: pos + Vec3::new(-0.3, -0.3, 0.0), max: pos + Vec3::new(0.3, 0.3, 1.7) }; + let block_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; + + if this_aabb.collides_with_aabb(block_aabb) { + return true; + } + } + false + }; + */ + + //let collision_above = collision_with(pos.0 + Vec3::unit_z() * 1.1, near_iter.clone()); + //let collision_below = collision_with(pos.0 - Vec3::unit_z() * 1.01, near_iter.clone()); + + on_grounds.remove(entity); + pos.0.z -= 0.0001; // To force collision with the floor + // For every nearby block... + let mut on_ground = false; for (i, j, k) in near_iter { let block_pos = pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k); @@ -188,30 +199,38 @@ impl<'a> System<'a> for Sys { .unwrap_or(false) { // ...and calculate bounding boxes for both the player's body and the block. - let this_body_aabb = Aabb { min: pos.0 + Vec3::new(-0.4, -0.4, 1.0), max: pos.0 + Vec3::new(0.4, 0.4, 2.0) }; - let other_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; + let this_aabb = Aabb { min: pos.0 + Vec3::new(-0.3, -0.3, 0.0), max: pos.0 + Vec3::new(0.3, 0.3, 1.7) }; + let block_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; // If the bounding boxes collide, resolve the collision - if this_body_aabb.collides_with_aabb(other_aabb) { - let dir = this_body_aabb.collision_vector_with_aabb(other_aabb); + if this_aabb.collides_with_aabb(block_aabb) { + let dir = this_aabb.collision_vector_with_aabb(block_aabb); let max_axis = dir.map(|e| e.abs()).reduce_partial_min(); - let resolve_dir = dir.map(|e| if e.abs() == max_axis { e } else { 0.0 }); + let resolve_dir = -dir.map(|e| if e.abs() == max_axis { e } else { 0.0 }); - pos.0 -= resolve_dir; - vel.0 = vel.0.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); - } + // When the resolution direction is pointing upwards, we must be on the ground + if resolve_dir.z > 0.0 { + on_ground = true; + } - // Now, calculate a binding box for the player's feet... - let this_feet_aabb = Aabb { min: pos.0 + Vec3::new(-0.3, -0.3, 0.0), max: pos.0 + Vec3::new(0.3, 0.3, 1.0) }; - - // ...if it collides with the block, snap the player to the top of it... - if this_feet_aabb.collides_with_aabb(other_aabb) { - pos.0.z -= this_feet_aabb.collision_vector_with_aabb(other_aabb).z; - vel.0.z = vel.0.z.max(0.0); + //if resolve_dir.z == 0.0 && !collision_above { + // pos.0.z += 1.01; + // break; + //} else { + pos.0 += resolve_dir; + vel.0 = vel.0.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); + //} } } } + + + if on_ground { + on_grounds.insert(entity, OnGround); + }// else if collision_below && vel.0.z < 0.0 { + // pos.0.z -= 0.5; + //} } } } From 2c24ba777606575148407df5ed24664c00861c37 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Jun 2019 21:26:04 +0100 Subject: [PATCH 03/16] Fixed block-hopping, block-snapping, added interpolation to figures --- common/src/sys/phys.rs | 39 +++++++++++++++++++------------------ voxygen/src/scene/camera.rs | 2 +- voxygen/src/scene/figure.rs | 10 +++++++++- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 87fdbfbb02..803480753d 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -165,31 +165,32 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); - /* let collision_with = |pos: Vec3, near_iter| { for (i, j, k) in near_iter { let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k); - let this_aabb = Aabb { min: pos + Vec3::new(-0.3, -0.3, 0.0), max: pos + Vec3::new(0.3, 0.3, 1.7) }; - let block_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; + if terrain + .get(block_pos) + .map(|vox| !vox.is_empty()) + .unwrap_or(false) + { + let this_aabb = Aabb { min: pos + Vec3::new(-0.3, -0.3, 0.0), max: pos + Vec3::new(0.3, 0.3, 1.7) }; + let block_aabb = Aabb { min: block_pos.map(|e| e as f32), max: block_pos.map(|e| e as f32) + 1.0 }; - if this_aabb.collides_with_aabb(block_aabb) { - return true; + if this_aabb.collides_with_aabb(block_aabb) { + return true; + } } } false }; - */ - - //let collision_above = collision_with(pos.0 + Vec3::unit_z() * 1.1, near_iter.clone()); - //let collision_below = collision_with(pos.0 - Vec3::unit_z() * 1.01, near_iter.clone()); on_grounds.remove(entity); pos.0.z -= 0.0001; // To force collision with the floor // For every nearby block... let mut on_ground = false; - for (i, j, k) in near_iter { + for (i, j, k) in near_iter.clone() { let block_pos = pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k); // ...check to see whether it is solid... @@ -214,23 +215,23 @@ impl<'a> System<'a> for Sys { on_ground = true; } - //if resolve_dir.z == 0.0 && !collision_above { - // pos.0.z += 1.01; - // break; - //} else { + if resolve_dir.z == 0.0 && !collision_with(pos.0 + Vec3::unit_z() * 1.0, near_iter.clone()) { + pos.0.z += 1.0; + break; + } else { pos.0 += resolve_dir; vel.0 = vel.0.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 }); - //} + } } } } - if on_ground { on_grounds.insert(entity, OnGround); - }// else if collision_below && vel.0.z < 0.0 { - // pos.0.z -= 0.5; - //} + } else if collision_with(pos.0 - Vec3::unit_z() * 1.0, near_iter.clone()) && vel.0.z < 0.0 && vel.0.z > -1.0 { + pos.0.z = (pos.0.z - 0.05).floor(); + on_grounds.insert(entity, OnGround); + } } } } diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 6a520b36bf..40d5193a1e 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -6,7 +6,7 @@ use vek::*; const NEAR_PLANE: f32 = 0.1; const FAR_PLANE: f32 = 10000.0; -const INTERP_TIME: f32 = 0.025; +const INTERP_TIME: f32 = 0.05; pub struct Camera { tgt_focus: Vec3, diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 000c38233c..46dee347ef 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -741,6 +741,8 @@ pub struct FigureState { bone_consts: Consts, locals: Consts, skeleton: S, + pos: Vec3, + ori: Vec3, } impl FigureState { @@ -751,6 +753,8 @@ impl FigureState { .unwrap(), locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(), skeleton, + pos: Vec3::zero(), + ori: Vec3::zero(), } } @@ -761,8 +765,12 @@ impl FigureState { ori: Vec3, col: Rgba, ) { + // Update interpolate pos + self.pos = Lerp::lerp(self.pos, pos, 0.4); + self.ori = Slerp::slerp(self.ori, ori, 0.2); + let mat = Mat4::::identity() - * Mat4::translation_3d(pos) + * Mat4::translation_3d(self.pos) * Mat4::rotation_z(-ori.x.atan2(ori.y)) * Mat4::scaling_3d(Vec3::from(0.8)); From af432ec510504579b104e2e2c030fbcae74316eb Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Jun 2019 22:00:26 +0100 Subject: [PATCH 04/16] Calculate delta time properly, fix low fps collision issues by decreasing max dt --- common/src/state.rs | 7 ++++++- voxygen/src/menu/char_selection/scene.rs | 1 + voxygen/src/scene/figure.rs | 16 ++++++++-------- voxygen/src/session.rs | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/common/src/state.rs b/common/src/state.rs index 974c841258..56d476b4f4 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -38,7 +38,7 @@ pub struct DeltaTime(pub f32); /// too fast, we'd skip important physics events like collisions. This constant determines the /// upper limit. If delta time exceeds this value, the game's physics will begin to produce time /// lag. Ideally, we'd avoid such a situation. -const MAX_DELTA_TIME: f32 = 0.15; +const MAX_DELTA_TIME: f32 = 0.03; pub struct Changes { pub new_chunks: HashSet>, @@ -188,6 +188,11 @@ impl State { self.ecs.read_resource::