ambient_animation/
retargeting.rs1use std::sync::Arc;
2
3use ambient_core::transform::{rotation, translation};
4use ambient_model::{Model, ModelFromUrl};
5use ambient_std::{
6 asset_cache::{AssetCache, AssetKeepalive, AsyncAssetKey, AsyncAssetKeyExt},
7 asset_url::{AnimationAssetType, ModelAssetType, TypedAssetUrl},
8 download_asset::AssetError,
9};
10use anyhow::Context;
11use async_trait::async_trait;
12use serde::{Deserialize, Serialize};
13
14use super::{AnimationClip, AnimationClipFromUrl, AnimationOutputs, AnimationTrack};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17pub enum AnimationRetargeting {
18 None,
20 Skeleton,
22 AnimationScaled {
26 normalize_hip: bool,
28 },
29}
30impl Default for AnimationRetargeting {
31 fn default() -> Self {
32 Self::None
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct AnimationClipRetargetedFromModel {
38 pub clip: TypedAssetUrl<AnimationAssetType>,
39 pub translation_retargeting: AnimationRetargeting,
40 pub retarget_model: Option<TypedAssetUrl<ModelAssetType>>,
41}
42#[async_trait]
43impl AsyncAssetKey<Result<Arc<AnimationClip>, AssetError>> for AnimationClipRetargetedFromModel {
44 fn keepalive(&self) -> AssetKeepalive {
45 AssetKeepalive::Forever
49 }
50 async fn load(self, assets: AssetCache) -> Result<Arc<AnimationClip>, AssetError> {
51 let clip_url: TypedAssetUrl<AnimationAssetType> = self
52 .clip
53 .abs()
54 .context(format!("Expected absolute url, got: {}", self.clip))?
55 .into();
56 let anim_model = ModelFromUrl(clip_url.model_crate().context("Invalid clip url")?.model())
57 .get(&assets)
58 .await
59 .context("Failed to load model")?;
60 let clip = AnimationClipFromUrl::new(clip_url.unwrap_abs(), true)
61 .get(&assets)
62 .await
63 .context("No such clip")?;
64 match self.translation_retargeting {
65 AnimationRetargeting::None => Ok(clip),
66 AnimationRetargeting::Skeleton => {
67 let mut clip = (*clip).clone();
68 clip.tracks
69 .retain(|track| track.outputs.component() != translation());
70 Ok(Arc::new(clip))
71 }
72 AnimationRetargeting::AnimationScaled { normalize_hip } => {
73 let retarget_model_url = self
74 .retarget_model
75 .context("No retarget_model specified")?
76 .abs()
77 .context("Failed to resolve retarget url")?;
78 let retarget_model = ModelFromUrl(retarget_model_url.into())
79 .get(&assets)
80 .await
81 .context("Failed to load retarget model")?;
82 let mut clip = (*clip).clone();
83 let anim_root = anim_model.roots()[0];
84 let _retarget_root = retarget_model.roots()[0];
85 let anim_root_rot = anim_model.0.get(anim_root, rotation()).unwrap_or_default();
86 let retarget_root_rot = retarget_model
87 .0
88 .get(anim_root, rotation())
89 .unwrap_or_default();
90 clip.tracks.retain_mut(|track| {
91 if normalize_hip && track.target.bind_id() == Some("Hips") {
92 let zup = retarget_root_rot.inverse() * anim_root_rot;
93
94 if track.outputs.component() == rotation() {
95 if let AnimationOutputs::Quat { data, .. } = &mut track.outputs {
96 for v in data {
97 *v = zup * *v;
98 }
99 }
100 } else if track.outputs.component() == translation() {
101 if let AnimationOutputs::Vec3 { data, .. } = &mut track.outputs {
102 for v in data {
103 *v = zup * *v;
104 }
105 }
106 }
107 }
108 if track.outputs.component() == translation() {
109 retarget_track(track, &anim_model, &retarget_model).is_some()
110 } else {
111 true
112 }
113 });
114 Ok(Arc::new(clip))
115 }
116 }
117 }
118}
119fn retarget_track(
120 track: &mut AnimationTrack,
121 anim_model: &Model,
122 retarget_model: &Model,
123) -> Option<()> {
124 let bind_id = track.target.bind_id().unwrap();
125 let original = anim_model.get_entity_id_by_bind_id(bind_id).unwrap();
126 let target = retarget_model.get_entity_id_by_bind_id(bind_id)?;
127 let original = anim_model.0.get(original, translation()).unwrap().length();
128 let target = anim_model.0.get(target, translation()).ok()?.length();
129 if target == 0. {
130 return Some(());
131 }
132 let scale = target / original;
133 match &mut track.outputs {
134 AnimationOutputs::Vec3 { data, .. } => {
135 for v in data.iter_mut() {
136 *v *= scale;
137 }
138 }
139 AnimationOutputs::Quat { .. } => unreachable!(),
140 AnimationOutputs::Vec3Field { data, .. } => {
141 for v in data.iter_mut() {
142 *v *= scale;
143 }
144 }
145 }
146 Some(())
147}