mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
sync
This commit is contained in:
parent
9113f66d58
commit
c16ca3bfb0
@ -791,9 +791,8 @@ impl<'a> PhysicsData<'a> {
|
|||||||
.terrain
|
.terrain
|
||||||
.contains_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)));
|
.contains_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)));
|
||||||
|
|
||||||
// Don't move if we're not in a loaded chunk
|
let move_dir = if vel.0.x != 0.0 || vel.0.y != 0.0 {
|
||||||
let pos_delta = if in_loaded_chunk {
|
Vec3::new(vel.0.x, vel.0.y, 0.0).normalized()
|
||||||
vel.0 * read.dt.0
|
|
||||||
} else {
|
} else {
|
||||||
Vec3::zero()
|
Vec3::zero()
|
||||||
};
|
};
|
||||||
@ -815,7 +814,19 @@ impl<'a> PhysicsData<'a> {
|
|||||||
// resolves these sort of things well anyway.
|
// resolves these sort of things well anyway.
|
||||||
// At the very least, we don't do things that result in glitchy
|
// At the very least, we don't do things that result in glitchy
|
||||||
// velocities or entirely broken position snapping.
|
// velocities or entirely broken position snapping.
|
||||||
let mut tgt_pos = pos.0 + pos_delta;
|
// Don't move if we're not in a loaded chunk
|
||||||
|
let (tgt_vel, mut tgt_pos) = if in_loaded_chunk {
|
||||||
|
acc_with_frict_tick(move_dir, vel.0, pos.0, read.dt.0 as f64, FricParams::default())
|
||||||
|
} else {
|
||||||
|
(vel.0, pos.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
vel.0 = tgt_vel;
|
||||||
|
|
||||||
|
let pos_delta = tgt_pos - pos.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let was_on_ground = physics_state.on_ground.is_some();
|
let was_on_ground = physics_state.on_ground.is_some();
|
||||||
let block_snap =
|
let block_snap =
|
||||||
@ -1769,20 +1780,6 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
physics_state.skating_active = true;
|
physics_state.skating_active = true;
|
||||||
vel.0 = Vec3::new(new_ground_speed.x, new_ground_speed.y, 0.0);
|
vel.0 = Vec3::new(new_ground_speed.x, new_ground_speed.y, 0.0);
|
||||||
} else {
|
} else {
|
||||||
let ground_fric = physics_state
|
|
||||||
.on_ground
|
|
||||||
.map(|b| b.get_friction())
|
|
||||||
.unwrap_or(0.0);
|
|
||||||
let wall_fric = if physics_state.on_wall.is_some() && climbing {
|
|
||||||
FRIC_GROUND
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let fric = ground_fric.max(wall_fric);
|
|
||||||
if fric > 0.0 {
|
|
||||||
vel.0 *= (1.0 - fric.min(1.0) * fric_mod).powf(dt.0 * 60.0);
|
|
||||||
physics_state.ground_vel = ground_vel;
|
|
||||||
}
|
|
||||||
physics_state.skating_active = false;
|
physics_state.skating_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1813,6 +1810,161 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct FricParams {
|
||||||
|
friction_co: f32,
|
||||||
|
projected_area: f32,
|
||||||
|
density: f32,
|
||||||
|
mass: f32,
|
||||||
|
max_acc: f32,
|
||||||
|
}
|
||||||
|
impl Default for FricParams {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
friction_co: 0.98_f32,
|
||||||
|
projected_area: 0.75_f32,
|
||||||
|
density: 1.225_f32,
|
||||||
|
mass: 1.0_f32,
|
||||||
|
max_acc: 9.2_f32, /* on ground the maximum speed you can get by walking is the speed
|
||||||
|
* of gravity */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FricParams {
|
||||||
|
// https://en.wikipedia.org/wiki/Drag_(physics)
|
||||||
|
// Todo: old impl was (mass * acc.abs() / (friction_co * projected_area * 0.5 *
|
||||||
|
// density * mass )).sqrt();
|
||||||
|
fn v_term(&self, acc: f32) -> f32 {
|
||||||
|
((2.0 * self.mass * acc.abs()) / (self.density * self.projected_area * self.friction_co))
|
||||||
|
.sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trait MathHelp {
|
||||||
|
fn coth(&self) -> Self;
|
||||||
|
fn acoth(&self) -> Self;
|
||||||
|
}
|
||||||
|
impl MathHelp for f32 {
|
||||||
|
// coth(x) = 1/tanh(x)`
|
||||||
|
fn coth(&self) -> Self { 1.0 / self.tanh() }
|
||||||
|
|
||||||
|
// `acoth(x) = atanh(1/x)`
|
||||||
|
fn acoth(&self) -> Self { (1.0 / self).atanh() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ROLLING_FRICTION_FORCE + AIR_FRICTION_FORCE + TILT_FRICT_FORCE + ACCEL_FORCE
|
||||||
|
/// = TOTAL_FORCE
|
||||||
|
///
|
||||||
|
/// TILT_FRICT_FORCE = 0.0
|
||||||
|
/// TOTAL_FORCE = depends on char = const
|
||||||
|
/// ACCEL_FORCE = TOTAL_FORCE - ROLLING_FRICTION_FORCE - AIR_FRICTION_FORCE
|
||||||
|
/// ACCEL = ACCEL_FORCE / MASS
|
||||||
|
///
|
||||||
|
/// ROLLING_FRICTION_FORCE => Indepent of vel
|
||||||
|
/// AIR_FRICTION_FORCE => propotional to vel²
|
||||||
|
///
|
||||||
|
/// https://www.energie-lexikon.info/fahrwiderstand.html
|
||||||
|
/// https://www.energie-lexikon.info/reibung.html
|
||||||
|
/// https://sciencing.com/calculate-force-friction-6454395.html
|
||||||
|
/// https://www.leifiphysik.de/mechanik/reibung-und-fortbewegung
|
||||||
|
fn acc_with_frict_tick(
|
||||||
|
move_dir: Vec3<f32>,
|
||||||
|
vel: Vec3<f32>,
|
||||||
|
pos: Vec3<f32>,
|
||||||
|
dt: f64,
|
||||||
|
params: FricParams,
|
||||||
|
) -> (Vec3<f32>, Vec3<f32>) {
|
||||||
|
let acc = move_dir * params.max_acc; // btw: cant accelerate faster than gravity on foot
|
||||||
|
|
||||||
|
// controller
|
||||||
|
// I know what you think, wtf, yep: https://math.stackexchange.com/questions/1929436/line-integral-of-force-of-air-resistanc
|
||||||
|
// basically an integral of the air resistance formula which scales with v^2
|
||||||
|
// transformed with an ODE.
|
||||||
|
|
||||||
|
// terminal velocity equals the maximum velocity that can be reached by acc
|
||||||
|
// alone
|
||||||
|
let vel_t = acc.map(|xyz| xyz.signum() * params.v_term(xyz));
|
||||||
|
|
||||||
|
// thanks to kilpkonn for figuring this out
|
||||||
|
// https://en.wikipedia.org/wiki/Drag_(physics)
|
||||||
|
//
|
||||||
|
// upper and lower are upper and lower bound for integral
|
||||||
|
let revert_fak = vel / vel_t;
|
||||||
|
|
||||||
|
let (mut pos, mut vel) = (pos, vel);
|
||||||
|
for i in 0..2 {
|
||||||
|
let dt = dt as f32;
|
||||||
|
let (v, p) = {
|
||||||
|
let acc = acc[i];
|
||||||
|
let vel = vel[i];
|
||||||
|
let pos = pos[i];
|
||||||
|
let vel_t = vel_t[i];
|
||||||
|
let revert_fak = revert_fak[i];
|
||||||
|
if acc.abs() < f32::EPSILON {
|
||||||
|
// https://www.wolframalpha.com/input?i=m%2F%28Cx+%2B+m%2FV%29+dx+integrate
|
||||||
|
let c = params.density * params.projected_area * params.friction_co;
|
||||||
|
let lower = params.mass * params.mass.ln() / c;
|
||||||
|
let upper = params.mass * (c * vel * dt + params.mass).ln() / c;
|
||||||
|
let pos = pos + (upper - lower);
|
||||||
|
let vel = params.mass
|
||||||
|
/ (params.density * params.projected_area * params.friction_co * dt
|
||||||
|
+ params.mass / vel);
|
||||||
|
(vel, pos)
|
||||||
|
} else if revert_fak <= 0.0 {
|
||||||
|
// Handle passing through 0 differently as the function changes
|
||||||
|
// https://www.wolframalpha.com/input?i=V*tan%28x*g%2FV+%2B+atan%28v%2FV%29%29+%3D+0+solve+for+x
|
||||||
|
let dt_to_zero = vel_t * (vel / vel_t).atan() / acc.abs();
|
||||||
|
if dt_to_zero < dt {
|
||||||
|
// Step with only part of dt that is left after reaching 0 vel
|
||||||
|
let lower = vel_t.powi(2) * (vel / vel_t).atan().cos().ln() / acc;
|
||||||
|
let upper = -vel_t.powi(2)
|
||||||
|
* (acc * dt_to_zero / vel_t + (vel / vel_t).atan()).cos().ln()
|
||||||
|
/ acc;
|
||||||
|
let pos = pos + (upper - lower);
|
||||||
|
let dt = dt - dt_to_zero;
|
||||||
|
// https://www.wolframalpha.com/input?i=V+*+tanh%28xg%2FV%29+dx+integrate
|
||||||
|
// lower bound is 0
|
||||||
|
let pos = pos + vel_t.powi(2) * (acc * dt / vel_t).cosh().ln() / acc;
|
||||||
|
let vel = vel_t * (dt * acc / vel_t).tanh();
|
||||||
|
(vel, pos)
|
||||||
|
} else {
|
||||||
|
// https://www.wolframalpha.com/input?i=V+*+tan%28xg%2FV+%2B+atan%28v%2FV%29%29+dx+integrate
|
||||||
|
let lower = -vel_t.powi(2) * (vel / vel_t).atan().cos().ln() / acc;
|
||||||
|
let upper =
|
||||||
|
-vel_t.powi(2) * (acc * dt / vel_t + (vel / vel_t).atan()).cos().ln() / acc;
|
||||||
|
let pos = pos + (upper - lower);
|
||||||
|
let vel = vel_t * (dt * acc / vel_t + (vel / vel_t).atan()).tan();
|
||||||
|
(vel, pos)
|
||||||
|
}
|
||||||
|
} else if revert_fak >= 1.0 {
|
||||||
|
// https://www.wolframalpha.com/input?i=V+*+coth%28xg%2FV+%2B+acoth%28v%2FV%29%29+dx+integrate
|
||||||
|
let lower = (vel_t.powi(2) * (vel / vel_t).acoth().cosh().ln()
|
||||||
|
+ (vel / vel_t).acoth().tanh().ln())
|
||||||
|
/ acc;
|
||||||
|
let upper = (vel_t.powi(2)
|
||||||
|
* (acc * dt / vel_t + (vel / vel_t).acoth()).cosh().ln()
|
||||||
|
+ (acc * dt / vel_t + (vel / vel_t).acoth()).tanh().ln())
|
||||||
|
/ acc;
|
||||||
|
let pos = pos + (upper - lower);
|
||||||
|
let vel = vel_t * (dt * acc / vel_t + (vel / vel_t).acoth()).coth();
|
||||||
|
(vel, pos)
|
||||||
|
} else {
|
||||||
|
// https://www.wolframalpha.com/input?i=V+*+tanh%28xg%2FV+%2B+atanh%28v%2FV%29%29+dx+integrate
|
||||||
|
let lower = vel_t.powi(2) * ((vel / vel_t).atanh()).cosh().ln() / acc;
|
||||||
|
let upper =
|
||||||
|
vel_t.powi(2) * (acc * dt / vel_t + (vel / vel_t).atanh()).cosh().ln() / acc;
|
||||||
|
let pos = pos + (upper - lower);
|
||||||
|
let vel = vel_t * (dt * acc / vel_t + (vel / vel_t).atanh()).tanh();
|
||||||
|
(vel, pos)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
vel[i] = v;
|
||||||
|
pos[i] = p;
|
||||||
|
}
|
||||||
|
(vel, pos)
|
||||||
|
}
|
||||||
|
|
||||||
fn voxel_collider_bounding_sphere(
|
fn voxel_collider_bounding_sphere(
|
||||||
voxel_collider: &VoxelCollider,
|
voxel_collider: &VoxelCollider,
|
||||||
pos: &Pos,
|
pos: &Pos,
|
||||||
|
Loading…
Reference in New Issue
Block a user