diff options
Diffstat (limited to 'world/src/main.rs')
-rw-r--r-- | world/src/main.rs | 149 |
1 files changed, 111 insertions, 38 deletions
diff --git a/world/src/main.rs b/world/src/main.rs index 1931fdb..53489f3 100644 --- a/world/src/main.rs +++ b/world/src/main.rs @@ -22,7 +22,13 @@ pub mod vrm; use anyhow::{Context, Result, anyhow}; use clap::Parser; -use gltf::{Gltf, Node, image::Source, import_buffers, scene::Transform}; +use gltf::{ + Gltf, Node, + animation::{Property, util::ReadOutputs}, + image::Source, + import_buffers, + scene::Transform, +}; use humansize::BINARY; use image::{ImageReader, codecs::webp::WebPEncoder}; use log::{debug, info}; @@ -49,7 +55,10 @@ use weareshared::{ Affine3A, Vec3A, helper::ReadWrite, packets::{Data, Object, Packet, Resource}, - resources::{ArmaturePart, EnvironmentPart, Image, LightPart, ParticlesPart, Prefab}, + resources::{ + AnimationChannel, AnimationPart, ArmaturePart, EnvironmentPart, Image, LightPart, + ParticlesPart, Prefab, + }, store::ResourceStore, vec3a, }; @@ -223,10 +232,12 @@ fn main() -> Result<()> { .collect::<Vec<_>>() }; - let mut prefab = nodes + let prefab = Mutex::new(Prefab::default()); + let node_to_meshes = Mutex::new(BTreeMap::<usize, Vec<usize>>::new()); + + nodes .par_iter() .map(|(trans, node)| { - let mut prefab = Prefab::default(); // if node.name().unwrap_or_default() == "particles" { // eprintln!("{:?}", node.transform()); // eprintln!("{:?}", node.extensions()); @@ -241,20 +252,30 @@ fn main() -> Result<()> { if !name.ends_with("-collider") { if let Some(mesh) = node.mesh() { - import_mesh( + let meshes = import_mesh( mesh, *trans, &buffers, &store, path_base, node, - &mut prefab, &args, &texture_cache, &skin_index_to_arm_index, &vrm, &head_bones, )?; + for (node, trans, mesh) in meshes { + let mut k = prefab.lock().unwrap(); + let i = k.mesh.len(); + k.mesh.push((trans, mesh)); + node_to_meshes + .lock() + .unwrap() + .entry(node) + .or_default() + .push(i) + } } } if extras.get("particles") == Some(&Value::Bool(true)) { @@ -274,17 +295,21 @@ fn main() -> Result<()> { serde_json::from_value(extras).context("particles attributes")?; info!("adding particles part"); - prefab.particles.push(( - transform_to_affine(node.transform()), - store.set(&ParticlesPart { - sprite: None, - density: attr.density, - lifetime: attr.lifetime, - lifetime_spread: attr.lifetime_spread, - velocity: attr.velocity, - velocity_spread: attr.velocity_spread, - })?, - )); + + let part = store.set(&ParticlesPart { + sprite: None, + density: attr.density, + lifetime: attr.lifetime, + lifetime_spread: attr.lifetime_spread, + velocity: attr.velocity, + velocity_spread: attr.velocity_spread, + })?; + + prefab + .lock() + .unwrap() + .particles + .push((transform_to_affine(node.transform()), part)); } if let Some(light) = node.light() { @@ -299,33 +324,81 @@ fn main() -> Result<()> { debug!("emission is {e}"); } let (position, _, _) = node.transform().decomposed(); - prefab.light.push(( - Vec3A::from_array(position), - store.set(&LightPart { - emission, - name, - radius: None, - })?, - )); + let part = store.set(&LightPart { + emission, + name, + radius: None, + })?; + prefab + .lock() + .unwrap() + .light + .push((Vec3A::from_array(position), part)); } - import_physics(&gltf, *trans, node, &mut prefab, &store, &buffers)?; - Ok::<_, anyhow::Error>(prefab) + import_physics(&gltf, *trans, node, &store, &buffers)?; + + Ok::<_, anyhow::Error>(()) }) .reduce( - || Ok(Prefab::default()), - |a, b| { - let mut a = a?; - let b = b?; - a.collision.extend(b.collision); - a.mesh.extend(b.mesh); - a.light.extend(b.light); - a.particles.extend(b.particles); - a.environment = a.environment.or(b.environment); - a.name = a.name.or(b.name); - Ok(a) + || Ok(()), + |a, b| match (a, b) { + (Ok(()), Ok(())) => Ok(()), + (Ok(()), a) => a, + (a, _) => a, }, )?; + let mut prefab = prefab.into_inner().unwrap(); + let node_to_meshes = node_to_meshes.into_inner().unwrap(); + + for a in gltf.animations() { + let mut max_time = 0f32; + let mut channels = Vec::new(); + for c in a.channels() { + let node = c.target().node().index(); + let reader = c.reader(|i| Some(&buffers[i.index()].0)); + let inputs: Vec<f32> = reader.read_inputs().unwrap().collect::<Vec<f32>>(); + let outputs: Vec<f32> = match reader.read_outputs().unwrap() { + ReadOutputs::Translations(iter) => iter.flatten().collect(), + ReadOutputs::Rotations(iter) => iter.into_f32().flatten().collect(), + ReadOutputs::Scales(iter) => iter.flatten().collect(), + ReadOutputs::MorphTargetWeights(iter) => iter.into_f32().collect(), + }; + for x in &inputs { + max_time = max_time.max(*x) + } + let time = store.set(&inputs)?; + let value = store.set(&outputs)?; + let meshes = node_to_meshes + .get(&node) + .ok_or(anyhow!("animation ref to meshless node"))?; + for &m in meshes { + let mut ch = AnimationChannel::default(); + match c.target().property() { + Property::Translation => ch.t_mesh_translation = Some(m as u32), + Property::Rotation => ch.t_mesh_rotation = Some(m as u32), + Property::Scale => ch.t_mesh_scale = Some(m as u32), + Property::MorphTargetWeights => todo!(), + } + ch.time = Some(time.clone()); + ch.value = Some(value.clone()); + debug!( + "animation channel {:?} of mesh {m} with {} times and {} component values", + c.target().property(), + inputs.len(), + outputs.len() + ); + channels.push(ch); + } + } + info!("adding animation with {} channels", channels.len()); + prefab.animations.push(store.set(&AnimationPart { + name: a.name().map(|n| n.to_string()), + channel: channels, + duration: Some(max_time), + })?); + } + prefab.armature = if armature.parent.as_ref().is_some_and(|a| !a.is_empty()) { vec![store.set(&armature)?] } else { |