smpl_gloss_integration/
codec.rs

1use gloss_hecs::{Entity, EntityBuilder};
2use gloss_renderer::scene::Scene;
3use log::info;
4use nd::concatenate;
5use ndarray as nd;
6use smpl_core::{
7    codec::codec::SmplCodec,
8    common::{
9        animation::{AnimWrap, Animation},
10        betas::Betas,
11        metadata::smpl_metadata,
12        pose::Pose,
13        pose_override::PoseOverride,
14        pose_retarget::RetargetPoseYShift,
15        smpl_params::SmplParams,
16    },
17    conversions::{pose_chunked::PoseChunked, pose_remap::PoseRemap},
18};
19use smpl_utils::log;
20use std::cmp::Ordering;
21/// Creates a ``SmplCodec`` from an entity by extracting components from it or
22/// creates a ``gloss_hecs::EntityBuilder`` from the ``SmplCodec``
23pub trait SmplCodecGloss {
24    fn from_entity(entity: &Entity, scene: &Scene, max_texture_size: Option<u32>) -> SmplCodec;
25    fn to_entity_builder(&self) -> EntityBuilder;
26}
27/// Trait implementation for `SmplCodec`
28impl SmplCodecGloss for SmplCodec {
29    #[allow(clippy::too_many_lines)]
30    #[allow(clippy::cast_possible_truncation)]
31    #[allow(clippy::cast_possible_wrap)]
32    fn from_entity(entity: &Entity, scene: &Scene, _max_texture_size: Option<u32>) -> SmplCodec {
33        let mut codec = SmplCodec::default();
34        let smpl_params = scene.get_comp::<&SmplParams>(entity).expect("Entity should have SmplParams component");
35        let smpl_version = smpl_params.smpl_type as i32;
36        let gender = smpl_params.gender as i32;
37        codec.smpl_version = smpl_version;
38        codec.gender = gender;
39        if let Ok(betas) = scene.get_comp::<&Betas>(entity) {
40            codec.shape_parameters = Some(betas.betas.clone());
41        }
42        if scene.world.has::<Pose>(*entity).unwrap() && !scene.world.has::<Animation>(*entity).unwrap() {
43            log!("we are writing a pose in the codec");
44            let pose = scene.get_comp::<&Pose>(entity).unwrap();
45            let metadata = smpl_metadata(&smpl_params.smpl_type);
46            let chunked = PoseChunked::new(&pose, &metadata);
47            codec.body_translation = Some(chunked.global_trans);
48            if chunked.global_orient.is_some() && chunked.body_pose.is_some() {
49                let body_pose_with_root =
50                    concatenate(nd::Axis(0), &[chunked.global_orient.unwrap().view(), chunked.body_pose.unwrap().view()]).unwrap();
51                codec.body_pose = Some(body_pose_with_root.insert_axis(nd::Axis(0)));
52            }
53            if chunked.jaw_pose.is_some() && chunked.left_eye_pose.is_some() && chunked.right_eye_pose.is_some() {
54                let head_pose = concatenate(
55                    nd::Axis(0),
56                    &[
57                        chunked.jaw_pose.unwrap().view(),
58                        chunked.left_eye_pose.unwrap().view(),
59                        chunked.right_eye_pose.unwrap().view(),
60                    ],
61                )
62                .unwrap();
63                codec.head_pose = Some(head_pose.insert_axis(nd::Axis(0)));
64            }
65            if let Some(left_hand_pose) = chunked.left_hand_pose {
66                codec.left_hand_pose = Some(left_hand_pose.insert_axis(nd::Axis(0)));
67            }
68            if let Some(right_hand_pose) = chunked.right_hand_pose {
69                codec.right_hand_pose = Some(right_hand_pose.insert_axis(nd::Axis(0)));
70            }
71        } else if scene.world.has::<Animation>(*entity).unwrap() {
72            log!("we are writing a animation in the codec");
73            let anim = scene.get_comp::<&Animation>(entity).unwrap();
74            let metadata = smpl_metadata(&smpl_params.smpl_type);
75            let nr_frames = anim.num_animation_frames();
76            let mut full_body_translation = nd::Array2::<f32>::zeros((nr_frames, 3));
77            let mut full_body_pose = nd::Array3::<f32>::zeros((nr_frames, metadata.num_body_joints + 1, 3));
78            let mut full_head_pose = nd::Array3::<f32>::zeros((nr_frames, metadata.num_face_joints, 3));
79            let mut full_left_hand_pose = nd::Array3::<f32>::zeros((nr_frames, metadata.num_hand_joints, 3));
80            let mut full_right_hand_pose = nd::Array3::<f32>::zeros((nr_frames, metadata.num_hand_joints, 3));
81            for time_idx in 0..anim.num_animation_frames() {
82                let mut pose = anim.get_pose_at_idx(time_idx);
83                let pose_remap = PoseRemap::new(pose.smpl_type, smpl_params.smpl_type);
84                pose = pose_remap.remap(&pose);
85                if let Ok(ref pose_mask) = scene.get_comp::<&PoseOverride>(entity) {
86                    let mut new_pose_mask = PoseOverride::clone(pose_mask);
87                    pose.apply_mask(&mut new_pose_mask);
88                }
89                if let Ok(ref pose_retarget) = scene.get_comp::<&RetargetPoseYShift>(entity) {
90                    let mut pose_retarget_local = RetargetPoseYShift::clone(pose_retarget);
91                    pose_retarget_local.apply(&mut pose);
92                }
93                let chunked = PoseChunked::new(&pose, &metadata);
94                full_body_translation
95                    .index_axis_mut(nd::Axis(0), time_idx)
96                    .assign(&chunked.global_trans.to_shape(3).unwrap());
97                if chunked.global_orient.is_some() && chunked.body_pose.is_some() {
98                    let body_pose_with_root =
99                        concatenate(nd::Axis(0), &[chunked.global_orient.unwrap().view(), chunked.body_pose.unwrap().view()]).unwrap();
100                    full_body_pose.index_axis_mut(nd::Axis(0), time_idx).assign(&body_pose_with_root);
101                }
102                if chunked.jaw_pose.is_some() && chunked.left_eye_pose.is_some() && chunked.right_eye_pose.is_some() {
103                    let head_pose = concatenate(
104                        nd::Axis(0),
105                        &[
106                            chunked.jaw_pose.unwrap().view(),
107                            chunked.left_eye_pose.unwrap().view(),
108                            chunked.right_eye_pose.unwrap().view(),
109                        ],
110                    )
111                    .unwrap();
112                    full_head_pose.index_axis_mut(nd::Axis(0), time_idx).assign(&head_pose);
113                }
114                if let Some(left_hand_pose) = chunked.left_hand_pose {
115                    full_left_hand_pose.index_axis_mut(nd::Axis(0), time_idx).assign(&left_hand_pose);
116                }
117                if let Some(right_hand_pose) = chunked.right_hand_pose {
118                    full_right_hand_pose.index_axis_mut(nd::Axis(0), time_idx).assign(&right_hand_pose);
119                }
120            }
121            codec.frame_count = nr_frames as i32;
122            codec.frame_rate = Some(anim.config.fps);
123            codec.body_translation = Some(full_body_translation);
124            codec.body_pose = Some(full_body_pose);
125            codec.head_pose = Some(full_head_pose);
126            codec.left_hand_pose = Some(full_left_hand_pose);
127            codec.right_hand_pose = Some(full_right_hand_pose);
128        }
129        codec
130    }
131    fn to_entity_builder(&self) -> EntityBuilder {
132        let mut builder = EntityBuilder::new();
133        let smpl_params = SmplParams::new_from_smpl_codec(self);
134        info!("Found smpl_params in the .smpl file");
135        builder.add(smpl_params);
136        let betas = Betas::new_from_smpl_codec(self);
137        if let Some(betas) = betas {
138            info!("Found betas in the .smpl file");
139            builder.add(betas);
140        }
141        match self.frame_count.cmp(&1) {
142            Ordering::Greater => {
143                let anim = Animation::new_from_smpl_codec(self, AnimWrap::default()).expect("The framecount is >1 so the animation should be valid");
144                info!("Found animation in the .smpl file");
145                builder.add(anim);
146            }
147            Ordering::Equal => {
148                let pose = Pose::new_from_smpl_codec(self).expect("The framecount is =1 so the pose should be valid");
149                info!("Found pose in the .smpl file");
150                builder.add(pose);
151            }
152            Ordering::Less => {}
153        }
154        builder
155    }
156}