1use crate::{
2 codec::scene::SmplCamera,
3 common::types::{ChunkHeader, FaceType, GltfCompatibilityMode, GltfOutputType, SmplType},
4 smpl_x::smpl_x,
5};
6use gloss_geometry::geom;
7use gloss_img::dynamic_image::DynImage;
8use gloss_utils::nshare::ToNalgebra;
9use gltf::binary::Header;
10use gltf_json::validation::{Checked::Valid, USize64};
11use gltf_json::{material::AlphaMode, scene::UnitQuaternion, Node};
12use image::imageops::FilterType;
13use image::RgbImage;
14use itertools::izip;
15use log::info;
16use nalgebra as na;
17use nalgebra::DMatrix;
18use ndarray as nd;
19use ndarray::prelude::*;
20use smpl_utils::numerical::batch_rodrigues;
21use smpl_utils::{
22 log,
23 vector::{
24 addv3f, align_to_multiple_of_four, subv3f, to_padded_byte_vector, vec_from_array0_f, vec_from_vec, vec_to_vec, Vector2f, Vector3f, Vector4f,
25 Vector4s,
26 },
27};
28use std::borrow::Cow;
29use std::{
30 f32::consts::PI,
31 io::{Cursor, Write},
32 path::Path,
33};
34use std::{fs, mem};
35#[repr(u32)]
38#[derive(Debug, Clone, Copy)]
39enum PrimitiveAttrIDs {
40 Indices = 0,
41 Positions = 1,
42 Normals = 2,
43 TexCoords = 3,
44 Joints = 4,
45 Weights = 5,
46}
47#[repr(u32)]
49#[derive(Debug, Clone, Copy)]
50enum BufferViewIDs {
51 Index = 0,
52 VertexAttr = 1,
53 InvBindMat = 2,
54 Keyframe = 3,
55 Animation = 4,
56 Deformation = 5,
57}
58#[derive(Copy, Clone, Debug, bytemuck::NoUninit)]
60#[repr(C)]
61struct Vertex {
62 position: [f32; 3],
63 normal: [f32; 3],
64 uv: [f32; 2],
65 joint_index: [u16; 4],
66 joint_weight: [f32; 4],
67}
68#[derive(Copy, Clone, Debug, bytemuck::NoUninit)]
70#[repr(C)]
71struct VertexProp {
72 position: [f32; 3],
73 joint_index: [u16; 4],
74 joint_weight: [f32; 4],
75}
76#[derive(Copy, Clone, Debug, bytemuck::NoUninit)]
78#[repr(C)]
79struct VertexPropWithUV {
80 position: [f32; 3],
81 uv: [f32; 2],
82 joint_index: [u16; 4],
83 joint_weight: [f32; 4],
84}
85#[derive(Clone, Debug)]
87struct GltfTextureInfo {
88 buffer_size: usize,
89 image_data: Vec<u8>,
90 image: gltf_json::image::Image,
91 buffer_view: gltf_json::buffer::View,
92 buffer_index: usize,
93 texture: gltf_json::texture::Texture,
94 sampler: gltf_json::texture::Sampler,
95}
96#[allow(clippy::struct_field_names)]
98struct SmplTextures {
99 diffuse_index: Option<usize>,
100 normals_index: Option<usize>,
101 metalic_roughtness_index: Option<usize>,
102}
103#[derive(Clone, Debug)]
105pub struct PropData {
106 pub diffuse_texture: Option<DynImage>,
107 pub normals_texture: Option<DynImage>,
108 pub metalness_texture: Option<DynImage>,
109 pub roughness_texture: Option<DynImage>,
110 pub positions: DMatrix<f32>,
111 pub faces: DMatrix<u32>,
112 pub normals: Option<DMatrix<f32>>,
113 pub uvs: Option<DMatrix<f32>>,
114 pub translations: nd::Array2<f32>,
115 pub rotations: nd::Array3<f32>,
116 pub scales: nd::Array2<f32>,
117 pub default_translation: nd::Array2<f32>,
118 pub default_joint_poses: nd::Array2<f32>,
119}
120#[derive(Clone, Default, Debug)]
122pub struct PerBodyData {
123 pub diffuse_textures: Option<DynImage>,
124 pub normals_textures: Option<DynImage>,
125 pub metalness_textures: Option<DynImage>,
126 pub roughness_textures: Option<DynImage>,
127 pub positions: Option<DMatrix<f32>>,
128 pub normals: Option<DMatrix<f32>>,
129 pub default_joint_translations: Option<nd::Array2<f32>>,
130 pub body_translation: Option<nd::Array2<f32>>,
131 pub joint_poses: Option<nd::Array2<f32>>,
132 pub body_translations: Option<nd::Array2<f32>>,
133 pub body_rotations: Option<nd::Array3<f32>>,
134 pub body_scales: Option<nd::Array2<f32>>,
135 pub per_frame_blend_weights: Option<nd::Array2<f32>>,
136}
137pub struct GltfExportOptions {
138 pub out_type: GltfOutputType,
139 pub compatibility_mode: GltfCompatibilityMode,
140 pub face_type: FaceType,
141}
142impl Default for GltfExportOptions {
143 fn default() -> Self {
144 Self {
145 out_type: GltfOutputType::Binary,
146 compatibility_mode: GltfCompatibilityMode::Smpl,
147 face_type: FaceType::SmplX,
148 }
149 }
150}
151#[derive(Clone)]
153pub struct GltfCodec {
154 pub num_bodies: usize,
155 pub smpl_type: SmplType,
156 pub gender: i32,
157 pub faces: Option<DMatrix<u32>>,
158 pub uvs: Option<DMatrix<f32>>,
159 pub joint_index: Option<DMatrix<u32>>,
160 pub joint_weight: Option<DMatrix<f32>>,
161 pub default_joint_poses: Option<nd::Array2<f32>>,
162 pub frame_count: Option<usize>,
163 pub keyframe_times: Option<Vec<f32>>,
164 pub morph_targets: Option<nd::Array3<f32>>,
165 pub num_pose_morph_targets: usize,
166 pub num_expression_morph_targets: usize,
167 pub per_body_data: Vec<PerBodyData>,
168 pub smpl_camera: Option<SmplCamera>,
169 pub props: Vec<PropData>,
170}
171impl Default for GltfCodec {
172 fn default() -> Self {
173 Self {
174 num_bodies: 1,
175 smpl_type: SmplType::SmplX,
176 gender: 0,
177 faces: None,
178 uvs: None,
179 joint_index: None,
180 joint_weight: None,
181 default_joint_poses: None,
182 frame_count: None,
183 keyframe_times: None,
184 morph_targets: None,
185 num_pose_morph_targets: 0,
186 num_expression_morph_targets: 0,
187 per_body_data: Vec::new(),
188 smpl_camera: None,
189 props: Vec::new(),
190 }
191 }
192}
193impl GltfCodec {
194 pub fn to_file(&mut self, name: &str, path: &str, options: &GltfExportOptions) {
196 let parent_path = Path::new(path).parent();
197 let file_name = Path::new(path).file_name();
198 let Some(parent_path) = parent_path else {
199 log!("Error: Exporting GLTF - no directory name found: {}", path);
200 return;
201 };
202 let Some(file_name) = file_name else {
203 log!("Error: Exporting GLTF - no file name found: {}", path);
204 return;
205 };
206 let _ = fs::create_dir(parent_path);
207 let target_extension: &str = match options.out_type {
208 GltfOutputType::Standard => "gltf",
209 GltfOutputType::Binary => "glb",
210 };
211 let file_name_with_suffix = Path::new(file_name).with_extension(target_extension);
212 log!("Exporting GLTF: {}/{}", path, file_name_with_suffix.to_string_lossy());
213 let binary = matches!(options.out_type, GltfOutputType::Binary);
214 let (buffer_data, root) = self.create_buffer(name, binary, options.compatibility_mode, options.face_type);
215 match options.out_type {
216 GltfOutputType::Standard => {
217 let json_path = parent_path.join(file_name_with_suffix.clone());
218 let bin_path = parent_path.join("buffer0.bin");
219 let writer = fs::File::create(json_path).expect("I/O error");
220 gltf_json::serialize::to_writer_pretty(writer, &root).expect("Serialization error");
221 let bin = to_padded_byte_vector(&buffer_data);
222 let mut writer = fs::File::create(bin_path).expect("I/O error");
223 writer.write_all(&bin).expect("I/O error");
224 info!("Written glTF json + bin to {}", parent_path.display());
225 }
226 GltfOutputType::Binary => {
227 let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
228 let mut length = mem::size_of::<Header>() + mem::size_of::<ChunkHeader>() + json_string.len();
229 align_to_multiple_of_four(&mut length);
230 length += mem::size_of::<ChunkHeader>() + buffer_data.len();
231 align_to_multiple_of_four(&mut length);
232 let glb = gltf::binary::Glb {
233 header: gltf::binary::Header {
234 magic: *b"glTF",
235 version: 2,
236 length: length.try_into().expect("file size exceeds binary glTF limit"),
237 },
238 bin: Some(Cow::Owned(buffer_data)),
239 json: Cow::Owned(json_string.into_bytes()),
240 };
241 let glb_path = parent_path.join(file_name_with_suffix.clone());
242 let writer = std::fs::File::create(glb_path.clone()).expect("I/O error");
243 glb.to_writer(writer).expect("glTF binary output error");
244 info!("Written binary glB to {}", glb_path.display());
245 }
246 }
247 }
248 pub fn to_buf(&mut self, compatibility_mode: GltfCompatibilityMode, face_type: FaceType) -> Vec<u8> {
250 let (buffer_data, root) = self.create_buffer("Meshcapade Avatar", true, compatibility_mode, face_type);
251 let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
252 let mut length = mem::size_of::<Header>() + mem::size_of::<ChunkHeader>() + json_string.len();
253 align_to_multiple_of_four(&mut length);
254 length += mem::size_of::<ChunkHeader>() + buffer_data.len();
255 align_to_multiple_of_four(&mut length);
256 let glb = gltf::binary::Glb {
257 header: gltf::binary::Header {
258 magic: *b"glTF",
259 version: 2,
260 length: length.try_into().expect("file size exceeds binary glTF limit"),
261 },
262 bin: Some(Cow::Owned(buffer_data)),
263 json: Cow::Owned(json_string.into_bytes()),
264 };
265 glb.to_vec().expect("glTF binary output error")
266 }
267 fn is_animated(&self) -> bool {
268 self.frame_count.is_some()
269 }
270 #[allow(clippy::too_many_lines)]
272 #[allow(clippy::cast_possible_truncation)]
273 #[allow(clippy::cast_possible_wrap)]
274 fn create_buffer(
275 &mut self,
276 name: &str,
277 binary: bool,
278 compatibility_mode: GltfCompatibilityMode,
279 face_type: FaceType,
280 ) -> (Vec<u8>, gltf_json::Root) {
281 let mut full_buffer_data = vec![];
282 let mut accessors = vec![];
283 let mut buffers = vec![];
284 let mut buffer_views = vec![];
285 let mut meshes = vec![];
286 let mut nodes = vec![];
287 let mut skins = vec![];
288 let mut materials = vec![];
289 let mut channels = vec![];
290 let mut samplers = vec![];
291 let mut images = vec![];
292 let mut textures = vec![];
293 let mut texture_samplers: Vec<gltf_json::texture::Sampler> = vec![];
294 let mut cameras: Vec<gltf_json::camera::Camera> = vec![];
295 let mut global_buffer_offset = 0;
296 let mut global_buffer_index = 0;
297 let scene_root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
298 let scene_root_node = Node {
299 name: Some("SceneRoot".to_string()),
300 children: Some(vec![]),
301 ..Default::default()
302 };
303 nodes.push(scene_root_node);
304 if let Some(smpl_camera) = &self.smpl_camera {
305 let camera = gltf_json::camera::Camera {
306 name: Some("MoCapadeCamera".to_string()),
307 type_: gltf_json::validation::Checked::Valid(gltf_json::camera::Type::Perspective),
308 perspective: Some(gltf_json::camera::Perspective {
309 yfov: smpl_camera.projection.fovy,
310 znear: smpl_camera.projection.near,
311 zfar: Some(smpl_camera.projection.far),
312 aspect_ratio: Some(smpl_camera.projection.aspect_ratio),
313 extensions: None,
314 extras: Option::default(),
315 }),
316 orthographic: None,
317 extensions: None,
318 extras: Option::default(),
319 };
320 cameras.push(camera);
321 let smpl_camera_node = Node {
322 name: Some("AnimatedCamera".to_string()),
323 camera: Some(gltf_json::Index::new(0)),
324 ..Default::default()
325 };
326 let camera_node_idx = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
327 if let Some(ref mut scene_root_node_children) = nodes[0].children {
328 scene_root_node_children.push(gltf_json::Index::new(camera_node_idx));
329 }
330 nodes.push(smpl_camera_node);
331 }
332 let node_indices: Vec<gltf_json::Index<Node>> = vec![gltf_json::Index::new(scene_root_node_index)];
333 let scene: gltf_json::Scene = gltf_json::Scene {
334 extensions: Option::default(),
335 extras: Option::default(),
336 name: Some(name.to_string()),
337 nodes: node_indices,
338 };
339 let scenes = vec![scene];
340 for body_idx in 0..self.per_body_data.len() {
341 assert!(self.faces.is_some(), "GltfCodec: no faces!");
342 assert!(self.uvs.is_some(), "GltfCodec: no uvs!");
343 let mut current_body = self.per_body_data[body_idx].clone();
344 if compatibility_mode == GltfCompatibilityMode::Smpl && self.num_pose_morph_targets > 0 {
345 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
346 current_body
347 .per_frame_blend_weights
348 .as_mut()
349 .unwrap()
350 .slice_mut(s![.., 0..num_pose_morph_targets])
351 .mapv_inplace(|elem| (elem + PI) / (2.0 * PI));
352 current_body
353 .per_frame_blend_weights
354 .as_mut()
355 .unwrap()
356 .slice_mut(s![.., num_pose_morph_targets])
357 .assign(&nd::Array1::<f32>::from_elem(self.frame_count.unwrap(), 1.0));
358 }
359 if face_type == FaceType::SmplX && self.num_expression_morph_targets > 0 {
360 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
361 current_body
362 .per_frame_blend_weights
363 .as_mut()
364 .unwrap()
365 .slice_mut(s![
366 ..,
367 self.num_pose_morph_targets..self.num_pose_morph_targets + num_expression_morph_targets
368 ])
369 .mapv_inplace(|elem| (elem + 7.0) / (2.0 * 7.0));
370 current_body
371 .per_frame_blend_weights
372 .as_mut()
373 .unwrap()
374 .slice_mut(s![.., self.num_pose_morph_targets + num_expression_morph_targets])
375 .assign(&nd::Array1::<f32>::from_elem(self.frame_count.unwrap(), 1.0));
376 }
377
378 assert!(current_body.positions.is_some(), "GltfCodec: no vertices for body {body_idx}!");
379 assert!(current_body.normals.is_some(), "GltfCodec: no normals for body {body_idx}!");
380 let mut positions = current_body.positions.clone().unwrap();
381 let normals = current_body.normals.clone().unwrap();
382 let faces = self.faces.as_ref().unwrap();
383 let uvs = self.uvs.as_ref().unwrap();
384 let joint_index = self.joint_index.as_ref().unwrap();
385 let joint_weight = self.joint_weight.as_ref().unwrap();
386 let diffuse_tex = current_body.diffuse_textures.as_ref();
387 let normals_tex = current_body.normals_textures.as_ref();
388 let metalness_tex = current_body.metalness_textures.as_ref();
389 let roughness_tex = current_body.roughness_textures.as_ref();
390 let mut vertex_attributes_array: Vec<Vertex> = vec![];
391 let mut indices_array: Vec<u32> = vec![];
392 let mut inverse_bind_matrices: Vec<f32> = vec![];
393 let face_count = faces.shape().0;
394 let vertex_count = positions.shape().0;
395 let joint_count = current_body.default_joint_translations.as_ref().unwrap().shape()[0];
396 for row in faces.row_iter() {
397 indices_array.extend_from_slice(&[row[0], row[1], row[2]]);
398 }
399 let joint_rotations = batch_rodrigues(self.default_joint_poses.as_ref().unwrap());
400 let mut joint_translations = current_body.default_joint_translations.clone().unwrap();
401 if compatibility_mode == GltfCompatibilityMode::Unreal {
402 let (min, _) = geom::get_bounding_points(&positions, None);
403 let min_vec: Vec<f32> = min.iter().copied().collect();
404 let min_y = min_vec[1];
405 let offset = na::RowVector3::new(0.0, min_y, 0.0);
406 for i in 0..positions.nrows() {
407 let mut row = positions.row_mut(i);
408 row -= offset;
409 }
410 let offset_nd = ndarray::Array1::from_vec(vec![0.0, min_y, 0.0]);
411 for mut row in joint_translations.axis_iter_mut(Axis(0)) {
412 row -= &offset_nd;
413 }
414 current_body.positions = Some(positions.clone());
415 current_body.default_joint_translations = Some(joint_translations.clone());
416 }
417 let metadata = crate::common::metadata::smpl_metadata(&self.smpl_type);
418 let bind_matrices = self.create_bind_matrices(&joint_rotations, &joint_translations, &metadata.joint_parents);
419 let unreal_mapping: [usize; 10] = [0, 0, 0, 8, 7, 0, 21, 21, 20, 0];
420 if compatibility_mode == GltfCompatibilityMode::Unreal {
421 for j_idx in unreal_mapping {
422 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
423 let inverse_rotation_matrix = bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
424 let translation: nd::Array1<f32> = if j_idx == 0 {
425 nd::Array1::from_vec(vec![0.0, 0.0, 0.0])
426 } else {
427 bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned()
428 };
429 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
430 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
431 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
432 inverse_bind_matrix[(3, 3)] = 1.0;
433 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
434 }
435 }
436 for j_idx in 0..joint_count {
437 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
438 let inverse_rotation_matrix = bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
439 let translation: nd::Array1<f32> = bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned();
440 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
441 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
442 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
443 inverse_bind_matrix[(3, 3)] = 1.0;
444 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
445 }
446 let num_extra_joints: usize = if compatibility_mode == GltfCompatibilityMode::Unreal { 10 } else { 0 };
447 for (position, normal, uv, joint_index, joint_weight) in izip!(
448 positions.row_iter(),
449 normals.row_iter(),
450 uvs.row_iter(),
451 joint_index.row_iter(),
452 joint_weight.row_iter(),
453 ) {
454 let jw_sum = joint_weight.iter().sum::<f32>();
455 let indices = [
456 if joint_weight[0] > 0.0 {
457 joint_index[0] + u32::try_from(num_extra_joints).unwrap()
458 } else {
459 0
460 },
461 if joint_weight[1] > 0.0 {
462 joint_index[1] + u32::try_from(num_extra_joints).unwrap()
463 } else {
464 0
465 },
466 if joint_weight[2] > 0.0 {
467 joint_index[2] + u32::try_from(num_extra_joints).unwrap()
468 } else {
469 0
470 },
471 if joint_weight[3] > 0.0 {
472 joint_index[3] + u32::try_from(num_extra_joints).unwrap()
473 } else {
474 0
475 },
476 ]
477 .map(|idx| u16::try_from(idx).expect("Could not convert to u16!"));
478 vertex_attributes_array.push(Vertex {
479 position: Vector3f::new(position[0], position[1], position[2]).into(),
480 normal: Vector3f::new(normal[0], normal[1], normal[2]).into(),
481 uv: Vector2f::new(uv[0], 1.0 - uv[1]).into(),
482 joint_index: Vector4s::new(indices[0], indices[1], indices[2], indices[3]).into(),
483 joint_weight: Vector4f::new(
484 joint_weight[0] / jw_sum,
485 joint_weight[1] / jw_sum,
486 joint_weight[2] / jw_sum,
487 joint_weight[3] / jw_sum,
488 )
489 .into(),
490 });
491 }
492 let mut texture_infos: Vec<GltfTextureInfo> = vec![];
493 let mut smpl_textures = SmplTextures {
494 diffuse_index: None,
495 normals_index: None,
496 metalic_roughtness_index: None,
497 };
498 if let Some(img) = diffuse_tex {
499 let diffuse_tex = self.add_texture(img, texture_infos.len(), "diffuse");
500 if let Some(diffuse_tex) = diffuse_tex {
501 smpl_textures.diffuse_index = Some(texture_infos.len());
502 texture_infos.push(diffuse_tex);
503 }
504 }
505 self.prepare_normals(&mut smpl_textures, &mut texture_infos, normals_tex);
506 self.prepare_metallic_roughness(&mut smpl_textures, &mut texture_infos, metalness_tex, roughness_tex);
507 let mut base_color_texture: Option<gltf_json::texture::Info> = None;
508 let mut normal_texture: Option<gltf_json::material::NormalTexture> = None;
509 let mut metallic_roughness_texture: Option<gltf_json::texture::Info> = None;
510 if let Some(diffuse_texture_index) = smpl_textures.diffuse_index {
511 base_color_texture = Some(gltf_json::texture::Info {
512 index: gltf_json::Index::new(u32::try_from(diffuse_texture_index).expect("Could not convert to u32!")),
513 tex_coord: 0,
514 extensions: None,
515 extras: None,
516 });
517 }
518 if let Some(normal_texture_index) = smpl_textures.normals_index {
519 normal_texture = Some(gltf_json::material::NormalTexture {
520 scale: 1.,
521 index: gltf_json::Index::new(u32::try_from(normal_texture_index).expect("Could not convert to u32!")),
522 tex_coord: 0,
523 extensions: None,
524 extras: None,
525 });
526 }
527 if let Some(metallic_roughness_texture_index) = smpl_textures.metalic_roughtness_index {
528 metallic_roughness_texture = Some(gltf_json::texture::Info {
529 index: gltf_json::Index::new(u32::try_from(metallic_roughness_texture_index).expect("Could not convert to u32!")),
530 tex_coord: 0,
531 extensions: None,
532 extras: None,
533 });
534 }
535 let material = gltf_json::Material {
536 alpha_cutoff: None,
537 alpha_mode: gltf_json::validation::Checked::<AlphaMode>::Valid(AlphaMode::Opaque),
538 double_sided: false,
539 name: Some("SMPL_material".to_string()),
540 pbr_metallic_roughness: gltf_json::material::PbrMetallicRoughness {
541 base_color_factor: gltf_json::material::PbrBaseColorFactor([1., 1., 1., 1.]),
542 base_color_texture,
543 metallic_roughness_texture,
544 ..Default::default()
545 },
546 normal_texture,
547 occlusion_texture: None,
548 emissive_texture: None,
549 emissive_factor: gltf_json::material::EmissiveFactor([0., 0., 0.]),
550 extensions: None,
551 extras: None,
552 };
553 materials.push(material);
554 let mut morph_targets: Option<Vec<gltf_json::mesh::MorphTarget>> = None;
555 if self.num_morph_targets() > 0 && self.is_animated() {
556 let mut morph_target_accessors_start_idx = 7 + self.per_body_data[0].default_joint_translations.as_ref().unwrap().shape()[0] + 4;
557 if compatibility_mode == GltfCompatibilityMode::Unreal {
558 morph_target_accessors_start_idx += 1;
559 }
560 morph_targets = Some(self.create_morph_targets(morph_target_accessors_start_idx));
561 }
562 let primitive_offset = accessors.len() as u32;
563 let primitive = gltf_json::mesh::Primitive {
564 attributes: {
565 let mut map = std::collections::BTreeMap::new();
566 map.insert(
567 Valid(gltf_json::mesh::Semantic::Positions),
568 gltf_json::Index::new(PrimitiveAttrIDs::Positions as u32 + primitive_offset),
569 );
570 map.insert(
571 Valid(gltf_json::mesh::Semantic::Normals),
572 gltf_json::Index::new(PrimitiveAttrIDs::Normals as u32 + primitive_offset),
573 );
574 map.insert(
575 Valid(gltf_json::mesh::Semantic::TexCoords(0)),
576 gltf_json::Index::new(PrimitiveAttrIDs::TexCoords as u32 + primitive_offset),
577 );
578 map.insert(
579 Valid(gltf_json::mesh::Semantic::Joints(0)),
580 gltf_json::Index::new(PrimitiveAttrIDs::Joints as u32 + primitive_offset),
581 );
582 map.insert(
583 Valid(gltf_json::mesh::Semantic::Weights(0)),
584 gltf_json::Index::new(PrimitiveAttrIDs::Weights as u32 + primitive_offset),
585 );
586 map
587 },
588 extensions: Option::default(),
589 extras: Option::default(),
590 indices: Some(gltf_json::Index::new(PrimitiveAttrIDs::Indices as u32 + primitive_offset)),
591 material: Some(gltf_json::Index::new(body_idx as u32)),
592 mode: Valid(gltf_json::mesh::Mode::Triangles),
593 targets: morph_targets,
594 };
595 let mut morph_target_weights: Option<Vec<f32>> = None;
596 if self.num_morph_targets() > 0 && self.is_animated() {
597 morph_target_weights = Some(vec![0.0; self.num_morph_targets()]);
598 }
599 let mesh = gltf_json::Mesh {
600 extensions: Option::default(),
601 extras: Option::default(),
602 name: Some(format!("SMPL_mesh_{body_idx}")),
603 primitives: vec![primitive],
604 weights: morph_target_weights,
605 };
606 meshes.push(mesh);
607 let vertex_data = to_padded_byte_vector(&vertex_attributes_array);
608 let index_data = to_padded_byte_vector(&indices_array);
609 let inv_bind_mat_data = to_padded_byte_vector(&inverse_bind_matrices);
610 let mut per_view_running_offset: [usize; 6] = [0, 0, 0, 0, 0, 0];
611 let current_buffer_view_offset = buffer_views.len() as u32;
612 let current_accessor_offset = accessors.len() as u32;
613 let accessor = self.create_accessors(
614 body_idx,
615 vertex_count,
616 face_count,
617 joint_count,
618 current_buffer_view_offset,
619 &mut per_view_running_offset,
620 num_extra_joints,
621 compatibility_mode,
622 );
623 accessors.extend(accessor);
624 let mut current_buffer_views = vec![];
625 self.create_buffer_views(
626 body_idx as u32,
627 full_buffer_data.len(),
628 vertex_count,
629 face_count,
630 joint_count,
631 num_extra_joints,
632 &mut current_buffer_views,
633 compatibility_mode,
634 );
635 let (buffer_data, composed_buffer_views, buffer_offset, buffer_index) = self.compose_buffer_views(
636 body_idx,
637 ¤t_body,
638 current_buffer_views.clone(),
639 index_data.as_slice(),
640 vertex_data.as_slice(),
641 inv_bind_mat_data.as_slice(),
642 &mut texture_infos,
643 compatibility_mode,
644 );
645 global_buffer_offset += buffer_offset;
646 global_buffer_index += buffer_index;
647 full_buffer_data.extend(buffer_data);
648 buffer_views.extend(composed_buffer_views);
649 for texture in texture_infos {
650 images.push(texture.image);
651 textures.push(texture.texture);
652 texture_samplers.push(texture.sampler);
653 }
654 let armature_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
655 let armature_node = Node {
656 name: Some(format!("Armature_{body_idx}")),
657 children: Some(vec![]),
658 ..Default::default()
659 };
660 nodes.push(armature_node);
661 if let Some(ref mut scene_armatures) = nodes[0].children {
662 scene_armatures.push(gltf_json::Index::new(armature_node_index));
663 }
664 let mesh_skin_binding_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
665 let mesh_skin_binding_node = Node {
666 mesh: Some(gltf_json::Index::new(body_idx as u32)),
667 skin: Some(gltf_json::Index::new(body_idx as u32)),
668 name: Some(format!("MeshSkinBinding_{body_idx}")),
669 children: None,
670 ..Default::default()
671 };
672 nodes.push(mesh_skin_binding_node);
673 let root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
674 let mut joints = vec![];
675 if compatibility_mode == GltfCompatibilityMode::Unreal {
676 let root_node = Node {
677 name: Some("root".to_string()),
678 translation: Some([0.0, 0.0, 0.0]),
679 children: Some(vec![]),
680 ..Default::default()
681 };
682 let joint_index = gltf_json::Index::<Node>::new(u32::try_from(nodes.len()).expect("Issue converting Node idx to u32"));
683 nodes.push(root_node);
684 joints.push(joint_index);
685 let add_empty_node = |nodes: &mut Vec<Node>,
686 joints: &mut Vec<gltf_json::Index<Node>>,
687 name: &str,
688 parent_index: u32,
689 has_children: bool,
690 reference_bone: usize|
691 -> u32 {
692 let relative_parent_idx = parent_index - root_node_index;
693 let node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
694 let unit_quaternion = [0.0, 0.0, 0.0, 1.0];
695 let trans: Vec<f32> = if reference_bone == 0 {
696 vec![0.0, 0.0, 0.0]
697 } else {
698 let trans = vec_from_vec(&joint_translations.row(reference_bone).to_vec());
699 let parent_trans = if unreal_mapping[relative_parent_idx as usize] != 0 {
700 vec_from_vec(&joint_translations.row(unreal_mapping[relative_parent_idx as usize]).to_vec())
701 } else {
702 vec_from_vec(&[0.0, 0.0, 0.0])
703 };
704 vec_to_vec(&subv3f(&trans, &parent_trans))
705 };
706 let translation = [trans[0], trans[1], trans[2]];
707 let new_node = Node {
708 name: Some(name.to_string()),
709 rotation: Some(UnitQuaternion(unit_quaternion)),
710 translation: Some(translation),
711 children: if has_children { Some(vec![]) } else { None },
712 ..Default::default()
713 };
714 if let Some(ref mut parent_children) = nodes[parent_index as usize].children {
715 parent_children.push(gltf_json::Index::new(node_index));
716 }
717 let joint_index = gltf_json::Index::<Node>::new(node_index);
718 nodes.push(new_node);
719 joints.push(joint_index);
720 node_index
721 };
722 add_empty_node(&mut nodes, &mut joints, "center_of_mass", root_node_index, false, 0);
723 let ik_foot_root_index = add_empty_node(&mut nodes, &mut joints, "ik_foot_root", root_node_index, true, 0);
724 add_empty_node(&mut nodes, &mut joints, "ik_foot_r", ik_foot_root_index, false, 8);
725 add_empty_node(&mut nodes, &mut joints, "ik_foot_l", ik_foot_root_index, false, 7);
726 let ik_hand_root_index = add_empty_node(&mut nodes, &mut joints, "ik_hand_root", root_node_index, true, 0);
727 let ik_hand_gun_index = add_empty_node(&mut nodes, &mut joints, "ik_hand_gun", ik_hand_root_index, true, 21);
728 add_empty_node(&mut nodes, &mut joints, "ik_hand_r", ik_hand_gun_index, false, 21);
729 add_empty_node(&mut nodes, &mut joints, "ik_hand_l", ik_hand_gun_index, false, 20);
730 add_empty_node(&mut nodes, &mut joints, "interaction", root_node_index, false, 0);
731 }
732 let skeleton_root_index = self.add_skin(
733 format!("Skin_{body_idx}"),
734 ¤t_body,
735 armature_node_index,
736 current_accessor_offset,
737 &mut nodes,
738 &mut skins,
739 &mut joints,
740 compatibility_mode,
741 );
742 if compatibility_mode == GltfCompatibilityMode::Unreal {
743 if let Some(ref mut root) = nodes[root_node_index as usize].children {
744 root.push(skeleton_root_index);
745 }
746 }
747 if let Some(ref mut armature_children) = nodes[armature_node_index as usize].children {
748 armature_children.push(gltf_json::Index::new(mesh_skin_binding_node_index));
749 armature_children.push(gltf_json::Index::new(root_node_index));
750 }
751 if self.is_animated() {
752 let animation_channels = self.create_animation_channels(
753 joint_count,
754 root_node_index,
755 skeleton_root_index.value(),
756 samplers.len(),
757 compatibility_mode,
758 );
759 let animation_samplers = self.create_animation_samplers(joint_count, current_accessor_offset, compatibility_mode);
760 channels.extend(animation_channels);
761 samplers.extend(animation_samplers);
762 }
763 }
764 if self.smpl_camera.is_some() {
765 let (cam_track_buffer_views, cam_track_buffer_data) =
766 self.create_camera_animation_buffer_views(&mut full_buffer_data.len(), compatibility_mode);
767 let cam_track_accessors = self.create_camera_animation_accessors(buffer_views.len() as u32);
768 let (cam_track_channels, cam_track_samplers) =
769 self.create_camera_animation_channels_and_samplers(accessors.len() as u32, 1, samplers.len() as u32);
770 buffer_views.extend(cam_track_buffer_views);
771 full_buffer_data.extend(cam_track_buffer_data);
772 accessors.extend(cam_track_accessors);
773 channels.extend(cam_track_channels);
774 samplers.extend(cam_track_samplers);
775 }
776 for prop_idx in 0..self.props.len() {
777 let prop = self.props[prop_idx].clone();
778 let prop_mesh_index = self.per_body_data.len() + prop_idx;
779 info!("Writing prop {prop_idx} to GLTF");
780 let mut inverse_bind_matrices: Vec<f32> = vec![];
781 let joint_rotations = batch_rodrigues(&prop.default_joint_poses);
782 let joint_translations = prop.default_translation.clone();
783 let joint_count = 1;
784 let parents = [0];
785 let bind_matrices = self.create_bind_matrices(&joint_rotations, &joint_translations, &parents);
786 for j_idx in 0..joint_count {
787 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
788 let inverse_rotation_matrix: ArrayBase<ndarray::ViewRepr<&f32>, Dim<[usize; 2]>> =
789 bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
790 let translation: nd::Array1<f32> = bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned();
791 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
792 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
793 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
794 inverse_bind_matrix[(3, 3)] = 1.0;
795 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
796 }
797 let has_uv = prop.uvs.is_some();
798 info!("has uv: {has_uv}");
799 let vertex_data = if let Some(uvs) = prop.uvs.as_ref() {
800 info!("uv size: {:?}", uvs.shape());
801 info!("prop.positions size: {:?}", prop.positions.shape());
802 let mut vertex_attributes_array: Vec<VertexPropWithUV> = vec![];
803 for (position, uv) in izip!(prop.positions.row_iter(), uvs.row_iter()) {
804 vertex_attributes_array.push(VertexPropWithUV {
805 position: Vector3f::new(position[0], position[1], position[2]).into(),
806 uv: Vector2f::new(uv[0], 1.0 - uv[1]).into(),
807 joint_index: Vector4s::new(0, 0, 0, 0).into(),
808 joint_weight: Vector4f::new(1.0, 0.0, 0.0, 0.0).into(),
809 });
810 }
811 to_padded_byte_vector(&vertex_attributes_array)
812 } else {
813 println!("no uv found");
814 let mut vertex_attributes_array: Vec<VertexProp> = vec![];
815 for position in izip!(prop.positions.row_iter(),) {
816 vertex_attributes_array.push(VertexProp {
817 position: Vector3f::new(position[0], position[1], position[2]).into(),
818 joint_index: Vector4s::new(0, 0, 0, 0).into(),
819 joint_weight: Vector4f::new(1.0, 0.0, 0.0, 0.0).into(),
820 });
821 }
822 to_padded_byte_vector(&vertex_attributes_array)
823 };
824 let mut indices_array: Vec<u32> = vec![];
825 for row in prop.faces.row_iter() {
826 indices_array.extend_from_slice(&[row[0], row[1], row[2]]);
827 }
828 let index_data = to_padded_byte_vector(&indices_array);
829 let inv_bind_mat_data = to_padded_byte_vector(&inverse_bind_matrices);
830 let has_diffuse = prop.diffuse_texture.is_some();
831 let mut texture_infos: Vec<GltfTextureInfo> = vec![];
832 let mut diffuse_prop_texture_id = None;
833 let tex_offset = self.per_body_data.len() * 3;
834 if let Some(img) = prop.diffuse_texture.as_ref() {
835 let diffuse_tex = self.add_texture(img, texture_infos.len() + tex_offset, "diffuse_prop");
836 if let Some(diffuse_tex) = diffuse_tex {
837 diffuse_prop_texture_id = Some(texture_infos.len());
838 texture_infos.push(diffuse_tex);
839 }
840 }
841 diffuse_prop_texture_id = diffuse_prop_texture_id.map(|id| id + tex_offset);
842 let mut base_color_texture: Option<gltf_json::texture::Info> = None;
843 if let Some(diffuse_texture_index) = diffuse_prop_texture_id {
844 base_color_texture = Some(gltf_json::texture::Info {
845 index: gltf_json::Index::new(u32::try_from(diffuse_texture_index).expect("Could not convert to u32!")),
846 tex_coord: 0,
847 extensions: None,
848 extras: None,
849 });
850 }
851 let material = gltf_json::Material {
852 alpha_cutoff: None,
853 alpha_mode: gltf_json::validation::Checked::<AlphaMode>::Valid(AlphaMode::Opaque),
854 double_sided: false,
855 name: Some("prop_material".to_string()),
856 pbr_metallic_roughness: gltf_json::material::PbrMetallicRoughness {
857 base_color_factor: gltf_json::material::PbrBaseColorFactor([1., 1., 1., 1.]),
858 base_color_texture,
859 ..Default::default()
860 },
861 normal_texture: None,
862 occlusion_texture: None,
863 emissive_texture: None,
864 emissive_factor: gltf_json::material::EmissiveFactor([0., 0., 0.]),
865 extensions: None,
866 extras: None,
867 };
868 materials.push(material);
869 let primitive_offset = accessors.len() as u32;
870 let materials_selected = if has_diffuse {
871 Some(gltf_json::Index::new(prop_mesh_index as u32))
872 } else {
873 None
874 };
875 let primitive = gltf_json::mesh::Primitive {
876 #[allow(unused_assignments)]
877 attributes: {
878 let mut map = std::collections::BTreeMap::new();
879 let mut attr_idx = 1;
880 map.insert(
881 Valid(gltf_json::mesh::Semantic::Positions),
882 gltf_json::Index::new(attr_idx + primitive_offset),
883 );
884 attr_idx += 1;
885 if has_uv {
886 map.insert(
887 Valid(gltf_json::mesh::Semantic::TexCoords(0)),
888 gltf_json::Index::new(attr_idx + primitive_offset),
889 );
890 attr_idx += 1;
891 }
892 map.insert(
893 Valid(gltf_json::mesh::Semantic::Joints(0)),
894 gltf_json::Index::new(attr_idx + primitive_offset),
895 );
896 attr_idx += 1;
897 map.insert(
898 Valid(gltf_json::mesh::Semantic::Weights(0)),
899 gltf_json::Index::new(attr_idx + primitive_offset),
900 );
901 attr_idx += 1;
902 map
903 },
904 extensions: Option::default(),
905 extras: Option::default(),
906 indices: Some(gltf_json::Index::new(PrimitiveAttrIDs::Indices as u32 + primitive_offset)),
907 material: materials_selected,
908 mode: Valid(gltf_json::mesh::Mode::Triangles),
909 targets: None,
910 };
911 let mesh = gltf_json::Mesh {
912 extensions: Option::default(),
913 extras: Option::default(),
914 name: Some(format!("prop_{prop_idx}")),
915 primitives: vec![primitive],
916 weights: None,
917 };
918 meshes.push(mesh);
919 let vertex_count = prop.positions.shape().0;
920 let face_count = prop.faces.shape().0;
921 let current_buffer_view_offset = buffer_views.len() as u32;
922 let mut per_view_running_offset: [usize; 6] = [0, 0, 0, 0, 0, 0];
923 let accessor = self.create_accessors_props(
924 prop_idx,
925 vertex_count,
926 face_count,
927 current_buffer_view_offset,
928 &mut per_view_running_offset,
929 compatibility_mode,
930 has_uv,
931 );
932 accessors.extend(accessor);
933 let mut current_buffer_views = vec![];
934 self.create_buffer_views_props(
935 prop_idx as u32,
936 full_buffer_data.len(),
937 vertex_count,
938 face_count,
939 &mut current_buffer_views,
940 compatibility_mode,
941 has_uv,
942 );
943 let (buffer_data, composed_buffer_views, _buffer_offset, _buffer_index) = self.compose_buffer_views_props(
944 &self.props[prop_idx],
945 current_buffer_views.clone(),
946 index_data.as_slice(),
947 vertex_data.as_slice(),
948 inv_bind_mat_data.as_slice(),
949 &mut texture_infos,
950 compatibility_mode,
951 global_buffer_offset,
952 global_buffer_index,
953 );
954 full_buffer_data.extend(buffer_data);
955 buffer_views.extend(composed_buffer_views);
956 for texture in texture_infos {
957 images.push(texture.image);
958 textures.push(texture.texture);
959 texture_samplers.push(texture.sampler);
960 }
961 let prop_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
962 let armature_node = Node {
963 name: Some(format!("Armature_Prop_{prop_idx}")),
964 children: Some(vec![]),
965 ..Default::default()
966 };
967 nodes.push(armature_node);
968 if let Some(ref mut scene_root_node_children) = nodes[0].children {
969 scene_root_node_children.push(gltf_json::Index::new(prop_node_index));
970 }
971 let mesh_skin_binding_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
972 let mesh_skin_binding_node = Node {
973 mesh: Some(gltf_json::Index::new(prop_mesh_index as u32)),
974 skin: Some(gltf_json::Index::new(prop_mesh_index as u32)),
975 name: Some(format!("MeshSkinBinding_{prop_idx}")),
976 children: None,
977 ..Default::default()
978 };
979 nodes.push(mesh_skin_binding_node);
980 let root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
981 let mut joints = vec![];
982 let skeleton_root_index = self.add_skin_prop(
983 format!("Skin_prop_{prop_idx}"),
984 &prop,
985 prop_node_index,
986 accessors.len().try_into().unwrap(),
987 &mut nodes,
988 &mut skins,
989 &mut joints,
990 compatibility_mode,
991 );
992 if let Some(ref mut armature_children) = nodes[prop_node_index as usize].children {
993 armature_children.push(gltf_json::Index::new(mesh_skin_binding_node_index));
994 armature_children.push(gltf_json::Index::new(root_node_index));
995 }
996 let animation_channels = self.create_animation_channels_prop(
997 joint_count,
998 root_node_index,
999 skeleton_root_index.value(),
1000 samplers.len(),
1001 compatibility_mode,
1002 );
1003 let animation_samplers = self.create_animation_samplers_prop(joint_count, accessors.len().try_into().unwrap(), compatibility_mode);
1004 channels.extend(animation_channels);
1005 samplers.extend(animation_samplers);
1006 }
1007 let buffer = gltf_json::Buffer {
1008 byte_length: USize64::from(full_buffer_data.len()),
1009 extensions: Option::default(),
1010 extras: Option::default(),
1011 name: Some("scene_buffer".to_string()),
1012 uri: if binary { None } else { Some("buffer0.bin".into()) },
1013 };
1014 buffers.push(buffer);
1015 let mut animations: Vec<gltf_json::Animation> = vec![];
1016 if self.is_animated() {
1017 let animation = gltf_json::Animation {
1018 extensions: Option::default(),
1019 extras: Option::default(),
1020 channels,
1021 name: Some("Scene_animation".to_string()),
1022 samplers,
1023 };
1024 animations.push(animation);
1025 }
1026 let root = gltf_json::Root {
1027 accessors,
1028 animations,
1029 buffers,
1030 buffer_views,
1031 cameras,
1032 images,
1033 materials,
1034 meshes,
1035 nodes,
1036 samplers: texture_samplers,
1037 scenes,
1038 skins,
1039 textures,
1040 ..Default::default()
1041 };
1042 (full_buffer_data, root)
1043 }
1044 #[allow(clippy::too_many_arguments)]
1046 fn create_buffer_views(
1047 &self,
1048 body_idx: u32,
1049 mut running_offset: usize,
1050 vertex_count: usize,
1051 face_count: usize,
1052 joint_count: usize,
1053 num_extra_joints: usize,
1054 buffer_views: &mut Vec<gltf_json::buffer::View>,
1055 compatibility_mode: GltfCompatibilityMode,
1056 ) {
1057 let index_buffer_size = face_count * 3 * mem::size_of::<u32>();
1058 let index_buffer_view = gltf_json::buffer::View {
1059 buffer: gltf_json::Index::new(0),
1060 byte_length: USize64::from(index_buffer_size),
1061 byte_offset: Some(USize64::from(running_offset)),
1062 byte_stride: None,
1063 extensions: Option::default(),
1064 extras: Option::default(),
1065 name: Some(format!("index_buffer_view_{body_idx}")),
1066 target: Some(Valid(gltf_json::buffer::Target::ElementArrayBuffer)),
1067 };
1068 buffer_views.push(index_buffer_view);
1069 running_offset += index_buffer_size;
1070 let vertex_buffer_size = vertex_count * mem::size_of::<Vertex>();
1071 let vertex_buffer_view = gltf_json::buffer::View {
1072 buffer: gltf_json::Index::new(0),
1073 byte_length: USize64::from(vertex_buffer_size),
1074 byte_offset: Some(USize64::from(running_offset)),
1075 byte_stride: Some(gltf_json::buffer::Stride(mem::size_of::<Vertex>())),
1076 extensions: Option::default(),
1077 extras: Option::default(),
1078 name: Some(format!("vertex_buffer_view_{body_idx}")),
1079 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1080 };
1081 buffer_views.push(vertex_buffer_view);
1082 running_offset += vertex_buffer_size;
1083 let inv_bind_matrix_buffer_size = (joint_count + num_extra_joints) * 16 * mem::size_of::<f32>();
1084 let inverse_bind_mat_buffer_view = gltf_json::buffer::View {
1085 buffer: gltf_json::Index::new(0),
1086 byte_length: USize64::from(inv_bind_matrix_buffer_size),
1087 byte_offset: Some(USize64::from(running_offset)),
1088 byte_stride: None,
1089 extensions: Option::default(),
1090 extras: Option::default(),
1091 name: Some(format!("inv_bind_matrix_buffer_view_{body_idx}")),
1092 target: None,
1093 };
1094 buffer_views.push(inverse_bind_mat_buffer_view);
1095 running_offset += inv_bind_matrix_buffer_size;
1096 if self.is_animated() {
1097 let rotation_animation_buffer_size = self.frame_count.unwrap() * 4 * mem::size_of::<f32>();
1098 let translation_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1099 let scale_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1100 let animation_buffer_views = self.create_animation_buffer_views(
1101 body_idx,
1102 joint_count,
1103 rotation_animation_buffer_size,
1104 translation_animation_buffer_size,
1105 scale_animation_buffer_size,
1106 &mut running_offset,
1107 compatibility_mode,
1108 );
1109 buffer_views.extend(animation_buffer_views);
1110 if self.num_morph_targets() > 0 && body_idx == 0 {
1111 let morph_target_buffer_size = vertex_count * 3 * mem::size_of::<f32>();
1112 let morph_target_buffer_views = self.create_morph_target_buffer_views(morph_target_buffer_size, &mut running_offset);
1113 buffer_views.extend(morph_target_buffer_views);
1114 }
1115 }
1116 }
1117 #[allow(clippy::too_many_arguments)]
1119 fn create_buffer_views_props(
1120 &self,
1121 prop_idx: u32,
1122 mut running_offset: usize,
1123 vertex_count: usize,
1124 face_count: usize,
1125 buffer_views: &mut Vec<gltf_json::buffer::View>,
1126 compatibility_mode: GltfCompatibilityMode,
1127 with_uv: bool,
1128 ) {
1129 let joint_count = 1;
1130 let index_buffer_size = face_count * 3 * mem::size_of::<u32>();
1131 let index_buffer_view = gltf_json::buffer::View {
1132 buffer: gltf_json::Index::new(0),
1133 byte_length: USize64::from(index_buffer_size),
1134 byte_offset: Some(USize64::from(running_offset)),
1135 byte_stride: None,
1136 extensions: Option::default(),
1137 extras: Option::default(),
1138 name: Some(format!("index_buffer_view_prop_{prop_idx}")),
1139 target: Some(Valid(gltf_json::buffer::Target::ElementArrayBuffer)),
1140 };
1141 buffer_views.push(index_buffer_view);
1142 running_offset += index_buffer_size;
1143 let vertex_size = if with_uv {
1144 mem::size_of::<VertexPropWithUV>()
1145 } else {
1146 mem::size_of::<VertexProp>()
1147 };
1148 let vertex_buffer_size = vertex_count * vertex_size;
1149 let vertex_buffer_view = gltf_json::buffer::View {
1150 buffer: gltf_json::Index::new(0),
1151 byte_length: USize64::from(vertex_buffer_size),
1152 byte_offset: Some(USize64::from(running_offset)),
1153 byte_stride: Some(gltf_json::buffer::Stride(vertex_size)),
1154 extensions: Option::default(),
1155 extras: Option::default(),
1156 name: Some(format!("vertex_buffer_view_prop_{prop_idx}")),
1157 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1158 };
1159 buffer_views.push(vertex_buffer_view);
1160 running_offset += vertex_buffer_size;
1161 let inv_bind_matrix_buffer_size = (joint_count) * 16 * mem::size_of::<f32>();
1162 let inverse_bind_mat_buffer_view = gltf_json::buffer::View {
1163 buffer: gltf_json::Index::new(0),
1164 byte_length: USize64::from(inv_bind_matrix_buffer_size),
1165 byte_offset: Some(USize64::from(running_offset)),
1166 byte_stride: None,
1167 extensions: Option::default(),
1168 extras: Option::default(),
1169 name: Some(format!("inv_bind_matrix_buffer_view_{prop_idx}")),
1170 target: None,
1171 };
1172 buffer_views.push(inverse_bind_mat_buffer_view);
1173 running_offset += inv_bind_matrix_buffer_size;
1174 let rotation_animation_buffer_size = self.frame_count.unwrap() * 4 * mem::size_of::<f32>();
1175 let translation_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1176 let scale_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1177 let animation_buffer_views = self.create_animation_buffer_views_prop(
1178 prop_idx,
1179 joint_count,
1180 rotation_animation_buffer_size,
1181 translation_animation_buffer_size,
1182 scale_animation_buffer_size,
1183 &mut running_offset,
1184 compatibility_mode,
1185 );
1186 buffer_views.extend(animation_buffer_views);
1187 }
1188 #[allow(clippy::too_many_arguments)]
1190 fn create_animation_buffer_views(
1191 &self,
1192 body_idx: u32,
1193 joint_count: usize,
1194 rotation_buffer_size: usize,
1195 translation_buffer_size: usize,
1196 scale_buffer_size: usize,
1197 running_offset: &mut usize,
1198 compatibility_mode: GltfCompatibilityMode,
1199 ) -> Vec<gltf_json::buffer::View> {
1200 let mut animation_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1201 let keyframe_buffer_size = self.frame_count.unwrap() * mem::size_of::<f32>();
1202 let keyframe_buffer_view = gltf_json::buffer::View {
1203 buffer: gltf_json::Index::new(0),
1204 byte_length: USize64::from(keyframe_buffer_size),
1205 byte_offset: Some(USize64::from(*running_offset)),
1206 byte_stride: None,
1207 extensions: Option::default(),
1208 extras: Option::default(),
1209 name: Some(format!("keyframe_buffer_view_{body_idx}")),
1210 target: None,
1211 };
1212 animation_buffer_views.push(keyframe_buffer_view);
1213 *running_offset += keyframe_buffer_size;
1214 for j_idx in 0..joint_count {
1215 let buffer_view_name = format!("joint_{j_idx}_animations_buffer_view_{body_idx}");
1216 let animation_buffer_view = gltf_json::buffer::View {
1217 buffer: gltf_json::Index::new(0),
1218 byte_length: USize64::from(rotation_buffer_size),
1219 byte_offset: Some(USize64::from(*running_offset)),
1220 byte_stride: None,
1221 extensions: Option::default(),
1222 extras: Option::default(),
1223 name: Some(buffer_view_name),
1224 target: None,
1225 };
1226 animation_buffer_views.push(animation_buffer_view);
1227 *running_offset += rotation_buffer_size;
1228 }
1229 let buffer_view_name = format!("root_translation_animations_buffer_view_{body_idx}");
1230 let animation_buffer_view = gltf_json::buffer::View {
1231 buffer: gltf_json::Index::new(0),
1232 byte_length: USize64::from(translation_buffer_size),
1233 byte_offset: Some(USize64::from(*running_offset)),
1234 byte_stride: None,
1235 extensions: Option::default(),
1236 extras: Option::default(),
1237 name: Some(buffer_view_name),
1238 target: None,
1239 };
1240 animation_buffer_views.push(animation_buffer_view);
1241 *running_offset += translation_buffer_size;
1242 let buffer_view_name = format!("root_scale_animations_buffer_view_{body_idx}");
1243 let animation_buffer_view = gltf_json::buffer::View {
1244 buffer: gltf_json::Index::new(0),
1245 byte_length: USize64::from(scale_buffer_size),
1246 byte_offset: Some(USize64::from(*running_offset)),
1247 byte_stride: None,
1248 extensions: Option::default(),
1249 extras: Option::default(),
1250 name: Some(buffer_view_name),
1251 target: None,
1252 };
1253 animation_buffer_views.push(animation_buffer_view);
1254 *running_offset += scale_buffer_size;
1255 if compatibility_mode == GltfCompatibilityMode::Unreal {
1256 let buffer_view_name = format!("pelvis_rel_translation_animations_buffer_view_{body_idx}");
1257 let animation_buffer_view = gltf_json::buffer::View {
1258 buffer: gltf_json::Index::new(0),
1259 byte_length: USize64::from(translation_buffer_size),
1260 byte_offset: Some(USize64::from(*running_offset)),
1261 byte_stride: None,
1262 extensions: Option::default(),
1263 extras: Option::default(),
1264 name: Some(buffer_view_name),
1265 target: None,
1266 };
1267 animation_buffer_views.push(animation_buffer_view);
1268 *running_offset += translation_buffer_size;
1269 }
1270 if self.num_morph_targets() > 0 {
1271 let morph_weights_buffer_size = self.frame_count.unwrap() * self.num_morph_targets() * mem::size_of::<f32>();
1272 let buffer_view_name = format!("morph_target_weights_{body_idx}");
1273 let morph_weights_buffer_view = gltf_json::buffer::View {
1274 buffer: gltf_json::Index::new(0),
1275 byte_length: USize64::from(morph_weights_buffer_size),
1276 byte_offset: Some(USize64::from(*running_offset)),
1277 byte_stride: None,
1278 extensions: Option::default(),
1279 extras: Option::default(),
1280 name: Some(buffer_view_name),
1281 target: None,
1282 };
1283 animation_buffer_views.push(morph_weights_buffer_view);
1284 *running_offset += morph_weights_buffer_size;
1285 }
1286 animation_buffer_views
1287 }
1288 #[allow(clippy::too_many_arguments)]
1289 fn create_animation_buffer_views_prop(
1290 &self,
1291 prop_idx: u32,
1292 joint_count: usize,
1293 rotation_buffer_size: usize,
1294 translation_buffer_size: usize,
1295 scale_buffer_size: usize,
1296 running_offset: &mut usize,
1297 _compatibility_mode: GltfCompatibilityMode,
1298 ) -> Vec<gltf_json::buffer::View> {
1299 let mut animation_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1300 let keyframe_buffer_size = self.frame_count.unwrap() * mem::size_of::<f32>();
1301 let keyframe_buffer_view = gltf_json::buffer::View {
1302 buffer: gltf_json::Index::new(0),
1303 byte_length: USize64::from(keyframe_buffer_size),
1304 byte_offset: Some(USize64::from(*running_offset)),
1305 byte_stride: None,
1306 extensions: Option::default(),
1307 extras: Option::default(),
1308 name: Some(format!("keyframe_buffer_view_prop_{prop_idx}")),
1309 target: None,
1310 };
1311 animation_buffer_views.push(keyframe_buffer_view);
1312 *running_offset += keyframe_buffer_size;
1313 for j_idx in 0..joint_count {
1314 let buffer_view_name = format!("joint_{j_idx}_animations_buffer_view_prop_{prop_idx}");
1315 let animation_buffer_view = gltf_json::buffer::View {
1316 buffer: gltf_json::Index::new(0),
1317 byte_length: USize64::from(rotation_buffer_size),
1318 byte_offset: Some(USize64::from(*running_offset)),
1319 byte_stride: None,
1320 extensions: Option::default(),
1321 extras: Option::default(),
1322 name: Some(buffer_view_name),
1323 target: None,
1324 };
1325 animation_buffer_views.push(animation_buffer_view);
1326 *running_offset += rotation_buffer_size;
1327 }
1328 let buffer_view_name = format!("root_translation_animations_buffer_view_prop_{prop_idx}");
1329 let animation_buffer_view = gltf_json::buffer::View {
1330 buffer: gltf_json::Index::new(0),
1331 byte_length: USize64::from(translation_buffer_size),
1332 byte_offset: Some(USize64::from(*running_offset)),
1333 byte_stride: None,
1334 extensions: Option::default(),
1335 extras: Option::default(),
1336 name: Some(buffer_view_name),
1337 target: None,
1338 };
1339 animation_buffer_views.push(animation_buffer_view);
1340 *running_offset += translation_buffer_size;
1341 let buffer_view_name = format!("root_scale_animations_buffer_view_prop_{prop_idx}");
1342 let animation_buffer_view = gltf_json::buffer::View {
1343 buffer: gltf_json::Index::new(0),
1344 byte_length: USize64::from(scale_buffer_size),
1345 byte_offset: Some(USize64::from(*running_offset)),
1346 byte_stride: None,
1347 extensions: Option::default(),
1348 extras: Option::default(),
1349 name: Some(buffer_view_name),
1350 target: None,
1351 };
1352 animation_buffer_views.push(animation_buffer_view);
1353 *running_offset += scale_buffer_size;
1354 animation_buffer_views
1355 }
1356 fn create_morph_target_buffer_views(&self, morph_target_buffer_size: usize, running_offset: &mut usize) -> Vec<gltf_json::buffer::View> {
1358 let mut morph_targets_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1359 for morph_target_idx in 0..self.num_morph_targets() {
1360 let buffer_view_name = format!("morph_{morph_target_idx}_buffer_view");
1361 let morph_target_buffer_view = gltf_json::buffer::View {
1362 buffer: gltf_json::Index::new(0),
1363 byte_length: USize64::from(morph_target_buffer_size),
1364 byte_offset: Some(USize64::from(*running_offset)),
1365 byte_stride: None,
1366 extensions: Option::default(),
1367 extras: Option::default(),
1368 name: Some(buffer_view_name),
1369 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1370 };
1371 morph_targets_buffer_views.push(morph_target_buffer_view);
1372 *running_offset += morph_target_buffer_size;
1373 }
1374 morph_targets_buffer_views
1375 }
1376 #[allow(clippy::too_many_lines)]
1378 #[allow(clippy::too_many_arguments)]
1379 fn create_accessors(
1380 &self,
1381 body_idx: usize,
1382 vertex_count: usize,
1383 face_count: usize,
1384 joint_count: usize,
1385 current_buffer_view_offset: u32,
1386 per_view_running_offset: &mut [usize; 6],
1387 num_extra_joints: usize,
1388 compatibility_mode: GltfCompatibilityMode,
1389 ) -> Vec<gltf_json::Accessor> {
1390 let (min, max) = geom::get_bounding_points(self.per_body_data[body_idx].positions.as_ref().unwrap(), None);
1391 let (min_vec, max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1392 let mut accessors: Vec<gltf_json::Accessor> = vec![];
1393 let indices = gltf_json::Accessor {
1394 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Index as u32 + current_buffer_view_offset)),
1395 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Index as usize])),
1396 count: USize64::from(face_count * 3),
1397 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U32)),
1398 extensions: Option::default(),
1399 extras: Option::default(),
1400 type_: Valid(gltf_json::accessor::Type::Scalar),
1401 min: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().min()]))),
1402 max: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().max()]))),
1403 name: Some(format!("index_accessor_{body_idx}")),
1404 normalized: false,
1405 sparse: None,
1406 };
1407 accessors.push(indices);
1408 let position_element_size = 3 * mem::size_of::<f32>();
1409 let positions = gltf_json::Accessor {
1410 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1411 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1412 count: USize64::from(vertex_count),
1413 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1414 extensions: Option::default(),
1415 extras: Option::default(),
1416 type_: Valid(gltf_json::accessor::Type::Vec3),
1417 min: Some(gltf_json::Value::from(min_vec)),
1418 max: Some(gltf_json::Value::from(max_vec)),
1419 name: Some(format!("position_accessor_{body_idx}")),
1420 normalized: false,
1421 sparse: None,
1422 };
1423 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += position_element_size;
1424 accessors.push(positions);
1425 let normal_element_size = 3 * mem::size_of::<f32>();
1426 let normals = gltf_json::Accessor {
1427 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1428 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1429 count: USize64::from(vertex_count),
1430 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1431 extensions: Option::default(),
1432 extras: Option::default(),
1433 type_: Valid(gltf_json::accessor::Type::Vec3),
1434 min: None,
1435 max: None,
1436 name: Some(format!("normal_accessor_{body_idx}")),
1437 normalized: false,
1438 sparse: None,
1439 };
1440 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += normal_element_size;
1441 accessors.push(normals);
1442 let uv_element_size = 2 * mem::size_of::<f32>();
1443 let uvs = gltf_json::Accessor {
1444 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1445 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1446 count: USize64::from(vertex_count),
1447 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1448 extensions: Option::default(),
1449 extras: Option::default(),
1450 type_: Valid(gltf_json::accessor::Type::Vec2),
1451 min: None,
1452 max: None,
1453 name: Some("uv_accessor".to_string()),
1454 normalized: false,
1455 sparse: None,
1456 };
1457 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += uv_element_size;
1458 accessors.push(uvs);
1459 let joint_index_element_size = 4 * mem::size_of::<u16>();
1460 let joint_indices = gltf_json::Accessor {
1461 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1462 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1463 count: USize64::from(vertex_count),
1464 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U16)),
1465 extensions: Option::default(),
1466 extras: Option::default(),
1467 type_: Valid(gltf_json::accessor::Type::Vec4),
1468 min: None,
1469 max: None,
1470 name: Some("joint_index_accessor".to_string()),
1471 normalized: false,
1472 sparse: None,
1473 };
1474 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_index_element_size;
1475 accessors.push(joint_indices);
1476 let joint_weight_element_size = 4 * mem::size_of::<f32>();
1477 let joint_weights = gltf_json::Accessor {
1478 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1479 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1480 count: USize64::from(vertex_count),
1481 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1482 extensions: Option::default(),
1483 extras: Option::default(),
1484 type_: Valid(gltf_json::accessor::Type::Vec4),
1485 min: None,
1486 max: None,
1487 name: Some("joint_index_accessor".to_string()),
1488 normalized: false,
1489 sparse: None,
1490 };
1491 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_weight_element_size;
1492 accessors.push(joint_weights);
1493 let inv_bind_matrices = gltf_json::Accessor {
1494 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::InvBindMat as u32 + current_buffer_view_offset)),
1495 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::InvBindMat as usize])),
1496 count: USize64::from(joint_count + num_extra_joints),
1497 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1498 extensions: Option::default(),
1499 extras: Option::default(),
1500 type_: Valid(gltf_json::accessor::Type::Mat4),
1501 min: None,
1502 max: None,
1503 name: Some("inv_bind_matrices_accessor".to_string()),
1504 normalized: false,
1505 sparse: None,
1506 };
1507 accessors.push(inv_bind_matrices);
1508 if self.is_animated() {
1509 let animation_accessors =
1510 self.create_animation_accessors(joint_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1511 accessors.extend(animation_accessors);
1512 if self.num_morph_targets() > 0 && body_idx == 0 {
1513 let morph_target_accessors =
1514 self.create_morph_target_accessors(vertex_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1515 accessors.extend(morph_target_accessors);
1516 }
1517 }
1518 accessors
1519 }
1520 #[allow(clippy::too_many_lines)]
1522 #[allow(clippy::too_many_arguments)]
1523 fn create_accessors_props(
1524 &self,
1525 prop_idx: usize,
1526 vertex_count: usize,
1527 face_count: usize,
1528 current_buffer_view_offset: u32,
1529 per_view_running_offset: &mut [usize; 6],
1530 compatibility_mode: GltfCompatibilityMode,
1531 with_uv: bool,
1532 ) -> Vec<gltf_json::Accessor> {
1533 let joint_count = 1;
1534 let (min, max) = geom::get_bounding_points(&self.props[prop_idx].positions, None);
1535 let (min_vec, max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1536 let mut accessors: Vec<gltf_json::Accessor> = vec![];
1537 let indices = gltf_json::Accessor {
1538 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Index as u32 + current_buffer_view_offset)),
1539 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Index as usize])),
1540 count: USize64::from(face_count * 3),
1541 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U32)),
1542 extensions: Option::default(),
1543 extras: Option::default(),
1544 type_: Valid(gltf_json::accessor::Type::Scalar),
1545 min: Some(gltf_json::Value::from(Vec::from([self.props[prop_idx].faces.min()]))),
1546 max: Some(gltf_json::Value::from(Vec::from([self.props[prop_idx].faces.max()]))),
1547 name: Some(format!("index_accessor_prop_{prop_idx}")),
1548 normalized: false,
1549 sparse: None,
1550 };
1551 accessors.push(indices);
1552 let position_element_size = 3 * mem::size_of::<f32>();
1553 let positions = gltf_json::Accessor {
1554 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1555 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1556 count: USize64::from(vertex_count),
1557 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1558 extensions: Option::default(),
1559 extras: Option::default(),
1560 type_: Valid(gltf_json::accessor::Type::Vec3),
1561 min: Some(gltf_json::Value::from(min_vec)),
1562 max: Some(gltf_json::Value::from(max_vec)),
1563 name: Some(format!("position_accessor_prop_{prop_idx}")),
1564 normalized: false,
1565 sparse: None,
1566 };
1567 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += position_element_size;
1568 accessors.push(positions);
1569 if with_uv {
1570 let uv_element_size = 2 * mem::size_of::<f32>();
1571 let uvs = gltf_json::Accessor {
1572 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1573 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1574 count: USize64::from(vertex_count),
1575 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1576 extensions: Option::default(),
1577 extras: Option::default(),
1578 type_: Valid(gltf_json::accessor::Type::Vec2),
1579 min: None,
1580 max: None,
1581 name: Some(format!("uv_accessor_prop_{prop_idx}")),
1582 normalized: false,
1583 sparse: None,
1584 };
1585 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += uv_element_size;
1586 accessors.push(uvs);
1587 }
1588 let joint_index_element_size = 4 * mem::size_of::<u16>();
1589 let joint_indices = gltf_json::Accessor {
1590 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1591 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1592 count: USize64::from(vertex_count),
1593 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U16)),
1594 extensions: Option::default(),
1595 extras: Option::default(),
1596 type_: Valid(gltf_json::accessor::Type::Vec4),
1597 min: None,
1598 max: None,
1599 name: Some("joint_index_accessor_prop".to_string()),
1600 normalized: false,
1601 sparse: None,
1602 };
1603 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_index_element_size;
1604 accessors.push(joint_indices);
1605 let joint_weight_element_size = 4 * mem::size_of::<f32>();
1606 let joint_weights = gltf_json::Accessor {
1607 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1608 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1609 count: USize64::from(vertex_count),
1610 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1611 extensions: Option::default(),
1612 extras: Option::default(),
1613 type_: Valid(gltf_json::accessor::Type::Vec4),
1614 min: None,
1615 max: None,
1616 name: Some("joint_weight_accessor_prop".to_string()),
1617 normalized: false,
1618 sparse: None,
1619 };
1620 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_weight_element_size;
1621 accessors.push(joint_weights);
1622 let inv_bind_matrices = gltf_json::Accessor {
1623 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::InvBindMat as u32 + current_buffer_view_offset)),
1624 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::InvBindMat as usize])),
1625 count: USize64::from(joint_count),
1626 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1627 extensions: Option::default(),
1628 extras: Option::default(),
1629 type_: Valid(gltf_json::accessor::Type::Mat4),
1630 min: None,
1631 max: None,
1632 name: Some("inv_bind_matrices_accessor_prop".to_string()),
1633 normalized: false,
1634 sparse: None,
1635 };
1636 accessors.push(inv_bind_matrices);
1637 let animation_accessors =
1638 self.create_animation_accessors_props(joint_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1639 accessors.extend(animation_accessors);
1640 accessors
1641 }
1642 #[allow(clippy::too_many_lines)]
1644 fn create_animation_accessors(
1645 &self,
1646 joint_count: usize,
1647 current_buffer_view_offset: u32,
1648 per_view_running_offset: &mut [usize; 6],
1649 compatibility_mode: GltfCompatibilityMode,
1650 ) -> Vec<gltf_json::Accessor> {
1651 let mut animation_accessors: Vec<gltf_json::Accessor> = vec![];
1652 let min_keyframe = self
1653 .keyframe_times
1654 .as_ref()
1655 .expect("keyframe_times should exist")
1656 .iter()
1657 .copied()
1658 .min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1659 .expect("keyframe_times should have elements in the vector");
1660 let max_keyframe = self
1661 .keyframe_times
1662 .as_ref()
1663 .unwrap()
1664 .iter()
1665 .copied()
1666 .max_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1667 .unwrap();
1668 let keyframe_times = gltf_json::Accessor {
1669 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Keyframe as u32 + current_buffer_view_offset)),
1670 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Keyframe as usize])),
1671 count: USize64::from(self.frame_count.unwrap()),
1672 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1673 extensions: Option::default(),
1674 extras: Option::default(),
1675 type_: Valid(gltf_json::accessor::Type::Scalar),
1676 min: Some(gltf_json::Value::from(Vec::from([min_keyframe]))),
1677 max: Some(gltf_json::Value::from(Vec::from([max_keyframe]))),
1678 name: Some("keyframes_accessor".to_string()),
1679 normalized: false,
1680 sparse: None,
1681 };
1682 animation_accessors.push(keyframe_times);
1683 let mut running_buffer_view = BufferViewIDs::Animation as u32 + current_buffer_view_offset;
1684 for j_idx in 0..joint_count {
1685 let accessor_name = format!("joint_{j_idx}_animations_accessor");
1686 let joint_animation_accessor = gltf_json::Accessor {
1687 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1688 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1689 count: USize64::from(self.frame_count.unwrap()),
1690 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1691 extensions: Option::default(),
1692 extras: Option::default(),
1693 type_: Valid(gltf_json::accessor::Type::Vec4),
1694 min: None,
1695 max: None,
1696 name: Some(accessor_name),
1697 normalized: false,
1698 sparse: None,
1699 };
1700 animation_accessors.push(joint_animation_accessor);
1701 running_buffer_view += 1;
1702 }
1703 let accessor_name = "root_translation_animations_accessor".to_string();
1704 let body_animation_accessor = gltf_json::Accessor {
1705 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1706 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1707 count: USize64::from(self.frame_count.unwrap()),
1708 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1709 extensions: Option::default(),
1710 extras: Option::default(),
1711 type_: Valid(gltf_json::accessor::Type::Vec3),
1712 min: None,
1713 max: None,
1714 name: Some(accessor_name),
1715 normalized: false,
1716 sparse: None,
1717 };
1718 animation_accessors.push(body_animation_accessor);
1719 running_buffer_view += 1;
1720 let accessor_name = "root_scale_animations_accessor".to_string();
1721 let vis_animation_accessor = gltf_json::Accessor {
1722 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1723 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1724 count: USize64::from(self.frame_count.unwrap()),
1725 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1726 extensions: Option::default(),
1727 extras: Option::default(),
1728 type_: Valid(gltf_json::accessor::Type::Vec3),
1729 min: None,
1730 max: None,
1731 name: Some(accessor_name),
1732 normalized: false,
1733 sparse: None,
1734 };
1735 animation_accessors.push(vis_animation_accessor);
1736 running_buffer_view += 1;
1737 if compatibility_mode == GltfCompatibilityMode::Unreal {
1738 let accessor_name = "pelvis_rel_translation_animations_accessor".to_string();
1739 let pelvis_animation_accessor = gltf_json::Accessor {
1740 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1741 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1742 count: USize64::from(self.frame_count.unwrap()),
1743 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1744 extensions: Option::default(),
1745 extras: Option::default(),
1746 type_: Valid(gltf_json::accessor::Type::Vec3),
1747 min: None,
1748 max: None,
1749 name: Some(accessor_name),
1750 normalized: false,
1751 sparse: None,
1752 };
1753 animation_accessors.push(pelvis_animation_accessor);
1754 running_buffer_view += 1;
1755 }
1756 if self.num_morph_targets() > 0 {
1757 let accessor_name = "morph_targets_weights_accessor".to_string();
1758 let morph_targets_weights_accessor = gltf_json::Accessor {
1759 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1760 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1761 count: USize64::from(self.frame_count.unwrap() * self.num_morph_targets()),
1762 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1763 extensions: Option::default(),
1764 extras: Option::default(),
1765 type_: Valid(gltf_json::accessor::Type::Scalar),
1766 min: None,
1767 max: None,
1768 name: Some(accessor_name),
1769 normalized: false,
1770 sparse: None,
1771 };
1772 animation_accessors.push(morph_targets_weights_accessor);
1773 running_buffer_view += 1;
1774 }
1775 per_view_running_offset[BufferViewIDs::Animation as usize] += running_buffer_view as usize;
1776 animation_accessors
1777 }
1778 #[allow(clippy::too_many_lines)]
1779 fn create_animation_accessors_props(
1780 &self,
1781 joint_count: usize,
1782 current_buffer_view_offset: u32,
1783 per_view_running_offset: &mut [usize; 6],
1784 _compatibility_mode: GltfCompatibilityMode,
1785 ) -> Vec<gltf_json::Accessor> {
1786 let mut animation_accessors: Vec<gltf_json::Accessor> = vec![];
1787 let min_keyframe = self
1788 .keyframe_times
1789 .as_ref()
1790 .expect("keyframe_times should exist")
1791 .iter()
1792 .copied()
1793 .min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1794 .expect("keyframe_times should have elements in the vector");
1795 let max_keyframe = self
1796 .keyframe_times
1797 .as_ref()
1798 .unwrap()
1799 .iter()
1800 .copied()
1801 .max_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1802 .unwrap();
1803 let keyframe_times = gltf_json::Accessor {
1804 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Keyframe as u32 + current_buffer_view_offset)),
1805 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Keyframe as usize])),
1806 count: USize64::from(self.frame_count.unwrap()),
1807 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1808 extensions: Option::default(),
1809 extras: Option::default(),
1810 type_: Valid(gltf_json::accessor::Type::Scalar),
1811 min: Some(gltf_json::Value::from(Vec::from([min_keyframe]))),
1812 max: Some(gltf_json::Value::from(Vec::from([max_keyframe]))),
1813 name: Some("keyframes_accessor_prop".to_string()),
1814 normalized: false,
1815 sparse: None,
1816 };
1817 animation_accessors.push(keyframe_times);
1818 let mut running_buffer_view = BufferViewIDs::Animation as u32 + current_buffer_view_offset;
1819 for j_idx in 0..joint_count {
1820 let accessor_name = format!("joint_{j_idx}_animations_accessor_prop");
1821 let joint_animation_accessor = gltf_json::Accessor {
1822 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1823 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1824 count: USize64::from(self.frame_count.unwrap()),
1825 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1826 extensions: Option::default(),
1827 extras: Option::default(),
1828 type_: Valid(gltf_json::accessor::Type::Vec4),
1829 min: None,
1830 max: None,
1831 name: Some(accessor_name),
1832 normalized: false,
1833 sparse: None,
1834 };
1835 animation_accessors.push(joint_animation_accessor);
1836 running_buffer_view += 1;
1837 }
1838 let accessor_name = "root_translation_animations_accessor_prop".to_string();
1839 let body_animation_accessor = gltf_json::Accessor {
1840 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1841 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1842 count: USize64::from(self.frame_count.unwrap()),
1843 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1844 extensions: Option::default(),
1845 extras: Option::default(),
1846 type_: Valid(gltf_json::accessor::Type::Vec3),
1847 min: None,
1848 max: None,
1849 name: Some(accessor_name),
1850 normalized: false,
1851 sparse: None,
1852 };
1853 animation_accessors.push(body_animation_accessor);
1854 running_buffer_view += 1;
1855 let accessor_name = "root_scale_animations_accessor_prop".to_string();
1856 let vis_animation_accessor = gltf_json::Accessor {
1857 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1858 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1859 count: USize64::from(self.frame_count.unwrap()),
1860 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1861 extensions: Option::default(),
1862 extras: Option::default(),
1863 type_: Valid(gltf_json::accessor::Type::Vec3),
1864 min: None,
1865 max: None,
1866 name: Some(accessor_name),
1867 normalized: false,
1868 sparse: None,
1869 };
1870 animation_accessors.push(vis_animation_accessor);
1871 running_buffer_view += 1;
1872 per_view_running_offset[BufferViewIDs::Animation as usize] += running_buffer_view as usize;
1873 animation_accessors
1874 }
1875 fn create_morph_target_accessors(
1877 &self,
1878 vertex_count: usize,
1879 current_buffer_view_offset: u32,
1880 per_view_running_offset: &mut [usize; 6],
1881 compatibility_mode: GltfCompatibilityMode,
1882 ) -> Vec<gltf_json::Accessor> {
1883 let mut morph_target_accessors: Vec<gltf_json::Accessor> = vec![];
1884 let mut running_buffer_view = u32::try_from(per_view_running_offset[BufferViewIDs::Animation as usize]).expect("Could not convert to U32!")
1885 + current_buffer_view_offset;
1886 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
1887 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
1888 for morph_target_idx in 0..self.num_morph_targets() {
1889 let accessor_name = format!("morph_{morph_target_idx}_accessor");
1890 let current_morph_target = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]);
1891 let current_morph_target_na = current_morph_target.to_owned().clone().into_nalgebra();
1892 let (min, max) = geom::get_bounding_points(¤t_morph_target_na, None);
1893 let (mut min_vec, mut max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1894 if compatibility_mode == GltfCompatibilityMode::Smpl && (morph_target_idx < num_pose_morph_targets) {
1895 max_vec = max_vec.iter().map(|x| x * 2.0 * PI).collect();
1896 min_vec = min_vec.iter().map(|x| x * 2.0 * PI).collect();
1897 }
1898 if compatibility_mode == GltfCompatibilityMode::Smpl
1899 && (morph_target_idx > num_pose_morph_targets && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets)
1900 {
1901 max_vec = max_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1902 min_vec = min_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1903 }
1904 let morph_target_accessor = gltf_json::Accessor {
1905 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1906 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Deformation as usize])),
1907 count: USize64::from(vertex_count),
1908 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1909 extensions: Option::default(),
1910 extras: Option::default(),
1911 type_: Valid(gltf_json::accessor::Type::Vec3),
1912 min: Some(gltf_json::Value::from(min_vec)),
1913 max: Some(gltf_json::Value::from(max_vec)),
1914 name: Some(accessor_name),
1915 normalized: false,
1916 sparse: None,
1917 };
1918 morph_target_accessors.push(morph_target_accessor);
1919 running_buffer_view += 1;
1920 }
1921 per_view_running_offset[BufferViewIDs::Deformation as usize] += running_buffer_view as usize;
1922 morph_target_accessors
1923 }
1924 #[allow(clippy::cast_possible_truncation)]
1926 fn create_animation_channels(
1927 &self,
1928 joint_count: usize,
1929 root_idx: u32,
1930 skeleton_root_idx: usize,
1931 sampler_start_idx: usize,
1932 compatibility_mode: GltfCompatibilityMode,
1933 ) -> Vec<gltf_json::animation::Channel> {
1934 let mut animation_channels: Vec<gltf_json::animation::Channel> = vec![];
1935 let mut sampler_idx = sampler_start_idx;
1936 for j_idx in 0..joint_count {
1937 let animation_target = gltf_json::animation::Target {
1938 extensions: Option::default(),
1939 extras: Option::default(),
1940 node: gltf_json::Index::new(u32::try_from(j_idx + skeleton_root_idx).expect("Could not convert to u32!")),
1941 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Rotation),
1942 };
1943 let channel = gltf_json::animation::Channel {
1944 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1945 target: animation_target,
1946 extensions: Option::default(),
1947 extras: Option::default(),
1948 };
1949 animation_channels.push(channel);
1950 sampler_idx += 1;
1951 }
1952 let animation_target = gltf_json::animation::Target {
1953 extensions: Option::default(),
1954 extras: Option::default(),
1955 node: gltf_json::Index::new(root_idx),
1956 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1957 };
1958 let channel = gltf_json::animation::Channel {
1959 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1960 target: animation_target,
1961 extensions: Option::default(),
1962 extras: Option::default(),
1963 };
1964 animation_channels.push(channel);
1965 sampler_idx += 1;
1966 let animation_target = gltf_json::animation::Target {
1967 extensions: Option::default(),
1968 extras: Option::default(),
1969 node: gltf_json::Index::new(root_idx),
1970 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Scale),
1971 };
1972 let channel = gltf_json::animation::Channel {
1973 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1974 target: animation_target,
1975 extensions: Option::default(),
1976 extras: Option::default(),
1977 };
1978 animation_channels.push(channel);
1979 sampler_idx += 1;
1980 let mesh_skin_binding_node_idx = root_idx - 1;
1981 if compatibility_mode == GltfCompatibilityMode::Unreal {
1982 let animation_target = gltf_json::animation::Target {
1983 extensions: Option::default(),
1984 extras: Option::default(),
1985 node: gltf_json::Index::new(u32::try_from(skeleton_root_idx).expect("Could not convert to u32!")),
1986 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1987 };
1988 let channel = gltf_json::animation::Channel {
1989 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1990 target: animation_target,
1991 extensions: Option::default(),
1992 extras: Option::default(),
1993 };
1994 animation_channels.push(channel);
1995 sampler_idx += 1;
1996 }
1997 if self.num_morph_targets() > 0 {
1998 let mtw_animation_target = gltf_json::animation::Target {
1999 extensions: Option::default(),
2000 extras: Option::default(),
2001 node: gltf_json::Index::new(mesh_skin_binding_node_idx),
2002 path: Valid(gltf_json::animation::Property::MorphTargetWeights),
2003 };
2004 let channel = gltf_json::animation::Channel {
2005 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2006 target: mtw_animation_target,
2007 extensions: Option::default(),
2008 extras: Option::default(),
2009 };
2010 animation_channels.push(channel);
2011 }
2012 animation_channels
2013 }
2014 fn create_animation_channels_prop(
2015 &self,
2016 joint_count: usize,
2017 root_idx: u32,
2018 skeleton_root_idx: usize,
2019 sampler_start_idx: usize,
2020 _compatibility_mode: GltfCompatibilityMode,
2021 ) -> Vec<gltf_json::animation::Channel> {
2022 let mut animation_channels: Vec<gltf_json::animation::Channel> = vec![];
2023 let mut sampler_idx = sampler_start_idx;
2024 for j_idx in 0..joint_count {
2025 let animation_target = gltf_json::animation::Target {
2026 extensions: Option::default(),
2027 extras: Option::default(),
2028 node: gltf_json::Index::new(u32::try_from(j_idx + skeleton_root_idx).expect("Could not convert to u32!")),
2029 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Rotation),
2030 };
2031 let channel = gltf_json::animation::Channel {
2032 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2033 target: animation_target,
2034 extensions: Option::default(),
2035 extras: Option::default(),
2036 };
2037 animation_channels.push(channel);
2038 sampler_idx += 1;
2039 }
2040 let animation_target = gltf_json::animation::Target {
2041 extensions: Option::default(),
2042 extras: Option::default(),
2043 node: gltf_json::Index::new(root_idx),
2044 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
2045 };
2046 let channel = gltf_json::animation::Channel {
2047 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2048 target: animation_target,
2049 extensions: Option::default(),
2050 extras: Option::default(),
2051 };
2052 animation_channels.push(channel);
2053 sampler_idx += 1;
2054 let animation_target = gltf_json::animation::Target {
2055 extensions: Option::default(),
2056 extras: Option::default(),
2057 node: gltf_json::Index::new(root_idx),
2058 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Scale),
2059 };
2060 let channel = gltf_json::animation::Channel {
2061 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2062 target: animation_target,
2063 extensions: Option::default(),
2064 extras: Option::default(),
2065 };
2066 animation_channels.push(channel);
2067 animation_channels
2068 }
2069 fn create_animation_samplers(
2071 &self,
2072 joint_count: usize,
2073 current_buffer_view_offset: u32,
2074 compatibility_mode: GltfCompatibilityMode,
2075 ) -> Vec<gltf_json::animation::Sampler> {
2076 let mut animation_samplers: Vec<gltf_json::animation::Sampler> = vec![];
2077 let mut current_accessor = 8 + current_buffer_view_offset;
2078 for _ in 0..joint_count {
2079 let sampler = gltf_json::animation::Sampler {
2080 extensions: Option::default(),
2081 extras: Option::default(),
2082 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2083 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2084 output: gltf_json::Index::new(current_accessor),
2085 };
2086 animation_samplers.push(sampler);
2087 current_accessor += 1;
2088 }
2089 let sampler = gltf_json::animation::Sampler {
2090 extensions: Option::default(),
2091 extras: Option::default(),
2092 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2093 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2094 output: gltf_json::Index::new(current_accessor),
2095 };
2096 animation_samplers.push(sampler);
2097 current_accessor += 1;
2098 let sampler = gltf_json::animation::Sampler {
2099 extensions: Option::default(),
2100 extras: Option::default(),
2101 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2102 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Step),
2103 output: gltf_json::Index::new(current_accessor),
2104 };
2105 animation_samplers.push(sampler);
2106 current_accessor += 1;
2107 if compatibility_mode == GltfCompatibilityMode::Unreal {
2108 let sampler = gltf_json::animation::Sampler {
2109 extensions: Option::default(),
2110 extras: Option::default(),
2111 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2112 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2113 output: gltf_json::Index::new(current_accessor),
2114 };
2115 animation_samplers.push(sampler);
2116 current_accessor += 1;
2117 }
2118 if self.num_morph_targets() > 0 {
2119 let sampler = gltf_json::animation::Sampler {
2120 extensions: Option::default(),
2121 extras: Option::default(),
2122 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2123 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2124 output: gltf_json::Index::new(current_accessor),
2125 };
2126 animation_samplers.push(sampler);
2127 }
2128 animation_samplers
2129 }
2130 fn create_animation_samplers_prop(
2131 &self,
2132 joint_count: usize,
2133 current_buffer_view_offset: u32,
2134 _compatibility_mode: GltfCompatibilityMode,
2135 ) -> Vec<gltf_json::animation::Sampler> {
2136 let mut animation_samplers: Vec<gltf_json::animation::Sampler> = vec![];
2137 let mut current_accessor = current_buffer_view_offset - 3;
2138 for _ in 0..joint_count {
2139 let sampler = gltf_json::animation::Sampler {
2140 extensions: Option::default(),
2141 extras: Option::default(),
2142 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2143 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2144 output: gltf_json::Index::new(current_accessor),
2145 };
2146 animation_samplers.push(sampler);
2147 current_accessor += 1;
2148 }
2149 let sampler = gltf_json::animation::Sampler {
2150 extensions: Option::default(),
2151 extras: Option::default(),
2152 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2153 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2154 output: gltf_json::Index::new(current_accessor),
2155 };
2156 animation_samplers.push(sampler);
2157 current_accessor += 1;
2158 let sampler = gltf_json::animation::Sampler {
2159 extensions: Option::default(),
2160 extras: Option::default(),
2161 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2162 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Step),
2163 output: gltf_json::Index::new(current_accessor),
2164 };
2165 animation_samplers.push(sampler);
2166 animation_samplers
2167 }
2168 pub fn create_morph_targets(&self, pose_dirs_accessors_start_idx: usize) -> Vec<gltf_json::mesh::MorphTarget> {
2170 let mut pose_dirs_morph_targets: Vec<gltf_json::mesh::MorphTarget> = vec![];
2171 let mut running_pose_dirs_accessor = u32::try_from(pose_dirs_accessors_start_idx).expect("Not able to convert to u32");
2172 for _ in 0..self.num_morph_targets() {
2173 let morph_target = gltf_json::mesh::MorphTarget {
2174 positions: Some(gltf_json::Index::new(running_pose_dirs_accessor)),
2175 normals: None,
2176 tangents: None,
2177 };
2178 pose_dirs_morph_targets.push(morph_target);
2179 running_pose_dirs_accessor += 1;
2180 }
2181 pose_dirs_morph_targets
2182 }
2183 pub fn create_bind_matrices(&self, rot_mat: &nd::Array3<f32>, joint_trans: &nd::Array2<f32>, joint_parents: &[u32]) -> nd::Array3<f32> {
2185 assert!(
2186 rot_mat.shape()[0] == joint_trans.shape()[0],
2187 "Number of rotation matrices dont match number of translation matrices!"
2188 );
2189 let num_joints = rot_mat.shape()[0];
2190 let mut bind_matrices = ndarray::Array3::<f32>::zeros((num_joints, 4, 4));
2191 bind_matrices.slice_mut(s![0, 0..3, 0..3]).assign(&rot_mat.slice(s![0, .., ..]));
2192 bind_matrices.slice_mut(s![0, 0..3, 3]).assign(&joint_trans.slice(s![0, ..]));
2193 bind_matrices[[0, 3, 3]] = 1.0;
2194 for j_idx in 1..num_joints {
2195 let parent_index = joint_parents[j_idx] as usize;
2196 let parent_transform = bind_matrices.index_axis(nd::Axis(0), parent_index);
2197 let mut local_transform = ndarray::Array2::<f32>::zeros((4, 4));
2198 local_transform.slice_mut(s![0..3, 0..3]).assign(&rot_mat.slice(s![j_idx, .., ..]));
2199 let local_translation = Array::from_vec(vec_to_vec(&compute_local_translation(j_idx, joint_parents, joint_trans)));
2200 local_transform.slice_mut(s![0..3, 3]).assign(&local_translation);
2201 local_transform[[3, 3]] = 1.0;
2202 let global_transform = parent_transform.dot(&local_transform);
2203 bind_matrices.slice_mut(s![j_idx, .., ..]).assign(&global_transform);
2204 }
2205 bind_matrices
2206 }
2207 pub fn create_animation_data(&self, current_body: &PerBodyData, compatibility_mode: GltfCompatibilityMode) -> Vec<u8> {
2209 let mut animation_data: Vec<u8> = vec![];
2210 let keyframe_data = to_padded_byte_vector(self.keyframe_times.as_ref().unwrap());
2211 let rotation_animation_data = current_body.body_rotations.as_ref().unwrap();
2212 let mut translation_animation_data = current_body.body_translations.as_ref().unwrap().clone();
2213 let scale_animation_data = current_body.body_scales.as_ref().unwrap().clone();
2214 animation_data.extend_from_slice(keyframe_data.as_slice());
2215 assert_eq!(rotation_animation_data.shape()[1], translation_animation_data.shape()[0]);
2216 for j_idx in 0..rotation_animation_data.shape()[0] {
2217 let mut quaternions: Vec<f32> = vec![];
2218 for r_idx in 0..rotation_animation_data.shape()[1] {
2219 let rotation = rotation_animation_data.slice(s![j_idx, r_idx, ..]);
2220 let axis_angle_rotation = na::Vector3::new(rotation[0], rotation[1], rotation[2]);
2221 let mut quaternion_rotation =
2222 na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_angle_rotation), axis_angle_rotation.norm());
2223 if axis_angle_rotation.norm() == 0.0 {
2224 quaternion_rotation = na::UnitQuaternion::default();
2225 }
2226 quaternions.extend(quaternion_rotation.as_vector().data.as_slice());
2227 }
2228 let joint_anim_data = to_padded_byte_vector(&quaternions);
2229 animation_data.append(&mut joint_anim_data.clone());
2230 }
2231 if compatibility_mode == GltfCompatibilityMode::Unreal {
2232 let mut pelvis_relative_trans = translation_animation_data.clone();
2233 for mut row in translation_animation_data.axis_iter_mut(Axis(0)) {
2234 row[1] = 0.0;
2235 }
2236 for mut row in pelvis_relative_trans.axis_iter_mut(Axis(0)) {
2237 row[0] = 0.0;
2238 row[2] = 0.0;
2239 }
2240 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec());
2241 animation_data.append(&mut trans_anim_data.clone());
2242 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec());
2243 animation_data.append(&mut scale_anim_data.clone());
2244 let pelvis_rel_anim_data = to_padded_byte_vector(&pelvis_relative_trans.to_owned().into_raw_vec());
2245 animation_data.append(&mut pelvis_rel_anim_data.clone());
2246 } else {
2247 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec());
2248 animation_data.append(&mut trans_anim_data.clone());
2249 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec());
2250 animation_data.append(&mut scale_anim_data.clone());
2251 }
2252 if self.num_morph_targets() > 0 {
2253 let morph_target_weights_data = current_body.per_frame_blend_weights.as_ref().unwrap();
2254 let weights_anim_data = to_padded_byte_vector(&morph_target_weights_data.to_owned().into_raw_vec());
2255 animation_data.append(&mut weights_anim_data.clone());
2256 }
2257 animation_data
2258 }
2259 pub fn create_animation_data_prop(&self, current_prop: &PropData, _compatibility_mode: GltfCompatibilityMode) -> Vec<u8> {
2260 let mut animation_data: Vec<u8> = vec![];
2261 let keyframe_data = to_padded_byte_vector(self.keyframe_times.as_ref().unwrap());
2262 let rotation_animation_data = current_prop.rotations.clone();
2263 let translation_animation_data = current_prop.translations.clone();
2264 let scale_animation_data = current_prop.scales.clone();
2265 animation_data.extend_from_slice(keyframe_data.as_slice());
2266 assert_eq!(rotation_animation_data.shape()[1], translation_animation_data.shape()[0]);
2267 for j_idx in 0..rotation_animation_data.shape()[0] {
2268 let mut quaternions: Vec<f32> = vec![];
2269 for r_idx in 0..rotation_animation_data.shape()[1] {
2270 let rotation = rotation_animation_data.slice(s![j_idx, r_idx, ..]);
2271 let axis_angle_rotation = na::Vector3::new(rotation[0], rotation[1], rotation[2]);
2272 let mut quaternion_rotation =
2273 na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_angle_rotation), axis_angle_rotation.norm());
2274 if axis_angle_rotation.norm() == 0.0 {
2275 quaternion_rotation = na::UnitQuaternion::default();
2276 }
2277 quaternions.extend(quaternion_rotation.as_vector().data.as_slice());
2278 }
2279 let joint_anim_data = to_padded_byte_vector(&quaternions);
2280 animation_data.append(&mut joint_anim_data.clone());
2281 }
2282 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec());
2283 animation_data.append(&mut trans_anim_data.clone());
2284 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec());
2285 animation_data.append(&mut scale_anim_data.clone());
2286 animation_data
2287 }
2288 #[allow(clippy::too_many_arguments)]
2290 fn compose_buffer_views(
2291 &self,
2292 body_idx: usize,
2293 current_body: &PerBodyData,
2294 buffer_views: Vec<gltf_json::buffer::View>,
2295 index_data: &[u8],
2296 vertex_data: &[u8],
2297 inv_bind_mat_data: &[u8],
2298 textures: &mut [GltfTextureInfo],
2299 compatibility_mode: GltfCompatibilityMode,
2300 ) -> (Vec<u8>, Vec<gltf_json::buffer::View>, usize, usize) {
2301 let mut out_data: Vec<u8> = vec![];
2302 let mut out_buffer_views: Vec<gltf_json::buffer::View> = vec![];
2303 out_data.append(&mut index_data.to_owned());
2304 out_data.append(&mut vertex_data.to_owned());
2305 out_data.append(&mut inv_bind_mat_data.to_owned());
2306 if self.is_animated() {
2307 let mut animation_data = self.create_animation_data(current_body, compatibility_mode);
2308 out_data.append(&mut animation_data);
2309 if self.num_morph_targets() > 0 && body_idx == 0 {
2310 for morph_target_idx in 0..self.num_morph_targets() {
2311 let mut posedir = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]).to_owned();
2312 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
2313 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
2314 if compatibility_mode == GltfCompatibilityMode::Smpl
2315 && self.num_pose_morph_targets > 0
2316 && morph_target_idx < num_pose_morph_targets
2317 {
2318 posedir *= 2.0 * PI;
2319 }
2320 if compatibility_mode == GltfCompatibilityMode::Smpl
2321 && self.num_expression_morph_targets > 0
2322 && morph_target_idx > num_pose_morph_targets
2323 && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets
2324 {
2325 posedir *= 2.0 * 7.0;
2326 }
2327 let posedir_data = to_padded_byte_vector(&posedir.to_owned().into_raw_vec());
2328 out_data.append(&mut posedir_data.clone());
2329 }
2330 }
2331 }
2332 out_buffer_views.extend(buffer_views);
2333 let mut buffer_offset = out_data.len();
2334 let mut buffer_index: usize = out_buffer_views.len();
2335 for (sampler_index, texture) in textures.iter_mut().enumerate() {
2336 let mut buffer_view = texture.buffer_view.clone();
2337 buffer_view.byte_offset = Some(USize64::from(buffer_offset));
2338 out_buffer_views.push(buffer_view);
2339 texture.buffer_index = buffer_index;
2340 texture.image.buffer_view = Some(gltf_json::Index::new(u32::try_from(buffer_index).expect("Issue converting to u32!")));
2341 texture.texture.sampler = Some(gltf_json::Index::new(u32::try_from(sampler_index).expect("Issue converting to u32!")));
2342 out_data.append(&mut texture.image_data.clone());
2343 buffer_offset += texture.buffer_size;
2344 buffer_index += 1;
2345 }
2346 (out_data, out_buffer_views, buffer_offset, buffer_index)
2347 }
2348 #[allow(clippy::too_many_arguments)]
2350 fn compose_buffer_views_props(
2351 &self,
2352 current_prop: &PropData,
2353 buffer_views: Vec<gltf_json::buffer::View>,
2354 index_data: &[u8],
2355 vertex_data: &[u8],
2356 inv_bind_mat_data: &[u8],
2357 textures: &mut [GltfTextureInfo],
2358 compatibility_mode: GltfCompatibilityMode,
2359 global_buffer_offset: usize,
2360 global_buffer_index: usize,
2361 ) -> (Vec<u8>, Vec<gltf_json::buffer::View>, usize, usize) {
2362 let mut out_data: Vec<u8> = vec![];
2363 let mut out_buffer_views: Vec<gltf_json::buffer::View> = vec![];
2364 out_data.append(&mut index_data.to_owned());
2365 out_data.append(&mut vertex_data.to_owned());
2366 out_data.append(&mut inv_bind_mat_data.to_owned());
2367 let mut animation_data = self.create_animation_data_prop(current_prop, compatibility_mode);
2368 out_data.append(&mut animation_data);
2369 out_buffer_views.extend(buffer_views);
2370 let mut buffer_offset = out_data.len() + global_buffer_offset;
2371 let mut buffer_index: usize = out_buffer_views.len() + global_buffer_index;
2372 for (sampler_index, texture) in textures.iter_mut().enumerate() {
2373 let mut buffer_view = texture.buffer_view.clone();
2374 buffer_view.byte_offset = Some(USize64::from(buffer_offset));
2375 out_buffer_views.push(buffer_view);
2376 texture.buffer_index = buffer_index;
2377 texture.image.buffer_view = Some(gltf_json::Index::new(u32::try_from(buffer_index).expect("Issue converting to u32!")));
2378 texture.texture.sampler = Some(gltf_json::Index::new(u32::try_from(sampler_index).expect("Issue converting to u32!")));
2379 out_data.append(&mut texture.image_data.clone());
2380 buffer_offset += texture.buffer_size;
2381 buffer_index += 1;
2382 }
2383 (out_data, out_buffer_views, buffer_offset, buffer_index)
2384 }
2385 fn add_texture(&self, img: &DynImage, index: usize, name: &str) -> Option<GltfTextureInfo> {
2387 let mut image_data: Vec<u8> = vec![];
2388 let mut target = Cursor::new(&mut image_data);
2389 let image_data_buffer = img.write_to(&mut target, image::ImageFormat::Png);
2390 if image_data_buffer.is_ok() {
2391 let _ = target.flush();
2392 while image_data.len() % 4 != 0 {
2393 image_data.push(0);
2394 }
2395 let mut image_buffer_size = image_data.len();
2396 align_to_multiple_of_four(&mut image_buffer_size);
2397 let image_buffer_view = gltf_json::buffer::View {
2398 buffer: gltf_json::Index::new(0),
2399 byte_length: USize64::from(image_buffer_size),
2400 byte_offset: Some(USize64::from(0_usize)),
2401 byte_stride: Option::default(),
2402 extensions: Option::default(),
2403 extras: Option::default(),
2404 name: Some(name.to_string()),
2405 target: None,
2406 };
2407 let image = gltf_json::image::Image {
2408 buffer_view: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
2409 mime_type: Some(gltf_json::image::MimeType("image/png".to_string())),
2410 name: Some(name.to_string()),
2411 uri: None,
2412 extensions: None,
2413 extras: None,
2414 };
2415 let texture = gltf_json::Texture {
2416 name: Some(name.to_string()),
2417 sampler: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
2418 source: gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!")),
2419 extensions: None,
2420 extras: None,
2421 };
2422 let sampler = gltf_json::texture::Sampler {
2423 name: Some(name.to_string()),
2424 mag_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MagFilter::Linear)),
2425 min_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MinFilter::Linear)),
2426 wrap_s: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
2427 wrap_t: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
2428 extensions: None,
2429 extras: None,
2430 };
2431 let texture_info = GltfTextureInfo {
2432 buffer_size: image_data.len(),
2433 image_data,
2434 image,
2435 buffer_view: image_buffer_view,
2436 buffer_index: 0,
2437 texture,
2438 sampler,
2439 };
2440 return Some(texture_info);
2441 }
2442 log!("add_texture FAILED: {}", name);
2443 None
2444 }
2445 #[allow(clippy::cast_sign_loss)]
2447 fn prepare_normals(&self, smpl_textures: &mut SmplTextures, texture_infos: &mut Vec<GltfTextureInfo>, normals_tex: Option<&DynImage>) {
2448 if let Some(img) = normals_tex {
2449 let normals_tex = self.add_texture(img, texture_infos.len(), "normals");
2450 if let Some(normals_tex) = normals_tex {
2451 smpl_textures.normals_index = Some(texture_infos.len());
2452 texture_infos.push(normals_tex);
2453 }
2454 }
2455 }
2456 fn prepare_metallic_roughness(
2458 &self,
2459 smpl_textures: &mut SmplTextures,
2460 texture_infos: &mut Vec<GltfTextureInfo>,
2461 metalness_tex: Option<&DynImage>,
2462 roughness_tex: Option<&DynImage>,
2463 ) {
2464 let mut w: u32 = 0;
2465 let mut h: u32 = 0;
2466 if let Some(img) = metalness_tex {
2467 w = img.width();
2468 h = img.height();
2469 }
2470 if let Some(img) = roughness_tex {
2471 w = w.max(img.width());
2472 h = h.max(img.height());
2473 }
2474 let mut metalness: Option<Vec<u8>> = None;
2475 if let Some(img) = metalness_tex {
2476 if img.width() != w || img.height() != h {
2477 let resized_img = img.resize(w, h, FilterType::Gaussian);
2478 metalness = Some(resized_img.as_luma8().unwrap().to_vec());
2479 } else {
2480 metalness = Some(img.as_bytes().to_vec());
2481 }
2482 }
2483 let mut roughness: Option<Vec<u8>> = None;
2484 if let Some(img) = roughness_tex {
2485 if img.width() != w || img.height() != h {
2486 let resized_img = img.resize(w, h, FilterType::Gaussian);
2487 roughness = Some(resized_img.as_luma8().unwrap().to_vec());
2488 } else {
2489 roughness = Some(img.as_bytes().to_vec());
2490 }
2491 }
2492 let num_pixels: usize = (w * h) as usize;
2493 let mut metal_roughness_pixels: Vec<u8> = vec![];
2494 if let Some(metalness_pixels) = metalness {
2495 if let Some(roughness_pixels) = roughness {
2496 for (m, r) in metalness_pixels.iter().zip(roughness_pixels.iter()).take(num_pixels) {
2497 metal_roughness_pixels.push(0);
2498 metal_roughness_pixels.push(*r);
2499 metal_roughness_pixels.push(*m);
2500 }
2501 } else {
2502 for &m in metalness_pixels.iter().take(num_pixels) {
2503 metal_roughness_pixels.push(0);
2504 metal_roughness_pixels.push(0);
2505 metal_roughness_pixels.push(m);
2506 }
2507 }
2508 } else if let Some(roughness_pixels) = roughness {
2509 for &r in roughness_pixels.iter().take(num_pixels) {
2510 metal_roughness_pixels.push(0);
2511 metal_roughness_pixels.push(r);
2512 metal_roughness_pixels.push(0);
2513 }
2514 }
2515 if !metal_roughness_pixels.is_empty() {
2516 let metal_roughness_image = RgbImage::from_vec(w, h, metal_roughness_pixels);
2517 if let Some(image) = metal_roughness_image {
2518 let image = DynImage::from(image);
2519 let metallic_roughness = self.add_texture(&image, texture_infos.len(), "metal_roughness");
2520 if let Some(metallic_roughness) = metallic_roughness {
2521 smpl_textures.metalic_roughtness_index = Some(texture_infos.len());
2522 texture_infos.push(metallic_roughness);
2523 }
2524 }
2525 }
2526 }
2527 fn create_joint(&self, name: String, translation: &[f32], rotation: &Vector3f, children: Option<Vec<gltf_json::Index<Node>>>) -> Node {
2529 let cur_vec = na::Vector3::new(rotation.x, rotation.y, rotation.z);
2530 let mut cur_q = na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(cur_vec), rotation.norm());
2531 if rotation.norm() == 0.0 {
2532 cur_q = na::UnitQuaternion::default();
2533 }
2534 let translation: [f32; 3] = [translation[0], translation[1], translation[2]];
2535 let unit_quaternion = [cur_q[0], cur_q[1], cur_q[2], cur_q[3]];
2536 Node {
2537 children,
2538 mesh: None,
2539 skin: None,
2540 name: Some(name),
2541 rotation: Some(UnitQuaternion(unit_quaternion)),
2542 translation: Some(translation),
2543 ..Default::default()
2544 }
2545 }
2546 fn gather_children(&self, id: u32, parent_ids: &[u32], offset: u32) -> Option<Vec<gltf_json::Index<Node>>> {
2547 let mut children: Vec<gltf_json::Index<Node>> = vec![];
2548 for (p, &parent_id) in parent_ids.iter().enumerate() {
2549 if parent_id == id {
2550 let index = u32::try_from(p).expect("Index conversion error: usize value is too large to fit in a u32");
2551 children.push(gltf_json::Index::<Node>::new(index + offset));
2552 }
2553 }
2554 if !children.is_empty() {
2555 return Some(children);
2556 }
2557 None
2558 }
2559 #[allow(clippy::too_many_arguments)]
2561 fn add_skin(
2562 &mut self,
2563 name: String,
2564 current_body: &PerBodyData,
2565 current_armature_idx: u32,
2566 accessor_offset: u32,
2567 nodes: &mut Vec<Node>,
2568 skins: &mut Vec<gltf_json::Skin>,
2569 joints: &mut Vec<gltf_json::Index<Node>>,
2570 compatibility_mode: GltfCompatibilityMode,
2571 ) -> gltf_json::Index<Node> {
2572 let metadata = crate::common::metadata::smpl_metadata(&self.smpl_type);
2573 let joint_translations = current_body.default_joint_translations.as_ref().unwrap();
2574 let skeleton_root_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
2575 let global_translation = vec_from_array0_f(current_body.body_translation.as_ref().unwrap());
2576 let mut skeleton_root_translation = compute_local_translation(0, &metadata.joint_parents, joint_translations);
2577 if compatibility_mode == GltfCompatibilityMode::Smpl {
2578 skeleton_root_translation = addv3f(&skeleton_root_translation, &global_translation);
2579 }
2580 let mut joint_rotation = Vector3f::zeros();
2581 if let Some(joint_poses) = current_body.joint_poses.as_ref() {
2582 let rot = joint_poses.row(0).to_owned();
2583 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
2584 }
2585 let skeleton_root = self.create_joint(
2586 "pelvis".to_string(),
2587 vec_to_vec(&skeleton_root_translation).as_slice(),
2588 &joint_rotation,
2589 self.gather_children(0, &metadata.joint_parents, skeleton_root_index),
2590 );
2591 nodes.push(skeleton_root);
2592 joints.push(gltf_json::Index::new(skeleton_root_index));
2593 let joint_names = if compatibility_mode == GltfCompatibilityMode::Unreal {
2594 smpl_x::JOINT_NAMES_UNREAL.map(std::string::ToString::to_string).to_vec()
2595 } else {
2596 metadata.joint_names
2597 };
2598 for (j, name) in joint_names.iter().enumerate().take(metadata.num_joints + 1).skip(1) {
2599 if let Some(joint_poses) = current_body.joint_poses.as_ref() {
2600 let rot = joint_poses.row(j).to_owned();
2601 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
2602 }
2603 let joint = self.create_joint(
2604 name.clone(),
2605 vec_to_vec(&compute_local_translation(j, &metadata.joint_parents, joint_translations)).as_slice(),
2606 &joint_rotation,
2607 self.gather_children(
2608 u32::try_from(j).expect("Issue converting Joint idx to u32"),
2609 &metadata.joint_parents,
2610 skeleton_root_index,
2611 ),
2612 );
2613 let joint_index = gltf_json::Index::<Node>::new(u32::try_from(nodes.len()).expect("Issue converting Joint idx to u32"));
2614 nodes.push(joint);
2615 joints.push(joint_index);
2616 }
2617 let skin = gltf_json::Skin {
2618 name: Some(name),
2619 inverse_bind_matrices: Some(gltf_json::Index::new(accessor_offset + 6)),
2620 joints: joints.clone(),
2621 skeleton: Some(gltf_json::Index::new(current_armature_idx)),
2622 extensions: None,
2623 extras: None,
2624 };
2625 skins.push(skin);
2626 gltf_json::Index::<Node>::new(skeleton_root_index)
2627 }
2628 #[allow(clippy::too_many_arguments)]
2629 fn add_skin_prop(
2630 &mut self,
2631 name: String,
2632 current_prop: &PropData,
2633 current_armature_idx: u32,
2634 accessor_offset: u32,
2635 nodes: &mut Vec<Node>,
2636 skins: &mut Vec<gltf_json::Skin>,
2637 joints: &mut Vec<gltf_json::Index<Node>>,
2638 _compatibility_mode: GltfCompatibilityMode,
2639 ) -> gltf_json::Index<Node> {
2640 let joint_translations = ¤t_prop.default_translation;
2641 let skeleton_root_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
2642 let skeleton_root_translation = vec_from_vec(&joint_translations.row(0).to_vec());
2643 let joint_rotation = Vector3f::zeros();
2644 let skeleton_root = self.create_joint(
2645 "root_prop".to_string(),
2646 vec_to_vec(&skeleton_root_translation).as_slice(),
2647 &joint_rotation,
2648 None,
2649 );
2650 nodes.push(skeleton_root);
2651 joints.push(gltf_json::Index::new(skeleton_root_index));
2652 let skin = gltf_json::Skin {
2653 name: Some(name),
2654 inverse_bind_matrices: Some(gltf_json::Index::new(accessor_offset - 5)),
2655 joints: joints.clone(),
2656 skeleton: Some(gltf_json::Index::new(current_armature_idx)),
2657 extensions: None,
2658 extras: None,
2659 };
2660 skins.push(skin);
2661 gltf_json::Index::<Node>::new(skeleton_root_index)
2662 }
2663 #[allow(clippy::cast_precision_loss)]
2665 fn create_camera_animation_buffer_views(
2666 &self,
2667 running_offset: &mut usize,
2668 compatibility_mode: GltfCompatibilityMode,
2669 ) -> (Vec<gltf_json::buffer::View>, Vec<u8>) {
2670 let mut buffer_views = Vec::new();
2671 let mut buffer_data = Vec::new();
2672 if let Some(smpl_camera) = &self.smpl_camera {
2673 let trans_data = to_padded_byte_vector(smpl_camera.transform_sequence.translations.as_slice().unwrap());
2674 let trans_len = trans_data.len();
2675 let trans_view = gltf_json::buffer::View {
2676 buffer: gltf_json::Index::new(0),
2677 byte_length: USize64::from(trans_len),
2678 byte_offset: Some(USize64::from(*running_offset)),
2679 byte_stride: None,
2680 extensions: None,
2681 extras: Option::default(),
2682 name: Some("camera_translations".to_string()),
2683 target: None,
2684 };
2685 buffer_data.extend(trans_data);
2686 *running_offset += trans_len;
2687 buffer_views.push(trans_view);
2688 let rotations = smpl_camera.transform_sequence.get_rotations_as_quaternions();
2689 let rotated_rots = if compatibility_mode == GltfCompatibilityMode::Unreal {
2690 let angle = 90.0;
2691 let axis = [0.0, 1.0, 0.0];
2692 self.rotate_camera_quaternions(angle, axis).as_ref().unwrap().clone()
2693 } else {
2694 rotations.clone()
2695 };
2696 let rot_data = to_padded_byte_vector(rotated_rots.as_slice().unwrap());
2697 let rot_len = rot_data.len();
2698 let rot_view = gltf_json::buffer::View {
2699 buffer: gltf_json::Index::new(0),
2700 byte_length: USize64::from(rot_len),
2701 byte_offset: Some(USize64::from(*running_offset)),
2702 byte_stride: None,
2703 extensions: None,
2704 extras: Option::default(),
2705 name: Some("camera_rotations".to_string()),
2706 target: None,
2707 };
2708 buffer_data.extend(rot_data);
2709 *running_offset += rot_len;
2710 buffer_views.push(rot_view);
2711 }
2712 (buffer_views, buffer_data)
2713 }
2714 fn create_camera_animation_accessors(&self, current_buffer_view_offset: u32) -> Vec<gltf_json::Accessor> {
2716 let mut accessors = Vec::new();
2717 let mut current_view = current_buffer_view_offset;
2718 if let Some(smpl_camera) = &self.smpl_camera {
2719 let translations = smpl_camera.transform_sequence.translations.clone();
2720 accessors.push(gltf_json::Accessor {
2721 buffer_view: Some(gltf_json::Index::new(current_view)),
2722 byte_offset: None,
2723 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
2724 count: USize64::from(translations.shape()[0]),
2725 type_: Valid(gltf_json::accessor::Type::Vec3),
2726 min: None,
2727 max: None,
2728 name: Some("camera_translations".to_string()),
2729 normalized: false,
2730 sparse: None,
2731 extensions: None,
2732 extras: Option::default(),
2733 });
2734 current_view += 1;
2735 let rotations = smpl_camera.transform_sequence.get_rotations_as_quaternions();
2736 accessors.push(gltf_json::Accessor {
2737 buffer_view: Some(gltf_json::Index::new(current_view)),
2738 byte_offset: None,
2739 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
2740 count: USize64::from(rotations.shape()[0]),
2741 type_: Valid(gltf_json::accessor::Type::Vec4),
2742 min: None,
2743 max: None,
2744 name: Some("camera_rotations".to_string()),
2745 normalized: false,
2746 sparse: None,
2747 extensions: None,
2748 extras: Option::default(),
2749 });
2750 }
2751 accessors
2752 }
2753 #[allow(clippy::cast_possible_truncation)]
2755 fn create_camera_animation_channels_and_samplers(
2756 &self,
2757 current_accessor_offset: u32,
2758 camera_node_index: u32,
2759 sampler_start_idx: u32,
2760 ) -> (Vec<gltf_json::animation::Channel>, Vec<gltf_json::animation::Sampler>) {
2761 let mut channels = Vec::new();
2762 let mut samplers = Vec::new();
2763 let mut current_accessor = current_accessor_offset;
2764 let times_accessor_index = 7;
2765 if self.smpl_camera.is_some() {
2766 samplers.push(gltf_json::animation::Sampler {
2767 input: gltf_json::Index::new(times_accessor_index),
2768 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
2769 output: gltf_json::Index::new(current_accessor),
2770 extensions: None,
2771 extras: Option::default(),
2772 });
2773 channels.push(gltf_json::animation::Channel {
2774 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
2775 target: gltf_json::animation::Target {
2776 node: gltf_json::Index::new(camera_node_index),
2777 path: Valid(gltf_json::animation::Property::Translation),
2778 extensions: None,
2779 extras: Option::default(),
2780 },
2781 extensions: None,
2782 extras: Option::default(),
2783 });
2784 current_accessor += 1;
2785 samplers.push(gltf_json::animation::Sampler {
2786 input: gltf_json::Index::new(times_accessor_index),
2787 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
2788 output: gltf_json::Index::new(current_accessor),
2789 extensions: None,
2790 extras: Option::default(),
2791 });
2792 channels.push(gltf_json::animation::Channel {
2793 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
2794 target: gltf_json::animation::Target {
2795 node: gltf_json::Index::new(camera_node_index),
2796 path: Valid(gltf_json::animation::Property::Rotation),
2797 extensions: None,
2798 extras: Option::default(),
2799 },
2800 extensions: None,
2801 extras: Option::default(),
2802 });
2803 }
2804 (channels, samplers)
2805 }
2806 fn num_morph_targets(&self) -> usize {
2807 self.morph_targets.as_ref().map_or(0, |x| x.shape()[0])
2808 }
2809 fn rotate_camera_quaternions(&self, angle_degrees: f32, axis: [f32; 3]) -> Option<nd::Array2<f32>> {
2811 if let Some(smpl_camera) = &self.smpl_camera {
2812 let rotations = smpl_camera.transform_sequence.get_rotations_as_quaternions();
2813 let mut rotated_quaternions = rotations.clone();
2814 let axis_vec = na::Vector3::new(axis[0], axis[1], axis[2]);
2815 let rotation_quat = na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_vec), angle_degrees.to_radians());
2816 for mut row in rotated_quaternions.axis_iter_mut(nd::Axis(0)) {
2817 let q = na::Quaternion::new(row[3], row[0], row[1], row[2]);
2818 let unit_q = na::UnitQuaternion::from_quaternion(q);
2819 let result = unit_q * rotation_quat;
2820 row[0] = result.i;
2821 row[1] = result.j;
2822 row[2] = result.k;
2823 row[3] = result.w;
2824 }
2825 return Some(rotated_quaternions);
2826 }
2827 None
2828 }
2829}
2830pub fn compute_local_translation(id: usize, parent_ids: &[u32], joint_translations: &nd::Array2<f32>) -> Vector3f {
2831 let trans = vec_from_vec(&joint_translations.row(id).to_vec());
2832 if id == 0 {
2833 return trans;
2834 }
2835 let parent_id = parent_ids[id] as usize;
2836 let parent_trans = vec_from_vec(&joint_translations.row(parent_id).to_vec());
2837 subv3f(&trans, &parent_trans)
2838}