Rework mounting animation so that full hierarchies of animation transforms can be applied to the mounter, factor out some common code in figure/mod.rs

This commit is contained in:
Imbris 2021-06-26 02:11:50 -04:00
parent fafb344404
commit b2bf83e200
6 changed files with 205 additions and 347 deletions

View File

@ -764,8 +764,8 @@ impl Body {
) )
} }
// Physical offset relative to the mountee /// Component of the mounting offset specific to the mountee
pub fn mounting_offset(&self) -> Vec3<f32> { pub fn mountee_offset(&self) -> Vec3<f32> {
match self { match self {
Body::QuadrupedMedium(quadruped_medium) => { Body::QuadrupedMedium(quadruped_medium) => {
match (quadruped_medium.species, quadruped_medium.body_type) { match (quadruped_medium.species, quadruped_medium.body_type) {
@ -819,6 +819,15 @@ impl Body {
} }
.into() .into()
} }
/// Component of the mounting offset specific to the mounter
pub fn mounter_offset(&self) -> Vec3<f32> {
match self {
Body::Humanoid(_) => [0.0, 0.0, 0.0],
_ => [0.0, 0.0, 0.0],
}
.into()
}
} }
impl Component for Body { impl Component for Body {

View File

@ -66,8 +66,9 @@ impl<'a> System<'a> for Sys {
let ori = orientations.get(entity).copied(); let ori = orientations.get(entity).copied();
let vel = velocities.get(entity).copied(); let vel = velocities.get(entity).copied();
if let (Some(pos), Some(ori), Some(vel)) = (pos, ori, vel) { if let (Some(pos), Some(ori), Some(vel)) = (pos, ori, vel) {
let mounting_offset = let mounter_body = bodies.get(mounter);
body.map_or(Vec3::unit_z(), Body::mounting_offset); let mounting_offset = body.map_or(Vec3::unit_z(), Body::mountee_offset)
+ mounter_body.map_or(Vec3::zero(), Body::mounter_offset);
let _ = positions.insert( let _ = positions.insert(
mounter, mounter,
Pos(Vec3 { Pos(Vec3 {

View File

@ -73,20 +73,12 @@ skeleton_impls!(struct CharacterSkeleton {
control_r, control_r,
:: // Begin non-bone fields :: // Begin non-bone fields
holding_lantern: bool, holding_lantern: bool,
offsets: Option<Transform<f32, f32, f32>>,
mountee_body: Option<comp::Body>,
}); });
impl CharacterSkeleton { impl CharacterSkeleton {
pub fn new( pub fn new(holding_lantern: bool) -> Self {
holding_lantern: bool,
offsets: Option<Transform<f32, f32, f32>>,
mountee_body: Option<comp::Body>,
) -> Self {
Self { Self {
holding_lantern, holding_lantern,
offsets,
mountee_body,
..Self::default() ..Self::default()
} }
} }
@ -107,21 +99,7 @@ impl Skeleton for CharacterSkeleton {
base_mat: Mat4<f32>, base_mat: Mat4<f32>,
buf: &mut [FigureBoneData; super::MAX_BONE_COUNT], buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
) -> Offsets { ) -> Offsets {
let torso_mat = base_mat let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
* if let Some((offset, body)) = self.offsets.zip(self.mountee_body) {
let hitbox_offsets = body.mounting_offset();
let visual_offset = mounting_offset(body);
Mat4::<f32>::from(Transform {
position: offset.position
- Vec3::from([0.0, hitbox_offsets.y, hitbox_offsets.z]),
orientation: offset.orientation,
scale: Vec3::<f32>::one(),
}) * Mat4::<f32>::from(self.torso).translated_3d(visual_offset)
} else {
Mat4::<f32>::from(self.torso)
};
let chest_mat = torso_mat * Mat4::<f32>::from(self.chest); let chest_mat = torso_mat * Mat4::<f32>::from(self.chest);
let head_mat = chest_mat * Mat4::<f32>::from(self.head); let head_mat = chest_mat * Mat4::<f32>::from(self.head);
let shorts_mat = chest_mat * Mat4::<f32>::from(self.shorts); let shorts_mat = chest_mat * Mat4::<f32>::from(self.shorts);
@ -356,53 +334,3 @@ impl<'a> From<&'a Body> for SkeletonAttr {
} }
} }
} }
pub fn mounting_offset(body: comp::Body) -> Vec3<f32> {
match body {
comp::Body::QuadrupedMedium(quadruped_medium) => {
match (quadruped_medium.species, quadruped_medium.body_type) {
(comp::quadruped_medium::Species::Grolgar, _) => Vec3::from([0.0, -0.6, 0.5]),
(comp::quadruped_medium::Species::Saber, _) => Vec3::from([0.0, -0.75, 0.23]),
(comp::quadruped_medium::Species::Tiger, _) => Vec3::from([0.0, -0.75, 0.23]),
(comp::quadruped_medium::Species::Tuskram, _) => Vec3::from([0.0, -0.75, 0.25]),
(comp::quadruped_medium::Species::Lion, _) => Vec3::from([0.0, -0.9, 0.25]),
(comp::quadruped_medium::Species::Tarasque, _) => Vec3::from([0.0, -1.1, 0.3]),
(comp::quadruped_medium::Species::Wolf, _) => Vec3::from([0.0, -0.7, 0.15]),
(comp::quadruped_medium::Species::Frostfang, _) => Vec3::from([0.0, -0.8, 0.1]),
(comp::quadruped_medium::Species::Mouflon, _) => Vec3::from([0.0, -0.8, 0.1]),
(comp::quadruped_medium::Species::Catoblepas, _) => Vec3::from([0.0, -0.4, 0.4]),
(comp::quadruped_medium::Species::Bonerattler, _) => Vec3::from([0.0, -0.3, 0.2]),
(comp::quadruped_medium::Species::Deer, _) => Vec3::from([0.0, -0.9, 0.1]),
(comp::quadruped_medium::Species::Hirdrasil, _) => Vec3::from([0.0, -1.0, 0.0]),
(comp::quadruped_medium::Species::Roshwalr, _) => Vec3::from([0.0, -0.2, 0.7]),
(comp::quadruped_medium::Species::Donkey, _) => Vec3::from([0.0, -0.5, 0.15]),
(comp::quadruped_medium::Species::Camel, _) => Vec3::from([0.0, -1.4, 0.3]),
(comp::quadruped_medium::Species::Zebra, _) => Vec3::from([0.0, -0.6, 0.1]),
(comp::quadruped_medium::Species::Antelope, _) => Vec3::from([0.0, -0.8, 0.1]),
(comp::quadruped_medium::Species::Kelpie, _) => Vec3::from([0.0, -0.8, 0.05]),
(comp::quadruped_medium::Species::Horse, _) => Vec3::from([0.0, -0.8, 0.1]),
(comp::quadruped_medium::Species::Barghest, _) => Vec3::from([0.0, -0.8, 0.6]),
(
comp::quadruped_medium::Species::Cattle,
comp::quadruped_medium::BodyType::Male,
) => Vec3::from([0.0, -0.4, 0.7]),
(
comp::quadruped_medium::Species::Cattle,
comp::quadruped_medium::BodyType::Female,
) => Vec3::from([0.0, -0.3, 0.5]),
(comp::quadruped_medium::Species::Darkhound, _) => Vec3::from([0.0, -0.5, 0.2]),
(comp::quadruped_medium::Species::Highland, _) => Vec3::from([0.0, -0.2, 0.8]),
(comp::quadruped_medium::Species::Yak, _) => Vec3::from([0.0, -0.2, 0.8]),
(comp::quadruped_medium::Species::Panda, _) => Vec3::from([0.0, -0.8, 0.2]),
(comp::quadruped_medium::Species::Bear, _) => Vec3::from([0.0, -1.5, 0.6]),
(comp::quadruped_medium::Species::Dreadhorn, _) => Vec3::from([0.0, -1.5, 1.6]),
(comp::quadruped_medium::Species::Moose, _) => Vec3::from([0.0, -0.9, 0.3]),
(comp::quadruped_medium::Species::Snowleopard, _) => Vec3::from([0.0, -0.9, 0.2]),
}
},
comp::Body::Ship(comp::ship::Body::DefaultAirship) => Vec3::from([0.0, 0.0, 10.0]),
comp::Body::Dragon(_) => Vec3::from([0.0, -0.7, 6.4]),
_ => Vec3::unit_z(),
}
}

View File

@ -81,9 +81,24 @@ impl Skeleton for QuadrupedMediumSkeleton {
make_bone(leg_bl_mat * Mat4::<f32>::from(self.foot_bl)), make_bone(leg_bl_mat * Mat4::<f32>::from(self.foot_bl)),
make_bone(leg_br_mat * Mat4::<f32>::from(self.foot_br)), make_bone(leg_br_mat * Mat4::<f32>::from(self.foot_br)),
]; ];
// Offset from the mounted bone's origin.
// Note: This could be its own bone if we need to animate it.
let mount_point = Vec3::new(0.0, -7.0, 3.0);
let mount_position = (torso_front_mat * Vec4::from_point(mount_point))
.homogenized()
.xyz();
// NOTE: We apply the ori from base_mat externally so we don't need to worry
// about it here for now.
let mount_orientation = self.torso_front.orientation;
Offsets { Offsets {
lantern: Vec3::default(), lantern: Vec3::default(),
mount_bone: self.torso_front, mount_bone: Transform {
position: mount_position,
orientation: mount_orientation,
scale: Vec3::one(),
},
} }
} }
} }

View File

@ -755,15 +755,30 @@ impl FigureMgr {
let hands = (active_tool_hand, second_tool_hand); let hands = (active_tool_hand, second_tool_hand);
// If a mountee exists, get its physical mounting offsets and its body // If a mountee exists, get its animated mounting transform and its position
let (mountee_offsets, mountee_body) = (|| -> Option<_> { let mount_transform_pos = (|| -> Option<_> {
let Mounting(entity) = mountings?; let Mounting(entity) = mountings?;
let entity = uid_allocator.retrieve_entity_internal((*entity).into())?; let entity = uid_allocator.retrieve_entity_internal((*entity).into())?;
let body = *bodies.get(entity)?; let body = *bodies.get(entity)?;
let meta = self.states.get_mut(&body, &entity)?; let meta = self.states.get_mut(&body, &entity)?;
Some((Some(meta.mountee_offset), Some(body))) Some((meta.mount_transform, meta.mount_world_pos))
})() })();
.unwrap_or((None, None));
let common_params = FigureUpdateCommonParameters {
pos: pos.0,
ori,
scale,
mount_transform_pos,
body: Some(*body),
col,
dt,
_lpindex: lpindex,
_visible: in_frustum,
is_player,
_camera: camera,
terrain,
ground_vel: physics.ground_vel,
};
match body { match body {
Body::Humanoid(body) => { Body::Humanoid(body) => {
@ -792,14 +807,7 @@ impl FigureMgr {
.character_states .character_states
.entry(entity) .entry(entity)
.or_insert_with(|| { .or_insert_with(|| {
FigureState::new( FigureState::new(renderer, CharacterSkeleton::new(holding_lantern))
renderer,
CharacterSkeleton::new(
holding_lantern,
mountee_offsets,
mountee_body,
),
)
}); });
// Average velocity relative to the current ground // Average velocity relative to the current ground
@ -823,11 +831,7 @@ impl FigureMgr {
// Standing // Standing
(true, false, false, false) => { (true, false, false, false) => {
anim::character::StandAnimation::update_skeleton( anim::character::StandAnimation::update_skeleton(
&CharacterSkeleton::new( &CharacterSkeleton::new(holding_lantern),
holding_lantern,
mountee_offsets,
mountee_body,
),
( (
active_tool_kind, active_tool_kind,
second_tool_kind, second_tool_kind,
@ -846,11 +850,7 @@ impl FigureMgr {
// Running // Running
(true, true, false, false) => { (true, true, false, false) => {
anim::character::RunAnimation::update_skeleton( anim::character::RunAnimation::update_skeleton(
&CharacterSkeleton::new( &CharacterSkeleton::new(holding_lantern),
holding_lantern,
mountee_offsets,
mountee_body,
),
( (
active_tool_kind, active_tool_kind,
second_tool_kind, second_tool_kind,
@ -871,11 +871,7 @@ impl FigureMgr {
// In air // In air
(false, _, false, false) => { (false, _, false, false) => {
anim::character::JumpAnimation::update_skeleton( anim::character::JumpAnimation::update_skeleton(
&CharacterSkeleton::new( &CharacterSkeleton::new(holding_lantern),
holding_lantern,
mountee_offsets,
mountee_body,
),
( (
active_tool_kind, active_tool_kind,
second_tool_kind, second_tool_kind,
@ -893,7 +889,7 @@ impl FigureMgr {
}, },
// Swim // Swim
(_, _, true, false) => anim::character::SwimAnimation::update_skeleton( (_, _, true, false) => anim::character::SwimAnimation::update_skeleton(
&CharacterSkeleton::new(holding_lantern, mountee_offsets, mountee_body), &CharacterSkeleton::new(holding_lantern),
( (
active_tool_kind, active_tool_kind,
second_tool_kind, second_tool_kind,
@ -911,7 +907,7 @@ impl FigureMgr {
), ),
// Mount // Mount
(_, _, _, true) => anim::character::MountAnimation::update_skeleton( (_, _, _, true) => anim::character::MountAnimation::update_skeleton(
&CharacterSkeleton::new(holding_lantern, mountee_offsets, mountee_body), &CharacterSkeleton::new(holding_lantern),
( (
active_tool_kind, active_tool_kind,
second_tool_kind, second_tool_kind,
@ -1589,20 +1585,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::QuadrupedSmall(body) => { Body::QuadrupedSmall(body) => {
@ -1787,20 +1773,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::QuadrupedMedium(body) => { Body::QuadrupedMedium(body) => {
@ -2110,20 +2086,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::QuadrupedLow(body) => { Body::QuadrupedLow(body) => {
@ -2466,20 +2432,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::BirdMedium(body) => { Body::BirdMedium(body) => {
@ -2576,20 +2532,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::FishMedium(body) => { Body::FishMedium(body) => {
@ -2665,20 +2611,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::BipedSmall(body) => { Body::BipedSmall(body) => {
@ -3009,20 +2945,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::Dragon(body) => { Body::Dragon(body) => {
@ -3103,20 +3029,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::Theropod(body) => { Body::Theropod(body) => {
@ -3286,20 +3202,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::BirdLarge(body) => { Body::BirdLarge(body) => {
@ -3607,20 +3513,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::FishSmall(body) => { Body::FishSmall(body) => {
@ -3696,20 +3592,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_base, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::BipedLarge(body) => { Body::BipedLarge(body) => {
@ -4324,20 +4210,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::Golem(body) => { Body::Golem(body) => {
@ -4572,20 +4448,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
in_frustum,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::Object(body) => { Body::Object(body) => {
@ -4700,20 +4566,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
true,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
Body::Ship(body) => { Body::Ship(body) => {
@ -4793,20 +4649,10 @@ impl FigureMgr {
state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp); state.skeleton = anim::vek::Lerp::lerp(&state.skeleton, &target_bones, dt_lerp);
state.update( state.update(
renderer, renderer,
pos.0, &mut update_buf,
ori, &common_params,
scale,
col,
dt,
state_animation_rate, state_animation_rate,
model, model,
lpindex,
true,
is_player,
camera,
&mut update_buf,
terrain,
physics.ground_vel,
); );
}, },
} }
@ -5392,7 +5238,14 @@ impl FigureColLights {
pub struct FigureStateMeta { pub struct FigureStateMeta {
lantern_offset: anim::vek::Vec3<f32>, lantern_offset: anim::vek::Vec3<f32>,
mountee_offset: anim::vek::Transform<f32, f32, f32>, // Animation to be applied to mounter of this entity
mount_transform: anim::vek::Transform<f32, f32, f32>,
// Contains the position of this figure or if it is a mounter it will contain the mountee's
// mount_world_pos
// Unlike the interpolated position stored in the ecs this will be propagated along
// mount chains
// For use if it is mounted by another figure
mount_world_pos: anim::vek::Vec3<f32>,
state_time: f32, state_time: f32,
last_ori: anim::vek::Quaternion<f32>, last_ori: anim::vek::Quaternion<f32>,
lpindex: u8, lpindex: u8,
@ -5430,6 +5283,27 @@ impl<S> DerefMut for FigureState<S> {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.meta } fn deref_mut(&mut self) -> &mut Self::Target { &mut self.meta }
} }
/// Parameters that don't depend on the body variant or animation results and
/// are also not mutable
pub struct FigureUpdateCommonParameters<'a> {
pub pos: anim::vek::Vec3<f32>,
pub ori: anim::vek::Quaternion<f32>,
pub scale: f32,
pub mount_transform_pos: Option<(anim::vek::Transform<f32, f32, f32>, anim::vek::Vec3<f32>)>,
pub body: Option<Body>,
pub col: vek::Rgba<f32>,
pub dt: f32,
// TODO: evaluate unused variable
pub _lpindex: u8,
// TODO: evaluate unused variable
pub _visible: bool,
pub is_player: bool,
// TODO: evaluate unused variable
pub _camera: &'a Camera,
pub terrain: Option<&'a Terrain>,
pub ground_vel: Vec3<f32>,
}
impl<S: Skeleton> FigureState<S> { impl<S: Skeleton> FigureState<S> {
pub fn new(renderer: &mut Renderer, skeleton: S) -> Self { pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
@ -5438,7 +5312,8 @@ impl<S: Skeleton> FigureState<S> {
Self { Self {
meta: FigureStateMeta { meta: FigureStateMeta {
lantern_offset: offsets.lantern, lantern_offset: offsets.lantern,
mountee_offset: offsets.mount_bone, mount_transform: offsets.mount_bone,
mount_world_pos: anim::vek::Vec3::zero(),
state_time: 0.0, state_time: 0.0,
last_ori: Ori::default().into(), last_ori: Ori::default().into(),
lpindex: 0, lpindex: 0,
@ -5455,24 +5330,27 @@ impl<S: Skeleton> FigureState<S> {
} }
} }
#[allow(clippy::too_many_arguments)] // TODO: Pending review in #587
pub fn update<const N: usize>( pub fn update<const N: usize>(
&mut self, &mut self,
renderer: &mut Renderer, renderer: &mut Renderer,
pos: anim::vek::Vec3<f32>, buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
ori: anim::vek::Quaternion<f32>, FigureUpdateCommonParameters {
scale: f32, pos,
col: vek::Rgba<f32>, ori,
dt: f32, scale,
mount_transform_pos,
body,
col,
dt,
_lpindex,
_visible,
is_player,
_camera,
terrain,
ground_vel,
}: &FigureUpdateCommonParameters,
state_animation_rate: f32, state_animation_rate: f32,
model: Option<&FigureModelEntry<N>>, model: Option<&FigureModelEntry<N>>,
_lpindex: u8,
_visible: bool,
is_player: bool,
_camera: &Camera,
buf: &mut [anim::FigureBoneData; anim::MAX_BONE_COUNT],
terrain: Option<&Terrain>,
ground_vel: Vec3<f32>,
) { ) {
// NOTE: As long as update() always gets called after get_or_create_model(), and // NOTE: As long as update() always gets called after get_or_create_model(), and
// visibility is not set again until after the model is rendered, we // visibility is not set again until after the model is rendered, we
@ -5500,12 +5378,34 @@ impl<S: Skeleton> FigureState<S> {
/* let radius = vek::Extent3::<f32>::from(model.bounds.half_size()).reduce_partial_max(); /* let radius = vek::Extent3::<f32>::from(model.bounds.half_size()).reduce_partial_max();
let _bounds = BoundingSphere::new(pos.into_array(), scale * 0.8 * radius); */ let _bounds = BoundingSphere::new(pos.into_array(), scale * 0.8 * radius); */
self.last_ori = vek::Lerp::lerp(self.last_ori, ori, 15.0 * dt).normalized(); self.last_ori = vek::Lerp::lerp(self.last_ori, *ori, 15.0 * dt).normalized();
self.state_time += dt * state_animation_rate; self.state_time += dt * state_animation_rate;
let mat = { let mat = {
anim::vek::Mat4::from(ori) * anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(scale)) let ori_scale = anim::vek::Mat4::from(*ori)
* anim::vek::Mat4::scaling_3d(anim::vek::Vec3::from(*scale));
// NOTE: It is kind of a hack to use this entity's ori here if it is
// mounted on another but this happens to match the ori of the
// mountee so it works, change this if it causes jankiness in the future.
if let Some((transform, _)) = *mount_transform_pos {
// Note: if we had a way to compute a "default" transform of the bones then in
// the animations we could make use of the mountee_offset from common by
// computing what the offset of the mounter is from the mounted
// bone in its default position when the mounter has the mount
// offset in common applied to it. Since we don't have this
// right now we instead need to recreate the same effect in the
// animations and keep it in sync.
//
// Component of mounting offset specific to the mounter.
let mounter_offset = anim::vek::Mat4::translation_3d(
body.map_or_else(Vec3::zero, |b| b.mounter_offset()),
);
anim::vek::Mat4::from(transform) * ori_scale * mounter_offset
} else {
ori_scale
}
}; };
let atlas_offs = model.allocation.rectangle.min; let atlas_offs = model.allocation.rectangle.min;
@ -5555,9 +5455,9 @@ impl<S: Skeleton> FigureState<S> {
let locals = FigureLocals::new( let locals = FigureLocals::new(
mat, mat,
col.rgb(), col.rgb(),
pos, mount_transform_pos.map_or(*pos, |(_, pos)| pos),
vek::Vec2::new(atlas_offs.x, atlas_offs.y), vek::Vec2::new(atlas_offs.x, atlas_offs.y),
is_player, *is_player,
self.last_light, self.last_light,
self.last_glow, self.last_glow,
); );
@ -5569,17 +5469,19 @@ impl<S: Skeleton> FigureState<S> {
renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]); renderer.update_consts(&mut self.meta.bound.1, &new_bone_consts[0..S::BONE_COUNT]);
self.lantern_offset = offsets.lantern; self.lantern_offset = offsets.lantern;
self.mountee_offset = offsets.mount_bone; // TODO: compute the mount bone only when it is needed
self.mount_transform = offsets.mount_bone;
self.mount_world_pos = mount_transform_pos.map_or(*pos, |(_, pos)| pos);
let smoothing = (5.0 * dt).min(1.0); let smoothing = (5.0 * dt).min(1.0);
if let Some(last_pos) = self.last_pos { if let Some(last_pos) = self.last_pos {
self.avg_vel = (1.0 - smoothing) * self.avg_vel + smoothing * (pos - last_pos) / dt; self.avg_vel = (1.0 - smoothing) * self.avg_vel + smoothing * (pos - last_pos) / *dt;
} }
self.last_pos = Some(pos); self.last_pos = Some(*pos);
// Can potentially overflow // Can potentially overflow
if self.avg_vel.magnitude_squared() != 0.0 { if self.avg_vel.magnitude_squared() != 0.0 {
self.acc_vel += (self.avg_vel - ground_vel).magnitude() * dt; self.acc_vel += (self.avg_vel - *ground_vel).magnitude() * dt;
} else { } else {
self.acc_vel = 0.0; self.acc_vel = 0.0;
} }

View File

@ -7,7 +7,10 @@ use crate::{
}, },
scene::{ scene::{
camera::{self, Camera, CameraMode}, camera::{self, Camera, CameraMode},
figure::{load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState}, figure::{
load_mesh, FigureColLights, FigureModelCache, FigureModelEntry, FigureState,
FigureUpdateCommonParameters,
},
}, },
window::{Event, PressState}, window::{Event, PressState},
}; };
@ -144,26 +147,25 @@ impl Scene {
col_lights col_lights
.create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]); .create_figure(renderer, greedy.finalize(), (opaque_mesh, bounds), [range]);
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
state.update( let common_params = FigureUpdateCommonParameters {
renderer, pos: anim::vek::Vec3::zero(),
anim::vek::Vec3::zero(), ori: anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Vec3::unit_y(), anim::vek::Vec3::unit_y(),
anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0), anim::vek::Vec3::new(start_angle.sin(), -start_angle.cos(), 0.0),
), ),
1.0, scale: 1.0,
Rgba::broadcast(1.0), mount_transform_pos: None,
15.0, // Want to get there immediately. body: None,
1.0, col: Rgba::broadcast(1.0),
Some(&model), dt: 15.0, // Want to get there immediately.
0, _lpindex: 0,
true, _visible: true,
false, is_player: false,
&camera, _camera: &camera,
&mut buf, terrain: None,
None, ground_vel: Vec3::zero(),
Vec3::zero(), };
); state.update(renderer, &mut buf, &common_params, 1.0, Some(&model));
(model, state) (model, state)
}), }),
col_lights, col_lights,
@ -322,26 +324,27 @@ impl Scene {
) )
.0; .0;
let mut buf = [Default::default(); anim::MAX_BONE_COUNT]; let mut buf = [Default::default(); anim::MAX_BONE_COUNT];
self.figure_state.update( let common_params = FigureUpdateCommonParameters {
renderer, pos: anim::vek::Vec3::zero(),
anim::vek::Vec3::zero(), ori: anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Quaternion::rotation_from_to_3d(
anim::vek::Vec3::unit_y(), anim::vek::Vec3::unit_y(),
anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0), anim::vek::Vec3::new(self.char_ori.sin(), -self.char_ori.cos(), 0.0),
), ),
1.0, scale: 1.0,
Rgba::broadcast(1.0), mount_transform_pos: None,
scene_data.delta_time, body: None,
1.0, col: Rgba::broadcast(1.0),
model, dt: scene_data.delta_time,
0, _lpindex: 0,
true, _visible: true,
false, is_player: false,
&self.camera, _camera: &self.camera,
&mut buf, terrain: None,
None, ground_vel: Vec3::zero(),
Vec3::zero(), };
);
self.figure_state
.update(renderer, &mut buf, &common_params, 1.0, model);
} }
} }