1use super::scene::CameraTrack;
2use crate::{
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(Debug, 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 camera_track: Option<CameraTrack>,
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 camera_track: 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:?}");
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:?}");
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(camera_track) = &self.camera_track {
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: camera_track.yfov,
310 znear: camera_track.znear,
311 zfar: camera_track.zfar,
312 aspect_ratio: camera_track.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 camera_track_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(camera_track_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.camera_track.is_some() {
765 let (cam_track_buffer_views, cam_track_buffer_data) = self
766 .create_camera_animation_buffer_views(&mut full_buffer_data.len(), compatibility_mode)
767 .unwrap();
768 let cam_track_accessors = self.create_camera_animation_accessors(buffer_views.len() as u32).unwrap();
769 let (cam_track_channels, cam_track_samplers) = self
770 .create_camera_animation_channels_and_samplers(accessors.len() as u32, 1, samplers.len() as u32)
771 .unwrap();
772 buffer_views.extend(cam_track_buffer_views);
773 full_buffer_data.extend(cam_track_buffer_data);
774 accessors.extend(cam_track_accessors);
775 channels.extend(cam_track_channels);
776 samplers.extend(cam_track_samplers);
777 }
778 for prop_idx in 0..self.props.len() {
779 let prop = self.props[prop_idx].clone();
780 let prop_mesh_index = self.per_body_data.len() + prop_idx;
781 info!("Writing prop {prop_idx} to GLTF");
782 let mut inverse_bind_matrices: Vec<f32> = vec![];
783 let joint_rotations = batch_rodrigues(&prop.default_joint_poses);
784 let joint_translations = prop.default_translation.clone();
785 let joint_count = 1;
786 let parents = [0];
787 let bind_matrices = self.create_bind_matrices(&joint_rotations, &joint_translations, &parents);
788 for j_idx in 0..joint_count {
789 let mut inverse_bind_matrix = nd::Array2::<f32>::zeros((4, 4));
790 let inverse_rotation_matrix: ArrayBase<ndarray::ViewRepr<&f32>, Dim<[usize; 2]>> =
791 bind_matrices.slice(s![j_idx, 0..3, 0..3]).reversed_axes();
792 let translation: nd::Array1<f32> = bind_matrices.slice(s![j_idx, 0..3, 3]).to_owned();
793 let inverse_translation = -inverse_rotation_matrix.dot(&translation);
794 inverse_bind_matrix.slice_mut(s![0..3, 0..3]).assign(&inverse_rotation_matrix);
795 inverse_bind_matrix.slice_mut(s![0..3, 3]).assign(&inverse_translation);
796 inverse_bind_matrix[(3, 3)] = 1.0;
797 inverse_bind_matrices.extend(inverse_bind_matrix.t().iter());
798 }
799 let has_uv = prop.uvs.is_some();
800 println!("has uv: {has_uv}");
801 let vertex_data = if let Some(uvs) = prop.uvs.as_ref() {
802 println!("uv size: {:?}", uvs.shape());
803 println!("prop.positions size: {:?}", prop.positions.shape());
804 let mut vertex_attributes_array: Vec<VertexPropWithUV> = vec![];
805 for (position, uv) in izip!(prop.positions.row_iter(), uvs.row_iter()) {
806 vertex_attributes_array.push(VertexPropWithUV {
807 position: Vector3f::new(position[0], position[1], position[2]).into(),
808 uv: Vector2f::new(uv[0], 1.0 - uv[1]).into(),
809 joint_index: Vector4s::new(0, 0, 0, 0).into(),
810 joint_weight: Vector4f::new(1.0, 0.0, 0.0, 0.0).into(),
811 });
812 }
813 to_padded_byte_vector(&vertex_attributes_array)
814 } else {
815 println!("no uv found");
816 let mut vertex_attributes_array: Vec<VertexProp> = vec![];
817 for position in izip!(prop.positions.row_iter(),) {
818 vertex_attributes_array.push(VertexProp {
819 position: Vector3f::new(position[0], position[1], position[2]).into(),
820 joint_index: Vector4s::new(0, 0, 0, 0).into(),
821 joint_weight: Vector4f::new(1.0, 0.0, 0.0, 0.0).into(),
822 });
823 }
824 to_padded_byte_vector(&vertex_attributes_array)
825 };
826 let mut indices_array: Vec<u32> = vec![];
827 for row in prop.faces.row_iter() {
828 indices_array.extend_from_slice(&[row[0], row[1], row[2]]);
829 }
830 let index_data = to_padded_byte_vector(&indices_array);
831 let inv_bind_mat_data = to_padded_byte_vector(&inverse_bind_matrices);
832 let has_diffuse = prop.diffuse_texture.is_some();
833 let mut texture_infos: Vec<GltfTextureInfo> = vec![];
834 let mut diffuse_prop_texture_id = None;
835 let tex_offset = self.per_body_data.len() * 3;
836 if let Some(img) = prop.diffuse_texture.as_ref() {
837 let diffuse_tex = self.add_texture(img, texture_infos.len() + tex_offset, "diffuse_prop");
838 if let Some(diffuse_tex) = diffuse_tex {
839 diffuse_prop_texture_id = Some(texture_infos.len());
840 texture_infos.push(diffuse_tex);
841 }
842 }
843 diffuse_prop_texture_id = diffuse_prop_texture_id.map(|id| id + tex_offset);
844 let mut base_color_texture: Option<gltf_json::texture::Info> = None;
845 if let Some(diffuse_texture_index) = diffuse_prop_texture_id {
846 base_color_texture = Some(gltf_json::texture::Info {
847 index: gltf_json::Index::new(u32::try_from(diffuse_texture_index).expect("Could not convert to u32!")),
848 tex_coord: 0,
849 extensions: None,
850 extras: None,
851 });
852 }
853 let material = gltf_json::Material {
854 alpha_cutoff: None,
855 alpha_mode: gltf_json::validation::Checked::<AlphaMode>::Valid(AlphaMode::Opaque),
856 double_sided: false,
857 name: Some("prop_material".to_string()),
858 pbr_metallic_roughness: gltf_json::material::PbrMetallicRoughness {
859 base_color_factor: gltf_json::material::PbrBaseColorFactor([1., 1., 1., 1.]),
860 base_color_texture,
861 ..Default::default()
862 },
863 normal_texture: None,
864 occlusion_texture: None,
865 emissive_texture: None,
866 emissive_factor: gltf_json::material::EmissiveFactor([0., 0., 0.]),
867 extensions: None,
868 extras: None,
869 };
870 materials.push(material);
871 let primitive_offset = accessors.len() as u32;
872 let materials_selected = if has_diffuse {
873 Some(gltf_json::Index::new(prop_mesh_index as u32))
874 } else {
875 None
876 };
877 let primitive = gltf_json::mesh::Primitive {
878 #[allow(unused_assignments)]
879 attributes: {
880 let mut map = std::collections::BTreeMap::new();
881 let mut attr_idx = 1;
882 map.insert(
883 Valid(gltf_json::mesh::Semantic::Positions),
884 gltf_json::Index::new(attr_idx + primitive_offset),
885 );
886 attr_idx += 1;
887 if has_uv {
888 map.insert(
889 Valid(gltf_json::mesh::Semantic::TexCoords(0)),
890 gltf_json::Index::new(attr_idx + primitive_offset),
891 );
892 attr_idx += 1;
893 }
894 map.insert(
895 Valid(gltf_json::mesh::Semantic::Joints(0)),
896 gltf_json::Index::new(attr_idx + primitive_offset),
897 );
898 attr_idx += 1;
899 map.insert(
900 Valid(gltf_json::mesh::Semantic::Weights(0)),
901 gltf_json::Index::new(attr_idx + primitive_offset),
902 );
903 attr_idx += 1;
904 map
905 },
906 extensions: Option::default(),
907 extras: Option::default(),
908 indices: Some(gltf_json::Index::new(PrimitiveAttrIDs::Indices as u32 + primitive_offset)),
909 material: materials_selected,
910 mode: Valid(gltf_json::mesh::Mode::Triangles),
911 targets: None,
912 };
913 let mesh = gltf_json::Mesh {
914 extensions: Option::default(),
915 extras: Option::default(),
916 name: Some(format!("prop_{prop_idx}")),
917 primitives: vec![primitive],
918 weights: None,
919 };
920 meshes.push(mesh);
921 let vertex_count = prop.positions.shape().0;
922 let face_count = prop.faces.shape().0;
923 let current_buffer_view_offset = buffer_views.len() as u32;
924 let mut per_view_running_offset: [usize; 6] = [0, 0, 0, 0, 0, 0];
925 let accessor = self.create_accessors_props(
926 prop_idx,
927 vertex_count,
928 face_count,
929 current_buffer_view_offset,
930 &mut per_view_running_offset,
931 compatibility_mode,
932 has_uv,
933 );
934 accessors.extend(accessor);
935 let mut current_buffer_views = vec![];
936 self.create_buffer_views_props(
937 prop_idx as u32,
938 full_buffer_data.len(),
939 vertex_count,
940 face_count,
941 &mut current_buffer_views,
942 compatibility_mode,
943 has_uv,
944 );
945 let (buffer_data, composed_buffer_views, _buffer_offset, _buffer_index) = self.compose_buffer_views_props(
946 &self.props[prop_idx],
947 current_buffer_views.clone(),
948 index_data.as_slice(),
949 vertex_data.as_slice(),
950 inv_bind_mat_data.as_slice(),
951 &mut texture_infos,
952 compatibility_mode,
953 global_buffer_offset,
954 global_buffer_index,
955 );
956 full_buffer_data.extend(buffer_data);
957 buffer_views.extend(composed_buffer_views);
958 for texture in texture_infos {
959 images.push(texture.image);
960 textures.push(texture.texture);
961 texture_samplers.push(texture.sampler);
962 }
963 let prop_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
964 let armature_node = Node {
965 name: Some(format!("Armature_Prop_{prop_idx}")),
966 children: Some(vec![]),
967 ..Default::default()
968 };
969 nodes.push(armature_node);
970 if let Some(ref mut scene_root_node_children) = nodes[0].children {
971 scene_root_node_children.push(gltf_json::Index::new(prop_node_index));
972 }
973 let mesh_skin_binding_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
974 let mesh_skin_binding_node = Node {
975 mesh: Some(gltf_json::Index::new(prop_mesh_index as u32)),
976 skin: Some(gltf_json::Index::new(prop_mesh_index as u32)),
977 name: Some(format!("MeshSkinBinding_{prop_idx}")),
978 children: None,
979 ..Default::default()
980 };
981 nodes.push(mesh_skin_binding_node);
982 let root_node_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
983 let mut joints = vec![];
984 let skeleton_root_index = self.add_skin_prop(
985 format!("Skin_prop_{prop_idx}"),
986 &prop,
987 prop_node_index,
988 accessors.len().try_into().unwrap(),
989 &mut nodes,
990 &mut skins,
991 &mut joints,
992 compatibility_mode,
993 );
994 if let Some(ref mut armature_children) = nodes[prop_node_index as usize].children {
995 armature_children.push(gltf_json::Index::new(mesh_skin_binding_node_index));
996 armature_children.push(gltf_json::Index::new(root_node_index));
997 }
998 let animation_channels = self.create_animation_channels_prop(
999 joint_count,
1000 root_node_index,
1001 skeleton_root_index.value(),
1002 samplers.len(),
1003 compatibility_mode,
1004 );
1005 let animation_samplers = self.create_animation_samplers_prop(joint_count, accessors.len().try_into().unwrap(), compatibility_mode);
1006 channels.extend(animation_channels);
1007 samplers.extend(animation_samplers);
1008 }
1009 let buffer = gltf_json::Buffer {
1010 byte_length: USize64::from(full_buffer_data.len()),
1011 extensions: Option::default(),
1012 extras: Option::default(),
1013 name: Some("scene_buffer".to_string()),
1014 uri: if binary { None } else { Some("buffer0.bin".into()) },
1015 };
1016 buffers.push(buffer);
1017 let mut animations: Vec<gltf_json::Animation> = vec![];
1018 if self.is_animated() {
1019 let animation = gltf_json::Animation {
1020 extensions: Option::default(),
1021 extras: Option::default(),
1022 channels,
1023 name: Some("Scene_animation".to_string()),
1024 samplers,
1025 };
1026 animations.push(animation);
1027 }
1028 let root = gltf_json::Root {
1029 accessors,
1030 animations,
1031 buffers,
1032 buffer_views,
1033 cameras,
1034 images,
1035 materials,
1036 meshes,
1037 nodes,
1038 samplers: texture_samplers,
1039 scenes,
1040 skins,
1041 textures,
1042 ..Default::default()
1043 };
1044 (full_buffer_data, root)
1045 }
1046 #[allow(clippy::too_many_arguments)]
1048 fn create_buffer_views(
1049 &self,
1050 body_idx: u32,
1051 mut running_offset: usize,
1052 vertex_count: usize,
1053 face_count: usize,
1054 joint_count: usize,
1055 num_extra_joints: usize,
1056 buffer_views: &mut Vec<gltf_json::buffer::View>,
1057 compatibility_mode: GltfCompatibilityMode,
1058 ) {
1059 let index_buffer_size = face_count * 3 * mem::size_of::<u32>();
1060 let index_buffer_view = gltf_json::buffer::View {
1061 buffer: gltf_json::Index::new(0),
1062 byte_length: USize64::from(index_buffer_size),
1063 byte_offset: Some(USize64::from(running_offset)),
1064 byte_stride: None,
1065 extensions: Option::default(),
1066 extras: Option::default(),
1067 name: Some(format!("index_buffer_view_{body_idx}")),
1068 target: Some(Valid(gltf_json::buffer::Target::ElementArrayBuffer)),
1069 };
1070 buffer_views.push(index_buffer_view);
1071 running_offset += index_buffer_size;
1072 let vertex_buffer_size = vertex_count * mem::size_of::<Vertex>();
1073 let vertex_buffer_view = gltf_json::buffer::View {
1074 buffer: gltf_json::Index::new(0),
1075 byte_length: USize64::from(vertex_buffer_size),
1076 byte_offset: Some(USize64::from(running_offset)),
1077 byte_stride: Some(gltf_json::buffer::Stride(mem::size_of::<Vertex>())),
1078 extensions: Option::default(),
1079 extras: Option::default(),
1080 name: Some(format!("vertex_buffer_view_{body_idx}")),
1081 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1082 };
1083 buffer_views.push(vertex_buffer_view);
1084 running_offset += vertex_buffer_size;
1085 let inv_bind_matrix_buffer_size = (joint_count + num_extra_joints) * 16 * mem::size_of::<f32>();
1086 let inverse_bind_mat_buffer_view = gltf_json::buffer::View {
1087 buffer: gltf_json::Index::new(0),
1088 byte_length: USize64::from(inv_bind_matrix_buffer_size),
1089 byte_offset: Some(USize64::from(running_offset)),
1090 byte_stride: None,
1091 extensions: Option::default(),
1092 extras: Option::default(),
1093 name: Some(format!("inv_bind_matrix_buffer_view_{body_idx}")),
1094 target: None,
1095 };
1096 buffer_views.push(inverse_bind_mat_buffer_view);
1097 running_offset += inv_bind_matrix_buffer_size;
1098 if self.is_animated() {
1099 let rotation_animation_buffer_size = self.frame_count.unwrap() * 4 * mem::size_of::<f32>();
1100 let translation_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1101 let scale_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1102 let animation_buffer_views = self.create_animation_buffer_views(
1103 body_idx,
1104 joint_count,
1105 rotation_animation_buffer_size,
1106 translation_animation_buffer_size,
1107 scale_animation_buffer_size,
1108 &mut running_offset,
1109 compatibility_mode,
1110 );
1111 buffer_views.extend(animation_buffer_views);
1112 if self.num_morph_targets() > 0 && body_idx == 0 {
1113 let morph_target_buffer_size = vertex_count * 3 * mem::size_of::<f32>();
1114 let morph_target_buffer_views = self.create_morph_target_buffer_views(morph_target_buffer_size, &mut running_offset);
1115 buffer_views.extend(morph_target_buffer_views);
1116 }
1117 }
1118 }
1119 #[allow(clippy::too_many_arguments)]
1121 fn create_buffer_views_props(
1122 &self,
1123 prop_idx: u32,
1124 mut running_offset: usize,
1125 vertex_count: usize,
1126 face_count: usize,
1127 buffer_views: &mut Vec<gltf_json::buffer::View>,
1128 compatibility_mode: GltfCompatibilityMode,
1129 with_uv: bool,
1130 ) {
1131 let joint_count = 1;
1132 let index_buffer_size = face_count * 3 * mem::size_of::<u32>();
1133 let index_buffer_view = gltf_json::buffer::View {
1134 buffer: gltf_json::Index::new(0),
1135 byte_length: USize64::from(index_buffer_size),
1136 byte_offset: Some(USize64::from(running_offset)),
1137 byte_stride: None,
1138 extensions: Option::default(),
1139 extras: Option::default(),
1140 name: Some(format!("index_buffer_view_prop_{prop_idx}")),
1141 target: Some(Valid(gltf_json::buffer::Target::ElementArrayBuffer)),
1142 };
1143 buffer_views.push(index_buffer_view);
1144 running_offset += index_buffer_size;
1145 let vertex_size = if with_uv {
1146 mem::size_of::<VertexPropWithUV>()
1147 } else {
1148 mem::size_of::<VertexProp>()
1149 };
1150 let vertex_buffer_size = vertex_count * vertex_size;
1151 let vertex_buffer_view = gltf_json::buffer::View {
1152 buffer: gltf_json::Index::new(0),
1153 byte_length: USize64::from(vertex_buffer_size),
1154 byte_offset: Some(USize64::from(running_offset)),
1155 byte_stride: Some(gltf_json::buffer::Stride(vertex_size)),
1156 extensions: Option::default(),
1157 extras: Option::default(),
1158 name: Some(format!("vertex_buffer_view_prop_{prop_idx}")),
1159 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1160 };
1161 buffer_views.push(vertex_buffer_view);
1162 running_offset += vertex_buffer_size;
1163 let inv_bind_matrix_buffer_size = (joint_count) * 16 * mem::size_of::<f32>();
1164 let inverse_bind_mat_buffer_view = gltf_json::buffer::View {
1165 buffer: gltf_json::Index::new(0),
1166 byte_length: USize64::from(inv_bind_matrix_buffer_size),
1167 byte_offset: Some(USize64::from(running_offset)),
1168 byte_stride: None,
1169 extensions: Option::default(),
1170 extras: Option::default(),
1171 name: Some(format!("inv_bind_matrix_buffer_view_{prop_idx}")),
1172 target: None,
1173 };
1174 buffer_views.push(inverse_bind_mat_buffer_view);
1175 running_offset += inv_bind_matrix_buffer_size;
1176 let rotation_animation_buffer_size = self.frame_count.unwrap() * 4 * mem::size_of::<f32>();
1177 let translation_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1178 let scale_animation_buffer_size = self.frame_count.unwrap() * 3 * mem::size_of::<f32>();
1179 let animation_buffer_views = self.create_animation_buffer_views_prop(
1180 prop_idx,
1181 joint_count,
1182 rotation_animation_buffer_size,
1183 translation_animation_buffer_size,
1184 scale_animation_buffer_size,
1185 &mut running_offset,
1186 compatibility_mode,
1187 );
1188 buffer_views.extend(animation_buffer_views);
1189 }
1190 #[allow(clippy::too_many_arguments)]
1192 fn create_animation_buffer_views(
1193 &self,
1194 body_idx: u32,
1195 joint_count: usize,
1196 rotation_buffer_size: usize,
1197 translation_buffer_size: usize,
1198 scale_buffer_size: usize,
1199 running_offset: &mut usize,
1200 compatibility_mode: GltfCompatibilityMode,
1201 ) -> Vec<gltf_json::buffer::View> {
1202 let mut animation_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1203 let keyframe_buffer_size = self.frame_count.unwrap() * mem::size_of::<f32>();
1204 let keyframe_buffer_view = gltf_json::buffer::View {
1205 buffer: gltf_json::Index::new(0),
1206 byte_length: USize64::from(keyframe_buffer_size),
1207 byte_offset: Some(USize64::from(*running_offset)),
1208 byte_stride: None,
1209 extensions: Option::default(),
1210 extras: Option::default(),
1211 name: Some(format!("keyframe_buffer_view_{body_idx}")),
1212 target: None,
1213 };
1214 animation_buffer_views.push(keyframe_buffer_view);
1215 *running_offset += keyframe_buffer_size;
1216 for j_idx in 0..joint_count {
1217 let buffer_view_name = format!("joint_{j_idx}_animations_buffer_view_{body_idx}");
1218 let animation_buffer_view = gltf_json::buffer::View {
1219 buffer: gltf_json::Index::new(0),
1220 byte_length: USize64::from(rotation_buffer_size),
1221 byte_offset: Some(USize64::from(*running_offset)),
1222 byte_stride: None,
1223 extensions: Option::default(),
1224 extras: Option::default(),
1225 name: Some(buffer_view_name),
1226 target: None,
1227 };
1228 animation_buffer_views.push(animation_buffer_view);
1229 *running_offset += rotation_buffer_size;
1230 }
1231 let buffer_view_name = format!("root_translation_animations_buffer_view_{body_idx}");
1232 let animation_buffer_view = gltf_json::buffer::View {
1233 buffer: gltf_json::Index::new(0),
1234 byte_length: USize64::from(translation_buffer_size),
1235 byte_offset: Some(USize64::from(*running_offset)),
1236 byte_stride: None,
1237 extensions: Option::default(),
1238 extras: Option::default(),
1239 name: Some(buffer_view_name),
1240 target: None,
1241 };
1242 animation_buffer_views.push(animation_buffer_view);
1243 *running_offset += translation_buffer_size;
1244 let buffer_view_name = format!("root_scale_animations_buffer_view_{body_idx}");
1245 let animation_buffer_view = gltf_json::buffer::View {
1246 buffer: gltf_json::Index::new(0),
1247 byte_length: USize64::from(scale_buffer_size),
1248 byte_offset: Some(USize64::from(*running_offset)),
1249 byte_stride: None,
1250 extensions: Option::default(),
1251 extras: Option::default(),
1252 name: Some(buffer_view_name),
1253 target: None,
1254 };
1255 animation_buffer_views.push(animation_buffer_view);
1256 *running_offset += scale_buffer_size;
1257 if compatibility_mode == GltfCompatibilityMode::Unreal {
1258 let buffer_view_name = format!("pelvis_rel_translation_animations_buffer_view_{body_idx}");
1259 let animation_buffer_view = gltf_json::buffer::View {
1260 buffer: gltf_json::Index::new(0),
1261 byte_length: USize64::from(translation_buffer_size),
1262 byte_offset: Some(USize64::from(*running_offset)),
1263 byte_stride: None,
1264 extensions: Option::default(),
1265 extras: Option::default(),
1266 name: Some(buffer_view_name),
1267 target: None,
1268 };
1269 animation_buffer_views.push(animation_buffer_view);
1270 *running_offset += translation_buffer_size;
1271 }
1272 if self.num_morph_targets() > 0 {
1273 let morph_weights_buffer_size = self.frame_count.unwrap() * self.num_morph_targets() * mem::size_of::<f32>();
1274 let buffer_view_name = format!("morph_target_weights_{body_idx}");
1275 let morph_weights_buffer_view = gltf_json::buffer::View {
1276 buffer: gltf_json::Index::new(0),
1277 byte_length: USize64::from(morph_weights_buffer_size),
1278 byte_offset: Some(USize64::from(*running_offset)),
1279 byte_stride: None,
1280 extensions: Option::default(),
1281 extras: Option::default(),
1282 name: Some(buffer_view_name),
1283 target: None,
1284 };
1285 animation_buffer_views.push(morph_weights_buffer_view);
1286 *running_offset += morph_weights_buffer_size;
1287 }
1288 animation_buffer_views
1289 }
1290 #[allow(clippy::too_many_arguments)]
1291 fn create_animation_buffer_views_prop(
1292 &self,
1293 prop_idx: u32,
1294 joint_count: usize,
1295 rotation_buffer_size: usize,
1296 translation_buffer_size: usize,
1297 scale_buffer_size: usize,
1298 running_offset: &mut usize,
1299 _compatibility_mode: GltfCompatibilityMode,
1300 ) -> Vec<gltf_json::buffer::View> {
1301 let mut animation_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1302 let keyframe_buffer_size = self.frame_count.unwrap() * mem::size_of::<f32>();
1303 let keyframe_buffer_view = gltf_json::buffer::View {
1304 buffer: gltf_json::Index::new(0),
1305 byte_length: USize64::from(keyframe_buffer_size),
1306 byte_offset: Some(USize64::from(*running_offset)),
1307 byte_stride: None,
1308 extensions: Option::default(),
1309 extras: Option::default(),
1310 name: Some(format!("keyframe_buffer_view_prop_{prop_idx}")),
1311 target: None,
1312 };
1313 animation_buffer_views.push(keyframe_buffer_view);
1314 *running_offset += keyframe_buffer_size;
1315 for j_idx in 0..joint_count {
1316 let buffer_view_name = format!("joint_{j_idx}_animations_buffer_view_prop_{prop_idx}");
1317 let animation_buffer_view = gltf_json::buffer::View {
1318 buffer: gltf_json::Index::new(0),
1319 byte_length: USize64::from(rotation_buffer_size),
1320 byte_offset: Some(USize64::from(*running_offset)),
1321 byte_stride: None,
1322 extensions: Option::default(),
1323 extras: Option::default(),
1324 name: Some(buffer_view_name),
1325 target: None,
1326 };
1327 animation_buffer_views.push(animation_buffer_view);
1328 *running_offset += rotation_buffer_size;
1329 }
1330 let buffer_view_name = format!("root_translation_animations_buffer_view_prop_{prop_idx}");
1331 let animation_buffer_view = gltf_json::buffer::View {
1332 buffer: gltf_json::Index::new(0),
1333 byte_length: USize64::from(translation_buffer_size),
1334 byte_offset: Some(USize64::from(*running_offset)),
1335 byte_stride: None,
1336 extensions: Option::default(),
1337 extras: Option::default(),
1338 name: Some(buffer_view_name),
1339 target: None,
1340 };
1341 animation_buffer_views.push(animation_buffer_view);
1342 *running_offset += translation_buffer_size;
1343 let buffer_view_name = format!("root_scale_animations_buffer_view_prop_{prop_idx}");
1344 let animation_buffer_view = gltf_json::buffer::View {
1345 buffer: gltf_json::Index::new(0),
1346 byte_length: USize64::from(scale_buffer_size),
1347 byte_offset: Some(USize64::from(*running_offset)),
1348 byte_stride: None,
1349 extensions: Option::default(),
1350 extras: Option::default(),
1351 name: Some(buffer_view_name),
1352 target: None,
1353 };
1354 animation_buffer_views.push(animation_buffer_view);
1355 *running_offset += scale_buffer_size;
1356 animation_buffer_views
1357 }
1358 fn create_morph_target_buffer_views(&self, morph_target_buffer_size: usize, running_offset: &mut usize) -> Vec<gltf_json::buffer::View> {
1360 let mut morph_targets_buffer_views: Vec<gltf_json::buffer::View> = vec![];
1361 for morph_target_idx in 0..self.num_morph_targets() {
1362 let buffer_view_name = format!("morph_{morph_target_idx}_buffer_view");
1363 let morph_target_buffer_view = gltf_json::buffer::View {
1364 buffer: gltf_json::Index::new(0),
1365 byte_length: USize64::from(morph_target_buffer_size),
1366 byte_offset: Some(USize64::from(*running_offset)),
1367 byte_stride: None,
1368 extensions: Option::default(),
1369 extras: Option::default(),
1370 name: Some(buffer_view_name),
1371 target: Some(Valid(gltf_json::buffer::Target::ArrayBuffer)),
1372 };
1373 morph_targets_buffer_views.push(morph_target_buffer_view);
1374 *running_offset += morph_target_buffer_size;
1375 }
1376 morph_targets_buffer_views
1377 }
1378 #[allow(clippy::too_many_lines)]
1380 #[allow(clippy::too_many_arguments)]
1381 fn create_accessors(
1382 &self,
1383 body_idx: usize,
1384 vertex_count: usize,
1385 face_count: usize,
1386 joint_count: usize,
1387 current_buffer_view_offset: u32,
1388 per_view_running_offset: &mut [usize; 6],
1389 num_extra_joints: usize,
1390 compatibility_mode: GltfCompatibilityMode,
1391 ) -> Vec<gltf_json::Accessor> {
1392 let (min, max) = geom::get_bounding_points(self.per_body_data[body_idx].positions.as_ref().unwrap(), None);
1393 let (min_vec, max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1394 let mut accessors: Vec<gltf_json::Accessor> = vec![];
1395 let indices = gltf_json::Accessor {
1396 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Index as u32 + current_buffer_view_offset)),
1397 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Index as usize])),
1398 count: USize64::from(face_count * 3),
1399 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U32)),
1400 extensions: Option::default(),
1401 extras: Option::default(),
1402 type_: Valid(gltf_json::accessor::Type::Scalar),
1403 min: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().min()]))),
1404 max: Some(gltf_json::Value::from(Vec::from([self.faces.as_ref().unwrap().max()]))),
1405 name: Some(format!("index_accessor_{body_idx}")),
1406 normalized: false,
1407 sparse: None,
1408 };
1409 accessors.push(indices);
1410 let position_element_size = 3 * mem::size_of::<f32>();
1411 let positions = gltf_json::Accessor {
1412 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1413 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1414 count: USize64::from(vertex_count),
1415 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1416 extensions: Option::default(),
1417 extras: Option::default(),
1418 type_: Valid(gltf_json::accessor::Type::Vec3),
1419 min: Some(gltf_json::Value::from(min_vec)),
1420 max: Some(gltf_json::Value::from(max_vec)),
1421 name: Some(format!("position_accessor_{body_idx}")),
1422 normalized: false,
1423 sparse: None,
1424 };
1425 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += position_element_size;
1426 accessors.push(positions);
1427 let normal_element_size = 3 * mem::size_of::<f32>();
1428 let normals = gltf_json::Accessor {
1429 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1430 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1431 count: USize64::from(vertex_count),
1432 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1433 extensions: Option::default(),
1434 extras: Option::default(),
1435 type_: Valid(gltf_json::accessor::Type::Vec3),
1436 min: None,
1437 max: None,
1438 name: Some(format!("normal_accessor_{body_idx}")),
1439 normalized: false,
1440 sparse: None,
1441 };
1442 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += normal_element_size;
1443 accessors.push(normals);
1444 let uv_element_size = 2 * mem::size_of::<f32>();
1445 let uvs = gltf_json::Accessor {
1446 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1447 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1448 count: USize64::from(vertex_count),
1449 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1450 extensions: Option::default(),
1451 extras: Option::default(),
1452 type_: Valid(gltf_json::accessor::Type::Vec2),
1453 min: None,
1454 max: None,
1455 name: Some("uv_accessor".to_string()),
1456 normalized: false,
1457 sparse: None,
1458 };
1459 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += uv_element_size;
1460 accessors.push(uvs);
1461 let joint_index_element_size = 4 * mem::size_of::<u16>();
1462 let joint_indices = gltf_json::Accessor {
1463 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1464 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1465 count: USize64::from(vertex_count),
1466 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U16)),
1467 extensions: Option::default(),
1468 extras: Option::default(),
1469 type_: Valid(gltf_json::accessor::Type::Vec4),
1470 min: None,
1471 max: None,
1472 name: Some("joint_index_accessor".to_string()),
1473 normalized: false,
1474 sparse: None,
1475 };
1476 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_index_element_size;
1477 accessors.push(joint_indices);
1478 let joint_weight_element_size = 4 * mem::size_of::<f32>();
1479 let joint_weights = gltf_json::Accessor {
1480 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1481 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1482 count: USize64::from(vertex_count),
1483 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1484 extensions: Option::default(),
1485 extras: Option::default(),
1486 type_: Valid(gltf_json::accessor::Type::Vec4),
1487 min: None,
1488 max: None,
1489 name: Some("joint_index_accessor".to_string()),
1490 normalized: false,
1491 sparse: None,
1492 };
1493 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_weight_element_size;
1494 accessors.push(joint_weights);
1495 let inv_bind_matrices = gltf_json::Accessor {
1496 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::InvBindMat as u32 + current_buffer_view_offset)),
1497 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::InvBindMat as usize])),
1498 count: USize64::from(joint_count + num_extra_joints),
1499 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1500 extensions: Option::default(),
1501 extras: Option::default(),
1502 type_: Valid(gltf_json::accessor::Type::Mat4),
1503 min: None,
1504 max: None,
1505 name: Some("inv_bind_matrices_accessor".to_string()),
1506 normalized: false,
1507 sparse: None,
1508 };
1509 accessors.push(inv_bind_matrices);
1510 if self.is_animated() {
1511 let animation_accessors =
1512 self.create_animation_accessors(joint_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1513 accessors.extend(animation_accessors);
1514 if self.num_morph_targets() > 0 && body_idx == 0 {
1515 let morph_target_accessors =
1516 self.create_morph_target_accessors(vertex_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1517 accessors.extend(morph_target_accessors);
1518 }
1519 }
1520 accessors
1521 }
1522 #[allow(clippy::too_many_lines)]
1524 #[allow(clippy::too_many_arguments)]
1525 fn create_accessors_props(
1526 &self,
1527 prop_idx: usize,
1528 vertex_count: usize,
1529 face_count: usize,
1530 current_buffer_view_offset: u32,
1531 per_view_running_offset: &mut [usize; 6],
1532 compatibility_mode: GltfCompatibilityMode,
1533 with_uv: bool,
1534 ) -> Vec<gltf_json::Accessor> {
1535 let joint_count = 1;
1536 let (min, max) = geom::get_bounding_points(&self.props[prop_idx].positions, None);
1537 let (min_vec, max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1538 let mut accessors: Vec<gltf_json::Accessor> = vec![];
1539 let indices = gltf_json::Accessor {
1540 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Index as u32 + current_buffer_view_offset)),
1541 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Index as usize])),
1542 count: USize64::from(face_count * 3),
1543 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U32)),
1544 extensions: Option::default(),
1545 extras: Option::default(),
1546 type_: Valid(gltf_json::accessor::Type::Scalar),
1547 min: Some(gltf_json::Value::from(Vec::from([self.props[prop_idx].faces.min()]))),
1548 max: Some(gltf_json::Value::from(Vec::from([self.props[prop_idx].faces.max()]))),
1549 name: Some(format!("index_accessor_prop_{prop_idx}")),
1550 normalized: false,
1551 sparse: None,
1552 };
1553 accessors.push(indices);
1554 let position_element_size = 3 * mem::size_of::<f32>();
1555 let positions = gltf_json::Accessor {
1556 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1557 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1558 count: USize64::from(vertex_count),
1559 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1560 extensions: Option::default(),
1561 extras: Option::default(),
1562 type_: Valid(gltf_json::accessor::Type::Vec3),
1563 min: Some(gltf_json::Value::from(min_vec)),
1564 max: Some(gltf_json::Value::from(max_vec)),
1565 name: Some(format!("position_accessor_prop_{prop_idx}")),
1566 normalized: false,
1567 sparse: None,
1568 };
1569 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += position_element_size;
1570 accessors.push(positions);
1571 if with_uv {
1572 let uv_element_size = 2 * mem::size_of::<f32>();
1573 let uvs = gltf_json::Accessor {
1574 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1575 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1576 count: USize64::from(vertex_count),
1577 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1578 extensions: Option::default(),
1579 extras: Option::default(),
1580 type_: Valid(gltf_json::accessor::Type::Vec2),
1581 min: None,
1582 max: None,
1583 name: Some(format!("uv_accessor_prop_{prop_idx}")),
1584 normalized: false,
1585 sparse: None,
1586 };
1587 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += uv_element_size;
1588 accessors.push(uvs);
1589 }
1590 let joint_index_element_size = 4 * mem::size_of::<u16>();
1591 let joint_indices = gltf_json::Accessor {
1592 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1593 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1594 count: USize64::from(vertex_count),
1595 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::U16)),
1596 extensions: Option::default(),
1597 extras: Option::default(),
1598 type_: Valid(gltf_json::accessor::Type::Vec4),
1599 min: None,
1600 max: None,
1601 name: Some("joint_index_accessor_prop".to_string()),
1602 normalized: false,
1603 sparse: None,
1604 };
1605 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_index_element_size;
1606 accessors.push(joint_indices);
1607 let joint_weight_element_size = 4 * mem::size_of::<f32>();
1608 let joint_weights = gltf_json::Accessor {
1609 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::VertexAttr as u32 + current_buffer_view_offset)),
1610 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::VertexAttr as usize])),
1611 count: USize64::from(vertex_count),
1612 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1613 extensions: Option::default(),
1614 extras: Option::default(),
1615 type_: Valid(gltf_json::accessor::Type::Vec4),
1616 min: None,
1617 max: None,
1618 name: Some("joint_weight_accessor_prop".to_string()),
1619 normalized: false,
1620 sparse: None,
1621 };
1622 per_view_running_offset[BufferViewIDs::VertexAttr as usize] += joint_weight_element_size;
1623 accessors.push(joint_weights);
1624 let inv_bind_matrices = gltf_json::Accessor {
1625 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::InvBindMat as u32 + current_buffer_view_offset)),
1626 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::InvBindMat as usize])),
1627 count: USize64::from(joint_count),
1628 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1629 extensions: Option::default(),
1630 extras: Option::default(),
1631 type_: Valid(gltf_json::accessor::Type::Mat4),
1632 min: None,
1633 max: None,
1634 name: Some("inv_bind_matrices_accessor_prop".to_string()),
1635 normalized: false,
1636 sparse: None,
1637 };
1638 accessors.push(inv_bind_matrices);
1639 let animation_accessors =
1640 self.create_animation_accessors_props(joint_count, current_buffer_view_offset, per_view_running_offset, compatibility_mode);
1641 accessors.extend(animation_accessors);
1642 accessors
1643 }
1644 #[allow(clippy::too_many_lines)]
1646 fn create_animation_accessors(
1647 &self,
1648 joint_count: usize,
1649 current_buffer_view_offset: u32,
1650 per_view_running_offset: &mut [usize; 6],
1651 compatibility_mode: GltfCompatibilityMode,
1652 ) -> Vec<gltf_json::Accessor> {
1653 let mut animation_accessors: Vec<gltf_json::Accessor> = vec![];
1654 let min_keyframe = self
1655 .keyframe_times
1656 .as_ref()
1657 .expect("keyframe_times should exist")
1658 .iter()
1659 .copied()
1660 .min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1661 .expect("keyframe_times should have elements in the vector");
1662 let max_keyframe = self
1663 .keyframe_times
1664 .as_ref()
1665 .unwrap()
1666 .iter()
1667 .copied()
1668 .max_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1669 .unwrap();
1670 let keyframe_times = gltf_json::Accessor {
1671 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Keyframe as u32 + current_buffer_view_offset)),
1672 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Keyframe as usize])),
1673 count: USize64::from(self.frame_count.unwrap()),
1674 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1675 extensions: Option::default(),
1676 extras: Option::default(),
1677 type_: Valid(gltf_json::accessor::Type::Scalar),
1678 min: Some(gltf_json::Value::from(Vec::from([min_keyframe]))),
1679 max: Some(gltf_json::Value::from(Vec::from([max_keyframe]))),
1680 name: Some("keyframes_accessor".to_string()),
1681 normalized: false,
1682 sparse: None,
1683 };
1684 animation_accessors.push(keyframe_times);
1685 let mut running_buffer_view = BufferViewIDs::Animation as u32 + current_buffer_view_offset;
1686 for j_idx in 0..joint_count {
1687 let accessor_name = format!("joint_{j_idx}_animations_accessor");
1688 let joint_animation_accessor = gltf_json::Accessor {
1689 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1690 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1691 count: USize64::from(self.frame_count.unwrap()),
1692 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1693 extensions: Option::default(),
1694 extras: Option::default(),
1695 type_: Valid(gltf_json::accessor::Type::Vec4),
1696 min: None,
1697 max: None,
1698 name: Some(accessor_name),
1699 normalized: false,
1700 sparse: None,
1701 };
1702 animation_accessors.push(joint_animation_accessor);
1703 running_buffer_view += 1;
1704 }
1705 let accessor_name = "root_translation_animations_accessor".to_string();
1706 let body_animation_accessor = gltf_json::Accessor {
1707 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1708 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1709 count: USize64::from(self.frame_count.unwrap()),
1710 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1711 extensions: Option::default(),
1712 extras: Option::default(),
1713 type_: Valid(gltf_json::accessor::Type::Vec3),
1714 min: None,
1715 max: None,
1716 name: Some(accessor_name),
1717 normalized: false,
1718 sparse: None,
1719 };
1720 animation_accessors.push(body_animation_accessor);
1721 running_buffer_view += 1;
1722 let accessor_name = "root_scale_animations_accessor".to_string();
1723 let vis_animation_accessor = gltf_json::Accessor {
1724 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1725 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1726 count: USize64::from(self.frame_count.unwrap()),
1727 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1728 extensions: Option::default(),
1729 extras: Option::default(),
1730 type_: Valid(gltf_json::accessor::Type::Vec3),
1731 min: None,
1732 max: None,
1733 name: Some(accessor_name),
1734 normalized: false,
1735 sparse: None,
1736 };
1737 animation_accessors.push(vis_animation_accessor);
1738 running_buffer_view += 1;
1739 if compatibility_mode == GltfCompatibilityMode::Unreal {
1740 let accessor_name = "pelvis_rel_translation_animations_accessor".to_string();
1741 let pelvis_animation_accessor = gltf_json::Accessor {
1742 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1743 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1744 count: USize64::from(self.frame_count.unwrap()),
1745 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1746 extensions: Option::default(),
1747 extras: Option::default(),
1748 type_: Valid(gltf_json::accessor::Type::Vec3),
1749 min: None,
1750 max: None,
1751 name: Some(accessor_name),
1752 normalized: false,
1753 sparse: None,
1754 };
1755 animation_accessors.push(pelvis_animation_accessor);
1756 running_buffer_view += 1;
1757 }
1758 if self.num_morph_targets() > 0 {
1759 let accessor_name = "morph_targets_weights_accessor".to_string();
1760 let morph_targets_weights_accessor = gltf_json::Accessor {
1761 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1762 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1763 count: USize64::from(self.frame_count.unwrap() * self.num_morph_targets()),
1764 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1765 extensions: Option::default(),
1766 extras: Option::default(),
1767 type_: Valid(gltf_json::accessor::Type::Scalar),
1768 min: None,
1769 max: None,
1770 name: Some(accessor_name),
1771 normalized: false,
1772 sparse: None,
1773 };
1774 animation_accessors.push(morph_targets_weights_accessor);
1775 running_buffer_view += 1;
1776 }
1777 per_view_running_offset[BufferViewIDs::Animation as usize] += running_buffer_view as usize;
1778 animation_accessors
1779 }
1780 #[allow(clippy::too_many_lines)]
1781 fn create_animation_accessors_props(
1782 &self,
1783 joint_count: usize,
1784 current_buffer_view_offset: u32,
1785 per_view_running_offset: &mut [usize; 6],
1786 _compatibility_mode: GltfCompatibilityMode,
1787 ) -> Vec<gltf_json::Accessor> {
1788 let mut animation_accessors: Vec<gltf_json::Accessor> = vec![];
1789 let min_keyframe = self
1790 .keyframe_times
1791 .as_ref()
1792 .expect("keyframe_times should exist")
1793 .iter()
1794 .copied()
1795 .min_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1796 .expect("keyframe_times should have elements in the vector");
1797 let max_keyframe = self
1798 .keyframe_times
1799 .as_ref()
1800 .unwrap()
1801 .iter()
1802 .copied()
1803 .max_by(|a, b| a.partial_cmp(b).expect("Tried to compare a NaN"))
1804 .unwrap();
1805 let keyframe_times = gltf_json::Accessor {
1806 buffer_view: Some(gltf_json::Index::new(BufferViewIDs::Keyframe as u32 + current_buffer_view_offset)),
1807 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Keyframe as usize])),
1808 count: USize64::from(self.frame_count.unwrap()),
1809 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1810 extensions: Option::default(),
1811 extras: Option::default(),
1812 type_: Valid(gltf_json::accessor::Type::Scalar),
1813 min: Some(gltf_json::Value::from(Vec::from([min_keyframe]))),
1814 max: Some(gltf_json::Value::from(Vec::from([max_keyframe]))),
1815 name: Some("keyframes_accessor_prop".to_string()),
1816 normalized: false,
1817 sparse: None,
1818 };
1819 animation_accessors.push(keyframe_times);
1820 let mut running_buffer_view = BufferViewIDs::Animation as u32 + current_buffer_view_offset;
1821 for j_idx in 0..joint_count {
1822 let accessor_name = format!("joint_{j_idx}_animations_accessor_prop");
1823 let joint_animation_accessor = gltf_json::Accessor {
1824 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1825 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1826 count: USize64::from(self.frame_count.unwrap()),
1827 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1828 extensions: Option::default(),
1829 extras: Option::default(),
1830 type_: Valid(gltf_json::accessor::Type::Vec4),
1831 min: None,
1832 max: None,
1833 name: Some(accessor_name),
1834 normalized: false,
1835 sparse: None,
1836 };
1837 animation_accessors.push(joint_animation_accessor);
1838 running_buffer_view += 1;
1839 }
1840 let accessor_name = "root_translation_animations_accessor_prop".to_string();
1841 let body_animation_accessor = gltf_json::Accessor {
1842 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1843 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1844 count: USize64::from(self.frame_count.unwrap()),
1845 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1846 extensions: Option::default(),
1847 extras: Option::default(),
1848 type_: Valid(gltf_json::accessor::Type::Vec3),
1849 min: None,
1850 max: None,
1851 name: Some(accessor_name),
1852 normalized: false,
1853 sparse: None,
1854 };
1855 animation_accessors.push(body_animation_accessor);
1856 running_buffer_view += 1;
1857 let accessor_name = "root_scale_animations_accessor_prop".to_string();
1858 let vis_animation_accessor = gltf_json::Accessor {
1859 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1860 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Animation as usize])),
1861 count: USize64::from(self.frame_count.unwrap()),
1862 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1863 extensions: Option::default(),
1864 extras: Option::default(),
1865 type_: Valid(gltf_json::accessor::Type::Vec3),
1866 min: None,
1867 max: None,
1868 name: Some(accessor_name),
1869 normalized: false,
1870 sparse: None,
1871 };
1872 animation_accessors.push(vis_animation_accessor);
1873 running_buffer_view += 1;
1874 per_view_running_offset[BufferViewIDs::Animation as usize] += running_buffer_view as usize;
1875 animation_accessors
1876 }
1877 fn create_morph_target_accessors(
1879 &self,
1880 vertex_count: usize,
1881 current_buffer_view_offset: u32,
1882 per_view_running_offset: &mut [usize; 6],
1883 compatibility_mode: GltfCompatibilityMode,
1884 ) -> Vec<gltf_json::Accessor> {
1885 let mut morph_target_accessors: Vec<gltf_json::Accessor> = vec![];
1886 let mut running_buffer_view = u32::try_from(per_view_running_offset[BufferViewIDs::Animation as usize]).expect("Could not convert to U32!")
1887 + current_buffer_view_offset;
1888 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
1889 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
1890 for morph_target_idx in 0..self.num_morph_targets() {
1891 let accessor_name = format!("morph_{morph_target_idx}_accessor");
1892 let current_morph_target = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]);
1893 let current_morph_target_na = current_morph_target.to_owned().clone().into_nalgebra();
1894 let (min, max) = geom::get_bounding_points(¤t_morph_target_na, None);
1895 let (mut min_vec, mut max_vec): (Vec<f32>, Vec<f32>) = (min.iter().copied().collect(), max.iter().copied().collect());
1896 if compatibility_mode == GltfCompatibilityMode::Smpl && (morph_target_idx < num_pose_morph_targets) {
1897 max_vec = max_vec.iter().map(|x| x * 2.0 * PI).collect();
1898 min_vec = min_vec.iter().map(|x| x * 2.0 * PI).collect();
1899 }
1900 if compatibility_mode == GltfCompatibilityMode::Smpl
1901 && (morph_target_idx > num_pose_morph_targets && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets)
1902 {
1903 max_vec = max_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1904 min_vec = min_vec.iter().map(|x| x * 2.0 * 7.0).collect();
1905 }
1906 let morph_target_accessor = gltf_json::Accessor {
1907 buffer_view: Some(gltf_json::Index::new(running_buffer_view)),
1908 byte_offset: Some(USize64::from(per_view_running_offset[BufferViewIDs::Deformation as usize])),
1909 count: USize64::from(vertex_count),
1910 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
1911 extensions: Option::default(),
1912 extras: Option::default(),
1913 type_: Valid(gltf_json::accessor::Type::Vec3),
1914 min: Some(gltf_json::Value::from(min_vec)),
1915 max: Some(gltf_json::Value::from(max_vec)),
1916 name: Some(accessor_name),
1917 normalized: false,
1918 sparse: None,
1919 };
1920 morph_target_accessors.push(morph_target_accessor);
1921 running_buffer_view += 1;
1922 }
1923 per_view_running_offset[BufferViewIDs::Deformation as usize] += running_buffer_view as usize;
1924 morph_target_accessors
1925 }
1926 #[allow(clippy::cast_possible_truncation)]
1928 fn create_animation_channels(
1929 &self,
1930 joint_count: usize,
1931 root_idx: u32,
1932 skeleton_root_idx: usize,
1933 sampler_start_idx: usize,
1934 compatibility_mode: GltfCompatibilityMode,
1935 ) -> Vec<gltf_json::animation::Channel> {
1936 let mut animation_channels: Vec<gltf_json::animation::Channel> = vec![];
1937 let mut sampler_idx = sampler_start_idx;
1938 for j_idx in 0..joint_count {
1939 let animation_target = gltf_json::animation::Target {
1940 extensions: Option::default(),
1941 extras: Option::default(),
1942 node: gltf_json::Index::new(u32::try_from(j_idx + skeleton_root_idx).expect("Could not convert to u32!")),
1943 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Rotation),
1944 };
1945 let channel = gltf_json::animation::Channel {
1946 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1947 target: animation_target,
1948 extensions: Option::default(),
1949 extras: Option::default(),
1950 };
1951 animation_channels.push(channel);
1952 sampler_idx += 1;
1953 }
1954 let animation_target = gltf_json::animation::Target {
1955 extensions: Option::default(),
1956 extras: Option::default(),
1957 node: gltf_json::Index::new(root_idx),
1958 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1959 };
1960 let channel = gltf_json::animation::Channel {
1961 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1962 target: animation_target,
1963 extensions: Option::default(),
1964 extras: Option::default(),
1965 };
1966 animation_channels.push(channel);
1967 sampler_idx += 1;
1968 let animation_target = gltf_json::animation::Target {
1969 extensions: Option::default(),
1970 extras: Option::default(),
1971 node: gltf_json::Index::new(root_idx),
1972 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Scale),
1973 };
1974 let channel = gltf_json::animation::Channel {
1975 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1976 target: animation_target,
1977 extensions: Option::default(),
1978 extras: Option::default(),
1979 };
1980 animation_channels.push(channel);
1981 sampler_idx += 1;
1982 let mesh_skin_binding_node_idx = root_idx - 1;
1983 if compatibility_mode == GltfCompatibilityMode::Unreal {
1984 let animation_target = gltf_json::animation::Target {
1985 extensions: Option::default(),
1986 extras: Option::default(),
1987 node: gltf_json::Index::new(u32::try_from(skeleton_root_idx).expect("Could not convert to u32!")),
1988 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
1989 };
1990 let channel = gltf_json::animation::Channel {
1991 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
1992 target: animation_target,
1993 extensions: Option::default(),
1994 extras: Option::default(),
1995 };
1996 animation_channels.push(channel);
1997 sampler_idx += 1;
1998 }
1999 if self.num_morph_targets() > 0 {
2000 let mtw_animation_target = gltf_json::animation::Target {
2001 extensions: Option::default(),
2002 extras: Option::default(),
2003 node: gltf_json::Index::new(mesh_skin_binding_node_idx),
2004 path: Valid(gltf_json::animation::Property::MorphTargetWeights),
2005 };
2006 let channel = gltf_json::animation::Channel {
2007 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2008 target: mtw_animation_target,
2009 extensions: Option::default(),
2010 extras: Option::default(),
2011 };
2012 animation_channels.push(channel);
2013 }
2014 animation_channels
2015 }
2016 fn create_animation_channels_prop(
2017 &self,
2018 joint_count: usize,
2019 root_idx: u32,
2020 skeleton_root_idx: usize,
2021 sampler_start_idx: usize,
2022 _compatibility_mode: GltfCompatibilityMode,
2023 ) -> Vec<gltf_json::animation::Channel> {
2024 let mut animation_channels: Vec<gltf_json::animation::Channel> = vec![];
2025 let mut sampler_idx = sampler_start_idx;
2026 for j_idx in 0..joint_count {
2027 let animation_target = gltf_json::animation::Target {
2028 extensions: Option::default(),
2029 extras: Option::default(),
2030 node: gltf_json::Index::new(u32::try_from(j_idx + skeleton_root_idx).expect("Could not convert to u32!")),
2031 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Rotation),
2032 };
2033 let channel = gltf_json::animation::Channel {
2034 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2035 target: animation_target,
2036 extensions: Option::default(),
2037 extras: Option::default(),
2038 };
2039 animation_channels.push(channel);
2040 sampler_idx += 1;
2041 }
2042 let animation_target = gltf_json::animation::Target {
2043 extensions: Option::default(),
2044 extras: Option::default(),
2045 node: gltf_json::Index::new(root_idx),
2046 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Translation),
2047 };
2048 let channel = gltf_json::animation::Channel {
2049 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2050 target: animation_target,
2051 extensions: Option::default(),
2052 extras: Option::default(),
2053 };
2054 animation_channels.push(channel);
2055 sampler_idx += 1;
2056 let animation_target = gltf_json::animation::Target {
2057 extensions: Option::default(),
2058 extras: Option::default(),
2059 node: gltf_json::Index::new(root_idx),
2060 path: gltf_json::validation::Checked::Valid(gltf_json::animation::Property::Scale),
2061 };
2062 let channel = gltf_json::animation::Channel {
2063 sampler: gltf_json::Index::new(u32::try_from(sampler_idx).expect("Could not convert to u32!")),
2064 target: animation_target,
2065 extensions: Option::default(),
2066 extras: Option::default(),
2067 };
2068 animation_channels.push(channel);
2069 animation_channels
2070 }
2071 fn create_animation_samplers(
2073 &self,
2074 joint_count: usize,
2075 current_buffer_view_offset: u32,
2076 compatibility_mode: GltfCompatibilityMode,
2077 ) -> Vec<gltf_json::animation::Sampler> {
2078 let mut animation_samplers: Vec<gltf_json::animation::Sampler> = vec![];
2079 let mut current_accessor = 8 + current_buffer_view_offset;
2080 for _ in 0..joint_count {
2081 let sampler = gltf_json::animation::Sampler {
2082 extensions: Option::default(),
2083 extras: Option::default(),
2084 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2085 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2086 output: gltf_json::Index::new(current_accessor),
2087 };
2088 animation_samplers.push(sampler);
2089 current_accessor += 1;
2090 }
2091 let sampler = gltf_json::animation::Sampler {
2092 extensions: Option::default(),
2093 extras: Option::default(),
2094 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2095 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2096 output: gltf_json::Index::new(current_accessor),
2097 };
2098 animation_samplers.push(sampler);
2099 current_accessor += 1;
2100 let sampler = gltf_json::animation::Sampler {
2101 extensions: Option::default(),
2102 extras: Option::default(),
2103 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2104 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Step),
2105 output: gltf_json::Index::new(current_accessor),
2106 };
2107 animation_samplers.push(sampler);
2108 current_accessor += 1;
2109 if compatibility_mode == GltfCompatibilityMode::Unreal {
2110 let sampler = gltf_json::animation::Sampler {
2111 extensions: Option::default(),
2112 extras: Option::default(),
2113 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2114 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2115 output: gltf_json::Index::new(current_accessor),
2116 };
2117 animation_samplers.push(sampler);
2118 current_accessor += 1;
2119 }
2120 if self.num_morph_targets() > 0 {
2121 let sampler = gltf_json::animation::Sampler {
2122 extensions: Option::default(),
2123 extras: Option::default(),
2124 input: gltf_json::Index::new(7 + current_buffer_view_offset),
2125 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2126 output: gltf_json::Index::new(current_accessor),
2127 };
2128 animation_samplers.push(sampler);
2129 }
2130 animation_samplers
2131 }
2132 fn create_animation_samplers_prop(
2133 &self,
2134 joint_count: usize,
2135 current_buffer_view_offset: u32,
2136 _compatibility_mode: GltfCompatibilityMode,
2137 ) -> Vec<gltf_json::animation::Sampler> {
2138 let mut animation_samplers: Vec<gltf_json::animation::Sampler> = vec![];
2139 let mut current_accessor = current_buffer_view_offset - 3;
2140 for _ in 0..joint_count {
2141 let sampler = gltf_json::animation::Sampler {
2142 extensions: Option::default(),
2143 extras: Option::default(),
2144 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2145 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2146 output: gltf_json::Index::new(current_accessor),
2147 };
2148 animation_samplers.push(sampler);
2149 current_accessor += 1;
2150 }
2151 let sampler = gltf_json::animation::Sampler {
2152 extensions: Option::default(),
2153 extras: Option::default(),
2154 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2155 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Linear),
2156 output: gltf_json::Index::new(current_accessor),
2157 };
2158 animation_samplers.push(sampler);
2159 current_accessor += 1;
2160 let sampler = gltf_json::animation::Sampler {
2161 extensions: Option::default(),
2162 extras: Option::default(),
2163 input: gltf_json::Index::new(current_buffer_view_offset - 4),
2164 interpolation: gltf_json::validation::Checked::Valid(gltf_json::animation::Interpolation::Step),
2165 output: gltf_json::Index::new(current_accessor),
2166 };
2167 animation_samplers.push(sampler);
2168 animation_samplers
2169 }
2170 pub fn create_morph_targets(&self, pose_dirs_accessors_start_idx: usize) -> Vec<gltf_json::mesh::MorphTarget> {
2172 let mut pose_dirs_morph_targets: Vec<gltf_json::mesh::MorphTarget> = vec![];
2173 let mut running_pose_dirs_accessor = u32::try_from(pose_dirs_accessors_start_idx).expect("Not able to convert to u32");
2174 for _ in 0..self.num_morph_targets() {
2175 let morph_target = gltf_json::mesh::MorphTarget {
2176 positions: Some(gltf_json::Index::new(running_pose_dirs_accessor)),
2177 normals: None,
2178 tangents: None,
2179 };
2180 pose_dirs_morph_targets.push(morph_target);
2181 running_pose_dirs_accessor += 1;
2182 }
2183 pose_dirs_morph_targets
2184 }
2185 pub fn create_bind_matrices(&self, rot_mat: &nd::Array3<f32>, joint_trans: &nd::Array2<f32>, joint_parents: &[u32]) -> nd::Array3<f32> {
2187 assert!(
2188 rot_mat.shape()[0] == joint_trans.shape()[0],
2189 "Number of rotation matrices dont match number of translation matrices!"
2190 );
2191 let num_joints = rot_mat.shape()[0];
2192 let mut bind_matrices = ndarray::Array3::<f32>::zeros((num_joints, 4, 4));
2193 bind_matrices.slice_mut(s![0, 0..3, 0..3]).assign(&rot_mat.slice(s![0, .., ..]));
2194 bind_matrices.slice_mut(s![0, 0..3, 3]).assign(&joint_trans.slice(s![0, ..]));
2195 bind_matrices[[0, 3, 3]] = 1.0;
2196 for j_idx in 1..num_joints {
2197 let parent_index = joint_parents[j_idx] as usize;
2198 let parent_transform = bind_matrices.index_axis(nd::Axis(0), parent_index);
2199 let mut local_transform = ndarray::Array2::<f32>::zeros((4, 4));
2200 local_transform.slice_mut(s![0..3, 0..3]).assign(&rot_mat.slice(s![j_idx, .., ..]));
2201 let local_translation = Array::from_vec(vec_to_vec(&compute_local_translation(j_idx, joint_parents, joint_trans)));
2202 local_transform.slice_mut(s![0..3, 3]).assign(&local_translation);
2203 local_transform[[3, 3]] = 1.0;
2204 let global_transform = parent_transform.dot(&local_transform);
2205 bind_matrices.slice_mut(s![j_idx, .., ..]).assign(&global_transform);
2206 }
2207 bind_matrices
2208 }
2209 pub fn create_animation_data(&self, current_body: &PerBodyData, compatibility_mode: GltfCompatibilityMode) -> Vec<u8> {
2211 let mut animation_data: Vec<u8> = vec![];
2212 let keyframe_data = to_padded_byte_vector(self.keyframe_times.as_ref().unwrap());
2213 let rotation_animation_data = current_body.body_rotations.as_ref().unwrap();
2214 let mut translation_animation_data = current_body.body_translations.as_ref().unwrap().clone();
2215 let scale_animation_data = current_body.body_scales.as_ref().unwrap().clone();
2216 animation_data.extend_from_slice(keyframe_data.as_slice());
2217 assert_eq!(rotation_animation_data.shape()[1], translation_animation_data.shape()[0]);
2218 for j_idx in 0..rotation_animation_data.shape()[0] {
2219 let mut quaternions: Vec<f32> = vec![];
2220 for r_idx in 0..rotation_animation_data.shape()[1] {
2221 let rotation = rotation_animation_data.slice(s![j_idx, r_idx, ..]);
2222 let axis_angle_rotation = na::Vector3::new(rotation[0], rotation[1], rotation[2]);
2223 let mut quaternion_rotation =
2224 na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_angle_rotation), axis_angle_rotation.norm());
2225 if axis_angle_rotation.norm() == 0.0 {
2226 quaternion_rotation = na::UnitQuaternion::default();
2227 }
2228 quaternions.extend(quaternion_rotation.as_vector().data.as_slice());
2229 }
2230 let joint_anim_data = to_padded_byte_vector(&quaternions);
2231 animation_data.append(&mut joint_anim_data.clone());
2232 }
2233 if compatibility_mode == GltfCompatibilityMode::Unreal {
2234 let mut pelvis_relative_trans = translation_animation_data.clone();
2235 for mut row in translation_animation_data.axis_iter_mut(Axis(0)) {
2236 row[1] = 0.0;
2237 }
2238 for mut row in pelvis_relative_trans.axis_iter_mut(Axis(0)) {
2239 row[0] = 0.0;
2240 row[2] = 0.0;
2241 }
2242 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec_and_offset().0);
2243 animation_data.append(&mut trans_anim_data.clone());
2244 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec_and_offset().0);
2245 animation_data.append(&mut scale_anim_data.clone());
2246 let pelvis_rel_anim_data = to_padded_byte_vector(&pelvis_relative_trans.to_owned().into_raw_vec_and_offset().0);
2247 animation_data.append(&mut pelvis_rel_anim_data.clone());
2248 } else {
2249 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec_and_offset().0);
2250 animation_data.append(&mut trans_anim_data.clone());
2251 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec_and_offset().0);
2252 animation_data.append(&mut scale_anim_data.clone());
2253 }
2254 if self.num_morph_targets() > 0 {
2255 let morph_target_weights_data = current_body.per_frame_blend_weights.as_ref().unwrap();
2256 let weights_anim_data = to_padded_byte_vector(&morph_target_weights_data.to_owned().into_raw_vec_and_offset().0);
2257 animation_data.append(&mut weights_anim_data.clone());
2258 }
2259 animation_data
2260 }
2261 pub fn create_animation_data_prop(&self, current_prop: &PropData, _compatibility_mode: GltfCompatibilityMode) -> Vec<u8> {
2262 let mut animation_data: Vec<u8> = vec![];
2263 let keyframe_data = to_padded_byte_vector(self.keyframe_times.as_ref().unwrap());
2264 let rotation_animation_data = current_prop.rotations.clone();
2265 let translation_animation_data = current_prop.translations.clone();
2266 let scale_animation_data = current_prop.scales.clone();
2267 animation_data.extend_from_slice(keyframe_data.as_slice());
2268 assert_eq!(rotation_animation_data.shape()[1], translation_animation_data.shape()[0]);
2269 for j_idx in 0..rotation_animation_data.shape()[0] {
2270 let mut quaternions: Vec<f32> = vec![];
2271 for r_idx in 0..rotation_animation_data.shape()[1] {
2272 let rotation = rotation_animation_data.slice(s![j_idx, r_idx, ..]);
2273 let axis_angle_rotation = na::Vector3::new(rotation[0], rotation[1], rotation[2]);
2274 let mut quaternion_rotation =
2275 na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_angle_rotation), axis_angle_rotation.norm());
2276 if axis_angle_rotation.norm() == 0.0 {
2277 quaternion_rotation = na::UnitQuaternion::default();
2278 }
2279 quaternions.extend(quaternion_rotation.as_vector().data.as_slice());
2280 }
2281 let joint_anim_data = to_padded_byte_vector(&quaternions);
2282 animation_data.append(&mut joint_anim_data.clone());
2283 }
2284 let trans_anim_data = to_padded_byte_vector(&translation_animation_data.to_owned().into_raw_vec_and_offset().0);
2285 animation_data.append(&mut trans_anim_data.clone());
2286 let scale_anim_data = to_padded_byte_vector(&scale_animation_data.to_owned().into_raw_vec_and_offset().0);
2287 animation_data.append(&mut scale_anim_data.clone());
2288 animation_data
2289 }
2290 #[allow(clippy::too_many_arguments)]
2292 fn compose_buffer_views(
2293 &self,
2294 body_idx: usize,
2295 current_body: &PerBodyData,
2296 buffer_views: Vec<gltf_json::buffer::View>,
2297 index_data: &[u8],
2298 vertex_data: &[u8],
2299 inv_bind_mat_data: &[u8],
2300 textures: &mut [GltfTextureInfo],
2301 compatibility_mode: GltfCompatibilityMode,
2302 ) -> (Vec<u8>, Vec<gltf_json::buffer::View>, usize, usize) {
2303 let mut out_data: Vec<u8> = vec![];
2304 let mut out_buffer_views: Vec<gltf_json::buffer::View> = vec![];
2305 out_data.append(&mut index_data.to_owned());
2306 out_data.append(&mut vertex_data.to_owned());
2307 out_data.append(&mut inv_bind_mat_data.to_owned());
2308 if self.is_animated() {
2309 let mut animation_data = self.create_animation_data(current_body, compatibility_mode);
2310 out_data.append(&mut animation_data);
2311 if self.num_morph_targets() > 0 && body_idx == 0 {
2312 for morph_target_idx in 0..self.num_morph_targets() {
2313 let mut posedir = self.morph_targets.as_ref().unwrap().slice(s![morph_target_idx, .., ..]).to_owned();
2314 let num_pose_morph_targets = self.num_pose_morph_targets.saturating_sub(1);
2315 let num_expression_morph_targets = self.num_expression_morph_targets.saturating_sub(1);
2316 if compatibility_mode == GltfCompatibilityMode::Smpl
2317 && self.num_pose_morph_targets > 0
2318 && morph_target_idx < num_pose_morph_targets
2319 {
2320 posedir *= 2.0 * PI;
2321 }
2322 if compatibility_mode == GltfCompatibilityMode::Smpl
2323 && self.num_expression_morph_targets > 0
2324 && morph_target_idx > num_pose_morph_targets
2325 && morph_target_idx < self.num_pose_morph_targets + num_expression_morph_targets
2326 {
2327 posedir *= 2.0 * 7.0;
2328 }
2329 let posedir_data = to_padded_byte_vector(&posedir.to_owned().into_raw_vec_and_offset().0);
2330 out_data.append(&mut posedir_data.clone());
2331 }
2332 }
2333 }
2334 out_buffer_views.extend(buffer_views);
2335 let mut buffer_offset = out_data.len();
2336 let mut buffer_index: usize = out_buffer_views.len();
2337 for (sampler_index, texture) in textures.iter_mut().enumerate() {
2338 let mut buffer_view = texture.buffer_view.clone();
2339 buffer_view.byte_offset = Some(USize64::from(buffer_offset));
2340 out_buffer_views.push(buffer_view);
2341 texture.buffer_index = buffer_index;
2342 texture.image.buffer_view = Some(gltf_json::Index::new(u32::try_from(buffer_index).expect("Issue converting to u32!")));
2343 texture.texture.sampler = Some(gltf_json::Index::new(u32::try_from(sampler_index).expect("Issue converting to u32!")));
2344 out_data.append(&mut texture.image_data.clone());
2345 buffer_offset += texture.buffer_size;
2346 buffer_index += 1;
2347 }
2348 (out_data, out_buffer_views, buffer_offset, buffer_index)
2349 }
2350 #[allow(clippy::too_many_arguments)]
2352 fn compose_buffer_views_props(
2353 &self,
2354 current_prop: &PropData,
2355 buffer_views: Vec<gltf_json::buffer::View>,
2356 index_data: &[u8],
2357 vertex_data: &[u8],
2358 inv_bind_mat_data: &[u8],
2359 textures: &mut [GltfTextureInfo],
2360 compatibility_mode: GltfCompatibilityMode,
2361 global_buffer_offset: usize,
2362 global_buffer_index: usize,
2363 ) -> (Vec<u8>, Vec<gltf_json::buffer::View>, usize, usize) {
2364 let mut out_data: Vec<u8> = vec![];
2365 let mut out_buffer_views: Vec<gltf_json::buffer::View> = vec![];
2366 out_data.append(&mut index_data.to_owned());
2367 out_data.append(&mut vertex_data.to_owned());
2368 out_data.append(&mut inv_bind_mat_data.to_owned());
2369 let mut animation_data = self.create_animation_data_prop(current_prop, compatibility_mode);
2370 out_data.append(&mut animation_data);
2371 out_buffer_views.extend(buffer_views);
2372 let mut buffer_offset = out_data.len() + global_buffer_offset;
2373 let mut buffer_index: usize = out_buffer_views.len() + global_buffer_index;
2374 for (sampler_index, texture) in textures.iter_mut().enumerate() {
2375 let mut buffer_view = texture.buffer_view.clone();
2376 buffer_view.byte_offset = Some(USize64::from(buffer_offset));
2377 out_buffer_views.push(buffer_view);
2378 texture.buffer_index = buffer_index;
2379 texture.image.buffer_view = Some(gltf_json::Index::new(u32::try_from(buffer_index).expect("Issue converting to u32!")));
2380 texture.texture.sampler = Some(gltf_json::Index::new(u32::try_from(sampler_index).expect("Issue converting to u32!")));
2381 out_data.append(&mut texture.image_data.clone());
2382 buffer_offset += texture.buffer_size;
2383 buffer_index += 1;
2384 }
2385 (out_data, out_buffer_views, buffer_offset, buffer_index)
2386 }
2387 fn add_texture(&self, img: &DynImage, index: usize, name: &str) -> Option<GltfTextureInfo> {
2389 let mut image_data: Vec<u8> = vec![];
2390 let mut target = Cursor::new(&mut image_data);
2391 let image_data_buffer = img.write_to(&mut target, image::ImageFormat::Png);
2392 if image_data_buffer.is_ok() {
2393 let _ = target.flush();
2394 while image_data.len() % 4 != 0 {
2395 image_data.push(0);
2396 }
2397 let mut image_buffer_size = image_data.len();
2398 align_to_multiple_of_four(&mut image_buffer_size);
2399 let image_buffer_view = gltf_json::buffer::View {
2400 buffer: gltf_json::Index::new(0),
2401 byte_length: USize64::from(image_buffer_size),
2402 byte_offset: Some(USize64::from(0_usize)),
2403 byte_stride: Option::default(),
2404 extensions: Option::default(),
2405 extras: Option::default(),
2406 name: Some(name.to_string()),
2407 target: None,
2408 };
2409 let image = gltf_json::image::Image {
2410 buffer_view: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
2411 mime_type: Some(gltf_json::image::MimeType("image/png".to_string())),
2412 name: Some(name.to_string()),
2413 uri: None,
2414 extensions: None,
2415 extras: None,
2416 };
2417 let texture = gltf_json::Texture {
2418 name: Some(name.to_string()),
2419 sampler: Some(gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!"))),
2420 source: gltf_json::Index::new(u32::try_from(index).expect("Issue converting to u32!")),
2421 extensions: None,
2422 extras: None,
2423 };
2424 let sampler = gltf_json::texture::Sampler {
2425 name: Some(name.to_string()),
2426 mag_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MagFilter::Linear)),
2427 min_filter: Some(gltf_json::validation::Checked::Valid(gltf_json::texture::MinFilter::Linear)),
2428 wrap_s: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
2429 wrap_t: gltf_json::validation::Checked::Valid(gltf_json::texture::WrappingMode::ClampToEdge),
2430 extensions: None,
2431 extras: None,
2432 };
2433 let texture_info = GltfTextureInfo {
2434 buffer_size: image_data.len(),
2435 image_data,
2436 image,
2437 buffer_view: image_buffer_view,
2438 buffer_index: 0,
2439 texture,
2440 sampler,
2441 };
2442 return Some(texture_info);
2443 }
2444 log!("add_texture FAILED: {}", name);
2445 None
2446 }
2447 #[allow(clippy::cast_sign_loss)]
2449 fn prepare_normals(&self, smpl_textures: &mut SmplTextures, texture_infos: &mut Vec<GltfTextureInfo>, normals_tex: Option<&DynImage>) {
2450 if let Some(img) = normals_tex {
2451 let normals_tex = self.add_texture(img, texture_infos.len(), "normals");
2452 if let Some(normals_tex) = normals_tex {
2453 smpl_textures.normals_index = Some(texture_infos.len());
2454 texture_infos.push(normals_tex);
2455 }
2456 }
2457 }
2458 fn prepare_metallic_roughness(
2460 &self,
2461 smpl_textures: &mut SmplTextures,
2462 texture_infos: &mut Vec<GltfTextureInfo>,
2463 metalness_tex: Option<&DynImage>,
2464 roughness_tex: Option<&DynImage>,
2465 ) {
2466 let mut w: u32 = 0;
2467 let mut h: u32 = 0;
2468 if let Some(img) = metalness_tex {
2469 w = img.width();
2470 h = img.height();
2471 }
2472 if let Some(img) = roughness_tex {
2473 w = w.max(img.width());
2474 h = h.max(img.height());
2475 }
2476 let mut metalness: Option<Vec<u8>> = None;
2477 if let Some(img) = metalness_tex {
2478 if img.width() != w || img.height() != h {
2479 let resized_img = img.resize(w, h, FilterType::Gaussian);
2480 metalness = Some(resized_img.as_luma8().unwrap().to_vec());
2481 } else {
2482 metalness = Some(img.as_bytes().to_vec());
2483 }
2484 }
2485 let mut roughness: Option<Vec<u8>> = None;
2486 if let Some(img) = roughness_tex {
2487 if img.width() != w || img.height() != h {
2488 let resized_img = img.resize(w, h, FilterType::Gaussian);
2489 roughness = Some(resized_img.as_luma8().unwrap().to_vec());
2490 } else {
2491 roughness = Some(img.as_bytes().to_vec());
2492 }
2493 }
2494 let num_pixels: usize = (w * h) as usize;
2495 let mut metal_roughness_pixels: Vec<u8> = vec![];
2496 if let Some(metalness_pixels) = metalness {
2497 if let Some(roughness_pixels) = roughness {
2498 for (m, r) in metalness_pixels.iter().zip(roughness_pixels.iter()).take(num_pixels) {
2499 metal_roughness_pixels.push(0);
2500 metal_roughness_pixels.push(*r);
2501 metal_roughness_pixels.push(*m);
2502 }
2503 } else {
2504 for &m in metalness_pixels.iter().take(num_pixels) {
2505 metal_roughness_pixels.push(0);
2506 metal_roughness_pixels.push(0);
2507 metal_roughness_pixels.push(m);
2508 }
2509 }
2510 } else if let Some(roughness_pixels) = roughness {
2511 for &r in roughness_pixels.iter().take(num_pixels) {
2512 metal_roughness_pixels.push(0);
2513 metal_roughness_pixels.push(r);
2514 metal_roughness_pixels.push(0);
2515 }
2516 }
2517 if !metal_roughness_pixels.is_empty() {
2518 let metal_roughness_image = RgbImage::from_vec(w, h, metal_roughness_pixels);
2519 if let Some(image) = metal_roughness_image {
2520 let image = DynImage::from(image);
2521 let metallic_roughness = self.add_texture(&image, texture_infos.len(), "metal_roughness");
2522 if let Some(metallic_roughness) = metallic_roughness {
2523 smpl_textures.metalic_roughtness_index = Some(texture_infos.len());
2524 texture_infos.push(metallic_roughness);
2525 }
2526 }
2527 }
2528 }
2529 fn create_joint(&self, name: String, translation: &[f32], rotation: &Vector3f, children: Option<Vec<gltf_json::Index<Node>>>) -> Node {
2531 let cur_vec = na::Vector3::new(rotation.x, rotation.y, rotation.z);
2532 let mut cur_q = na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(cur_vec), rotation.norm());
2533 if rotation.norm() == 0.0 {
2534 cur_q = na::UnitQuaternion::default();
2535 }
2536 let translation: [f32; 3] = [translation[0], translation[1], translation[2]];
2537 let unit_quaternion = [cur_q[0], cur_q[1], cur_q[2], cur_q[3]];
2538 Node {
2539 children,
2540 mesh: None,
2541 skin: None,
2542 name: Some(name),
2543 rotation: Some(UnitQuaternion(unit_quaternion)),
2544 translation: Some(translation),
2545 ..Default::default()
2546 }
2547 }
2548 fn gather_children(&self, id: u32, parent_ids: &[u32], offset: u32) -> Option<Vec<gltf_json::Index<Node>>> {
2549 let mut children: Vec<gltf_json::Index<Node>> = vec![];
2550 for (p, &parent_id) in parent_ids.iter().enumerate() {
2551 if parent_id == id {
2552 let index = u32::try_from(p).expect("Index conversion error: usize value is too large to fit in a u32");
2553 children.push(gltf_json::Index::<Node>::new(index + offset));
2554 }
2555 }
2556 if !children.is_empty() {
2557 return Some(children);
2558 }
2559 None
2560 }
2561 #[allow(clippy::too_many_arguments)]
2563 fn add_skin(
2564 &mut self,
2565 name: String,
2566 current_body: &PerBodyData,
2567 current_armature_idx: u32,
2568 accessor_offset: u32,
2569 nodes: &mut Vec<Node>,
2570 skins: &mut Vec<gltf_json::Skin>,
2571 joints: &mut Vec<gltf_json::Index<Node>>,
2572 compatibility_mode: GltfCompatibilityMode,
2573 ) -> gltf_json::Index<Node> {
2574 let metadata = crate::common::metadata::smpl_metadata(&self.smpl_type);
2575 let joint_translations = current_body.default_joint_translations.as_ref().unwrap();
2576 let skeleton_root_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
2577 let global_translation = vec_from_array0_f(current_body.body_translation.as_ref().unwrap());
2578 let mut skeleton_root_translation = compute_local_translation(0, &metadata.joint_parents, joint_translations);
2579 if compatibility_mode == GltfCompatibilityMode::Smpl {
2580 skeleton_root_translation = addv3f(&skeleton_root_translation, &global_translation);
2581 }
2582 let mut joint_rotation = Vector3f::zeros();
2583 if let Some(joint_poses) = current_body.joint_poses.as_ref() {
2584 let rot = joint_poses.row(0).to_owned();
2585 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
2586 }
2587 let skeleton_root = self.create_joint(
2588 "pelvis".to_string(),
2589 vec_to_vec(&skeleton_root_translation).as_slice(),
2590 &joint_rotation,
2591 self.gather_children(0, &metadata.joint_parents, skeleton_root_index),
2592 );
2593 nodes.push(skeleton_root);
2594 joints.push(gltf_json::Index::new(skeleton_root_index));
2595 let joint_names = if compatibility_mode == GltfCompatibilityMode::Unreal {
2596 smpl_x::JOINT_NAMES_UNREAL.map(std::string::ToString::to_string).to_vec()
2597 } else {
2598 metadata.joint_names
2599 };
2600 for (j, name) in joint_names.iter().enumerate().take(metadata.num_joints + 1).skip(1) {
2601 if let Some(joint_poses) = current_body.joint_poses.as_ref() {
2602 let rot = joint_poses.row(j).to_owned();
2603 joint_rotation = Vector3f::new(rot[0], rot[1], rot[2]);
2604 }
2605 let joint = self.create_joint(
2606 name.clone(),
2607 vec_to_vec(&compute_local_translation(j, &metadata.joint_parents, joint_translations)).as_slice(),
2608 &joint_rotation,
2609 self.gather_children(
2610 u32::try_from(j).expect("Issue converting Joint idx to u32"),
2611 &metadata.joint_parents,
2612 skeleton_root_index,
2613 ),
2614 );
2615 let joint_index = gltf_json::Index::<Node>::new(u32::try_from(nodes.len()).expect("Issue converting Joint idx to u32"));
2616 nodes.push(joint);
2617 joints.push(joint_index);
2618 }
2619 let skin = gltf_json::Skin {
2620 name: Some(name),
2621 inverse_bind_matrices: Some(gltf_json::Index::new(accessor_offset + 6)),
2622 joints: joints.clone(),
2623 skeleton: Some(gltf_json::Index::new(current_armature_idx)),
2624 extensions: None,
2625 extras: None,
2626 };
2627 skins.push(skin);
2628 gltf_json::Index::<Node>::new(skeleton_root_index)
2629 }
2630 #[allow(clippy::too_many_arguments)]
2631 fn add_skin_prop(
2632 &mut self,
2633 name: String,
2634 current_prop: &PropData,
2635 current_armature_idx: u32,
2636 accessor_offset: u32,
2637 nodes: &mut Vec<Node>,
2638 skins: &mut Vec<gltf_json::Skin>,
2639 joints: &mut Vec<gltf_json::Index<Node>>,
2640 _compatibility_mode: GltfCompatibilityMode,
2641 ) -> gltf_json::Index<Node> {
2642 let joint_translations = ¤t_prop.default_translation;
2643 let skeleton_root_index = u32::try_from(nodes.len()).expect("Issue converting Node idx to u32");
2644 let skeleton_root_translation = vec_from_vec(&joint_translations.row(0).to_vec());
2645 let joint_rotation = Vector3f::zeros();
2646 let skeleton_root = self.create_joint(
2647 "root_prop".to_string(),
2648 vec_to_vec(&skeleton_root_translation).as_slice(),
2649 &joint_rotation,
2650 None,
2651 );
2652 nodes.push(skeleton_root);
2653 joints.push(gltf_json::Index::new(skeleton_root_index));
2654 let skin = gltf_json::Skin {
2655 name: Some(name),
2656 inverse_bind_matrices: Some(gltf_json::Index::new(accessor_offset - 5)),
2657 joints: joints.clone(),
2658 skeleton: Some(gltf_json::Index::new(current_armature_idx)),
2659 extensions: None,
2660 extras: None,
2661 };
2662 skins.push(skin);
2663 gltf_json::Index::<Node>::new(skeleton_root_index)
2664 }
2665 #[allow(clippy::cast_precision_loss)]
2667 fn create_camera_animation_buffer_views(
2668 &self,
2669 running_offset: &mut usize,
2670 compatibility_mode: GltfCompatibilityMode,
2671 ) -> Option<(Vec<gltf_json::buffer::View>, Vec<u8>)> {
2672 let camera_track = self.camera_track.as_ref()?;
2673 let mut buffer_views = Vec::new();
2674 let mut buffer_data = Vec::new();
2675 if let Some(translations) = camera_track.per_frame_translations.as_ref() {
2676 let trans_data = to_padded_byte_vector(translations.as_slice().unwrap());
2677 let trans_len = trans_data.len();
2678 let trans_view = gltf_json::buffer::View {
2679 buffer: gltf_json::Index::new(0),
2680 byte_length: USize64::from(trans_len),
2681 byte_offset: Some(USize64::from(*running_offset)),
2682 byte_stride: None,
2683 extensions: None,
2684 extras: Option::default(),
2685 name: Some("camera_translations".to_string()),
2686 target: None,
2687 };
2688 buffer_data.extend(trans_data);
2689 *running_offset += trans_len;
2690 buffer_views.push(trans_view);
2691 }
2692 if let Some(rotations) = camera_track.per_frame_rotations.as_ref() {
2693 let rotated_rots = if compatibility_mode == GltfCompatibilityMode::Unreal {
2694 let angle = 90.0;
2695 let axis = [0.0, 1.0, 0.0];
2696 self.rotate_camera_quaternions(angle, axis).as_ref().unwrap().clone()
2697 } else {
2698 rotations.clone()
2699 };
2700 let rot_data = to_padded_byte_vector(rotated_rots.as_slice().unwrap());
2701 let rot_len = rot_data.len();
2702 let rot_view = gltf_json::buffer::View {
2703 buffer: gltf_json::Index::new(0),
2704 byte_length: USize64::from(rot_len),
2705 byte_offset: Some(USize64::from(*running_offset)),
2706 byte_stride: None,
2707 extensions: None,
2708 extras: Option::default(),
2709 name: Some("camera_rotations".to_string()),
2710 target: None,
2711 };
2712 buffer_data.extend(rot_data);
2713 *running_offset += rot_len;
2714 buffer_views.push(rot_view);
2715 }
2716 Some((buffer_views, buffer_data))
2717 }
2718 fn create_camera_animation_accessors(&self, current_buffer_view_offset: u32) -> Option<Vec<gltf_json::Accessor>> {
2720 let camera_track = self.camera_track.as_ref()?;
2721 let mut accessors = Vec::new();
2722 let mut current_view = current_buffer_view_offset;
2723 if let Some(translations) = camera_track.per_frame_translations.as_ref() {
2724 accessors.push(gltf_json::Accessor {
2725 buffer_view: Some(gltf_json::Index::new(current_view)),
2726 byte_offset: None,
2727 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
2728 count: USize64::from(translations.shape()[0]),
2729 type_: Valid(gltf_json::accessor::Type::Vec3),
2730 min: None,
2731 max: None,
2732 name: Some("camera_translations".to_string()),
2733 normalized: false,
2734 sparse: None,
2735 extensions: None,
2736 extras: Option::default(),
2737 });
2738 current_view += 1;
2739 }
2740 if let Some(rotations) = camera_track.per_frame_rotations.as_ref() {
2741 accessors.push(gltf_json::Accessor {
2742 buffer_view: Some(gltf_json::Index::new(current_view)),
2743 byte_offset: None,
2744 component_type: Valid(gltf_json::accessor::GenericComponentType(gltf_json::accessor::ComponentType::F32)),
2745 count: USize64::from(rotations.shape()[0]),
2746 type_: Valid(gltf_json::accessor::Type::Vec4),
2747 min: None,
2748 max: None,
2749 name: Some("camera_rotations".to_string()),
2750 normalized: false,
2751 sparse: None,
2752 extensions: None,
2753 extras: Option::default(),
2754 });
2755 }
2756 Some(accessors)
2757 }
2758 #[allow(clippy::cast_possible_truncation)]
2760 fn create_camera_animation_channels_and_samplers(
2761 &self,
2762 current_accessor_offset: u32,
2763 camera_node_index: u32,
2764 sampler_start_idx: u32,
2765 ) -> Option<(Vec<gltf_json::animation::Channel>, Vec<gltf_json::animation::Sampler>)> {
2766 let camera_track = self.camera_track.as_ref()?;
2767 let mut channels = Vec::new();
2768 let mut samplers = Vec::new();
2769 let mut current_accessor = current_accessor_offset;
2770 let times_accessor_index = 7;
2771 if camera_track.per_frame_translations.is_some() {
2772 samplers.push(gltf_json::animation::Sampler {
2773 input: gltf_json::Index::new(times_accessor_index),
2774 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
2775 output: gltf_json::Index::new(current_accessor),
2776 extensions: None,
2777 extras: Option::default(),
2778 });
2779 channels.push(gltf_json::animation::Channel {
2780 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
2781 target: gltf_json::animation::Target {
2782 node: gltf_json::Index::new(camera_node_index),
2783 path: Valid(gltf_json::animation::Property::Translation),
2784 extensions: None,
2785 extras: Option::default(),
2786 },
2787 extensions: None,
2788 extras: Option::default(),
2789 });
2790 current_accessor += 1;
2791 }
2792 if camera_track.per_frame_rotations.is_some() {
2793 samplers.push(gltf_json::animation::Sampler {
2794 input: gltf_json::Index::new(times_accessor_index),
2795 interpolation: Valid(gltf_json::animation::Interpolation::Linear),
2796 output: gltf_json::Index::new(current_accessor),
2797 extensions: None,
2798 extras: Option::default(),
2799 });
2800 channels.push(gltf_json::animation::Channel {
2801 sampler: gltf_json::Index::new(sampler_start_idx + samplers.len() as u32 - 1),
2802 target: gltf_json::animation::Target {
2803 node: gltf_json::Index::new(camera_node_index),
2804 path: Valid(gltf_json::animation::Property::Rotation),
2805 extensions: None,
2806 extras: Option::default(),
2807 },
2808 extensions: None,
2809 extras: Option::default(),
2810 });
2811 }
2812 Some((channels, samplers))
2813 }
2814 fn num_morph_targets(&self) -> usize {
2815 self.morph_targets.as_ref().map_or(0, |x| x.shape()[0])
2816 }
2817 fn rotate_camera_quaternions(&self, angle_degrees: f32, axis: [f32; 3]) -> Option<nd::Array2<f32>> {
2819 if let Some(camera_track) = &self.camera_track {
2820 if let Some(rotations) = &camera_track.per_frame_rotations {
2821 let mut rotated_quaternions = rotations.clone();
2822 let axis_vec = na::Vector3::new(axis[0], axis[1], axis[2]);
2823 let rotation_quat = na::UnitQuaternion::from_axis_angle(&na::UnitVector3::new_normalize(axis_vec), angle_degrees.to_radians());
2824 for mut row in rotated_quaternions.axis_iter_mut(nd::Axis(0)) {
2825 let q = na::Quaternion::new(row[3], row[0], row[1], row[2]);
2826 let unit_q = na::UnitQuaternion::from_quaternion(q);
2827 let result = rotation_quat * unit_q;
2828 row[0] = result.i;
2829 row[1] = result.j;
2830 row[2] = result.k;
2831 row[3] = result.w;
2832 }
2833 return Some(rotated_quaternions);
2834 }
2835 }
2836 None
2837 }
2838}
2839pub fn compute_local_translation(id: usize, parent_ids: &[u32], joint_translations: &nd::Array2<f32>) -> Vector3f {
2840 let trans = vec_from_vec(&joint_translations.row(id).to_vec());
2841 if id == 0 {
2842 return trans;
2843 }
2844 let parent_id = parent_ids[id] as usize;
2845 let parent_trans = vec_from_vec(&joint_translations.row(parent_id).to_vec());
2846 subv3f(&trans, &parent_trans)
2847}