mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cleaned up and documented voxel collider code
This commit is contained in:
parent
04687aa0b2
commit
a09dbf0396
@ -163,7 +163,7 @@
|
|||||||
),
|
),
|
||||||
Submarine: (
|
Submarine: (
|
||||||
bone0: (
|
bone0: (
|
||||||
offset: (-5.5, -18.0, -4.5),
|
offset: (-5.5, -18.0, -1.0),
|
||||||
central: ("submarine.structure"),
|
central: ("submarine.structure"),
|
||||||
),
|
),
|
||||||
bone1: (
|
bone1: (
|
||||||
|
@ -75,7 +75,7 @@ impl Body {
|
|||||||
Body::SailBoat => Vec3::new(12.0, 32.0, 6.0),
|
Body::SailBoat => Vec3::new(12.0, 32.0, 6.0),
|
||||||
Body::Galleon => Vec3::new(14.0, 48.0, 10.0),
|
Body::Galleon => Vec3::new(14.0, 48.0, 10.0),
|
||||||
Body::Skiff => Vec3::new(7.0, 15.0, 10.0),
|
Body::Skiff => Vec3::new(7.0, 15.0, 10.0),
|
||||||
Body::Submarine => Vec3::new(2.0, 15.0, 2.0),
|
Body::Submarine => Vec3::new(2.0, 15.0, 8.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ impl Body {
|
|||||||
Body::DefaultAirship | Body::AirBalloon | Body::Volume => Density(AIR_DENSITY),
|
Body::DefaultAirship | Body::AirBalloon | Body::Volume => Density(AIR_DENSITY),
|
||||||
Body::Submarine => Density(WATER_DENSITY), // Neutrally buoyant
|
Body::Submarine => Density(WATER_DENSITY), // Neutrally buoyant
|
||||||
_ => Density(AIR_DENSITY * 0.95 + WATER_DENSITY * 0.05), /* Most boats should be very
|
_ => Density(AIR_DENSITY * 0.95 + WATER_DENSITY * 0.05), /* Most boats should be very
|
||||||
* buoyant */
|
* buoyant */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ impl Body {
|
|||||||
match self {
|
match self {
|
||||||
Body::Object(_) => return None,
|
Body::Object(_) => return None,
|
||||||
Body::ItemDrop(_) => return None,
|
Body::ItemDrop(_) => return None,
|
||||||
Body::Ship(ship::Body::Submarine) => 2000.0 * self.mass().0,
|
Body::Ship(ship::Body::Submarine) => 1000.0 * self.mass().0,
|
||||||
Body::Ship(ship) if ship.has_water_thrust() => 500.0 * self.mass().0,
|
Body::Ship(ship) if ship.has_water_thrust() => 500.0 * self.mass().0,
|
||||||
Body::Ship(_) => return None,
|
Body::Ship(_) => return None,
|
||||||
Body::BipedLarge(_) => 120.0 * self.mass().0,
|
Body::BipedLarge(_) => 120.0 * self.mass().0,
|
||||||
|
@ -1119,96 +1119,125 @@ impl<'a> PhysicsData<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut physics_state_delta = physics_state.clone();
|
let mut physics_state_delta = physics_state.clone();
|
||||||
// deliberately don't use scale yet here, because the
|
|
||||||
// 11.0/0.8 thing is
|
|
||||||
// in the comp::Scale for visual reasons
|
|
||||||
let mut cpos = *pos;
|
|
||||||
let wpos = cpos.0;
|
|
||||||
|
|
||||||
// TODO: Cache the matrices here to avoid recomputing
|
// Helper function for computing a transformation matrix and its
|
||||||
|
// inverse. Should
|
||||||
|
// be much cheaper than using `Mat4::inverted`.
|
||||||
|
let from_to_matricies =
|
||||||
|
|entity_rpos: Vec3<f32>, collider_ori: Quaternion<f32>| {
|
||||||
|
(
|
||||||
|
Mat4::<f32>::translation_3d(entity_rpos)
|
||||||
|
* Mat4::from(collider_ori)
|
||||||
|
* Mat4::scaling_3d(previous_cache_other.scale)
|
||||||
|
* Mat4::translation_3d(
|
||||||
|
voxel_collider.translation,
|
||||||
|
),
|
||||||
|
Mat4::<f32>::translation_3d(
|
||||||
|
-voxel_collider.translation,
|
||||||
|
) * Mat4::scaling_3d(
|
||||||
|
1.0 / previous_cache_other.scale,
|
||||||
|
) * Mat4::from(collider_ori.inverse())
|
||||||
|
* Mat4::translation_3d(-entity_rpos),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let transform_last_from =
|
// Compute matrices that allow us to transform to and from the
|
||||||
Mat4::<f32>::translation_3d(
|
// coordinate space of
|
||||||
|
// the collider. We have two variants of each, one for the
|
||||||
|
// current state and one for
|
||||||
|
// the previous state. This allows us to 'perfectly' track
|
||||||
|
// change in position
|
||||||
|
// between ticks, which prevents entities falling through voxel
|
||||||
|
// colliders due to spurious
|
||||||
|
// issues like differences in ping/variable dt.
|
||||||
|
// TODO: Cache the matrices here to avoid recomputing for each
|
||||||
|
// entity on them
|
||||||
|
let (_transform_last_from, transform_last_to) =
|
||||||
|
from_to_matricies(
|
||||||
previous_cache_other.pos.unwrap_or(*pos_other).0
|
previous_cache_other.pos.unwrap_or(*pos_other).0
|
||||||
- previous_cache.pos.unwrap_or(Pos(wpos)).0,
|
- previous_cache.pos.unwrap_or(*pos).0,
|
||||||
) * Mat4::from(previous_cache_other.ori)
|
previous_cache_other.ori,
|
||||||
* Mat4::<f32>::scaling_3d(previous_cache_other.scale)
|
);
|
||||||
* Mat4::<f32>::translation_3d(
|
let (transform_from, transform_to) =
|
||||||
voxel_collider.translation,
|
from_to_matricies(pos_other.0 - pos.0, ori_other.to_quat());
|
||||||
);
|
|
||||||
let transform_last_to = transform_last_from.inverted();
|
|
||||||
|
|
||||||
let transform_from =
|
// Compute the velocity of the collider, accounting for changes
|
||||||
Mat4::<f32>::translation_3d(pos_other.0 - wpos)
|
// in orientation
|
||||||
* Mat4::from(ori_other.to_quat())
|
// from the last tick. We then model this change as a change in
|
||||||
* Mat4::<f32>::scaling_3d(previous_cache_other.scale)
|
// surface velocity
|
||||||
* Mat4::<f32>::translation_3d(
|
// for the collider.
|
||||||
voxel_collider.translation,
|
let vel_other = {
|
||||||
);
|
let pos_rel =
|
||||||
let transform_to = transform_from.inverted();
|
(Mat4::<f32>::translation_3d(
|
||||||
|
-voxel_collider.translation,
|
||||||
|
) * Mat4::from(ori_other.to_quat().inverse()))
|
||||||
|
.mul_point(pos.0 - pos_other.0);
|
||||||
|
let rpos_last =
|
||||||
|
(Mat4::<f32>::from(previous_cache_other.ori)
|
||||||
|
* Mat4::translation_3d(voxel_collider.translation))
|
||||||
|
.mul_point(pos_rel);
|
||||||
|
vel_other.0
|
||||||
|
+ (pos.0 - (pos_other.0 + rpos_last)) / read.dt.0
|
||||||
|
};
|
||||||
|
|
||||||
let ori_last_from = Mat4::from(previous_cache_other.ori);
|
{
|
||||||
let ori_last_to = ori_last_from.inverted();
|
// Transform the entity attributes into the coordinate space
|
||||||
|
// of the collider ready
|
||||||
|
// for collision resolution
|
||||||
|
let mut rpos =
|
||||||
|
Pos(transform_last_to.mul_point(Vec3::zero()));
|
||||||
|
vel.0 = previous_cache_other.ori.inverse()
|
||||||
|
* (vel.0 - vel_other);
|
||||||
|
|
||||||
let ori_from = Mat4::from(ori_other.to_quat());
|
// Perform collision resolution
|
||||||
let ori_to = ori_from.inverted();
|
box_voxel_collision(
|
||||||
|
(radius, z_min, z_max),
|
||||||
|
&voxel_collider.volume(),
|
||||||
|
entity,
|
||||||
|
&mut rpos,
|
||||||
|
transform_to.mul_point(tgt_pos - pos.0),
|
||||||
|
&mut vel,
|
||||||
|
&mut physics_state_delta,
|
||||||
|
previous_cache_other.ori.inverse() * vel_other,
|
||||||
|
&read.dt,
|
||||||
|
was_on_ground,
|
||||||
|
block_snap,
|
||||||
|
climbing,
|
||||||
|
|entity, vel| {
|
||||||
|
land_on_ground = Some((
|
||||||
|
entity,
|
||||||
|
Vel(ori_other.to_quat() * vel.0),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
read,
|
||||||
|
&ori,
|
||||||
|
);
|
||||||
|
|
||||||
// The velocity of the collider, taking into account
|
// Transform entity attributes back into world space now
|
||||||
// orientation.
|
// that we've performed
|
||||||
let pos_rel = (Mat4::<f32>::translation_3d(Vec3::zero())
|
// collision resolution with them
|
||||||
* Mat4::from(ori_other.to_quat())
|
tgt_pos = transform_from.mul_point(rpos.0) + pos.0;
|
||||||
* Mat4::<f32>::translation_3d(voxel_collider.translation))
|
vel.0 = previous_cache_other.ori * vel.0 + vel_other;
|
||||||
.inverted()
|
}
|
||||||
.mul_point(wpos - pos_other.0);
|
|
||||||
let rpos_last = (Mat4::<f32>::translation_3d(Vec3::zero())
|
|
||||||
* Mat4::from(previous_cache_other.ori)
|
|
||||||
* Mat4::<f32>::translation_3d(voxel_collider.translation))
|
|
||||||
.mul_point(pos_rel);
|
|
||||||
let vel_other = vel_other.0
|
|
||||||
+ (wpos - (pos_other.0 + rpos_last)) / read.dt.0;
|
|
||||||
|
|
||||||
// Velocity added due to change in orientation, relative to the
|
// Collision resolution may also change the physics state. Since
|
||||||
// craft
|
// we may be interacting
|
||||||
let ori_vel = previous_cache_other.ori.inverse()
|
// with multiple colliders at once (along with the regular
|
||||||
* (pos.0 - pos_other.0)
|
// terrain!) we keep track
|
||||||
- ori_other.to_quat().inverse() * (pos.0 - pos_other.0);
|
// of a physics state 'delta' and try to sensibly resolve them
|
||||||
|
// against one-another at each step.
|
||||||
cpos.0 = transform_last_to.mul_point(Vec3::zero());
|
|
||||||
vel.0 = ori_last_to.mul_direction(vel.0 - vel_other) - ori_vel;
|
|
||||||
let cylinder = (radius, z_min, z_max);
|
|
||||||
box_voxel_collision(
|
|
||||||
cylinder,
|
|
||||||
&voxel_collider.volume(),
|
|
||||||
entity,
|
|
||||||
&mut cpos,
|
|
||||||
transform_to.mul_point(tgt_pos - wpos),
|
|
||||||
&mut vel,
|
|
||||||
&mut physics_state_delta,
|
|
||||||
ori_last_to.mul_direction(vel_other),
|
|
||||||
&read.dt,
|
|
||||||
was_on_ground,
|
|
||||||
block_snap,
|
|
||||||
climbing,
|
|
||||||
|entity, vel| {
|
|
||||||
land_on_ground =
|
|
||||||
Some((entity, Vel(ori_from.mul_direction(vel.0))));
|
|
||||||
},
|
|
||||||
read,
|
|
||||||
&ori,
|
|
||||||
);
|
|
||||||
|
|
||||||
cpos.0 = transform_from.mul_point(cpos.0) + wpos;
|
|
||||||
vel.0 = ori_from.mul_direction(vel.0 + ori_vel) + vel_other;
|
|
||||||
tgt_pos = cpos.0;
|
|
||||||
|
|
||||||
// union in the state updates, so that the state isn't just
|
|
||||||
// based on the most
|
|
||||||
// recent terrain that collision was attempted with
|
|
||||||
if physics_state_delta.on_ground.is_some() {
|
if physics_state_delta.on_ground.is_some() {
|
||||||
physics_state.ground_vel =
|
// TODO: Do we need to do this? Perhaps just take the
|
||||||
vel_other + ori_from.mul_direction(ori_vel);
|
// ground_vel regardless?
|
||||||
|
physics_state.ground_vel = vel_other;
|
||||||
// Rotate if on ground
|
}
|
||||||
|
if physics_state_delta.on_surface().is_some() {
|
||||||
|
// If the collision resulted in us being on a surface,
|
||||||
|
// rotate us with the
|
||||||
|
// collider. Really this should be modelled via friction or
|
||||||
|
// something, but
|
||||||
|
// our physics model doesn't really take orientation into
|
||||||
|
// consideration.
|
||||||
ori = ori.rotated(
|
ori = ori.rotated(
|
||||||
ori_other.to_quat()
|
ori_other.to_quat()
|
||||||
* previous_cache_other.ori.inverse(),
|
* previous_cache_other.ori.inverse(),
|
||||||
@ -1220,7 +1249,7 @@ impl<'a> PhysicsData<'a> {
|
|||||||
physics_state.on_wall = physics_state.on_wall.or_else(|| {
|
physics_state.on_wall = physics_state.on_wall.or_else(|| {
|
||||||
physics_state_delta
|
physics_state_delta
|
||||||
.on_wall
|
.on_wall
|
||||||
.map(|dir| ori_from.mul_direction(dir))
|
.map(|dir| previous_cache_other.ori * dir)
|
||||||
});
|
});
|
||||||
physics_state.in_fluid = match (
|
physics_state.in_fluid = match (
|
||||||
physics_state.in_fluid,
|
physics_state.in_fluid,
|
||||||
|
@ -114,6 +114,7 @@ pub enum TrailSource {
|
|||||||
Weapon,
|
Weapon,
|
||||||
GliderLeft,
|
GliderLeft,
|
||||||
GliderRight,
|
GliderRight,
|
||||||
|
Propeller(f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TrailSource {
|
impl TrailSource {
|
||||||
@ -147,6 +148,10 @@ impl TrailSource {
|
|||||||
Vec4::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
|
Vec4::new(-GLIDER_HORIZ, 0.0, GLIDER_VERT, 1.0),
|
||||||
Vec4::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT, 1.0),
|
Vec4::new(-(GLIDER_HORIZ + GLIDER_WIDTH), 0.0, GLIDER_VERT, 1.0),
|
||||||
),
|
),
|
||||||
|
Self::Propeller(length) => (
|
||||||
|
Vec4::new(0.0, 0.0, *length * 0.5, 1.0),
|
||||||
|
Vec4::new(0.0, 0.0, *length, 1.0),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ pub mod idle;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::idle::IdleAnimation;
|
pub use self::idle::IdleAnimation;
|
||||||
|
|
||||||
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton};
|
use super::{make_bone, vek::*, FigureBoneData, Offsets, Skeleton, TrailSource};
|
||||||
use common::comp::{self};
|
use common::comp::{self};
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
@ -34,12 +34,16 @@ impl Skeleton for ShipSkeleton {
|
|||||||
// Ships are normal scale
|
// Ships are normal scale
|
||||||
let scale_mat = Mat4::scaling_3d(1.0);
|
let scale_mat = Mat4::scaling_3d(1.0);
|
||||||
|
|
||||||
|
let attr = SkeletonAttr::from(&body);
|
||||||
|
|
||||||
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
|
let bone0_mat = base_mat * scale_mat * Mat4::<f32>::from(self.bone0);
|
||||||
|
let bone1_mat = bone0_mat * Mat4::<f32>::from(self.bone1);
|
||||||
|
let bone2_mat = bone0_mat * Mat4::<f32>::from(self.bone2);
|
||||||
|
|
||||||
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
|
*(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
|
||||||
make_bone(bone0_mat),
|
make_bone(bone0_mat),
|
||||||
make_bone(bone0_mat * Mat4::<f32>::from(self.bone1)),
|
make_bone(bone1_mat),
|
||||||
make_bone(bone0_mat * Mat4::<f32>::from(self.bone2)),
|
make_bone(bone2_mat),
|
||||||
make_bone(bone0_mat * Mat4::<f32>::from(self.bone3)),
|
make_bone(bone0_mat * Mat4::<f32>::from(self.bone3)),
|
||||||
];
|
];
|
||||||
Offsets {
|
Offsets {
|
||||||
@ -51,8 +55,12 @@ impl Skeleton for ShipSkeleton {
|
|||||||
.mul_point(comp::Body::Ship(body).mount_offset().into_tuple().into()),
|
.mul_point(comp::Body::Ship(body).mount_offset().into_tuple().into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
primary_trail_mat: None,
|
primary_trail_mat: attr
|
||||||
secondary_trail_mat: None,
|
.bone1_prop_trail_offset
|
||||||
|
.map(|offset| (bone1_mat, TrailSource::Propeller(offset))),
|
||||||
|
secondary_trail_mat: attr
|
||||||
|
.bone2_prop_trail_offset
|
||||||
|
.map(|offset| (bone2_mat, TrailSource::Propeller(offset))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,6 +70,8 @@ pub struct SkeletonAttr {
|
|||||||
bone1: (f32, f32, f32),
|
bone1: (f32, f32, f32),
|
||||||
bone2: (f32, f32, f32),
|
bone2: (f32, f32, f32),
|
||||||
bone3: (f32, f32, f32),
|
bone3: (f32, f32, f32),
|
||||||
|
bone1_prop_trail_offset: Option<f32>,
|
||||||
|
bone2_prop_trail_offset: Option<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
|
impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
|
||||||
@ -82,6 +92,8 @@ impl Default for SkeletonAttr {
|
|||||||
bone1: (0.0, 0.0, 0.0),
|
bone1: (0.0, 0.0, 0.0),
|
||||||
bone2: (0.0, 0.0, 0.0),
|
bone2: (0.0, 0.0, 0.0),
|
||||||
bone3: (0.0, 0.0, 0.0),
|
bone3: (0.0, 0.0, 0.0),
|
||||||
|
bone1_prop_trail_offset: None,
|
||||||
|
bone2_prop_trail_offset: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +117,7 @@ impl<'a> From<&'a Body> for SkeletonAttr {
|
|||||||
SailBoat => (0.0, 0.0, 0.0),
|
SailBoat => (0.0, 0.0, 0.0),
|
||||||
Galleon => (0.0, 0.0, 0.0),
|
Galleon => (0.0, 0.0, 0.0),
|
||||||
Skiff => (0.0, 0.0, 0.0),
|
Skiff => (0.0, 0.0, 0.0),
|
||||||
Submarine => (0.0, -15.0, 0.0),
|
Submarine => (0.0, -15.0, 3.5),
|
||||||
Volume => (0.0, 0.0, 0.0),
|
Volume => (0.0, 0.0, 0.0),
|
||||||
},
|
},
|
||||||
bone2: match body {
|
bone2: match body {
|
||||||
@ -123,9 +135,18 @@ impl<'a> From<&'a Body> for SkeletonAttr {
|
|||||||
SailBoat => (0.0, 0.0, 0.0),
|
SailBoat => (0.0, 0.0, 0.0),
|
||||||
Galleon => (0.0, 0.0, 0.0),
|
Galleon => (0.0, 0.0, 0.0),
|
||||||
Skiff => (0.0, 0.0, 0.0),
|
Skiff => (0.0, 0.0, 0.0),
|
||||||
Submarine => (0.0, -18.0, 0.0),
|
Submarine => (0.0, -18.0, 3.5),
|
||||||
Volume => (0.0, 0.0, 0.0),
|
Volume => (0.0, 0.0, 0.0),
|
||||||
},
|
},
|
||||||
|
bone1_prop_trail_offset: match body {
|
||||||
|
DefaultAirship => Some(8.5),
|
||||||
|
Submarine => Some(3.5),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
bone2_prop_trail_offset: match body {
|
||||||
|
DefaultAirship => Some(8.5),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user