veloren_voxygen_anim/character/
mod.rs

1pub mod basic;
2pub mod boost;
3pub mod climb;
4pub mod collect;
5pub mod consume;
6pub mod crawl;
7pub mod dance;
8pub mod equip;
9pub mod glidewield;
10pub mod gliding;
11pub mod idle;
12pub mod jump;
13pub mod mount;
14pub mod multi;
15pub mod music;
16pub mod pet;
17pub mod roll;
18pub mod run;
19pub mod sit;
20pub mod sleep;
21pub mod sneak;
22pub mod sneakequip;
23pub mod sneakwield;
24pub mod staggered;
25pub mod stand;
26pub mod steer;
27pub mod stunned;
28pub mod swim;
29pub mod swimwield;
30pub mod talk;
31pub mod throw;
32pub mod wallrun;
33pub mod wield;
34
35// Reexports
36pub use self::{
37    basic::{BasicAction, BasicActionDependency},
38    boost::BoostAnimation,
39    climb::ClimbAnimation,
40    collect::CollectAnimation,
41    consume::ConsumeAnimation,
42    crawl::CrawlAnimation,
43    dance::DanceAnimation,
44    equip::EquipAnimation,
45    glidewield::GlideWieldAnimation,
46    gliding::GlidingAnimation,
47    idle::IdleAnimation,
48    jump::JumpAnimation,
49    mount::MountAnimation,
50    multi::{MultiAction, MultiActionDependency},
51    music::MusicAnimation,
52    pet::PetAnimation,
53    roll::RollAnimation,
54    run::RunAnimation,
55    sit::SitAnimation,
56    sleep::SleepAnimation,
57    sneak::SneakAnimation,
58    sneakequip::SneakEquipAnimation,
59    sneakwield::SneakWieldAnimation,
60    staggered::StaggeredAnimation,
61    stand::StandAnimation,
62    steer::SteerAnimation,
63    stunned::StunnedAnimation,
64    swim::SwimAnimation,
65    swimwield::SwimWieldAnimation,
66    talk::TalkAnimation,
67    throw::ThrowAnimation,
68    wallrun::WallrunAnimation,
69    wield::WieldAnimation,
70};
71use super::{FigureBoneData, Offsets, Skeleton, TrailSource, make_bone, vek::*};
72use common::comp::{
73    self,
74    tool::{Hands, ToolKind},
75};
76use core::{convert::TryFrom, f32::consts::PI};
77
78pub type Body = comp::humanoid::Body;
79
80skeleton_impls!(struct CharacterSkeleton {
81    + head,
82    + chest,
83    + belt,
84    + back,
85    + shorts,
86    + hand_l,
87    + hand_r,
88    + foot_l,
89    + foot_r,
90    + shoulder_l,
91    + shoulder_r,
92    + glider,
93    + main,
94    + second,
95    + lantern,
96    + hold,
97    torso,
98    control,
99    control_l,
100    control_r,
101    :: // Begin non-bone fields
102    holding_lantern: bool,
103    // The offset from the back that carried weapons should be given to avoid clipping due to, say, a backpack
104    back_carry_offset: f32,
105    main_weapon_trail: bool,
106    off_weapon_trail: bool,
107    // Cannot exist at same time as weapon trails. Since gliding and attacking are mutually exclusive, should never be a concern.
108    glider_trails: bool,
109});
110
111impl CharacterSkeleton {
112    pub fn new(holding_lantern: bool, back_carry_offset: f32) -> Self {
113        Self {
114            holding_lantern,
115            back_carry_offset,
116            ..Self::default()
117        }
118    }
119}
120
121impl Skeleton for CharacterSkeleton {
122    type Attr = SkeletonAttr;
123    type Body = Body;
124
125    const BONE_COUNT: usize = 16;
126    #[cfg(feature = "use-dyn-lib")]
127    const COMPUTE_FN: &'static [u8] = b"character_compute_mats\0";
128
129    #[cfg_attr(feature = "be-dyn-lib", unsafe(export_name = "character_compute_mats"))]
130    fn compute_matrices_inner(
131        &self,
132        base_mat: Mat4<f32>,
133        buf: &mut [FigureBoneData; super::MAX_BONE_COUNT],
134        body: Self::Body,
135    ) -> Offsets {
136        // TODO: extract scaler from body to it's own method so we can call that
137        // directly instead of going through SkeletonAttr? (note todo also
138        // appiles to other body variant animations)
139        let base_mat = base_mat * Mat4::scaling_3d(SkeletonAttr::from(&body).scaler / 11.0);
140
141        let torso_mat = base_mat * Mat4::<f32>::from(self.torso);
142        let chest_mat = torso_mat * Mat4::<f32>::from(self.chest);
143        let head_mat = chest_mat * Mat4::<f32>::from(self.head);
144        let shorts_mat = chest_mat * Mat4::<f32>::from(self.shorts);
145        let control_mat = chest_mat * Mat4::<f32>::from(self.control);
146        let control_l_mat = control_mat * Mat4::<f32>::from(self.control_l);
147        let control_r_mat = control_mat * Mat4::<f32>::from(self.control_r);
148        let hand_r_mat = control_r_mat * Mat4::<f32>::from(self.hand_r);
149
150        let hand_l_mat = Mat4::<f32>::from(self.hand_l);
151        let lantern_mat = if self.holding_lantern {
152            hand_r_mat
153        } else {
154            shorts_mat
155        } * Mat4::<f32>::from(self.lantern);
156        let main_mat = control_l_mat * Mat4::<f32>::from(self.main);
157        let second_mat = control_r_mat * Mat4::<f32>::from(self.second);
158        let glider_mat = chest_mat * Mat4::<f32>::from(self.glider);
159
160        *(<&mut [_; Self::BONE_COUNT]>::try_from(&mut buf[0..Self::BONE_COUNT]).unwrap()) = [
161            make_bone(head_mat),
162            make_bone(chest_mat),
163            make_bone(chest_mat * Mat4::<f32>::from(self.belt)),
164            make_bone(chest_mat * Mat4::<f32>::from(self.back)),
165            make_bone(shorts_mat),
166            make_bone(control_l_mat * hand_l_mat),
167            make_bone(hand_r_mat),
168            make_bone(torso_mat * Mat4::<f32>::from(self.foot_l)),
169            make_bone(torso_mat * Mat4::<f32>::from(self.foot_r)),
170            make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_l)),
171            make_bone(chest_mat * Mat4::<f32>::from(self.shoulder_r)),
172            make_bone(glider_mat),
173            make_bone(main_mat),
174            make_bone(second_mat),
175            make_bone(lantern_mat),
176            // FIXME: Should this be control_l_mat?
177            make_bone(control_mat * hand_l_mat * Mat4::<f32>::from(self.hold)),
178        ];
179
180        // Offset from the mounted bone's origin.
181        // Note: This could be its own bone if we need to animate it independently.
182        let mount_position = (chest_mat * Vec4::from_point(Vec3::new(5.5, 0.0, 6.5)))
183            .homogenized()
184            .xyz();
185        // NOTE: We apply the ori from base_mat externally so we don't need to worry
186        // about it here for now.
187        let mount_orientation =
188            self.torso.orientation * self.chest.orientation * Quaternion::rotation_y(0.4);
189
190        let weapon_trails = self.main_weapon_trail || self.off_weapon_trail;
191        Offsets {
192            lantern: Some((lantern_mat * Vec4::new(0.0, 0.5, -6.0, 1.0)).xyz()),
193            viewpoint: Some((head_mat * Vec4::new(0.0, 0.0, 4.0, 1.0)).xyz()),
194            mount_bone: Transform {
195                position: mount_position,
196                orientation: mount_orientation,
197                scale: Vec3::one(),
198            },
199            primary_trail_mat: if weapon_trails {
200                self.main_weapon_trail
201                    .then_some((main_mat, TrailSource::Weapon))
202            } else {
203                self.glider_trails
204                    .then_some((glider_mat, TrailSource::GliderLeft))
205            },
206            secondary_trail_mat: if weapon_trails {
207                self.off_weapon_trail
208                    .then_some((second_mat, TrailSource::Weapon))
209            } else {
210                self.glider_trails
211                    .then_some((glider_mat, TrailSource::GliderRight))
212            },
213            ..Default::default()
214        }
215    }
216}
217
218pub struct SkeletonAttr {
219    scaler: f32,
220    head_scale: f32,
221    head: (f32, f32),
222    chest: (f32, f32),
223    belt: (f32, f32),
224    back: (f32, f32),
225    shorts: (f32, f32),
226    hand: (f32, f32, f32),
227    foot: (f32, f32, f32),
228    shoulder: (f32, f32, f32),
229    lantern: (f32, f32, f32),
230    shl: (f32, f32, f32, f32, f32, f32),
231    shr: (f32, f32, f32, f32, f32, f32),
232    sc: (f32, f32, f32, f32, f32, f32),
233    hhl: (f32, f32, f32, f32, f32, f32),
234    hhr: (f32, f32, f32, f32, f32, f32),
235    hc: (f32, f32, f32, f32, f32, f32),
236    sthl: (f32, f32, f32, f32, f32, f32),
237    sthr: (f32, f32, f32, f32, f32, f32),
238    stc: (f32, f32, f32, f32, f32, f32),
239    ahl: (f32, f32, f32, f32, f32, f32),
240    ahr: (f32, f32, f32, f32, f32, f32),
241    ac: (f32, f32, f32, f32, f32, f32),
242    bhl: (f32, f32, f32, f32, f32, f32),
243    bhr: (f32, f32, f32, f32, f32, f32),
244    bc: (f32, f32, f32, f32, f32, f32),
245}
246
247impl Default for SkeletonAttr {
248    fn default() -> Self {
249        Self {
250            scaler: 0.0,
251            head_scale: 0.0,
252            head: (0.0, 0.0),
253            chest: (0.0, 0.0),
254            belt: (0.0, 0.0),
255            back: (0.0, 0.0),
256            shorts: (0.0, 0.0),
257            hand: (0.0, 0.0, 0.0),
258            foot: (0.0, 0.0, 0.0),
259            shoulder: (0.0, 0.0, 0.0),
260            lantern: (0.0, 0.0, 0.0),
261            shl: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
262            shr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
263            sc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
264            hhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
265            hhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
266            hc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
267            sthl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
268            sthr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
269            stc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
270            ahl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
271            ahr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
272            ac: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
273            bhl: (0.0, 0.0, 10.0, 0.0, 0.0, 0.0),
274            bhr: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
275            bc: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
276        }
277    }
278}
279
280impl<'a> TryFrom<&'a comp::Body> for SkeletonAttr {
281    type Error = ();
282
283    fn try_from(body: &'a comp::Body) -> Result<Self, Self::Error> {
284        match body {
285            comp::Body::Humanoid(body) => Ok(SkeletonAttr::from(body)),
286            _ => Err(()),
287        }
288    }
289}
290
291impl<'a> From<&'a Body> for SkeletonAttr {
292    fn from(body: &'a Body) -> Self {
293        use comp::humanoid::{BodyType::*, Species::*};
294        Self {
295            scaler: body.scaler(),
296            head_scale: match (body.species, body.body_type) {
297                (Orc, Male) => 0.9,
298                (Orc, Female) => 0.9,
299                (Human, Male) => 0.9,
300                (Human, Female) => 0.9,
301                (Elf, Male) => 0.9,
302                (Elf, Female) => 0.9,
303                (Dwarf, Male) => 1.0,
304                (Dwarf, Female) => 1.0,
305                (Draugr, Male) => 0.9,
306                (Draugr, Female) => 0.9,
307                (Danari, Male) => 1.15,
308                (Danari, Female) => 1.15,
309            },
310            head: match (body.species, body.body_type) {
311                (Orc, Male) => (-2.0, 9.0),
312                (Orc, Female) => (-2.0, 9.5),
313                (Human, Male) => (-2.3, 9.5),
314                (Human, Female) => (-2.0, 9.5),
315                (Elf, Male) => (-2.5, 9.5),
316                (Elf, Female) => (-1.0, 9.5),
317                (Dwarf, Male) => (-2.0, 10.0),
318                (Dwarf, Female) => (-2.0, 9.5),
319                (Draugr, Male) => (-1.5, 8.5),
320                (Draugr, Female) => (-1.5, 9.5),
321                (Danari, Male) => (-1.5, 7.0),
322                (Danari, Female) => (-1.5, 7.0),
323            },
324            chest: (0.0, 8.0),
325            belt: (0.0, -2.0),
326            back: (-3.1, 7.25),
327            shorts: (0.0, -5.0),
328            hand: (7.0, -0.25, 0.5),
329            foot: (3.4, 0.5, 2.0),
330            shoulder: (5.0, 0.0, 5.0),
331            lantern: (5.0, 2.5, 5.5),
332            shl: (-0.75, -1.0, 0.5, 1.47, -0.2, 0.0),
333            shr: (0.75, -1.5, -2.5, 1.47, 0.3, 0.0),
334            sc: (-6.0, 6.0, 0.0, -0.5, 0.0, 0.0),
335            hhl: (0.1, 0.0, 11.0, 4.71, 0.0, PI),
336            hhr: (0.0, 0.0, 0.0, 4.71, 0.0, PI),
337            hc: (6.0, 7.0, 1.0, -0.3, -PI / 2.0, 3.64),
338            sthl: (0.0, 0.0, 6.0, 1.97, 0.0, 0.0),
339            sthr: (0.0, 0.0, 0.0, 1.27, 0.2, 0.0),
340            stc: (-5.0, 7.0, -2.0, -0.3, 0.15, 0.0),
341            ahl: (-0.5, -1.0, 7.0, 1.17, PI, 0.0),
342            ahr: (0.0, -1.0, 1.0, -2.0, 0.0, PI),
343            ac: (-8.0, 11.0, 3.0, 2.0, 0.0, 0.0),
344            bhl: (0.0, -4.0, 1.0, PI / 2.0, 0.0, 0.0),
345            bhr: (1.0, 2.0, -2.0, PI / 2.0, 0.0, 0.0),
346            bc: (-5.0, 9.0, 1.0, 0.0, 1.2, -0.6),
347        }
348    }
349}
350
351impl CharacterSkeleton {
352    /// Animate tools (main and secondary) on the character's back, taking in
353    /// account backpack offsets.
354    pub fn do_tools_on_back(
355        &mut self,
356        hands: (Option<Hands>, Option<Hands>),
357        active_tool_kind: Option<ToolKind>,
358        second_tool_kind: Option<ToolKind>,
359    ) {
360        match (hands, active_tool_kind, second_tool_kind) {
361            ((Some(Hands::Two), _), tool, _) | ((None, Some(Hands::Two)), _, tool) => match tool {
362                Some(ToolKind::Bow) => {
363                    self.main.position = Vec3::new(0.0, -5.0 - self.back_carry_offset, 6.0);
364                    self.main.orientation =
365                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
366                },
367                Some(ToolKind::Staff) | Some(ToolKind::Sceptre) => {
368                    self.main.position = Vec3::new(2.0, -5.0 - self.back_carry_offset, -1.0);
369                    self.main.orientation =
370                        Quaternion::rotation_y(-0.5) * Quaternion::rotation_z(PI / 2.0);
371                },
372                Some(ToolKind::Shield) => {
373                    self.main.position = Vec3::new(-2.0, -3.0 - self.back_carry_offset, 1.0);
374                    self.main.orientation =
375                        Quaternion::rotation_y(-0.75) * Quaternion::rotation_z(PI / 2.0);
376                },
377                _ => {
378                    self.main.position = Vec3::new(-7.0, -5.0 - self.back_carry_offset, 15.0);
379                    self.main.orientation =
380                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
381                },
382            },
383            ((_, _), _, _) => {},
384        }
385
386        match hands {
387            (Some(Hands::One), _) => match active_tool_kind {
388                Some(ToolKind::Dagger) => {
389                    self.main.position = Vec3::new(5.0, 1.0 - self.back_carry_offset, 2.0);
390                    self.main.orientation =
391                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(2.0 * PI);
392                },
393                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
394                    self.main.position = Vec3::new(-4.0, -4.5 - self.back_carry_offset, 10.0);
395                    self.main.orientation =
396                        Quaternion::rotation_y(2.5) * Quaternion::rotation_z(PI / 2.0);
397                },
398                Some(ToolKind::Shield) => {
399                    self.main.position = Vec3::new(-2.0, -4.0 - self.back_carry_offset, 3.0);
400                    self.main.orientation =
401                        Quaternion::rotation_y(0.25 * PI) * Quaternion::rotation_z(-1.5 * PI);
402                },
403                Some(ToolKind::Throwable) => {
404                    self.main.position = Vec3::new(-6.0, 0.0, -4.0);
405                    self.main.scale = Vec3::zero();
406                },
407                _ => {},
408            },
409            (_, _) => {},
410        }
411        match hands {
412            (None | Some(Hands::One), Some(Hands::One)) => match second_tool_kind {
413                Some(ToolKind::Dagger) => {
414                    self.second.position = Vec3::new(-5.0, 1.0 - self.back_carry_offset, 2.0);
415                    self.second.orientation =
416                        Quaternion::rotation_x(-1.35 * PI) * Quaternion::rotation_z(-2.0 * PI);
417                },
418                Some(ToolKind::Axe) | Some(ToolKind::Hammer) | Some(ToolKind::Sword) => {
419                    self.second.position = Vec3::new(4.0, -5.0 - self.back_carry_offset, 10.0);
420                    self.second.orientation =
421                        Quaternion::rotation_y(-2.5) * Quaternion::rotation_z(-PI / 2.0);
422                },
423                Some(ToolKind::Shield) => {
424                    self.second.position = Vec3::new(1.5, -4.0 - self.back_carry_offset, 3.0);
425                    self.second.orientation =
426                        Quaternion::rotation_y(-0.25 * PI) * Quaternion::rotation_z(1.5 * PI);
427                },
428                Some(ToolKind::Throwable) => {
429                    self.second.position = Vec3::new(6.0, 0.0, -4.0);
430                    self.second.scale = Vec3::zero();
431                },
432                _ => {},
433            },
434            (_, _) => {},
435        }
436    }
437
438    /// If we're holding a lantern, animate hold the lantern in a reasonable
439    /// position.
440    pub fn do_hold_lantern(
441        &mut self,
442        s_a: &SkeletonAttr,
443        anim_time: f32,
444        acc_vel: f32,
445        speednorm: f32,
446        impact: f32,
447        tilt: f32,
448    ) {
449        let lab = 2.0 / s_a.scaler;
450
451        let short = ((5.0 / (1.5 + 3.5 * ((acc_vel * lab * 1.6 + PI * 0.5).sin()).powi(2))).sqrt())
452            * ((acc_vel * lab * 1.6 + PI * 0.5).sin());
453
454        let shorte = ((1.0 / (0.8 + 0.2 * ((acc_vel * lab * 1.6).sin()).powi(2))).sqrt())
455            * ((acc_vel * lab * 1.6).sin());
456
457        self.lantern.position = Vec3::new(s_a.lantern.0, s_a.lantern.1, s_a.lantern.2);
458        self.lantern.orientation = Quaternion::rotation_x(shorte * 0.7 * speednorm.powi(2) + 0.4)
459            * Quaternion::rotation_y(shorte * 0.4 * speednorm.powi(2));
460        self.lantern.scale = Vec3::one() * 0.65;
461        self.hold.scale = Vec3::one() * 0.0;
462
463        if self.holding_lantern {
464            self.hand_r.position = Vec3::new(
465                s_a.hand.0 + 1.0,
466                s_a.hand.1 + 2.0 - impact * 0.2,
467                s_a.hand.2 + 12.0 + impact * -0.1,
468            );
469            self.hand_r.orientation = Quaternion::rotation_x(2.25) * Quaternion::rotation_z(0.9);
470            self.shoulder_r.orientation = Quaternion::rotation_x(short * -0.15 + 2.0);
471
472            let fast = (anim_time * 8.0).sin();
473            let fast2 = (anim_time * 6.0 + 8.0).sin();
474
475            self.lantern.position = Vec3::new(-0.5, -0.5, -2.5);
476            self.lantern.orientation = self.hand_r.orientation.inverse()
477                * Quaternion::rotation_x(
478                    (fast + 0.5) * 1.0 * speednorm + (tilt.abs() * 2.0).min(PI * 0.5),
479                )
480                * Quaternion::rotation_y(tilt * 1.0 * fast + tilt * 1.0 + fast2 * speednorm * 0.25);
481        }
482    }
483}
484
485pub fn hammer_start(next: &mut CharacterSkeleton, s_a: &SkeletonAttr) {
486    next.main.position = Vec3::new(0.0, 0.0, 0.0);
487    next.main.orientation = Quaternion::rotation_z(0.0);
488    next.hand_l.position = Vec3::new(s_a.hhl.0, s_a.hhl.1 + 3.0, s_a.hhl.2 - 1.0);
489    next.hand_l.orientation = Quaternion::rotation_x(s_a.hhl.3)
490        * Quaternion::rotation_y(s_a.hhl.4)
491        * Quaternion::rotation_z(s_a.hhl.5);
492    next.hand_r.position = Vec3::new(s_a.hhr.0, s_a.hhr.1 + 3.0, s_a.hhr.2 + 1.0);
493    next.hand_r.orientation = Quaternion::rotation_x(s_a.hhr.3)
494        * Quaternion::rotation_y(s_a.hhr.4)
495        * Quaternion::rotation_z(s_a.hhr.5);
496
497    next.control.position = Vec3::new(s_a.hc.0 - 1.0, s_a.hc.1, s_a.hc.2 - 3.0);
498    next.control.orientation = Quaternion::rotation_x(s_a.hc.3)
499        * Quaternion::rotation_y(s_a.hc.4)
500        * Quaternion::rotation_z(s_a.hc.5);
501}
502
503pub fn twist_back(next: &mut CharacterSkeleton, move1: f32, c: f32, h: f32, b: f32, s: f32) {
504    next.chest.orientation.rotate_z(move1 * c);
505    next.head.orientation.rotate_z(move1 * -h);
506    next.belt.orientation.rotate_z(move1 * -b);
507    next.shorts.orientation.rotate_z(move1 * -s);
508}
509
510pub fn twist_forward(next: &mut CharacterSkeleton, move2: f32, c: f32, h: f32, b: f32, s: f32) {
511    next.chest.orientation.rotate_z(move2 * -c);
512    next.head.orientation.rotate_z(move2 * h);
513    next.belt.orientation.rotate_z(move2 * b);
514    next.shorts.orientation.rotate_z(move2 * s);
515}
516
517pub fn dual_wield_start(next: &mut CharacterSkeleton) {
518    next.main.position = Vec3::new(0.0, 0.0, 0.0);
519    next.main.orientation = Quaternion::rotation_z(0.0);
520    next.second.position = Vec3::new(0.0, 0.0, 0.0);
521    next.second.orientation = Quaternion::rotation_z(0.0);
522
523    next.control_l.position =
524        next.hand_l.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(-4.0, 0.0, 0.0);
525    next.control_l.orientation = Quaternion::lerp(
526        next.hand_l.orientation,
527        Quaternion::rotation_x(PI * -0.5),
528        0.65,
529    );
530    next.hand_l.position = Vec3::new(0.0, -2.0, 0.0);
531    next.hand_l.orientation = Quaternion::rotation_x(PI * 0.5);
532
533    next.control_r.position =
534        next.hand_r.position * Vec3::new(0.5, 0.5, 0.3) + Vec3::new(4.0, 0.0, 0.0);
535    next.control_r.orientation = Quaternion::lerp(
536        next.hand_r.orientation,
537        Quaternion::rotation_x(PI * -0.5),
538        0.65,
539    );
540    next.hand_r.position = Vec3::new(0.0, -2.0, 0.0);
541    next.hand_r.orientation = Quaternion::rotation_x(PI * 0.5);
542}