1use super::scene::CameraTrack;
2use crate::{
3 common::{
4 pose::Pose,
5 types::{ChunkHeader, FaceType, GltfCompatibilityMode, GltfOutputType, SmplType},
6 },
7 smpl_x::smpl_x,
8};
9use gloss_geometry::geom;
10use gloss_img::dynamic_image::DynImage;
11use gloss_utils::nshare::ToNalgebra;
12use gltf::binary::Header;
13use gltf_json::validation::{Checked::Valid, USize64};
14use gltf_json::{material::AlphaMode, scene::UnitQuaternion, Node};
15use image::imageops::FilterType;
16use image::RgbImage;
17use itertools::izip;
18use log::info;
19use nalgebra as na;
20use nalgebra::DMatrix;
21use ndarray as nd;
22use ndarray::prelude::*;
23use smpl_utils::numerical::batch_rodrigues;
24use smpl_utils::{
25 log,
26 vector::{
27 addv3f, align_to_multiple_of_four, subv3f, to_padded_byte_vector, vec_from_array0_f, vec_from_vec, vec_to_vec, Vector2f, Vector3f, Vector4f,
28 Vector4s,
29 },
30};
31use std::borrow::Cow;
32use std::{
33 f32::consts::PI,
34 io::{Cursor, Write},
35 path::Path,
36};
37use std::{fs, mem};
38#[repr(u32)]
41#[derive(Debug, Clone, Copy)]
42enum PrimitiveAttrIDs {
43 Indices = 0,
44 Positions = 1,
45 Normals = 2,
46 TexCoords = 3,
47 Joints = 4,
48 Weights = 5,
49}
50#[repr(u32)]
52#[derive(Debug, Clone, Copy)]
53enum BufferViewIDs {
54 Index = 0,
55 VertexAttr = 1,
56 InvBindMat = 2,
57 Keyframe = 3,
58 Animation = 4,
59 Deformation = 5,
60}
61#[derive(Copy, Clone, Debug, bytemuck::NoUninit)]
63#[repr(C)]
64struct Vertex {
65 position: [f32; 3],
66 normal: [f32; 3],
67 uv: [f32; 2],
68 joint_index: [u16; 4],
69 joint_weight: [f32; 4],
70}
71#[derive(Clone, Debug)]
73struct GltfTextureInfo {
74 buffer_size: usize,
75 image_data: Vec<u8>,
76 image: gltf_json::image::Image,
77 buffer_view: gltf_json::buffer::View,
78 buffer_index: usize,
79 texture: gltf_json::texture::Texture,
80 sampler: gltf_json::texture::Sampler,
81}
82#[allow(clippy::struct_field_names)]
84struct SmplTextures {
85 diffuse_index: Option<usize>,
86 normals_index: Option<usize>,
87 metalic_roughtness_index: Option<usize>,
88}
89#[derive(Clone, Default, Debug)]
91pub struct PerBodyData {
92 pub diffuse_textures: Option<DynImage>,
93 pub normals_textures: Option<DynImage>,
94 pub metalness_textures: Option<DynImage>,
95 pub roughness_textures: Option<DynImage>,
96 pub positions: Option<DMatrix<f32>>,
97 pub normals: Option<DMatrix<f32>>,
98 pub default_joint_translations: Option<nd::Array2<f32>>,
99 pub body_translation: Option<nd::Array2<f32>>,
100 pub pose: Option<Pose>,
101 pub body_translations: Option<nd::Array2<f32>>,
102 pub body_rotations: Option<nd::Array3<f32>>,
103 pub body_scales: Option<nd::Array2<f32>>,
104 pub per_frame_blend_weights: Option<nd::Array2<f32>>,
105}
106#[derive(Debug, Clone)]
108pub struct GltfCodec {
109 pub num_bodies: usize,
110 pub smpl_type: SmplType,
111 pub gender: i32,
112 pub faces: Option<DMatrix<u32>>,
113 pub uvs: Option<DMatrix<f32>>,
114 pub joint_index: Option<DMatrix<u32>>,
115 pub joint_weight: Option<DMatrix<f32>>,
116 pub default_joint_poses: Option<nd::Array2<f32>>,
117 pub frame_count: Option<usize>,
118 pub keyframe_times: Option<Vec<f32>>,
119 pub morph_targets: Option<nd::Array3<f32>>,
120 pub num_pose_morph_targets: usize,
121 pub num_expression_morph_targets: usize,
122 pub per_body_data: Vec<PerBodyData>,
123 pub camera_track: Option<CameraTrack>,
124}
125impl Default for GltfCodec {
126 fn default() -> Self {
127 Self {
128 num_bodies: 1,
129 smpl_type: SmplType::SmplX,
130 gender: 0,
131 faces: None,
132 uvs: None,
133 joint_index: None,
134 joint_weight: None,
135 default_joint_poses: None,
136 frame_count: None,
137 keyframe_times: None,
138 morph_targets: None,
139 num_pose_morph_targets: 0,
140 num_expression_morph_targets: 0,
141 per_body_data: Vec::new(),
142 camera_track: None,
143 }
144 }
145}
146impl GltfCodec {
147 pub fn to_file(&mut self, name: &str, path: &str, out_type: GltfOutputType, compatibility_mode: GltfCompatibilityMode, face_type: FaceType) {
149 let parent_path = Path::new(path).parent();
150 let file_name = Path::new(path).file_name();
151 let Some(parent_path) = parent_path else {
152 log!("Error: Exporting GLTF - no directory name found: {}", path);
153 return;
154 };
155 let Some(file_name) = file_name else {
156 log!("Error: Exporting GLTF - no file name found: {}", path);
157 return;
158 };
159 let _ = fs::create_dir(parent_path);
160 let target_extension: &str = match out_type {
161 GltfOutputType::Standard => "gltf",
162 GltfOutputType::Binary => "glb",
163 };
164 let file_name_with_suffix = Path::new(file_name).with_extension(target_extension);
165 log!("Exporting GLTF: {}/{}", path, file_name_with_suffix.to_string_lossy());
166 let binary = matches!(out_type, GltfOutputType::Binary);
167 let (buffer_data, root) = self.create_buffer(name, binary, compatibility_mode, face_type);
168 match out_type {
169 GltfOutputType::Standard => {
170 let json_path = parent_path.join(file_name_with_suffix.clone());
171 let bin_path = parent_path.join("buffer0.bin");
172 let writer = fs::File::create(json_path).expect("I/O error");
173 gltf_json::serialize::to_writer_pretty(writer, &root).expect("Serialization error");
174 let bin = to_padded_byte_vector(&buffer_data);
175 let mut writer = fs::File::create(bin_path).expect("I/O error");
176 writer.write_all(&bin).expect("I/O error");
177 info!("Written glTF json + bin to {parent_path:?}");
178 }
179 GltfOutputType::Binary => {
180 let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
181 let mut length = mem::size_of::<Header>() + mem::size_of::<ChunkHeader>() + json_string.len();
182 align_to_multiple_of_four(&mut length);
183 length += mem::size_of::<ChunkHeader>() + buffer_data.len();
184 align_to_multiple_of_four(&mut length);
185 let glb = gltf::binary::Glb {
186 header: gltf::binary::Header {
187 magic: *b"glTF",
188 version: 2,
189 length: length.try_into().expect("file size exceeds binary glTF limit"),
190 },
191 bin: Some(Cow::Owned(buffer_data)),
192 json: Cow::Owned(json_string.into_bytes()),
193 };
194 let glb_path = parent_path.join(file_name_with_suffix.clone());
195 let writer = std::fs::File::create(glb_path.clone()).expect("I/O error");
196 glb.to_writer(writer).expect("glTF binary output error");
197 info!("Written binary glB to {glb_path:?}");
198 }
199 }
200 }
201 pub fn to_buf(&mut self, compatibility_mode: GltfCompatibilityMode, face_type: FaceType) -> Vec<u8> {
203 let (buffer_data, root) = self.create_buffer("Meshcapade Avatar", true, compatibility_mode, face_type);
204 let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
205 let mut length = mem::size_of::<Header>() + mem::size_of::<ChunkHeader>() + json_string.len();
206 align_to_multiple_of_four(&mut length);
207 length += mem::size_of::<ChunkHeader>() + buffer_data.len();
208 align_to_multiple_of_four(&mut length);
209 let glb = gltf::binary::Glb {
210 header: gltf::binary::Header {
211 magic: *b"glTF",
212 version: 2,
213 length: length.try_into().expect("file size exceeds binary glTF limit"),
214 },
215 bin: Some(Cow::Owned(buffer_data)),
216 json: Cow::Owned(json_string.into_bytes()),
217 };
218 glb.to_vec().expect("glTF binary output error")
219 }
220 fn is_animated(&self) -> bool {
221 self.frame_count.is_some()
222 }
223 #[allow(clippy::too_many_lines)]
225 #[allow(clippy::cast_possible_truncation)]
226 #[allow(clippy::cast_possible_wrap)]
227 fn create_buffer(
228 &mut self,
229 name: &str,
230 binary: bool,
231 compatibility_mode: GltfCompatibilityMode,
232 face_type: FaceType,
233 ) -> (Vec<u8>, gltf_json::Root) {
234 assert!(self.faces.is_some(), "GltfCodec: no faces!");
235 assert!(self.uvs.is_some(), "GltfCodec: no uvs!");
236 let mut full_buffer_data = vec![];
237 let mut accessors = vec![];
238 let mut buffers = vec![];
239 let mut buffer_views = vec![];
240 let mut meshes = vec![];
241 let mut nodes = vec![];
242 let mut skins = vec![];
243 let mut materials = vec![];
244 let mut channels = vec![];
245 let mut samplers = vec![];
246 let mut images = vec![];
247 let mut textures = vec![];
248 let mut texture_samplers: Vec<gltf_json::texture::Sampler> = vec![];
249 let mut cameras: Vec<gltf_json::camera::Camera> = vec![];
250 let scene_root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
251 let scene_root_node = Node {
252 name: Some("SceneRoot".to_string()),
253 children: Some(vec![]),
254 ..Default::default()
255 };
256 nodes.push(scene_root_node);
257 if let Some(camera_track) = &self.camera_track {
258 let camera = gltf_json::camera::Camera {
259 name: Some("MoCapadeCamera".to_string()),
260 type_: gltf_json::validation::Checked::Valid(gltf_json::camera::Type::Perspective),
261 perspective: Some(gltf_json::camera::Perspective {
262 yfov: camera_track.yfov,
263 znear: camera_track.znear,
264 zfar: camera_track.zfar,
265 aspect_ratio: camera_track.aspect_ratio,
266 extensions: None,
267 extras: Option::default(),
268 }),
269 orthographic: None,
270 extensions: None,
271 extras: Option::default(),
272 };
273 cameras.push(camera);
274 let camera_track_node = Node {
275 name: Some("AnimatedCamera".to_string()),
276 camera: Some(gltf_json::Index::new(0)),
277 ..Default::default()
278 };
279 let camera_node_idx = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
280 if let Some(ref mut scene_root_node_children) = nodes[0].children {
281 scene_root_node_children.push(gltf_json::Index::new(camera_node_idx));
282 }
283 nodes.push(camera_track_node);
284 }
285 let node_indices: Vec<gltf_json::Index<Node>> = vec![gltf_json::Index::new(scene_root_node_index)];
286 let scene: gltf_json::Scene = gltf_json::Scene {
287 extensions: Option::default(),
288 extras: Option::default(),
289 name: Some(name.to_string()),
290 nodes: node_indices,
291 };
292 let scenes = vec![scene];
293 for body_idx in 0..self.per_body_data.len() {
294 let mut current_body = self.per_body_data[body_idx].clone();
295 if compatibility_mode == GltfCompatibilityMode::Smpl && self.num_pose_morph_targets > 0 {
296 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
297 current_body
298 .per_frame_blend_weights
299 .as_mut()
300 .unwrap()
301 .slice_mut(s![.., 0..num_pose_morph_targets])
302 .mapv_inplace(|elem| (elem + PI) / (2.0 * PI));
303 current_body
304 .per_frame_blend_weights
305 .as_mut()
306 .unwrap()
307 .slice_mut(s![.., num_pose_morph_targets])
308 .assign(&nd::Array1::<f32>::from_elem(self.frame_count.unwrap(), 1.0));
309 }
310 if face_type == FaceType::SmplX && self.num_expression_morph_targets > 0 {
311 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
312 current_body
313 .per_frame_blend_weights
314 .as_mut()
315 .unwrap()
316 .slice_mut(s![
317 ..,
318 self.num_pose_morph_targets..self.num_pose_morph_targets + num_expression_morph_targets
319 ])
320 .mapv_inplace(|elem| (elem + 7.0) / (2.0 * 7.0));
321 current_body
322 .per_frame_blend_weights
323 .as_mut()
324 .unwrap()
325 .slice_mut(s![.., self.num_pose_morph_targets + num_expression_morph_targets])
326 .assign(&nd::Array1::<f32>::from_elem(self.frame_count.unwrap(), 1.0));
327 }
328
329 assert!(current_body.positions.is_some(), "GltfCodec: no vertices for body {body_idx}!");
330 assert!(current_body.normals.is_some(), "GltfCodec: no normals for body {body_idx}!");
331 let mut positions = current_body.positions.clone().unwrap();
332 let normals = current_body.normals.clone().unwrap();
333 let faces = self.faces.as_ref().unwrap();
334 let uvs = self.uvs.as_ref().unwrap();
335 let joint_index = self.joint_index.as_ref().unwrap();
336 let joint_weight = self.joint_weight.as_ref().unwrap();
337 let diffuse_tex = current_body.diffuse_textures.as_ref();
338 let normals_tex = current_body.normals_textures.as_ref();
339 let metalness_tex = current_body.metalness_textures.as_ref();
340 let roughness_tex = current_body.roughness_textures.as_ref();
341 let mut vertex_attributes_array: Vec<Vertex> = vec![];
342 let mut indices_array: Vec<u32> = vec![];
343 let mut inverse_bind_matrices: Vec<f32> = vec![];
344 let face_count = faces.shape().0;
345 let vertex_count = positions.shape().0;
346 let joint_count = current_body.default_joint_translations.as_ref().unwrap().shape()[0];
347 for row in faces.row_iter() {
348 indices_array.extend_from_slice(&[row[0], row[1], row[2]]);
349 }
350 let joint_rotations = batch_rodrigues(self.default_joint_poses.as_ref().unwrap());
351 let mut joint_translations = current_body.default_joint_translations.clone().unwrap();
352 if compatibility_mode == GltfCompatibilityMode::Unreal {
353 let (min, _) = geom::get_bounding_points(&positions, None);
354 let min_vec: Vec<f32> = min.iter().copied().collect();
355 let min_y = min_vec[1];
356 let offset = na::RowVector3::new(0.0, min_y, 0.0);
357 for i in 0..positions.nrows() {
358 let mut row = positions.row_mut(i);
359 row -= offset;
360 }
361 let offset_nd = ndarray::Array1::from_vec(vec![0.0, min_y, 0.0]);
362 for mut row in joint_translations.axis_iter_mut(Axis(0)) {
363 row -= &offset_nd;
364 }
365 current_body.positions = Some(positions.clone());
366 current_body.default_joint_translations = Some(joint_translations.clone());
367 }
368 let metadata = crate::common::metadata::smpl_metadata(&self.smpl_type);
369 let bind_matrices = self.create_bind_matrices(&joint_rotations, &joint_translations, &metadata.joint_parents);
370 let unreal_mapping: [usize; 10] = [0, 0, 0, 8, 7, 0, 21, 21, 20, 0];
371 if compatibility_mode == GltfCompatibilityMode::Unreal {
372 for j_idx in unreal_mapping {
373 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
374 let inverse_rotation_matrix = bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
375 let translation: nd::Array1<f32> = if j_idx == 0 {
376 nd::Array1::from_vec(vec![0.0, 0.0, 0.0])
377 } else {
378 bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned()
379 };
380 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
381 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
382 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
383 inverse_bind_matrix[(3, 3)] = 1.0;
384 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
385 }
386 }
387 for j_idx in 0..joint_count {
388 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
389 let inverse_rotation_matrix = bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
390 let translation: nd::Array1<f32> = bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned();
391 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
392 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
393 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
394 inverse_bind_matrix[(3, 3)] = 1.0;
395 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
396 }
397 let num_extra_joints: usize = if compatibility_mode == GltfCompatibilityMode::Unreal { 10 } else { 0 };
398 for (position, normal, uv, joint_index, joint_weight) in izip!(
399 positions.row_iter(),
400 normals.row_iter(),
401 uvs.row_iter(),
402 joint_index.row_iter(),
403 joint_weight.row_iter(),
404 ) {
405 let jw_sum = joint_weight.iter().sum::<f32>();
406 let indices = [
407 if joint_weight[0] > 0.0 {
408 joint_index[0] + u32::try_from(num_extra_joints).unwrap()
409 } else {
410 0
411 },
412 if joint_weight[1] > 0.0 {
413 joint_index[1] + u32::try_from(num_extra_joints).unwrap()
414 } else {
415 0
416 },
417 if joint_weight[2] > 0.0 {
418 joint_index[2] + u32::try_from(num_extra_joints).unwrap()
419 } else {
420 0
421 },
422 if joint_weight[3] > 0.0 {
423 joint_index[3] + u32::try_from(num_extra_joints).unwrap()
424 } else {
425 0
426 },
427 ]
428 .map(|idx| u16::try_from(idx).expect("Could not convert to u16!"));
429 vertex_attributes_array.push(Vertex {
430 position: Vector3f::new(position[0], position[1], position[2]).into(),
431 normal: Vector3f::new(normal[0], normal[1], normal[2]).into(),
432 uv: Vector2f::new(uv[0], 1.0 - uv[1]).into(),
433 joint_index: Vector4s::new(indices[0], indices[1], indices[2], indices[3]).into(),
434 joint_weight: Vector4f::new(
435 joint_weight[0] / jw_sum,
436 joint_weight[1] / jw_sum,
437 joint_weight[2] / jw_sum,
438 joint_weight[3] / jw_sum,
439 )
440 .into(),
441 });
442 }
443 let mut texture_infos: Vec<GltfTextureInfo> = vec![];
444 let mut smpl_textures = SmplTextures {
445 diffuse_index: None,
446 normals_index: None,
447 metalic_roughtness_index: None,
448 };
449 if let Some(img) = diffuse_tex {
450 let diffuse_tex = self.add_texture(img, texture_infos.len(), "diffuse");
451 if let Some(diffuse_tex) = diffuse_tex {
452 smpl_textures.diffuse_index = Some(texture_infos.len());
453 texture_infos.push(diffuse_tex);
454 }
455 }
456 self.prepare_normals(&mut smpl_textures, &mut texture_infos, normals_tex);
457 self.prepare_metallic_roughness(&mut smpl_textures, &mut texture_infos, metalness_tex, roughness_tex);
458 let mut base_color_texture: Option<gltf_json::texture::Info> = None;
459 let mut normal_texture: Option<gltf_json::material::NormalTexture> = None;
460 let mut metallic_roughness_texture: Option<gltf_json::texture::Info> = None;
461 if let Some(diffuse_texture_index) = smpl_textures.diffuse_index {
462 base_color_texture = Some(gltf_json::texture::Info {
463 index: gltf_json::Index::new(u32::try_from(diffuse_texture_index).expect("Could not convert to u32!")),
464 tex_coord: 0,
465 extensions: None,
466 extras: None,
467 });
468 }
469 if let Some(normal_texture_index) = smpl_textures.normals_index {
470 normal_texture = Some(gltf_json::material::NormalTexture {
471 scale: 1.,
472 index: gltf_json::Index::new(u32::try_from(normal_texture_index).expect("Could not convert to u32!")),
473 tex_coord: 0,
474 extensions: None,
475 extras: None,
476 });
477 }
478 if let Some(metallic_roughness_texture_index) = smpl_textures.metalic_roughtness_index {
479 metallic_roughness_texture = Some(gltf_json::texture::Info {
480 index: gltf_json::Index::new(u32::try_from(metallic_roughness_texture_index).expect("Could not convert to u32!")),
481 tex_coord: 0,
482 extensions: None,
483 extras: None,
484 });
485 }
486 let material = gltf_json::Material {
487 alpha_cutoff: None,
488 alpha_mode: gltf_json::validation::Checked::<AlphaMode>::Valid(AlphaMode::Opaque),
489 double_sided: false,
490 name: Some("SMPL_material".to_string()),
491 pbr_metallic_roughness: gltf_json::material::PbrMetallicRoughness {
492 base_color_factor: gltf_json::material::PbrBaseColorFactor([1., 1., 1., 1.]),
493 base_color_texture,
494 metallic_roughness_texture,
495 ..Default::default()
496 },
497 normal_texture,
498 occlusion_texture: None,
499 emissive_texture: None,
500 emissive_factor: gltf_json::material::EmissiveFactor([0., 0., 0.]),
501 extensions: None,
502 extras: None,
503 };
504 materials.push(material);
505 let mut morph_targets: Option<Vec<gltf_json::mesh::MorphTarget>> = None;
506 if self.num_morph_targets() > 0 && self.is_animated() {
507 let mut morph_target_accessors_start_idx = 7 + self.per_body_data[0].default_joint_translations.as_ref().unwrap().shape()[0] + 4;
508 if compatibility_mode == GltfCompatibilityMode::Unreal {
509 morph_target_accessors_start_idx += 1;
510 }
511 morph_targets = Some(self.create_morph_targets(morph_target_accessors_start_idx));
512 }
513 let primitive_offset = accessors.len() as u32;
514 let primitive = gltf_json::mesh::Primitive {
515 attributes: {
516 let mut map = std::collections::BTreeMap::new();
517 map.insert(
518 Valid(gltf_json::mesh::Semantic::Positions),
519 gltf_json::Index::new(PrimitiveAttrIDs::Positions as u32 + primitive_offset),
520 );
521 map.insert(
522 Valid(gltf_json::mesh::Semantic::Normals),
523 gltf_json::Index::new(PrimitiveAttrIDs::Normals as u32 + primitive_offset),
524 );
525 map.insert(
526 Valid(gltf_json::mesh::Semantic::TexCoords(0)),
527 gltf_json::Index::new(PrimitiveAttrIDs::TexCoords as u32 + primitive_offset),
528 );
529 map.insert(
530 Valid(gltf_json::mesh::Semantic::Joints(0)),
531 gltf_json::Index::new(PrimitiveAttrIDs::Joints as u32 + primitive_offset),
532 );
533 map.insert(
534 Valid(gltf_json::mesh::Semantic::Weights(0)),
535 gltf_json::Index::new(PrimitiveAttrIDs::Weights as u32 + primitive_offset),
536 );
537 map
538 },
539 extensions: Option::default(),
540 extras: Option::default(),
541 indices: Some(gltf_json::Index::new(PrimitiveAttrIDs::Indices as u32 + primitive_offset)),
542 material: Some(gltf_json::Index::new(body_idx as u32)),
543 mode: Valid(gltf_json::mesh::Mode::Triangles),
544 targets: morph_targets,
545 };
546 let mut morph_target_weights: Option<Vec<f32>> = None;
547 if self.num_morph_targets() > 0 && self.is_animated() {
548 morph_target_weights = Some(vec![0.0; self.num_morph_targets()]);
549 }
550 let mesh = gltf_json::Mesh {
551 extensions: Option::default(),
552 extras: Option::default(),
553 name: Some(format!("SMPL_mesh_{body_idx}")),
554 primitives: vec![primitive],
555 weights: morph_target_weights,
556 };
557 meshes.push(mesh);
558 let vertex_data = to_padded_byte_vector(&vertex_attributes_array);
559 let index_data = to_padded_byte_vector(&indices_array);
560 let inv_bind_mat_data = to_padded_byte_vector(&inverse_bind_matrices);
561 let mut per_view_running_offset: [usize; 6] = [0, 0, 0, 0, 0, 0];
562 let current_buffer_view_offset = buffer_views.len() as u32;
563 let current_accessor_offset = accessors.len() as u32;
564 let accessor = self.create_accessors(
565 body_idx,
566 vertex_count,
567 face_count,
568 joint_count,
569 current_buffer_view_offset,
570 &mut per_view_running_offset,
571 num_extra_joints,
572 compatibility_mode,
573 );
574 accessors.extend(accessor);
575 let mut current_buffer_views = vec![];
576 self.create_buffer_views(
577 body_idx as u32,
578 full_buffer_data.len(),
579 vertex_count,
580 face_count,
581 joint_count,
582 num_extra_joints,
583 &mut current_buffer_views,
584 compatibility_mode,
585 );
586 let (buffer_data, composed_buffer_views) = self.compose_buffer_views(
587 body_idx,
588 ¤t_body,
589 current_buffer_views.clone(),
590 index_data.as_slice(),
591 vertex_data.as_slice(),
592 inv_bind_mat_data.as_slice(),
593 &mut texture_infos,
594 compatibility_mode,
595 );
596 full_buffer_data.extend(buffer_data);
597 buffer_views.extend(composed_buffer_views);
598 for texture in texture_infos {
599 images.push(texture.image);
600 textures.push(texture.texture);
601 texture_samplers.push(texture.sampler);
602 }
603 let armature_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
604 let armature_node = Node {
605 name: Some(format!("Armature_{body_idx}")),
606 children: Some(vec![]),
607 ..Default::default()
608 };
609 nodes.push(armature_node);
610 if let Some(ref mut scene_armatures) = nodes[0].children {
611 scene_armatures.push(gltf_json::Index::new(armature_node_index));
612 }
613 let mesh_skin_binding_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
614 let mesh_skin_binding_node = Node {
615 mesh: Some(gltf_json::Index::new(body_idx as u32)),
616 skin: Some(gltf_json::Index::new(body_idx as u32)),
617 name: Some(format!("MeshSkinBinding_{body_idx}")),
618 children: None,
619 ..Default::default()
620 };
621 nodes.push(mesh_skin_binding_node);
622 let root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
623 let mut joints = vec![];
624 if compatibility_mode == GltfCompatibilityMode::Unreal {
625 let root_node = Node {
626 name: Some("root".to_string()),
627 translation: Some([0.0, 0.0, 0.0]),
628 children: Some(vec![]),
629 ..Default::default()
630 };
631 let joint_index = gltf_json::Index::<Node>::new(u32::try_from(nodes.len()).expect("Issue converting Joint idx to u32"));
632 nodes.push(root_node);
633 joints.push(joint_index);
634 let add_empty_node = |nodes: &mut Vec<Node>,
635 joints: &mut Vec<gltf_json::Index<Node>>,
636 name: &str,
637 parent_index: u32,
638 has_children: bool,
639 reference_bone: usize|
640 -> u32 {
641 let relative_parent_idx = parent_index - root_node_index;
642 let node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
643 let unit_quaternion = [0.0, 0.0, 0.0, 1.0];
644 let trans: Vec<f32> = if reference_bone == 0 {
645 vec![0.0, 0.0, 0.0]
646 } else {
647 let trans = vec_from_vec(&joint_translations.row(reference_bone).to_vec());
648 let parent_trans = if unreal_mapping[relative_parent_idx as usize] != 0 {
649 vec_from_vec(&joint_translations.row(unreal_mapping[relative_parent_idx as usize]).to_vec())
650 } else {
651 vec_from_vec(&[0.0, 0.0, 0.0])
652 };
653 vec_to_vec(&subv3f(&trans, &parent_trans))
654 };
655 let translation = [trans[0], trans[1], trans[2]];
656 let new_node = Node {
657 name: Some(name.to_string()),
658 rotation: Some(UnitQuaternion(unit_quaternion)),
659 translation: Some(translation),
660 children: if has_children { Some(vec![]) } else { None },
661 ..Default::default()
662 };
663 if let Some(ref mut parent_children) = nodes[parent_index as usize].children {
664 parent_children.push(gltf_json::Index::new(node_index));
665 }
666 let joint_index = gltf_json::Index::<Node>::new(node_index);
667 nodes.push(new_node);
668 joints.push(joint_index);
669 node_index
670 };
671 add_empty_node(&mut nodes, &mut joints, "center_of_mass", root_node_index, false, 0);
672 let ik_foot_root_index = add_empty_node(&mut nodes, &mut joints, "ik_foot_root", root_node_index, true, 0);
673 add_empty_node(&mut nodes, &mut joints, "ik_foot_r", ik_foot_root_index, false, 8);
674 add_empty_node(&mut nodes, &mut joints, "ik_foot_l", ik_foot_root_index, false, 7);
675 let ik_hand_root_index = add_empty_node(&mut nodes, &mut joints, "ik_hand_root", root_node_index, true, 0);
676 let ik_hand_gun_index = add_empty_node(&mut nodes, &mut joints, "ik_hand_gun", ik_hand_root_index, true, 21);
677 add_empty_node(&mut nodes, &mut joints, "ik_hand_r", ik_hand_gun_index, false, 21);
678 add_empty_node(&mut nodes, &mut joints, "ik_hand_l", ik_hand_gun_index, false, 20);
679 add_empty_node(&mut nodes, &mut joints, "interaction", root_node_index, false, 0);
680 }
681 let skeleton_root_index = self.add_skin(
682 format!("Skin_{body_idx}"),
683 ¤t_body,
684 armature_node_index,
685 current_accessor_offset,
686 &mut nodes,
687 &mut skins,
688 &mut joints,
689 compatibility_mode,
690 );
691 if compatibility_mode == GltfCompatibilityMode::Unreal {
692 if let Some(ref mut root) = nodes[root_node_index as usize].children {
693 root.push(skeleton_root_index);
694 }
695 }
696 if let Some(ref mut armature_children) = nodes[armature_node_index as usize].children {
697 armature_children.push(gltf_json::Index::new(mesh_skin_binding_node_index));
698 armature_children.push(gltf_json::Index::new(root_node_index));
699 }
700 if self.is_animated() {
701 let animation_channels = self.create_animation_channels(
702 joint_count,
703 root_node_index,
704 skeleton_root_index.value(),
705 samplers.len(),
706 compatibility_mode,
707 );
708 let animation_samplers = self.create_animation_samplers(joint_count, current_accessor_offset, compatibility_mode);
709 channels.extend(animation_channels);
710 samplers.extend(animation_samplers);
711 }
712 }
713 if self.camera_track.is_some() {
714 let (cam_track_buffer_views, cam_track_buffer_data) = self.create_camera_animation_buffer_views(&mut full_buffer_data.len()).unwrap();
715 let cam_track_accessors = self.create_camera_animation_accessors(buffer_views.len() as u32).unwrap();
716 let (cam_track_channels, cam_track_samplers) = self
717 .create_camera_animation_channels_and_samplers(accessors.len() as u32, 1, samplers.len() as u32)
718 .unwrap();
719 buffer_views.extend(cam_track_buffer_views);
720 full_buffer_data.extend(cam_track_buffer_data);
721 accessors.extend(cam_track_accessors);
722 channels.extend(cam_track_channels);
723 samplers.extend(cam_track_samplers);
724 }
725 let buffer = gltf_json::Buffer {
726 byte_length: USize64::from(full_buffer_data.len()),
727 extensions: Option::default(),
728 extras: Option::default(),
729 name: Some("scene_buffer".to_string()),
730 uri: if binary { None } else { Some("buffer0.bin".into()) },
731 };
732 buffers.push(buffer);
733 let mut animations: Vec<gltf_json::Animation> = vec![];
734 if self.is_animated() {
735 let animation = gltf_json::Animation {
736 extensions: Option::default(),
737 extras: Option::default(),
738 channels,
739 name: Some("Scene_animation".to_string()),
740 samplers,
741 };
742 animations.push(animation);
743 }
744 let root = gltf_json::Root {
745 accessors,
746 animations,
747 buffers,
748 buffer_views,
749 cameras,
750 images,
751 materials,
752 meshes,
753 nodes,
754 samplers: texture_samplers,
755 scenes,
756 skins,
757 textures,
758 ..Default::default()
759 };
760 (full_buffer_data, root)
761 }
762 #[allow(clippy::too_many_arguments)]
764 fn create_buffer_views(
765 &self,
766 body_idx: u32,
767 mut running_offset: usize,
768 vertex_count: usize,
769 face_count: usize,
770 joint_count: usize,
771 num_extra_joints: usize,
772 buffer_views: &mut Vec<gltf_json::buffer::View>,
773 compatibility_mode: GltfCompatibilityMode,
774 ) {
775 let index_buffer_size = face_count * 3 * mem::size_of::<u32>();
776 let index_buffer_view = gltf_json::buffer::View {
777 buffer: gltf_json::Index::new(0),
778 byte_length: USize64::from(index_buffer_size),
779 byte_offset: Some(USize64::from(running_offset)),
780 byte_stride: None,
781 extensions: Option::default(),
782 extras: Option::default(),
783 name: Some(format!("index_buffer_view_{body_idx}")),
784 target: Some(Valid(gltf_json::buffer::Target::ElementArrayBuffer)),
785 };
786 buffer_views.push(index_buffer_view);
787 running_offset += index_buffer_size;
788 let vertex_buffer_size = vertex_count * mem::size_of::<Vertex>();
789 let vertex_buffer_view = gltf_json::buffer::View {
790 buffer: gltf_json::Index::new(0),
791 byte_length: USize64::from(vertex_buffer_size),
792 byte_offset: Some(USize64::from(running_offset)),
793 byte_stride: Some(gltf_json::buffer::Stride(mem::size_of::<Vertex>())),
794 extensions: Option::default(),
795 extras: Option::default(),
796 name: Some(format!("vertex_buffer_view_{body_idx}")),
797 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
798 };
799 buffer_views.push(vertex_buffer_view);
800 running_offset += vertex_buffer_size;
801 let inv_bind_matrix_buffer_size = (joint_count + num_extra_joints) * 16 * mem::size_of::<f32>();
802 let inverse_bind_mat_buffer_view = gltf_json::buffer::View {
803 buffer: gltf_json::Index::new(0),
804 byte_length: USize64::from(inv_bind_matrix_buffer_size),
805 byte_offset: Some(USize64::from(running_offset)),
806 byte_stride: None,
807 extensions: Option::default(),
808 extras: Option::default(),
809 name: Some(format!("inv_bind_matrix_buffer_view_{body_idx}")),
810 target: None,
811 };
812 buffer_views.push(inverse_bind_mat_buffer_view);
813 running_offset += inv_bind_matrix_buffer_size;
814 if self.is_animated() {
815 let rotation_animation_buffer_size = self.frame_count.unwrap() * 4 * mem::size_of::<f32>();
816 let translation_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
817 let scale_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
818 let animation_buffer_views = self.create_animation_buffer_views(
819 body_idx,
820 joint_count,
821 rotation_animation_buffer_size,
822 translation_animation_buffer_size,
823 scale_animation_buffer_size,
824 &mut running_offset,
825 compatibility_mode,
826 );
827 buffer_views.extend(animation_buffer_views);
828 if self.num_morph_targets() > 0 && body_idx == 0 {
829 let morph_target_buffer_size = vertex_count * 3 * mem::size_of::<f32>();
830 let morph_target_buffer_views = self.create_morph_target_buffer_views(morph_target_buffer_size, &mut running_offset);
831 buffer_views.extend(morph_target_buffer_views);
832 }
833 }
834 }
835 #[allow(clippy::too_many_arguments)]
837 fn create_animation_buffer_views(
838 &self,
839 body_idx: u32,
840 joint_count: usize,
841 rotation_buffer_size: usize,
842 translation_buffer_size: usize,
843 scale_buffer_size: usize,
844 running_offset: &mut usize,
845 compatibility_mode: GltfCompatibilityMode,
846 ) -> Vec<gltf_json::buffer::View> {
847 let mut animation_buffer_views: Vec<gltf_json::buffer::View> = vec![];
848 let keyframe_buffer_size = self.frame_count.unwrap() * mem::size_of::<f32>();
849 let keyframe_buffer_view = gltf_json::buffer::View {
850 buffer: gltf_json::Index::new(0),
851 byte_length: USize64::from(keyframe_buffer_size),
852 byte_offset: Some(USize64::from(*running_offset)),
853 byte_stride: None,
854 extensions: Option::default(),
855 extras: Option::default(),
856 name: Some(format!("keyframe_buffer_view_{body_idx}")),
857 target: None,
858 };
859 animation_buffer_views.push(keyframe_buffer_view);
860 *running_offset += keyframe_buffer_size;
861 for j_idx in 0..joint_count {
862 let buffer_view_name = format!("joint_{j_idx}_animations_buffer_view_{body_idx}");
863 let animation_buffer_view = gltf_json::buffer::View {
864 buffer: gltf_json::Index::new(0),
865 byte_length: USize64::from(rotation_buffer_size),
866 byte_offset: Some(USize64::from(*running_offset)),
867 byte_stride: None,
868 extensions: Option::default(),
869 extras: Option::default(),
870 name: Some(buffer_view_name),
871 target: None,
872 };
873 animation_buffer_views.push(animation_buffer_view);
874 *running_offset += rotation_buffer_size;
875 }
876 let buffer_view_name = format!("root_translation_animations_buffer_view_{body_idx}");
877 let animation_buffer_view = gltf_json::buffer::View {
878 buffer: gltf_json::Index::new(0),
879 byte_length: USize64::from(translation_buffer_size),
880 byte_offset: Some(USize64::from(*running_offset)),
881 byte_stride: None,
882 extensions: Option::default(),
883 extras: Option::default(),
884 name: Some(buffer_view_name),
885 target: None,
886 };
887 animation_buffer_views.push(animation_buffer_view);
888 *running_offset += translation_buffer_size;
889 let buffer_view_name = format!("root_scale_animations_buffer_view_{body_idx}");
890 let animation_buffer_view = gltf_json::buffer::View {
891 buffer: gltf_json::Index::new(0),
892 byte_length: USize64::from(scale_buffer_size),
893 byte_offset: Some(USize64::from(*running_offset)),
894 byte_stride: None,
895 extensions: Option::default(),
896 extras: Option::default(),
897 name: Some(buffer_view_name),
898 target: None,
899 };
900 animation_buffer_views.push(animation_buffer_view);
901 *running_offset += scale_buffer_size;
902 if compatibility_mode == GltfCompatibilityMode::Unreal {
903 let buffer_view_name = format!("pelvis_rel_translation_animations_buffer_view_{body_idx}");
904 let animation_buffer_view = gltf_json::buffer::View {
905 buffer: gltf_json::Index::new(0),
906 byte_length: USize64::from(translation_buffer_size),
907 byte_offset: Some(USize64::from(*running_offset)),
908 byte_stride: None,
909 extensions: Option::default(),
910 extras: Option::default(),
911 name: Some(buffer_view_name),
912 target: None,
913 };
914 animation_buffer_views.push(animation_buffer_view);
915 *running_offset += translation_buffer_size;
916 }
917 if self.num_morph_targets() > 0 {
918 let morph_weights_buffer_size = self.frame_count.unwrap() * self.num_morph_targets() * mem::size_of::<f32>();
919 let buffer_view_name = format!("morph_target_weights_{body_idx}");
920 let morph_weights_buffer_view = gltf_json::buffer::View {
921 buffer: gltf_json::Index::new(0),
922 byte_length: USize64::from(morph_weights_buffer_size),
923 byte_offset: Some(USize64::from(*running_offset)),
924 byte_stride: None,
925 extensions: Option::default(),
926 extras: Option::default(),
927 name: Some(buffer_view_name),
928 target: None,
929 };
930 animation_buffer_views.push(morph_weights_buffer_view);
931 *running_offset += morph_weights_buffer_size;
932 }
933 animation_buffer_views
934 }
935 fn create_morph_target_buffer_views(&self, morph_target_buffer_size: usize, running_offset: &mut usize) -> Vec<gltf_json::buffer::View> {
937 let mut morph_targets_buffer_views: Vec<gltf_json::buffer::View> = vec![];
938 for morph_target_idx in 0..self.num_morph_targets() {
939 let buffer_view_name = format!("morph_{morph_target_idx}_buffer_view");
940 let morph_target_buffer_view = gltf_json::buffer::View {
941 buffer: gltf_json::Index::new(0),
942 byte_length: USize64::from(morph_target_buffer_size),
943 byte_offset: Some(USize64::from(*running_offset)),
944 byte_stride: None,
945 extensions: Option::default(),
946 extras: Option::default(),
947 name: Some(buffer_view_name),
948 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
949 };
950 morph_targets_buffer_views.push(morph_target_buffer_view);
951 *running_offset += morph_target_buffer_size;
952 }
953 morph_targets_buffer_views
954 }
955 #[allow(clippy::too_many_lines)]
957 #[allow(clippy::too_many_arguments)]
958 fn create_accessors(
959 &self,
960 body_idx: usize,
961 vertex_count: usize,
962 face_count: usize,
963 joint_count: usize,
964 current_buffer_view_offset: u32,
965 per_view_running_offset: &mut [usize; 6],
966 num_extra_joints: usize,
967 compatibility_mode: GltfCompatibilityMode,
968 ) -> Vec<gltf_json::Accessor> {
969 let (min, max) = geom::get_bounding_points(self.per_body_data[body_idx].positions.as_ref().unwrap(), None);
970 let (min_vec, max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
971 let mut accessors: Vec<gltf_json::Accessor> = vec![];
972 let indices = gltf_json::Accessor {
973 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Index as u32 + current_buffer_view_offset)),
974 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Index as usize])),
975 count: USize64::from(face_count * 3),
976 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U32)),
977 extensions: Option::default(),
978 extras: Option::default(),
979 type_: Valid(gltf_json::accessor::Type::Scalar),
980 min: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().min()]))),
981 max: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().max()]))),
982 name: Some(format!("index_accessor_{body_idx}")),
983 normalized: false,
984 sparse: None,
985 };
986 accessors.push(indices);
987 let position_element_size = 3 * mem::size_of::<f32>();
988 let positions = gltf_json::Accessor {
989 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
990 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
991 count: USize64::from(vertex_count),
992 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
993 extensions: Option::default(),
994 extras: Option::default(),
995 type_: Valid(gltf_json::accessor::Type::Vec3),
996 min: Some(gltf_json::Value::from(min_vec)),
997 max: Some(gltf_json::Value::from(max_vec)),
998 name: Some(format!("position_accessor_{body_idx}")),
999 normalized: false,
1000 sparse: None,
1001 };
1002 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += position_element_size;
1003 accessors.push(positions);
1004 let normal_element_size = 3 * mem::size_of::<f32>();
1005 let normals = gltf_json::Accessor {
1006 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1007 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1008 count: USize64::from(vertex_count),
1009 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1010 extensions: Option::default(),
1011 extras: Option::default(),
1012 type_: Valid(gltf_json::accessor::Type::Vec3),
1013 min: None,
1014 max: None,
1015 name: Some(format!("normal_accessor_{body_idx}")),
1016 normalized: false,
1017 sparse: None,
1018 };
1019 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += normal_element_size;
1020 accessors.push(normals);
1021 let uv_element_size = 2 * mem::size_of::<f32>();
1022 let uvs = gltf_json::Accessor {
1023 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1024 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1025 count: USize64::from(vertex_count),
1026 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1027 extensions: Option::default(),
1028 extras: Option::default(),
1029 type_: Valid(gltf_json::accessor::Type::Vec2),
1030 min: None,
1031 max: None,
1032 name: Some("uv_accessor".to_string()),
1033 normalized: false,
1034 sparse: None,
1035 };
1036 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += uv_element_size;
1037 accessors.push(uvs);
1038 let joint_index_element_size = 4 * mem::size_of::<u16>();
1039 let joint_indices = gltf_json::Accessor {
1040 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1041 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1042 count: USize64::from(vertex_count),
1043 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U16)),
1044 extensions: Option::default(),
1045 extras: Option::default(),
1046 type_: Valid(gltf_json::accessor::Type::Vec4),
1047 min: None,
1048 max: None,
1049 name: Some("joint_index_accessor".to_string()),
1050 normalized: false,
1051 sparse: None,
1052 };
1053 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_index_element_size;
1054 accessors.push(joint_indices);
1055 let joint_weight_element_size = 4 * mem::size_of::<f32>();
1056 let joint_weights = gltf_json::Accessor {
1057 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1058 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1059 count: USize64::from(vertex_count),
1060 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1061 extensions: Option::default(),
1062 extras: Option::default(),
1063 type_: Valid(gltf_json::accessor::Type::Vec4),
1064 min: None,
1065 max: None,
1066 name: Some("joint_index_accessor".to_string()),
1067 normalized: false,
1068 sparse: None,
1069 };
1070 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_weight_element_size;
1071 accessors.push(joint_weights);
1072 let inv_bind_matrices = gltf_json::Accessor {
1073 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::InvBindMat as u32 + current_buffer_view_offset)),
1074 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::InvBindMat as usize])),
1075 count: USize64::from(joint_count + num_extra_joints),
1076 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1077 extensions: Option::default(),
1078 extras: Option::default(),
1079 type_: Valid(gltf_json::accessor::Type::Mat4),
1080 min: None,
1081 max: None,
1082 name: Some("inv_bind_matrices_accessor".to_string()),
1083 normalized: false,
1084 sparse: None,
1085 };
1086 accessors.push(inv_bind_matrices);
1087 if self.is_animated() {
1088 let animation_accessors =
1089 self.create_animation_accessors(joint_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1090 accessors.extend(animation_accessors);
1091 if self.num_morph_targets() > 0 && body_idx == 0 {
1092 let morph_target_accessors =
1093 self.create_morph_target_accessors(vertex_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1094 accessors.extend(morph_target_accessors);
1095 }
1096 }
1097 accessors
1098 }
1099 #[allow(clippy::too_many_lines)]
1101 fn create_animation_accessors(
1102 &self,
1103 joint_count: usize,
1104 current_buffer_view_offset: u32,
1105 per_view_running_offset: &mut [usize; 6],
1106 compatibility_mode: GltfCompatibilityMode,
1107 ) -> Vec<gltf_json::Accessor> {
1108 let mut animation_accessors: Vec<gltf_json::Accessor> = vec![];
1109 let min_keyframe = self
1110 .keyframe_times
1111 .as_ref()
1112 .expect("keyframe_times should exist")
1113 .iter()
1114 .copied()
1115 .min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1116 .expect("keyframe_times should have elements in the vector");
1117 let max_keyframe = self
1118 .keyframe_times
1119 .as_ref()
1120 .unwrap()
1121 .iter()
1122 .copied()
1123 .max_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1124 .unwrap();
1125 let keyframe_times = gltf_json::Accessor {
1126 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Keyframe as u32 + current_buffer_view_offset)),
1127 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Keyframe as usize])),
1128 count: USize64::from(self.frame_count.unwrap()),
1129 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1130 extensions: Option::default(),
1131 extras: Option::default(),
1132 type_: Valid(gltf_json::accessor::Type::Scalar),
1133 min: Some(gltf_json::Value::from(Vec::from([min_keyframe]))),
1134 max: Some(gltf_json::Value::from(Vec::from([max_keyframe]))),
1135 name: Some("keyframes_accessor".to_string()),
1136 normalized: false,
1137 sparse: None,
1138 };
1139 animation_accessors.push(keyframe_times);
1140 let mut running_buffer_view = BufferViewIDs::Animation as u32 + current_buffer_view_offset;
1141 for j_idx in 0..joint_count {
1142 let accessor_name = format!("joint_{j_idx}_animations_accessor");
1143 let joint_animation_accessor = gltf_json::Accessor {
1144 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1145 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1146 count: USize64::from(self.frame_count.unwrap()),
1147 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1148 extensions: Option::default(),
1149 extras: Option::default(),
1150 type_: Valid(gltf_json::accessor::Type::Vec4),
1151 min: None,
1152 max: None,
1153 name: Some(accessor_name),
1154 normalized: false,
1155 sparse: None,
1156 };
1157 animation_accessors.push(joint_animation_accessor);
1158 running_buffer_view += 1;
1159 }
1160 let accessor_name = "root_translation_animations_accessor".to_string();
1161 let body_animation_accessor = gltf_json::Accessor {
1162 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1163 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1164 count: USize64::from(self.frame_count.unwrap()),
1165 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1166 extensions: Option::default(),
1167 extras: Option::default(),
1168 type_: Valid(gltf_json::accessor::Type::Vec3),
1169 min: None,
1170 max: None,
1171 name: Some(accessor_name),
1172 normalized: false,
1173 sparse: None,
1174 };
1175 animation_accessors.push(body_animation_accessor);
1176 running_buffer_view += 1;
1177 let accessor_name = "root_scale_animations_accessor".to_string();
1178 let vis_animation_accessor = gltf_json::Accessor {
1179 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1180 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1181 count: USize64::from(self.frame_count.unwrap()),
1182 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1183 extensions: Option::default(),
1184 extras: Option::default(),
1185 type_: Valid(gltf_json::accessor::Type::Vec3),
1186 min: None,
1187 max: None,
1188 name: Some(accessor_name),
1189 normalized: false,
1190 sparse: None,
1191 };
1192 animation_accessors.push(vis_animation_accessor);
1193 running_buffer_view += 1;
1194 if compatibility_mode == GltfCompatibilityMode::Unreal {
1195 let accessor_name = "pelvis_rel_translation_animations_accessor".to_string();
1196 let pelvis_animation_accessor = gltf_json::Accessor {
1197 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1198 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1199 count: USize64::from(self.frame_count.unwrap()),
1200 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1201 extensions: Option::default(),
1202 extras: Option::default(),
1203 type_: Valid(gltf_json::accessor::Type::Vec3),
1204 min: None,
1205 max: None,
1206 name: Some(accessor_name),
1207 normalized: false,
1208 sparse: None,
1209 };
1210 animation_accessors.push(pelvis_animation_accessor);
1211 running_buffer_view += 1;
1212 }
1213 if self.num_morph_targets() > 0 {
1214 let accessor_name = "morph_targets_weights_accessor".to_string();
1215 let morph_targets_weights_accessor = gltf_json::Accessor {
1216 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1217 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1218 count: USize64::from(self.frame_count.unwrap() * self.num_morph_targets()),
1219 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1220 extensions: Option::default(),
1221 extras: Option::default(),
1222 type_: Valid(gltf_json::accessor::Type::Scalar),
1223 min: None,
1224 max: None,
1225 name: Some(accessor_name),
1226 normalized: false,
1227 sparse: None,
1228 };
1229 animation_accessors.push(morph_targets_weights_accessor);
1230 running_buffer_view += 1;
1231 }
1232 per_view_running_offset[BufferViewIDs::Animation as usize] += running_buffer_view as usize;
1233 animation_accessors
1234 }
1235 fn create_morph_target_accessors(
1237 &self,
1238 vertex_count: usize,
1239 current_buffer_view_offset: u32,
1240 per_view_running_offset: &mut [usize; 6],
1241 compatibility_mode: GltfCompatibilityMode,
1242 ) -> Vec<gltf_json::Accessor> {
1243 let mut morph_target_accessors: Vec<gltf_json::Accessor> = vec![];
1244 let mut running_buffer_view = u32::try_from(per_view_running_offset[BufferViewIDs::Animation as usize]).expect("Could not convert to U32!")
1245 + current_buffer_view_offset;
1246 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
1247 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
1248 for morph_target_idx in 0..self.num_morph_targets() {
1249 let accessor_name = format!("morph_{morph_target_idx}_accessor");
1250 let current_morph_target = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]);
1251 let current_morph_target_na = current_morph_target.to_owned().clone().into_nalgebra();
1252 let (min, max) = geom::get_bounding_points(¤t_morph_target_na, None);
1253 let (mut min_vec, mut max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1254 if compatibility_mode == GltfCompatibilityMode::Smpl && (morph_target_idx < num_pose_morph_targets) {
1255 max_vec = max_vec.iter().map(|x| x * 2.0 * PI).collect();
1256 min_vec = min_vec.iter().map(|x| x * 2.0 * PI).collect();
1257 }
1258 if compatibility_mode == GltfCompatibilityMode::Smpl
1259 && (morph_target_idx > num_pose_morph_targets && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets)
1260 {
1261 max_vec = max_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1262 min_vec = min_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1263 }
1264 let morph_target_accessor = gltf_json::Accessor {
1265 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1266 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Deformation as usize])),
1267 count: USize64::from(vertex_count),
1268 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1269 extensions: Option::default(),
1270 extras: Option::default(),
1271 type_: Valid(gltf_json::accessor::Type::Vec3),
1272 min: Some(gltf_json::Value::from(min_vec)),
1273 max: Some(gltf_json::Value::from(max_vec)),
1274 name: Some(accessor_name),
1275 normalized: false,
1276 sparse: None,
1277 };
1278 morph_target_accessors.push(morph_target_accessor);
1279 running_buffer_view += 1;
1280 }
1281 per_view_running_offset[BufferViewIDs::Deformation as usize] += running_buffer_view as usize;
1282 morph_target_accessors
1283 }
1284 #[allow(clippy::cast_possible_truncation)]
1286 fn create_animation_channels(
1287 &self,
1288 joint_count: usize,
1289 root_idx: u32,
1290 skeleton_root_idx: usize,
1291 sampler_start_idx: usize,
1292 compatibility_mode: GltfCompatibilityMode,
1293 ) -> Vec<gltf_json::animation::Channel> {
1294 let mut animation_channels: Vec<gltf_json::animation::Channel> = vec![];
1295 let mut sampler_idx = sampler_start_idx;
1296 for j_idx in 0..joint_count {
1297 let animation_target = gltf_json::animation::Target {
1298 extensions: Option::default(),
1299 extras: Option::default(),
1300 node: gltf_json::Index::new(u32::try_from(j_idx + skeleton_root_idx).expect("Could not convert to u32!")),
1301 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Rotation),
1302 };
1303 let channel = gltf_json::animation::Channel {
1304 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1305 target: animation_target,
1306 extensions: Option::default(),
1307 extras: Option::default(),
1308 };
1309 animation_channels.push(channel);
1310 sampler_idx += 1;
1311 }
1312 let animation_target = gltf_json::animation::Target {
1313 extensions: Option::default(),
1314 extras: Option::default(),
1315 node: gltf_json::Index::new(root_idx),
1316 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1317 };
1318 let channel = gltf_json::animation::Channel {
1319 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1320 target: animation_target,
1321 extensions: Option::default(),
1322 extras: Option::default(),
1323 };
1324 animation_channels.push(channel);
1325 sampler_idx += 1;
1326 let animation_target = gltf_json::animation::Target {
1327 extensions: Option::default(),
1328 extras: Option::default(),
1329 node: gltf_json::Index::new(root_idx),
1330 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Scale),
1331 };
1332 let channel = gltf_json::animation::Channel {
1333 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1334 target: animation_target,
1335 extensions: Option::default(),
1336 extras: Option::default(),
1337 };
1338 animation_channels.push(channel);
1339 sampler_idx += 1;
1340 let mesh_skin_binding_node_idx = root_idx - 1;
1341 if compatibility_mode == GltfCompatibilityMode::Unreal {
1342 let animation_target = gltf_json::animation::Target {
1343 extensions: Option::default(),
1344 extras: Option::default(),
1345 node: gltf_json::Index::new(u32::try_from(skeleton_root_idx).expect("Could not convert to u32!")),
1346 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1347 };
1348 let channel = gltf_json::animation::Channel {
1349 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1350 target: animation_target,
1351 extensions: Option::default(),
1352 extras: Option::default(),
1353 };
1354 animation_channels.push(channel);
1355 sampler_idx += 1;
1356 }
1357 if self.num_morph_targets() > 0 {
1358 let mtw_animation_target = gltf_json::animation::Target {
1359 extensions: Option::default(),
1360 extras: Option::default(),
1361 node: gltf_json::Index::new(mesh_skin_binding_node_idx),
1362 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::MorphTargetWeights),
1363 };
1364 let channel = gltf_json::animation::Channel {
1365 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1366 target: mtw_animation_target,
1367 extensions: Option::default(),
1368 extras: Option::default(),
1369 };
1370 animation_channels.push(channel);
1371 }
1372 animation_channels
1373 }
1374 fn create_animation_samplers(
1376 &self,
1377 joint_count: usize,
1378 current_buffer_view_offset: u32,
1379 compatibility_mode: GltfCompatibilityMode,
1380 ) -> Vec<gltf_json::animation::Sampler> {
1381 let mut animation_samplers: Vec<gltf_json::animation::Sampler> = vec![];
1382 let mut current_accessor = 8 + current_buffer_view_offset;
1383 for _ in 0..joint_count {
1384 let sampler = gltf_json::animation::Sampler {
1385 extensions: Option::default(),
1386 extras: Option::default(),
1387 input: gltf_json::Index::new(7 + current_buffer_view_offset),
1388 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
1389 output: gltf_json::Index::new(current_accessor),
1390 };
1391 animation_samplers.push(sampler);
1392 current_accessor += 1;
1393 }
1394 let sampler = gltf_json::animation::Sampler {
1395 extensions: Option::default(),
1396 extras: Option::default(),
1397 input: gltf_json::Index::new(7 + current_buffer_view_offset),
1398 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
1399 output: gltf_json::Index::new(current_accessor),
1400 };
1401 animation_samplers.push(sampler);
1402 current_accessor += 1;
1403 let sampler = gltf_json::animation::Sampler {
1404 extensions: Option::default(),
1405 extras: Option::default(),
1406 input: gltf_json::Index::new(7 + current_buffer_view_offset),
1407 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Step),
1408 output: gltf_json::Index::new(current_accessor),
1409 };
1410 animation_samplers.push(sampler);
1411 current_accessor += 1;
1412 if compatibility_mode == GltfCompatibilityMode::Unreal {
1413 let sampler = gltf_json::animation::Sampler {
1414 extensions: Option::default(),
1415 extras: Option::default(),
1416 input: gltf_json::Index::new(7 + current_buffer_view_offset),
1417 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
1418 output: gltf_json::Index::new(current_accessor),
1419 };
1420 animation_samplers.push(sampler);
1421 current_accessor += 1;
1422 }
1423 if self.num_morph_targets() > 0 {
1424 let sampler = gltf_json::animation::Sampler {
1425 extensions: Option::default(),
1426 extras: Option::default(),
1427 input: gltf_json::Index::new(7 + current_buffer_view_offset),
1428 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
1429 output: gltf_json::Index::new(current_accessor),
1430 };
1431 animation_samplers.push(sampler);
1432 }
1433 animation_samplers
1434 }
1435 pub fn create_morph_targets(&self, pose_dirs_accessors_start_idx: usize) -> Vec<gltf_json::mesh::MorphTarget> {
1437 let mut pose_dirs_morph_targets: Vec<gltf_json::mesh::MorphTarget> = vec![];
1438 let mut running_pose_dirs_accessor = u32::try_from(pose_dirs_accessors_start_idx).expect("Not able to convert to u32");
1439 for _ in 0..self.num_morph_targets() {
1440 let morph_target = gltf_json::mesh::MorphTarget {
1441 positions: Some(gltf_json::Index::new(running_pose_dirs_accessor)),
1442 normals: None,
1443 tangents: None,
1444 };
1445 pose_dirs_morph_targets.push(morph_target);
1446 running_pose_dirs_accessor += 1;
1447 }
1448 pose_dirs_morph_targets
1449 }
1450 pub fn create_bind_matrices(&self, rot_mat: &nd::Array3<f32>, joint_trans: &nd::Array2<f32>, joint_parents: &[u32]) -> nd::Array3<f32> {
1452 assert!(
1453 rot_mat.shape()[0] == joint_trans.shape()[0],
1454 "Number of rotation matrices dont match number of translation matrices!"
1455 );
1456 let num_joints = rot_mat.shape()[0];
1457 let mut bind_matrices = ndarray::Array3::<f32>::zeros((num_joints, 4, 4));
1458 bind_matrices.slice_mut(s![0, 0..3, 0..3]).assign(&rot_mat.slice(s![0, .., ..]));
1459 bind_matrices.slice_mut(s![0, 0..3, 3]).assign(&joint_trans.slice(s![0, ..]));
1460 bind_matrices[[0, 3, 3]] = 1.0;
1461 for j_idx in 1..num_joints {
1462 let parent_index = joint_parents[j_idx] as usize;
1463 let parent_transform = bind_matrices.index_axis(nd::Axis(0), parent_index);
1464 let mut local_transform = ndarray::Array2::<f32>::zeros((4, 4));
1465 local_transform.slice_mut(s![0..3, 0..3]).assign(&rot_mat.slice(s![j_idx, .., ..]));
1466 let local_translation = Array::from_vec(vec_to_vec(&compute_local_translation(j_idx, joint_parents, joint_trans)));
1467 local_transform.slice_mut(s![0..3, 3]).assign(&local_translation);
1468 local_transform[[3, 3]] = 1.0;
1469 let global_transform = parent_transform.dot(&local_transform);
1470 bind_matrices.slice_mut(s![j_idx, .., ..]).assign(&global_transform);
1471 }
1472 bind_matrices
1473 }
1474 pub fn create_animation_data(&self, current_body: &PerBodyData, compatibility_mode: GltfCompatibilityMode) -> Vec<u8> {
1476 let mut animation_data: Vec<u8> = vec![];
1477 let keyframe_data = to_padded_byte_vector(self.keyframe_times.as_ref().unwrap());
1478 let rotation_animation_data = current_body.body_rotations.as_ref().unwrap();
1479 let mut translation_animation_data = current_body.body_translations.as_ref().unwrap().clone();
1480 let scale_animation_data = current_body.body_scales.as_ref().unwrap().clone();
1481 animation_data.extend_from_slice(keyframe_data.as_slice());
1482 assert_eq!(rotation_animation_data.shape()[1], translation_animation_data.shape()[0]);
1483 for j_idx in 0..rotation_animation_data.shape()[0] {
1484 let mut quaternions: Vec<f32> = vec![];
1485 for r_idx in 0..rotation_animation_data.shape()[1] {
1486 let rotation = rotation_animation_data.slice(s![j_idx, r_idx, ..]);
1487 let axis_angle_rotation = na::Vector3::new(rotation[0], rotation[1], rotation[2]);
1488 let mut quaternion_rotation =
1489 na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_angle_rotation), axis_angle_rotation.norm());
1490 if axis_angle_rotation.norm() == 0.0 {
1491 quaternion_rotation = na::UnitQuaternion::default();
1492 }
1493 quaternions.extend(quaternion_rotation.as_vector().data.as_slice());
1494 }
1495 let joint_anim_data = to_padded_byte_vector(&quaternions);
1496 animation_data.append(&mut joint_anim_data.clone());
1497 }
1498 if compatibility_mode == GltfCompatibilityMode::Unreal {
1499 let mut pelvis_relative_trans = translation_animation_data.clone();
1500 for mut row in translation_animation_data.axis_iter_mut(Axis(0)) {
1501 row[1] = 0.0;
1502 }
1503 for mut row in pelvis_relative_trans.axis_iter_mut(Axis(0)) {
1504 row[0] = 0.0;
1505 row[2] = 0.0;
1506 }
1507 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec_and_offset().0);
1508 animation_data.append(&mut trans_anim_data.clone());
1509 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec_and_offset().0);
1510 animation_data.append(&mut scale_anim_data.clone());
1511 let pelvis_rel_anim_data = to_padded_byte_vector(&pelvis_relative_trans.to_owned().into_raw_vec_and_offset().0);
1512 animation_data.append(&mut pelvis_rel_anim_data.clone());
1513 } else {
1514 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec_and_offset().0);
1515 animation_data.append(&mut trans_anim_data.clone());
1516 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec_and_offset().0);
1517 animation_data.append(&mut scale_anim_data.clone());
1518 }
1519 if self.num_morph_targets() > 0 {
1520 let morph_target_weights_data = current_body.per_frame_blend_weights.as_ref().unwrap();
1521 let weights_anim_data = to_padded_byte_vector(&morph_target_weights_data.to_owned().into_raw_vec_and_offset().0);
1522 animation_data.append(&mut weights_anim_data.clone());
1523 }
1524 animation_data
1525 }
1526 #[allow(clippy::too_many_arguments)]
1528 fn compose_buffer_views(
1529 &self,
1530 body_idx: usize,
1531 current_body: &PerBodyData,
1532 buffer_views: Vec<gltf_json::buffer::View>,
1533 index_data: &[u8],
1534 vertex_data: &[u8],
1535 inv_bind_mat_data: &[u8],
1536 textures: &mut [GltfTextureInfo],
1537 compatibility_mode: GltfCompatibilityMode,
1538 ) -> (Vec<u8>, Vec<gltf_json::buffer::View>) {
1539 let mut out_data: Vec<u8> = vec![];
1540 let mut out_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1541 out_data.append(&mut index_data.to_owned());
1542 out_data.append(&mut vertex_data.to_owned());
1543 out_data.append(&mut inv_bind_mat_data.to_owned());
1544 if self.is_animated() {
1545 let mut animation_data = self.create_animation_data(current_body, compatibility_mode);
1546 out_data.append(&mut animation_data);
1547 if self.num_morph_targets() > 0 && body_idx == 0 {
1548 for morph_target_idx in 0..self.num_morph_targets() {
1549 let mut posedir = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]).to_owned();
1550 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
1551 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
1552 if compatibility_mode == GltfCompatibilityMode::Smpl
1553 && self.num_pose_morph_targets > 0
1554 && morph_target_idx < num_pose_morph_targets
1555 {
1556 posedir *= 2.0 * PI;
1557 }
1558 if compatibility_mode == GltfCompatibilityMode::Smpl
1559 && self.num_expression_morph_targets > 0
1560 && morph_target_idx > num_pose_morph_targets
1561 && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets
1562 {
1563 posedir *= 2.0 * 7.0;
1564 }
1565 let posedir_data = to_padded_byte_vector(&posedir.to_owned().into_raw_vec_and_offset().0);
1566 out_data.append(&mut posedir_data.clone());
1567 }
1568 }
1569 }
1570 out_buffer_views.extend(buffer_views);
1571 let mut buffer_offset = out_data.len();
1572 let mut buffer_index: usize = out_buffer_views.len();
1573 for (sampler_index, texture) in textures.iter_mut().enumerate() {
1574 let mut buffer_view = texture.buffer_view.clone();
1575 buffer_view.byte_offset = Some(USize64::from(buffer_offset));
1576 out_buffer_views.push(buffer_view);
1577 texture.buffer_index = buffer_index;
1578 texture.image.buffer_view = Some(gltf_json::Index::new(u32::try_from(buffer_index).expect("Issue converting to u32!")));
1579 texture.texture.sampler = Some(gltf_json::Index::new(u32::try_from(sampler_index).expect("Issue converting to u32!")));
1580 out_data.append(&mut texture.image_data.clone());
1581 buffer_offset += texture.buffer_size;
1582 buffer_index += 1;
1583 }
1584 (out_data, out_buffer_views)
1585 }
1586 fn add_texture(&self, img: &DynImage, index: usize, name: &str) -> Option<GltfTextureInfo> {
1588 let mut image_data: Vec<u8> = vec![];
1589 let mut target = Cursor::new(&mut image_data);
1590 let image_data_buffer = img.write_to(&mut target, image::ImageFormat::Png);
1591 if image_data_buffer.is_ok() {
1592 let _ = target.flush();
1593 while image_data.len() % 4 != 0 {
1594 image_data.push(0);
1595 }
1596 let mut image_buffer_size = image_data.len();
1597 align_to_multiple_of_four(&mut image_buffer_size);
1598 let image_buffer_view = gltf_json::buffer::View {
1599 buffer: gltf_json::Index::new(0),
1600 byte_length: USize64::from(image_buffer_size),
1601 byte_offset: Some(USize64::from(0_usize)),
1602 byte_stride: Option::default(),
1603 extensions: Option::default(),
1604 extras: Option::default(),
1605 name: Some(name.to_string()),
1606 target: None,
1607 };
1608 let image = gltf_json::image::Image {
1609 buffer_view: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
1610 mime_type: Some(gltf_json::image::MimeType("image/png".to_string())),
1611 name: Some(name.to_string()),
1612 uri: None,
1613 extensions: None,
1614 extras: None,
1615 };
1616 let texture = gltf_json::Texture {
1617 name: Some(name.to_string()),
1618 sampler: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
1619 source: gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!")),
1620 extensions: None,
1621 extras: None,
1622 };
1623 let sampler = gltf_json::texture::Sampler {
1624 name: Some(name.to_string()),
1625 mag_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MagFilter::Linear)),
1626 min_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MinFilter::Linear)),
1627 wrap_s: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
1628 wrap_t: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
1629 extensions: None,
1630 extras: None,
1631 };
1632 let texture_info = GltfTextureInfo {
1633 buffer_size: image_data.len(),
1634 image_data,
1635 image,
1636 buffer_view: image_buffer_view,
1637 buffer_index: 0,
1638 texture,
1639 sampler,
1640 };
1641 return Some(texture_info);
1642 }
1643 log!("add_texture FAILED: {}", name);
1644 None
1645 }
1646 #[allow(clippy::cast_sign_loss)]
1648 fn prepare_normals(&self, smpl_textures: &mut SmplTextures, texture_infos: &mut Vec<GltfTextureInfo>, normals_tex: Option<&DynImage>) {
1649 if let Some(img) = normals_tex {
1650 let normals_tex = self.add_texture(img, texture_infos.len(), "normals");
1651 if let Some(normals_tex) = normals_tex {
1652 smpl_textures.normals_index = Some(texture_infos.len());
1653 texture_infos.push(normals_tex);
1654 }
1655 }
1656 }
1657 fn prepare_metallic_roughness(
1659 &self,
1660 smpl_textures: &mut SmplTextures,
1661 texture_infos: &mut Vec<GltfTextureInfo>,
1662 metalness_tex: Option<&DynImage>,
1663 roughness_tex: Option<&DynImage>,
1664 ) {
1665 let mut w: u32 = 0;
1666 let mut h: u32 = 0;
1667 if let Some(img) = metalness_tex {
1668 w = img.width();
1669 h = img.height();
1670 }
1671 if let Some(img) = roughness_tex {
1672 w = w.max(img.width());
1673 h = h.max(img.height());
1674 }
1675 let mut metalness: Option<Vec<u8>> = None;
1676 if let Some(img) = metalness_tex {
1677 if img.width() != w || img.height() != h {
1678 let resized_img = img.resize(w, h, FilterType::Gaussian);
1679 metalness = Some(resized_img.as_luma8().unwrap().to_vec());
1680 } else {
1681 metalness = Some(img.as_bytes().to_vec());
1682 }
1683 }
1684 let mut roughness: Option<Vec<u8>> = None;
1685 if let Some(img) = roughness_tex {
1686 if img.width() != w || img.height() != h {
1687 let resized_img = img.resize(w, h, FilterType::Gaussian);
1688 roughness = Some(resized_img.as_luma8().unwrap().to_vec());
1689 } else {
1690 roughness = Some(img.as_bytes().to_vec());
1691 }
1692 }
1693 let num_pixels: usize = (w * h) as usize;
1694 let mut metal_roughness_pixels: Vec<u8> = vec![];
1695 if let Some(metalness_pixels) = metalness {
1696 if let Some(roughness_pixels) = roughness {
1697 for (m, r) in metalness_pixels.iter().zip(roughness_pixels.iter()).take(num_pixels) {
1698 metal_roughness_pixels.push(0);
1699 metal_roughness_pixels.push(*r);
1700 metal_roughness_pixels.push(*m);
1701 }
1702 } else {
1703 for &m in metalness_pixels.iter().take(num_pixels) {
1704 metal_roughness_pixels.push(0);
1705 metal_roughness_pixels.push(0);
1706 metal_roughness_pixels.push(m);
1707 }
1708 }
1709 } else if let Some(roughness_pixels) = roughness {
1710 for &r in roughness_pixels.iter().take(num_pixels) {
1711 metal_roughness_pixels.push(0);
1712 metal_roughness_pixels.push(r);
1713 metal_roughness_pixels.push(0);
1714 }
1715 }
1716 if !metal_roughness_pixels.is_empty() {
1717 let metal_roughness_image = RgbImage::from_vec(w, h, metal_roughness_pixels);
1718 if let Some(image) = metal_roughness_image {
1719 let image = DynImage::from(image);
1720 let metallic_roughness = self.add_texture(&image, texture_infos.len(), "metal_roughness");
1721 if let Some(metallic_roughness) = metallic_roughness {
1722 smpl_textures.metalic_roughtness_index = Some(texture_infos.len());
1723 texture_infos.push(metallic_roughness);
1724 }
1725 }
1726 }
1727 }
1728 fn create_joint(&self, name: String, translation: &[f32], rotation: &Vector3f, children: Option<Vec<gltf_json::Index<Node>>>) -> Node {
1730 let cur_vec = na::Vector3::new(rotation.x, rotation.y, rotation.z);
1731 let mut cur_q = na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(cur_vec), rotation.norm());
1732 if rotation.norm() == 0.0 {
1733 cur_q = na::UnitQuaternion::default();
1734 }
1735 let translation: [f32; 3] = [translation[0], translation[1], translation[2]];
1736 let unit_quaternion = [cur_q[0], cur_q[1], cur_q[2], cur_q[3]];
1737 Node {
1738 children,
1739 mesh: None,
1740 skin: None,
1741 name: Some(name),
1742 rotation: Some(UnitQuaternion(unit_quaternion)),
1743 translation: Some(translation),
1744 ..Default::default()
1745 }
1746 }
1747 fn gather_children(&self, id: u32, parent_ids: &[u32], offset: u32) -> Option<Vec<gltf_json::Index<Node>>> {
1748 let mut children: Vec<gltf_json::Index<Node>> = vec![];
1749 for (p, &parent_id) in parent_ids.iter().enumerate() {
1750 if parent_id == id {
1751 let index = u32::try_from(p).expect("Index conversion error: usize value is too large to fit in a u32");
1752 children.push(gltf_json::Index::<Node>::new(index + offset));
1753 }
1754 }
1755 if !children.is_empty() {
1756 return Some(children);
1757 }
1758 None
1759 }
1760 #[allow(clippy::too_many_arguments)]
1762 fn add_skin(
1763 &mut self,
1764 name: String,
1765 current_body: &PerBodyData,
1766 current_armature_idx: u32,
1767 accessor_offset: u32,
1768 nodes: &mut Vec<Node>,
1769 skins: &mut Vec<gltf_json::Skin>,
1770 joints: &mut Vec<gltf_json::Index<Node>>,
1771 compatibility_mode: GltfCompatibilityMode,
1772 ) -> gltf_json::Index<Node> {
1773 let metadata = crate::common::metadata::smpl_metadata(&self.smpl_type);
1774 let joint_translations = current_body.default_joint_translations.as_ref().unwrap();
1775 let skeleton_root_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
1776 let global_translation = vec_from_array0_f(current_body.body_translation.as_ref().unwrap());
1777 let mut skeleton_root_translation = compute_local_translation(0, &metadata.joint_parents, joint_translations);
1778 if compatibility_mode == GltfCompatibilityMode::Smpl {
1779 skeleton_root_translation = addv3f(&skeleton_root_translation, &global_translation);
1780 }
1781 let mut joint_rotation = Vector3f::zeros();
1782 if let Some(pose) = current_body.pose.as_ref() {
1783 let rot = pose.joint_poses.row(0);
1784 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
1785 }
1786 let skeleton_root = self.create_joint(
1787 "pelvis".to_string(),
1788 vec_to_vec(&skeleton_root_translation).as_slice(),
1789 &joint_rotation,
1790 self.gather_children(0, &metadata.joint_parents, skeleton_root_index),
1791 );
1792 nodes.push(skeleton_root);
1793 joints.push(gltf_json::Index::new(skeleton_root_index));
1794 let joint_names = if compatibility_mode == GltfCompatibilityMode::Unreal {
1795 smpl_x::JOINT_NAMES_UNREAL.map(std::string::ToString::to_string).to_vec()
1796 } else {
1797 metadata.joint_names
1798 };
1799 for (j, name) in joint_names.iter().enumerate().take(metadata.num_joints + 1).skip(1) {
1800 if let Some(pose) = current_body.pose.as_ref() {
1801 let rot = pose.joint_poses.row(j);
1802 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
1803 }
1804 let joint = self.create_joint(
1805 name.clone(),
1806 vec_to_vec(&compute_local_translation(j, &metadata.joint_parents, joint_translations)).as_slice(),
1807 &joint_rotation,
1808 self.gather_children(
1809 u32::try_from(j).expect("Issue converting Joint idx to u32"),
1810 &metadata.joint_parents,
1811 skeleton_root_index,
1812 ),
1813 );
1814 let joint_index = gltf_json::Index::<Node>::new(u32::try_from(nodes.len()).expect("Issue converting Joint idx to u32"));
1815 nodes.push(joint);
1816 joints.push(joint_index);
1817 }
1818 let skin = gltf_json::Skin {
1819 name: Some(name),
1820 inverse_bind_matrices: Some(gltf_json::Index::new(accessor_offset + 6)),
1821 joints: joints.clone(),
1822 skeleton: Some(gltf_json::Index::new(current_armature_idx)),
1823 extensions: None,
1824 extras: None,
1825 };
1826 skins.push(skin);
1827 gltf_json::Index::<Node>::new(skeleton_root_index)
1828 }
1829 #[allow(clippy::cast_precision_loss)]
1831 fn create_camera_animation_buffer_views(&self, running_offset: &mut usize) -> Option<(Vec<gltf_json::buffer::View>, Vec<u8>)> {
1832 let camera_track = self.camera_track.as_ref()?;
1833 let mut buffer_views = Vec::new();
1834 let mut buffer_data = Vec::new();
1835 if let Some(translations) = camera_track.per_frame_translations.as_ref() {
1836 let trans_data = to_padded_byte_vector(translations.as_slice().unwrap());
1837 let trans_len = trans_data.len();
1838 let trans_view = gltf_json::buffer::View {
1839 buffer: gltf_json::Index::new(0),
1840 byte_length: USize64::from(trans_len),
1841 byte_offset: Some(USize64::from(*running_offset)),
1842 byte_stride: None,
1843 extensions: None,
1844 extras: Option::default(),
1845 name: Some("camera_translations".to_string()),
1846 target: None,
1847 };
1848 buffer_data.extend(trans_data);
1849 *running_offset += trans_len;
1850 buffer_views.push(trans_view);
1851 }
1852 if let Some(rotations) = camera_track.per_frame_rotations.as_ref() {
1853 let rot_data = to_padded_byte_vector(rotations.as_slice().unwrap());
1854 let rot_len = rot_data.len();
1855 let rot_view = gltf_json::buffer::View {
1856 buffer: gltf_json::Index::new(0),
1857 byte_length: USize64::from(rot_len),
1858 byte_offset: Some(USize64::from(*running_offset)),
1859 byte_stride: None,
1860 extensions: None,
1861 extras: Option::default(),
1862 name: Some("camera_rotations".to_string()),
1863 target: None,
1864 };
1865 buffer_data.extend(rot_data);
1866 *running_offset += rot_len;
1867 buffer_views.push(rot_view);
1868 }
1869 Some((buffer_views, buffer_data))
1870 }
1871 fn create_camera_animation_accessors(&self, current_buffer_view_offset: u32) -> Option<Vec<gltf_json::Accessor>> {
1873 let camera_track = self.camera_track.as_ref()?;
1874 let mut accessors = Vec::new();
1875 let mut current_view = current_buffer_view_offset;
1876 if let Some(translations) = camera_track.per_frame_translations.as_ref() {
1877 accessors.push(gltf_json::Accessor {
1878 buffer_view: Some(gltf_json::Index::new(current_view)),
1879 byte_offset: None,
1880 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1881 count: USize64::from(translations.shape()[0]),
1882 type_: Valid(gltf_json::accessor::Type::Vec3),
1883 min: None,
1884 max: None,
1885 name: Some("camera_translations".to_string()),
1886 normalized: false,
1887 sparse: None,
1888 extensions: None,
1889 extras: Option::default(),
1890 });
1891 current_view += 1;
1892 }
1893 if let Some(rotations) = camera_track.per_frame_rotations.as_ref() {
1894 accessors.push(gltf_json::Accessor {
1895 buffer_view: Some(gltf_json::Index::new(current_view)),
1896 byte_offset: None,
1897 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1898 count: USize64::from(rotations.shape()[0]),
1899 type_: Valid(gltf_json::accessor::Type::Vec4),
1900 min: None,
1901 max: None,
1902 name: Some("camera_rotations".to_string()),
1903 normalized: false,
1904 sparse: None,
1905 extensions: None,
1906 extras: Option::default(),
1907 });
1908 }
1909 Some(accessors)
1910 }
1911 #[allow(clippy::cast_possible_truncation)]
1913 fn create_camera_animation_channels_and_samplers(
1914 &self,
1915 current_accessor_offset: u32,
1916 camera_node_index: u32,
1917 sampler_start_idx: u32,
1918 ) -> Option<(Vec<gltf_json::animation::Channel>, Vec<gltf_json::animation::Sampler>)> {
1919 let camera_track = self.camera_track.as_ref()?;
1920 let mut channels = Vec::new();
1921 let mut samplers = Vec::new();
1922 let mut current_accessor = current_accessor_offset;
1923 let times_accessor_index = 7;
1924 if camera_track.per_frame_translations.is_some() {
1925 samplers.push(gltf_json::animation::Sampler {
1926 input: gltf_json::Index::new(times_accessor_index),
1927 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
1928 output: gltf_json::Index::new(current_accessor),
1929 extensions: None,
1930 extras: Option::default(),
1931 });
1932 channels.push(gltf_json::animation::Channel {
1933 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
1934 target: gltf_json::animation::Target {
1935 node: gltf_json::Index::new(camera_node_index),
1936 path: Valid(gltf_json::animation::Property::Translation),
1937 extensions: None,
1938 extras: Option::default(),
1939 },
1940 extensions: None,
1941 extras: Option::default(),
1942 });
1943 current_accessor += 1;
1944 }
1945 if camera_track.per_frame_rotations.is_some() {
1946 samplers.push(gltf_json::animation::Sampler {
1947 input: gltf_json::Index::new(times_accessor_index),
1948 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
1949 output: gltf_json::Index::new(current_accessor),
1950 extensions: None,
1951 extras: Option::default(),
1952 });
1953 channels.push(gltf_json::animation::Channel {
1954 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
1955 target: gltf_json::animation::Target {
1956 node: gltf_json::Index::new(camera_node_index),
1957 path: Valid(gltf_json::animation::Property::Rotation),
1958 extensions: None,
1959 extras: Option::default(),
1960 },
1961 extensions: None,
1962 extras: Option::default(),
1963 });
1964 }
1965 Some((channels, samplers))
1966 }
1967 fn num_morph_targets(&self) -> usize {
1968 self.morph_targets.as_ref().map_or(0, |x| x.shape()[0])
1969 }
1970}
1971pub fn compute_local_translation(id: usize, parent_ids: &[u32], joint_translations: &nd::Array2<f32>) -> Vector3f {
1972 let trans = vec_from_vec(&joint_translations.row(id).to_vec());
1973 if id == 0 {
1974 return trans;
1975 }
1976 let parent_id = parent_ids[id] as usize;
1977 let parent_trans = vec_from_vec(&joint_translations.row(parent_id).to_vec());
1978 subv3f(&trans, &parent_trans)
1979}