From 713b59aeff3c70e617735e161e2c329a15f27d97 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Tue, 16 Apr 2019 20:15:49 +0200 Subject: [PATCH] Implement animation smoothing Former-commit-id: e89caca7d273934533c57c4324365a126d02e5df --- voxygen/src/anim/character/idle.rs | 43 ++++++++++++++++-------------- voxygen/src/anim/character/mod.rs | 13 +++++++++ voxygen/src/anim/character/run.rs | 42 ++++++++++++++++------------- voxygen/src/anim/mod.rs | 15 +++++++++-- voxygen/src/scene/figure.rs | 6 +++-- 5 files changed, 76 insertions(+), 43 deletions(-) diff --git a/voxygen/src/anim/character/idle.rs b/voxygen/src/anim/character/idle.rs index 5c29f48287..55a0f8f425 100644 --- a/voxygen/src/anim/character/idle.rs +++ b/voxygen/src/anim/character/idle.rs @@ -18,31 +18,34 @@ impl Animation for IdleAnimation { type Dependency = f64; fn update_skeleton( - skeleton: &mut Self::Skeleton, + skeleton: &Self::Skeleton, time: f64, - ) { - skeleton.head.offset = Vec3::unit_z() * 13.0 / 11.0; - skeleton.head.ori = Quaternion::rotation_z(0.0); + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + next.head.offset = Vec3::unit_z() * 13.0 / 11.0; + next.head.ori = Quaternion::rotation_z(0.0); - skeleton.chest.offset = Vec3::unit_z() * 9.0 / 11.0; - skeleton.chest.ori = Quaternion::rotation_z(0.0); + next.chest.offset = Vec3::unit_z() * 9.0 / 11.0; + next.chest.ori = Quaternion::rotation_z(0.0); - skeleton.belt.offset = Vec3::unit_z() * 7.0 / 11.0; - skeleton.belt.ori = Quaternion::rotation_z(0.0); + next.belt.offset = Vec3::unit_z() * 7.0 / 11.0; + next.belt.ori = Quaternion::rotation_z(0.0); - skeleton.shorts.offset = Vec3::unit_z() * 4.0 / 11.0; - skeleton.shorts.ori = Quaternion::rotation_z(0.0); + next.shorts.offset = Vec3::unit_z() * 4.0 / 11.0; + next.shorts.ori = Quaternion::rotation_z(0.0); - skeleton.l_hand.offset = Vec3::new(-8.0, 0.0, 9.0) / 11.0; - skeleton.r_hand.offset = Vec3::new(8.0, 0.0, 9.0 ) / 11.0; + next.l_hand.offset = Vec3::new(-8.0, 0.0, 9.0) / 11.0; + next.r_hand.offset = Vec3::new(8.0, 0.0, 9.0 ) / 11.0; - skeleton.l_foot.offset = Vec3::new(-3.5, 0.0, 3.0) / 11.0; - skeleton.l_foot.ori = Quaternion::rotation_x(0.0); - skeleton.r_foot.offset = Vec3::new(3.5, 0.0, 3.0) / 11.0; - skeleton.r_foot.ori = Quaternion::rotation_x(0.0); + next.l_foot.offset = Vec3::new(-3.5, 0.0, 3.0) / 11.0; + next.l_foot.ori = Quaternion::rotation_x(0.0); + next.r_foot.offset = Vec3::new(3.5, 0.0, 3.0) / 11.0; + next.r_foot.ori = Quaternion::rotation_x(0.0); - skeleton.back.offset = Vec3::new(-9.0, 5.0, 18.0); - skeleton.back.ori = Quaternion::rotation_y(2.5); - skeleton.back.scale = Vec3::one(); + next.back.offset = Vec3::new(-9.0, 5.0, 18.0); + next.back.ori = Quaternion::rotation_y(2.5); + next.back.scale = Vec3::one(); + + next } -} \ No newline at end of file +} diff --git a/voxygen/src/anim/character/mod.rs b/voxygen/src/anim/character/mod.rs index 8072b29ba4..f84cc18e09 100644 --- a/voxygen/src/anim/character/mod.rs +++ b/voxygen/src/anim/character/mod.rs @@ -14,6 +14,7 @@ use super::{ Bone, }; +#[derive(Clone)] pub struct CharacterSkeleton { head: Bone, chest: Bone, @@ -65,4 +66,16 @@ impl Skeleton for CharacterSkeleton { FigureBoneData::default(), ] } + + fn interpolate(&mut self, target: &Self) { + self.head.interpolate(&target.head); + self.chest.interpolate(&target.chest); + self.belt.interpolate(&target.belt); + self.shorts.interpolate(&target.shorts); + self.l_hand.interpolate(&target.l_hand); + self.r_hand.interpolate(&target.r_hand); + self.l_foot.interpolate(&target.l_foot); + self.r_foot.interpolate(&target.r_foot); + self.back.interpolate(&target.back); + } } diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs index ac78dca92e..abab662168 100644 --- a/voxygen/src/anim/character/run.rs +++ b/voxygen/src/anim/character/run.rs @@ -17,35 +17,39 @@ impl Animation for RunAnimation { type Dependency = f64; fn update_skeleton( - skeleton: &mut Self::Skeleton, + skeleton: &Self::Skeleton, time: f64, - ) { + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + let wave = (time as f32 * 12.0).sin(); let wave_slow = (time as f32 * 6.0 + PI).sin(); let wave_dip = (wave_slow.abs() - 0.5).abs(); - skeleton.head.offset = Vec3::unit_z() * 13.0 / 11.0; - skeleton.head.ori = Quaternion::rotation_z(wave * 0.3); + next.head.offset = Vec3::unit_z() * 13.0 / 11.0; + next.head.ori = Quaternion::rotation_z(wave * 0.3); - skeleton.chest.offset = Vec3::unit_z() * 9.0 / 11.0; - skeleton.chest.ori = Quaternion::rotation_z(wave * 0.3); + next.chest.offset = Vec3::unit_z() * 9.0 / 11.0; + next.chest.ori = Quaternion::rotation_z(wave * 0.3); - skeleton.belt.offset = Vec3::unit_z() * 7.0 / 11.0; - skeleton.belt.ori = Quaternion::rotation_z(wave * 0.2); + next.belt.offset = Vec3::unit_z() * 7.0 / 11.0; + next.belt.ori = Quaternion::rotation_z(wave * 0.2); - skeleton.shorts.offset = Vec3::unit_z() * 4.0 / 11.0; - skeleton.shorts.ori = Quaternion::rotation_z(wave * 0.1); + next.shorts.offset = Vec3::unit_z() * 4.0 / 11.0; + next.shorts.ori = Quaternion::rotation_z(wave * 0.1); - skeleton.l_hand.offset = Vec3::new(-6.0 - wave_dip * 6.0, wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0; - skeleton.r_hand.offset = Vec3::new(6.0 + wave_dip * 6.0, -wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0; + next.l_hand.offset = Vec3::new(-6.0 - wave_dip * 6.0, wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0; + next.r_hand.offset = Vec3::new(6.0 + wave_dip * 6.0, -wave * 5.0, 11.0 - wave_dip * 6.0) / 11.0; - skeleton.l_foot.offset = Vec3::new(-3.5, 1.0 - wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0; - skeleton.l_foot.ori = Quaternion::rotation_x(-wave + 1.0); - skeleton.r_foot.offset = Vec3::new(3.5, 1.0 + wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0; - skeleton.r_foot.ori = Quaternion::rotation_x(wave + 1.0); + next.l_foot.offset = Vec3::new(-3.5, 1.0 - wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0; + next.l_foot.ori = Quaternion::rotation_x(-wave + 1.0); + next.r_foot.offset = Vec3::new(3.5, 1.0 + wave * 8.0, 3.5 - wave_dip * 4.0) / 11.0; + next.r_foot.ori = Quaternion::rotation_x(wave + 1.0); - skeleton.back.offset = Vec3::new(-9.0, 5.0, 18.0); - skeleton.back.ori = Quaternion::rotation_y(2.5); - skeleton.back.scale = Vec3::one(); + next.back.offset = Vec3::new(-9.0, 5.0, 18.0); + next.back.ori = Quaternion::rotation_y(2.5); + next.back.scale = Vec3::one(); + + next } } diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index e226c48e7f..00a2da9bd0 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -25,18 +25,29 @@ impl Bone { pub fn compute_base_matrix(&self) -> Mat4 { Mat4::::translation_3d(self.offset) * Mat4::scaling_3d(self.scale) * Mat4::from(self.ori) } + + /// Change the current bone to be more like `target` + fn interpolate(&mut self, target: &Bone) { + // TODO: Make configurable + let factor = 0.3; + self.offset += (target.offset - self.offset) * factor; + } } pub trait Skeleton: Send + Sync + 'static { fn compute_matrices(&self) -> [FigureBoneData; 16]; + + /// Change the current skeleton to be more like `target` + fn interpolate(&mut self, target: &Self); } pub trait Animation { type Skeleton; type Dependency; + /// Returns a new skeleton that is generated by the animation fn update_skeleton( - skeleton: &mut Self::Skeleton, + skeleton: &Self::Skeleton, dependency: Self::Dependency, - ); + ) -> Self::Skeleton; } diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 0ed1092728..75b727b07f 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -94,10 +94,12 @@ impl Figures { .entry(entity) .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); - match animation { + let target_skeleton = match animation { comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time), comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time), - } + }; + + state.skeleton.interpolate(&target_skeleton); state.update(renderer, pos.0, dir.0); }