From 94b9f50efa502ea872c71dea62db71b19be60069 Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Thu, 5 Sep 2019 17:07:15 +0800 Subject: [PATCH 1/6] Exponential interpolation for linear damping With an additional approximation to allow for the same size jumps given different framerates. --- common/src/sys/phys.rs | 65 +++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 42ebc978c5..d816d21871 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -11,8 +11,14 @@ use { }; const GRAVITY: f32 = 9.81 * 4.0; -const FRIC_GROUND: f32 = 0.15; -const FRIC_AIR: f32 = 0.015; + +// Friction values used for linear damping. They are unitless quantities. The +// value of these quantities must be between zero and one. They represent the +// amount an object will slow down within 1/60th of a second. Eg. if the frction +// is 0.01, and the speed is 1.0, then after 1/60th of a second the speed will +// be 0.99. after 1 second the speed will be 0.54, which is 0.99 ^ 60. +const FRIC_GROUND: f32 = 0.125; +const FRIC_AIR: f32 = 0.0125; // Integrates forces, calculates the new velocity based off of the old velocity // dt = delta time @@ -20,10 +26,16 @@ const FRIC_AIR: f32 = 0.015; // damp = linear damping // Friction is a type of damping. fn integrate_forces(dt: f32, mut lv: Vec3, grav: f32, damp: f32) -> Vec3 { + // this is not linear damping, because it is proportional to the original + // velocity this "linear" damping in in fact, quite exponential. and thus + // must be interpolated accordingly + let linear_damp = if damp < 1.0 { + (1.0 - damp).powf(dt * 60.0) + } else { + 0.0 + }; + lv.z = (lv.z - grav * dt).max(-50.0); - - let linear_damp = (1.0 - dt * damp).max(0.0); - lv * linear_damp } @@ -61,7 +73,7 @@ impl<'a> System<'a> for Sys { let mut event_emitter = event_bus.emitter(); // Apply movement inputs - for (entity, scale, b, mut pos, mut vel, mut ori) in ( + for (entity, scale, _b, mut pos, mut vel, _ori) in ( &entities, scales.maybe(), &bodies, @@ -74,16 +86,6 @@ impl<'a> System<'a> for Sys { let mut physics_state = physics_states.get(entity).cloned().unwrap_or_default(); let scale = scale.map(|s| s.0).unwrap_or(1.0); - // Integrate forces - // Friction is assumed to be a constant dependent on location - let friction = 50.0 - * if physics_state.on_ground { - FRIC_GROUND - } else { - FRIC_AIR - }; - vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); - // Basic collision with terrain let player_rad = 0.3 * scale; // half-width of the player's AABB let player_height = 1.5 * scale; @@ -97,6 +99,27 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); + let old_vel = vel.clone(); + // Integrate forces + // Friction is assumed to be a constant dependent on location + let friction = if physics_state.on_ground { + FRIC_GROUND + } else { + FRIC_AIR + }; + vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); + + // Don't move if we're not in a loaded chunk + let pos_delta = if terrain + .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) + .is_some() + { + // this is an approximation that allows + (vel.0 + old_vel.0 * 4.0) * dt.0 * 0.2 + } else { + Vec3::zero() + }; + // Function for determining whether the player at a specific position collides with the ground let collision_with = |pos: Vec3, near_iter| { for (i, j, k) in near_iter { @@ -130,16 +153,6 @@ impl<'a> System<'a> for Sys { let mut on_ground = false; let mut attempts = 0; // Don't loop infinitely here - // Don't move if we're not in a loaded chunk - let pos_delta = if terrain - .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) - .is_some() - { - vel.0 * dt.0 - } else { - Vec3::zero() - }; - // Don't jump too far at once let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3) .ceil() From 8b9a3ae1df3adee5da0243ff5f7d4de1e0ade1d8 Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Thu, 5 Sep 2019 18:24:22 +0800 Subject: [PATCH 2/6] Revert "Exponential interpolation for linear damping" This reverts commit 94b9f50efa502ea872c71dea62db71b19be60069. --- common/src/sys/phys.rs | 65 +++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index d816d21871..42ebc978c5 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -11,14 +11,8 @@ use { }; const GRAVITY: f32 = 9.81 * 4.0; - -// Friction values used for linear damping. They are unitless quantities. The -// value of these quantities must be between zero and one. They represent the -// amount an object will slow down within 1/60th of a second. Eg. if the frction -// is 0.01, and the speed is 1.0, then after 1/60th of a second the speed will -// be 0.99. after 1 second the speed will be 0.54, which is 0.99 ^ 60. -const FRIC_GROUND: f32 = 0.125; -const FRIC_AIR: f32 = 0.0125; +const FRIC_GROUND: f32 = 0.15; +const FRIC_AIR: f32 = 0.015; // Integrates forces, calculates the new velocity based off of the old velocity // dt = delta time @@ -26,16 +20,10 @@ const FRIC_AIR: f32 = 0.0125; // damp = linear damping // Friction is a type of damping. fn integrate_forces(dt: f32, mut lv: Vec3, grav: f32, damp: f32) -> Vec3 { - // this is not linear damping, because it is proportional to the original - // velocity this "linear" damping in in fact, quite exponential. and thus - // must be interpolated accordingly - let linear_damp = if damp < 1.0 { - (1.0 - damp).powf(dt * 60.0) - } else { - 0.0 - }; - lv.z = (lv.z - grav * dt).max(-50.0); + + let linear_damp = (1.0 - dt * damp).max(0.0); + lv * linear_damp } @@ -73,7 +61,7 @@ impl<'a> System<'a> for Sys { let mut event_emitter = event_bus.emitter(); // Apply movement inputs - for (entity, scale, _b, mut pos, mut vel, _ori) in ( + for (entity, scale, b, mut pos, mut vel, mut ori) in ( &entities, scales.maybe(), &bodies, @@ -86,6 +74,16 @@ impl<'a> System<'a> for Sys { let mut physics_state = physics_states.get(entity).cloned().unwrap_or_default(); let scale = scale.map(|s| s.0).unwrap_or(1.0); + // Integrate forces + // Friction is assumed to be a constant dependent on location + let friction = 50.0 + * if physics_state.on_ground { + FRIC_GROUND + } else { + FRIC_AIR + }; + vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); + // Basic collision with terrain let player_rad = 0.3 * scale; // half-width of the player's AABB let player_height = 1.5 * scale; @@ -99,27 +97,6 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); - let old_vel = vel.clone(); - // Integrate forces - // Friction is assumed to be a constant dependent on location - let friction = if physics_state.on_ground { - FRIC_GROUND - } else { - FRIC_AIR - }; - vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); - - // Don't move if we're not in a loaded chunk - let pos_delta = if terrain - .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) - .is_some() - { - // this is an approximation that allows - (vel.0 + old_vel.0 * 4.0) * dt.0 * 0.2 - } else { - Vec3::zero() - }; - // Function for determining whether the player at a specific position collides with the ground let collision_with = |pos: Vec3, near_iter| { for (i, j, k) in near_iter { @@ -153,6 +130,16 @@ impl<'a> System<'a> for Sys { let mut on_ground = false; let mut attempts = 0; // Don't loop infinitely here + // Don't move if we're not in a loaded chunk + let pos_delta = if terrain + .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) + .is_some() + { + vel.0 * dt.0 + } else { + Vec3::zero() + }; + // Don't jump too far at once let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3) .ceil() From d0b2f7565aee7be2e3ed2eeb464a73dc59982302 Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Thu, 5 Sep 2019 18:24:38 +0800 Subject: [PATCH 3/6] Revert "Revert "Exponential interpolation for linear damping"" This reverts commit 8b9a3ae1df3adee5da0243ff5f7d4de1e0ade1d8. --- common/src/sys/phys.rs | 65 +++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 42ebc978c5..d816d21871 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -11,8 +11,14 @@ use { }; const GRAVITY: f32 = 9.81 * 4.0; -const FRIC_GROUND: f32 = 0.15; -const FRIC_AIR: f32 = 0.015; + +// Friction values used for linear damping. They are unitless quantities. The +// value of these quantities must be between zero and one. They represent the +// amount an object will slow down within 1/60th of a second. Eg. if the frction +// is 0.01, and the speed is 1.0, then after 1/60th of a second the speed will +// be 0.99. after 1 second the speed will be 0.54, which is 0.99 ^ 60. +const FRIC_GROUND: f32 = 0.125; +const FRIC_AIR: f32 = 0.0125; // Integrates forces, calculates the new velocity based off of the old velocity // dt = delta time @@ -20,10 +26,16 @@ const FRIC_AIR: f32 = 0.015; // damp = linear damping // Friction is a type of damping. fn integrate_forces(dt: f32, mut lv: Vec3, grav: f32, damp: f32) -> Vec3 { + // this is not linear damping, because it is proportional to the original + // velocity this "linear" damping in in fact, quite exponential. and thus + // must be interpolated accordingly + let linear_damp = if damp < 1.0 { + (1.0 - damp).powf(dt * 60.0) + } else { + 0.0 + }; + lv.z = (lv.z - grav * dt).max(-50.0); - - let linear_damp = (1.0 - dt * damp).max(0.0); - lv * linear_damp } @@ -61,7 +73,7 @@ impl<'a> System<'a> for Sys { let mut event_emitter = event_bus.emitter(); // Apply movement inputs - for (entity, scale, b, mut pos, mut vel, mut ori) in ( + for (entity, scale, _b, mut pos, mut vel, _ori) in ( &entities, scales.maybe(), &bodies, @@ -74,16 +86,6 @@ impl<'a> System<'a> for Sys { let mut physics_state = physics_states.get(entity).cloned().unwrap_or_default(); let scale = scale.map(|s| s.0).unwrap_or(1.0); - // Integrate forces - // Friction is assumed to be a constant dependent on location - let friction = 50.0 - * if physics_state.on_ground { - FRIC_GROUND - } else { - FRIC_AIR - }; - vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); - // Basic collision with terrain let player_rad = 0.3 * scale; // half-width of the player's AABB let player_height = 1.5 * scale; @@ -97,6 +99,27 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); + let old_vel = vel.clone(); + // Integrate forces + // Friction is assumed to be a constant dependent on location + let friction = if physics_state.on_ground { + FRIC_GROUND + } else { + FRIC_AIR + }; + vel.0 = integrate_forces(dt.0, vel.0, GRAVITY, friction); + + // Don't move if we're not in a loaded chunk + let pos_delta = if terrain + .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) + .is_some() + { + // this is an approximation that allows + (vel.0 + old_vel.0 * 4.0) * dt.0 * 0.2 + } else { + Vec3::zero() + }; + // Function for determining whether the player at a specific position collides with the ground let collision_with = |pos: Vec3, near_iter| { for (i, j, k) in near_iter { @@ -130,16 +153,6 @@ impl<'a> System<'a> for Sys { let mut on_ground = false; let mut attempts = 0; // Don't loop infinitely here - // Don't move if we're not in a loaded chunk - let pos_delta = if terrain - .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) - .is_some() - { - vel.0 * dt.0 - } else { - Vec3::zero() - }; - // Don't jump too far at once let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3) .ceil() From b4d5663fedc3cbd05a4d055138fc7cd06b661f44 Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Fri, 6 Sep 2019 12:04:20 +0800 Subject: [PATCH 4/6] Vec3 is copy --- common/src/sys/phys.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 511e94b136..3a2c516a69 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -99,7 +99,7 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); - let old_vel = vel.clone(); + let old_vel = vel; // Integrate forces // Friction is assumed to be a constant dependent on location let friction = if physics_state.on_ground { @@ -114,7 +114,8 @@ impl<'a> System<'a> for Sys { .get_key(terrain.pos_key(pos.0.map(|e| e.floor() as i32))) .is_some() { - // this is an approximation that allows + // this is an approximation that allows most framerates to + // behave in a similar manner. (vel.0 + old_vel.0 * 4.0) * dt.0 * 0.2 } else { Vec3::zero() From b4c74279b7789ac44379bbd26217c977bd0c56de Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Fri, 6 Sep 2019 13:24:42 +0800 Subject: [PATCH 5/6] Vec3 is apprently *not* Copy, Set near plane to 0.1 to prevent tirangle flickering --- common/src/sys/phys.rs | 2 +- voxygen/src/scene/camera.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 3a2c516a69..1eb41d48cc 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -99,7 +99,7 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); - let old_vel = vel; + let old_vel = vel.clone(); // Integrate forces // Friction is assumed to be a constant dependent on location let friction = if physics_state.on_ground { diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs index 4293b33001..57b6e54d42 100644 --- a/voxygen/src/scene/camera.rs +++ b/voxygen/src/scene/camera.rs @@ -4,7 +4,7 @@ use frustum_query::frustum::Frustum; use std::f32::consts::PI; use vek::*; -const NEAR_PLANE: f32 = 0.01; +const NEAR_PLANE: f32 = 0.1; const FAR_PLANE: f32 = 10000.0; const INTERP_TIME: f32 = 0.1; From 05dff792fce0f04935d5a11666c6095e52c0e6e5 Mon Sep 17 00:00:00 2001 From: Andrew Pritchard Date: Fri, 6 Sep 2019 14:22:58 +0800 Subject: [PATCH 6/6] Deref instead of clone vel --- common/src/sys/phys.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 1eb41d48cc..1793abbcf5 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -99,7 +99,7 @@ impl<'a> System<'a> for Sys { .flatten() .flatten(); - let old_vel = vel.clone(); + let old_vel = *vel; // Integrate forces // Friction is assumed to be a constant dependent on location let friction = if physics_state.on_ground {