summaryrefslogtreecommitdiff
path: root/world/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'world/src/main.rs')
-rw-r--r--world/src/main.rs149
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 {