From bf383d9562ea6a7c5758654701aab0af0718a116 Mon Sep 17 00:00:00 2001 From: Imbris Date: Thu, 18 Mar 2021 05:01:26 -0400 Subject: [PATCH 1/2] Combine 5 things into 1 --- common/sys/src/phys.rs | 101 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/common/sys/src/phys.rs b/common/sys/src/phys.rs index e36d545e4f..1a500d293e 100644 --- a/common/sys/src/phys.rs +++ b/common/sys/src/phys.rs @@ -622,6 +622,7 @@ impl<'a> PhysicsData<'a> { _previous_cache, _, )| { + prof_span!(_guard, "entity"); let mut land_on_ground = None; // Defer the writes of positions and velocities to allow an inner loop over // terrain-like entities @@ -803,6 +804,7 @@ impl<'a> PhysicsData<'a> { } }; // Collide with terrain-like entities + //prof_span!(guard, "terrain entity join"); let aabr = { let center = path_sphere.center.xy().map(|e| e as i32); let radius = path_sphere.radius.ceil() as i32; @@ -960,6 +962,7 @@ impl<'a> PhysicsData<'a> { } }, ); + //drop(guard); if tgt_pos != pos.0 { pos_vel_defer.pos = Some(Pos(tgt_pos)); @@ -1069,6 +1072,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( climbing: bool, mut land_on_ground: impl FnMut(Entity, Vel), ) { + //prof_span!(_guard, "box_voxel_collision"); let (radius, z_min, z_max) = cylinder; // Probe distances @@ -1129,6 +1133,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( radius: f32, z_range: Range, ) -> bool { + //prof_span!(_guard, "collision_with"); collision_iter( pos, terrain, @@ -1138,8 +1143,8 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( radius, z_range, ) - .count() - > 0 + .next() + .is_some() } physics_state.on_ground = false; @@ -1179,6 +1184,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( // Determine the block that we are colliding with most (based on minimum // collision axis) + //prof_span!(guard, "find colliding block"); let (_block_pos, block_aabb, block_height) = near_iter .clone() // Calculate the block's position in world space @@ -1213,6 +1219,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( * 1_000_000.0) as i32 }) .expect("Collision detected, but no colliding blocks found!"); + //drop(guard); // Find the intrusion vector of the collision let dir = player_aabb.collision_vector_with_aabb(block_aabb); @@ -1330,7 +1337,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( -Vec3::unit_y(), ]; - if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { + /*if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { if collision_with( pos.0 + *dir * 0.01, &terrain, @@ -1355,6 +1362,7 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( } // Figure out if we're in water + //prof_span!(guard, "water"); physics_state.in_liquid = collision_iter( pos.0, &*terrain, @@ -1363,10 +1371,95 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( &|_block| 1.0, near_iter, radius, - z_min..z_max, + z_range, ) .max_by_key(|block_aabb| (block_aabb.max.z * 100.0) as i32) .map(|block_aabb| block_aabb.max.z - pos.0.z); + //drop(guard); + */ + prof_span!(guard, "compound check"); + let player_aabb = Aabb { + min: pos.0 + Vec3::new(-radius, -radius, z_range.start), + max: pos.0 + Vec3::new(radius, radius, z_range.end), + }; + let player_voxel_pos = pos.0.map(|e| e.floor() as i32); + // TODO: use array nightly features + let wall_check_positions = [ + (pos.0 + dirs[0] * 0.01), + (pos.0 + dirs[1] * 0.01), + (pos.0 + dirs[2] * 0.01), + (pos.0 + dirs[3] * 0.01), + ]; + let p_aabb = |pos| { + let player_aabb = Aabb { + min: pos + Vec3::new(-radius, -radius, z_range.start), + max: pos + Vec3::new(radius, radius, z_range.end), + }; + player_aabb + }; + let player_wall_aabbs = [ + p_aabb(wall_check_positions[0]), + p_aabb(wall_check_positions[1]), + p_aabb(wall_check_positions[2]), + p_aabb(wall_check_positions[3]), + ]; + + // Find liquid immersion and wall collision all in one round of iteration + let mut max_liquid_z = None::; + let mut wall_dir_collisions = [false; 4]; + near_iter.for_each(|(i, j, k)| { + let block_pos = player_voxel_pos + Vec3::new(i, j, k); + + if let Some(block) = terrain.get(block_pos).ok().copied() { + // Check for liquid blocks + if block.is_liquid() { + let liquid_aabb = Aabb { + min: block_pos.map(|e| e as f32), + // The liquid part of a liquid block always extends 1 block high. + max: block_pos.map(|e| e as f32) + Vec3::one(), + }; + if player_aabb.collides_with_aabb(liquid_aabb) { + max_liquid_z = Some(match max_liquid_z { + Some(z) => z.max(liquid_aabb.max.z), + None => liquid_aabb.max.z, + }); + } + } + // Check for walls + if block.is_solid() { + let block_aabb = Aabb { + min: block_pos.map(|e| e as f32), + max: block_pos.map(|e| e as f32) + Vec3::new(1.0, 1.0, block.solid_height()), + }; + + for dir in 0..4 { + if player_wall_aabbs[dir].collides_with_aabb(block_aabb) { + wall_dir_collisions[dir] = true; + } + } + } + } + }); + + // Use wall collision results to determine if we are against a wall + let mut on_wall = None; + for dir in 0..4 { + if wall_dir_collisions[dir] { + on_wall = Some(match on_wall { + Some(acc) => acc + dirs[dir], + None => dirs[dir], + }); + } + } + physics_state.on_wall = on_wall; + if physics_state.on_ground || (physics_state.on_wall.is_some() && climbing) { + vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0); + physics_state.ground_vel = ground_vel; + } + + // Set in_liquid state + physics_state.in_liquid = max_liquid_z.map(|max_z| max_z - pos.0.z); + //drop(guard); } fn voxel_collider_bounding_sphere( From e6e56f19f9d22e6359bae2ee1fd49fbaf0b4d4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=A4rtens?= Date: Thu, 18 Mar 2021 14:01:03 +0100 Subject: [PATCH 2/2] cleanup faster physics calc --- common/sys/src/lib.rs | 2 +- common/sys/src/phys.rs | 72 +++--------------------------------------- 2 files changed, 6 insertions(+), 68 deletions(-) diff --git a/common/sys/src/lib.rs b/common/sys/src/lib.rs index c38136dc52..f8348b3b43 100644 --- a/common/sys/src/lib.rs +++ b/common/sys/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(label_break_value, bool_to_option, option_unwrap_none)] +#![feature(label_break_value, bool_to_option, option_unwrap_none, array_map)] #![allow(clippy::option_map_unit_fn)] mod aura; diff --git a/common/sys/src/phys.rs b/common/sys/src/phys.rs index 1a500d293e..621e0a5532 100644 --- a/common/sys/src/phys.rs +++ b/common/sys/src/phys.rs @@ -622,7 +622,6 @@ impl<'a> PhysicsData<'a> { _previous_cache, _, )| { - prof_span!(_guard, "entity"); let mut land_on_ground = None; // Defer the writes of positions and velocities to allow an inner loop over // terrain-like entities @@ -804,7 +803,6 @@ impl<'a> PhysicsData<'a> { } }; // Collide with terrain-like entities - //prof_span!(guard, "terrain entity join"); let aabr = { let center = path_sphere.center.xy().map(|e| e as i32); let radius = path_sphere.radius.ceil() as i32; @@ -962,7 +960,6 @@ impl<'a> PhysicsData<'a> { } }, ); - //drop(guard); if tgt_pos != pos.0 { pos_vel_defer.pos = Some(Pos(tgt_pos)); @@ -1072,7 +1069,6 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( climbing: bool, mut land_on_ground: impl FnMut(Entity, Vel), ) { - //prof_span!(_guard, "box_voxel_collision"); let (radius, z_min, z_max) = cylinder; // Probe distances @@ -1133,7 +1129,6 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( radius: f32, z_range: Range, ) -> bool { - //prof_span!(_guard, "collision_with"); collision_iter( pos, terrain, @@ -1184,7 +1179,6 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( // Determine the block that we are colliding with most (based on minimum // collision axis) - //prof_span!(guard, "find colliding block"); let (_block_pos, block_aabb, block_height) = near_iter .clone() // Calculate the block's position in world space @@ -1219,7 +1213,6 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( * 1_000_000.0) as i32 }) .expect("Collision detected, but no colliding blocks found!"); - //drop(guard); // Find the intrusion vector of the collision let dir = player_aabb.collision_vector_with_aabb(block_aabb); @@ -1337,72 +1330,18 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( -Vec3::unit_y(), ]; - /*if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| { - if collision_with( - pos.0 + *dir * 0.01, - &terrain, - block_true, - near_iter.clone(), - radius, - z_range.clone(), - ) { - (a + dir, true) - } else { - (a, hit) - } - }) { - physics_state.on_wall = Some(wall_dir); - } else { - physics_state.on_wall = None; - } - - if physics_state.on_ground || (physics_state.on_wall.is_some() && climbing) { - vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0); - physics_state.ground_vel = ground_vel; - } - - // Figure out if we're in water - //prof_span!(guard, "water"); - physics_state.in_liquid = collision_iter( - pos.0, - &*terrain, - &|block| block.is_liquid(), - // The liquid part of a liquid block always extends 1 block high. - &|_block| 1.0, - near_iter, - radius, - z_range, - ) - .max_by_key(|block_aabb| (block_aabb.max.z * 100.0) as i32) - .map(|block_aabb| block_aabb.max.z - pos.0.z); - //drop(guard); - */ - prof_span!(guard, "compound check"); let player_aabb = Aabb { min: pos.0 + Vec3::new(-radius, -radius, z_range.start), max: pos.0 + Vec3::new(radius, radius, z_range.end), }; let player_voxel_pos = pos.0.map(|e| e.floor() as i32); - // TODO: use array nightly features - let wall_check_positions = [ - (pos.0 + dirs[0] * 0.01), - (pos.0 + dirs[1] * 0.01), - (pos.0 + dirs[2] * 0.01), - (pos.0 + dirs[3] * 0.01), - ]; - let p_aabb = |pos| { - let player_aabb = Aabb { + let player_wall_aabbs = dirs.map(|dir| { + let pos = pos.0 + dir * 0.01; + Aabb { min: pos + Vec3::new(-radius, -radius, z_range.start), max: pos + Vec3::new(radius, radius, z_range.end), - }; - player_aabb - }; - let player_wall_aabbs = [ - p_aabb(wall_check_positions[0]), - p_aabb(wall_check_positions[1]), - p_aabb(wall_check_positions[2]), - p_aabb(wall_check_positions[3]), - ]; + } + }); // Find liquid immersion and wall collision all in one round of iteration let mut max_liquid_z = None::; @@ -1459,7 +1398,6 @@ fn box_voxel_collision<'a, T: BaseVol + ReadVol>( // Set in_liquid state physics_state.in_liquid = max_liquid_z.map(|max_z| max_z - pos.0.z); - //drop(guard); } fn voxel_collider_bounding_sphere(