summaryrefslogtreecommitdiff
path: root/world
diff options
context:
space:
mode:
Diffstat (limited to 'world')
-rw-r--r--world/src/main.rs21
-rw-r--r--world/src/mesh.rs10
-rw-r--r--world/src/vrm.rs107
3 files changed, 112 insertions, 26 deletions
diff --git a/world/src/main.rs b/world/src/main.rs
index 055be47..e3c365a 100644
--- a/world/src/main.rs
+++ b/world/src/main.rs
@@ -42,7 +42,7 @@ use std::{
thread::{self, sleep},
time::Duration,
};
-use vrm::{Vrm, Vrmc};
+use vrm::extract_vrm_data;
use weareshared::{
Affine3A, Vec3A,
helper::ReadWrite,
@@ -137,6 +137,8 @@ fn main() -> Result<()> {
traverse(&mut nodes, node, root_affine);
}
+ let vrm = extract_vrm_data(&gltf)?;
+
let mut skin_index_to_arm_index = BTreeMap::new();
let armature = {
let mut joint_index_to_arm_index = BTreeMap::new();
@@ -176,19 +178,9 @@ fn main() -> Result<()> {
})
.collect::<Vec<_>>();
- if let Some(vrm) = gltf.extension_value("VRM") {
- let vrm: Vrm = serde_json::from_value(vrm.clone())?;
- for bone in vrm.humanoid.human_bones {
- let ind = joint_index_to_arm_index[&bone.node];
- name[ind] = bone.bone;
- }
- }
- if let Some(vrm) = gltf.extension_value("VRMC_vrm") {
- let vrm: Vrmc = serde_json::from_value(vrm.clone())?;
- for (bname, bone) in vrm.humanoid.human_bones {
- let ind = joint_index_to_arm_index[&bone.node];
- name[ind] = bname;
- }
+ for (node, bname) in &vrm.bone_node_names {
+ let ind = joint_index_to_arm_index[node];
+ name[ind] = bname.to_owned();
}
for (i, (name, tr)) in name.iter().zip(transform.iter()).enumerate() {
@@ -226,6 +218,7 @@ fn main() -> Result<()> {
&args,
&texture_cache,
&skin_index_to_arm_index,
+ &vrm,
)?;
}
}
diff --git a/world/src/mesh.rs b/world/src/mesh.rs
index 6fff9c4..ebecfa5 100644
--- a/world/src/mesh.rs
+++ b/world/src/mesh.rs
@@ -14,7 +14,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::{Args, TextureCache, load_texture};
+use crate::{Args, TextureCache, load_texture, vrm::VrmInfo};
use anyhow::Result;
use gltf::{Mesh, Node, buffer::Data};
use log::{debug, info, warn};
@@ -37,6 +37,7 @@ pub fn import_mesh(
args: &Args,
texture_cache: &TextureCache,
joint_index_map: &BTreeMap<(usize, u16), u32>,
+ vrm: &VrmInfo,
) -> Result<()> {
for p in mesh.primitives() {
let name = mesh.name().or(node.name()).map(|e| e.to_owned());
@@ -348,6 +349,12 @@ pub fn import_mesh(
None
};
+ let hint_hide_first_person = if vrm.hide_first_person.contains(&node.index()) {
+ Some(())
+ } else {
+ None
+ };
+
let armature = node.skin().map(|_| 0);
let mesh = store.set(&MeshPart {
@@ -383,6 +390,7 @@ pub fn import_mesh(
tex_transmission,
tex_thickness,
tex_occlusion,
+ hint_hide_first_person,
// not supported by gltf
hint_mirror: None, // TODO
hint_static: None, // TODO Set when instancing
diff --git a/world/src/vrm.rs b/world/src/vrm.rs
index a9ea6f4..1b89642 100644
--- a/world/src/vrm.rs
+++ b/world/src/vrm.rs
@@ -1,6 +1,65 @@
-use std::collections::BTreeMap;
+/*
+ wearechat - generic multiplayer game with voip
+ Copyright (C) 2025 metamuffin
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, version 3 of the License only.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+use anyhow::Result;
+use gltf::Gltf;
use serde::Deserialize;
+use std::{
+ collections::{BTreeMap, BTreeSet},
+ fs::File,
+};
+
+pub struct VrmInfo {
+ pub bone_node_names: Vec<(usize, String)>,
+ pub hide_first_person: BTreeSet<usize>,
+}
+
+pub fn extract_vrm_data(gltf: &Gltf) -> Result<VrmInfo> {
+ let mut bone_node_names = Vec::new();
+ let mut hide_first_person = BTreeSet::new();
+ if let Some(vrm) = gltf.extension_value("VRM") {
+ serde_json::to_writer(File::create("/tmp/vrm").unwrap(), vrm).unwrap();
+ let vrm: Vrm = serde_json::from_value(vrm.clone())?;
+ for bone in vrm.humanoid.human_bones {
+ bone_node_names.push((bone.node, bone.bone))
+ }
+ }
+ if let Some(vrm) = gltf.extension_value("VRMC_vrm") {
+ serde_json::to_writer(File::create("/tmp/vrmc").unwrap(), vrm).unwrap();
+ let vrm: Vrmc = serde_json::from_value(vrm.clone())?;
+ for (name, bone) in vrm.humanoid.human_bones {
+ bone_node_names.push((bone.node, name))
+ }
+ if let Some(fp) = vrm.first_person {
+ for ann in fp.mesh_annotations {
+ match ann.first_person_flag {
+ FirstPersonFlag::ThirdPersonOnly => {
+ hide_first_person.insert(ann.node);
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ eprintln!("hide {hide_first_person:?}");
+ Ok(VrmInfo {
+ bone_node_names,
+ hide_first_person,
+ })
+}
#[derive(Debug, Deserialize)]
pub struct Vrm {
@@ -10,29 +69,55 @@ pub struct Vrm {
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VrmHumanoid {
- pub human_bones: Vec<VrmHumanBone>,
+ human_bones: Vec<VrmHumanBone>,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct VrmHumanBone {
+ bone: String,
+ node: usize,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct Vrmc {
+ humanoid: VrmcHumanoid,
+ first_person: Option<VrmcFirstPerson>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
-pub struct VrmHumanBone {
- pub bone: String,
- pub node: usize,
+struct VrmcFirstPerson {
+ mesh_annotations: Vec<VrmcFirstPersonMeshAnnotation>,
}
#[derive(Debug, Deserialize)]
-pub struct Vrmc {
- pub humanoid: VrmcHumanoid,
+#[serde(rename_all = "camelCase")]
+struct VrmcFirstPersonMeshAnnotation {
+ node: usize,
+ #[serde(alias = "type")] // spec says something but their sample uses "type" instead
+ first_person_flag: FirstPersonFlag,
+}
+
+#[derive(Debug, Deserialize, Default)]
+#[serde(rename_all = "camelCase")]
+enum FirstPersonFlag {
+ ThirdPersonOnly,
+ FirstPersonOnly,
+ Both,
+ #[default]
+ Auto,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
-pub struct VrmcHumanoid {
- pub human_bones: BTreeMap<String, VrmcHumanBone>,
+struct VrmcHumanoid {
+ human_bones: BTreeMap<String, VrmcHumanBone>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
-pub struct VrmcHumanBone {
- pub node: usize,
+struct VrmcHumanBone {
+ node: usize,
}