summaryrefslogtreecommitdiff
path: root/world/src/mesh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'world/src/mesh.rs')
-rw-r--r--world/src/mesh.rs431
1 files changed, 0 insertions, 431 deletions
diff --git a/world/src/mesh.rs b/world/src/mesh.rs
deleted file mode 100644
index ffc0f2f..0000000
--- a/world/src/mesh.rs
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- 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 crate::{Args, TextureCache, load_texture, vrm::VrmInfo};
-use anyhow::Result;
-use gltf::{Mesh, Node, buffer::Data};
-use log::{debug, info, warn};
-use std::{collections::BTreeMap, path::Path};
-use weareshared::{
- Affine3A, Vec3A, packets::Resource, resources::MeshPart, store::ResourceStore, vec2, vec3a,
- vec4,
-};
-
-pub fn import_mesh(
- mesh: Mesh,
- trans: Affine3A,
- buffers: &[Data],
- store: &ResourceStore,
- path_base: &Path,
- node: &Node,
- args: &Args,
- texture_cache: &TextureCache,
- joint_index_map: &BTreeMap<(usize, u16), u32>,
- vrm: &VrmInfo,
- head_bones: &[u32],
-) -> Result<Vec<(usize, Affine3A, Resource<MeshPart>)>> {
- let mut meshes = Vec::new();
- for p in mesh.primitives() {
- let name = mesh.name().or(node.name()).map(|e| e.to_owned());
- if let Some(name) = &name {
- info!("adding mesh {name:?}");
- } else {
- info!("adding mesh");
- }
- let reader = p.reader(|buf| Some(&buffers[buf.index()]));
-
- let mut num_vertex = 0;
- let va_position = reader
- .read_positions()
- .map(|iter| {
- let a = iter.map(|[x, y, z]| vec3a(x, y, z)).collect::<Vec<_>>();
- debug!("{} vertex positions", a.len());
- num_vertex = a.len();
- store.set(&a)
- })
- .transpose()?;
-
- let va_normal = reader
- .read_normals()
- .map(|iter| {
- let a = iter.map(|[x, y, z]| vec3a(x, y, z)).collect::<Vec<_>>();
- debug!("{} vertex normals", a.len());
- store.set(&a)
- })
- .transpose()?;
-
- let va_tangent = reader
- .read_tangents()
- .map(|iter| {
- // TODO dont ignore handedness
- let a = iter
- .map(|[x, y, z, h]| vec4(x, y, z, h))
- .collect::<Vec<_>>();
- debug!("{} vertex tangents", a.len());
- store.set(&a)
- })
- .transpose()?;
-
- let mut many_head_bones = false;
- let va_joint_index = reader
- .read_joints(0)
- .map(|iter| {
- let si = node.skin().unwrap().index();
- let a = iter
- .into_u16()
- .map(|x| x.map(|x| joint_index_map[&(si, x)]))
- .collect::<Vec<_>>();
-
- let head_bone_count = a
- .iter()
- .flatten()
- .filter(|b| head_bones.contains(*b))
- .count();
- many_head_bones |= head_bone_count > a.len() / 2;
- debug!("{} vertex joint indecies", a.len());
- if many_head_bones {
- debug!("many joints are head bones");
- }
- if a.len() != num_vertex {
- warn!("joint index count does not vertex count")
- }
- store.set(&a)
- })
- .transpose()?;
-
- let va_joint_weight = reader
- .read_weights(0)
- .map(|iter| {
- let a = iter.into_f32().collect::<Vec<_>>();
- debug!("{} vertex joint weights", a.len());
- if a.len() != num_vertex {
- warn!("joint weight count does not vertex count")
- }
- store.set(&a)
- })
- .transpose()?;
-
- let va_texcoord = reader
- .read_tex_coords(0)
- .map(|iter| {
- let a = iter.into_f32().map(|[x, y]| vec2(x, y)).collect::<Vec<_>>();
- debug!("{} vertex texture coordinates", a.len());
- store.set(&a)
- })
- .transpose()?;
-
- let va_albedo = reader
- .read_colors(0)
- .map(|iter| {
- let a = iter
- .into_rgb_f32()
- .map(|[x, y, z]| vec3a(x, y, z))
- .collect::<Vec<_>>();
- debug!("{} vertex colors", a.len());
- store.set(&a)
- })
- .transpose()?;
-
- let va_alpha = reader
- .read_colors(0)
- .map(|iter| {
- let mut color_a = vec![];
- for p in iter.into_rgba_f32() {
- color_a.push(p[3]);
- }
- let o = if color_a.iter().any(|x| *x != 1.) {
- debug!("{} vertex transmissions", color_a.len());
- Some(store.set(&color_a)?)
- } else {
- debug!("vertex transmission pruned");
- None
- };
- Ok::<_, anyhow::Error>(o)
- })
- .transpose()?
- .flatten();
-
- let index = reader
- .read_indices()
- .unwrap()
- .into_u32()
- .array_chunks::<3>()
- .collect::<Vec<_>>();
-
- debug!("{} indecies", index.len() * 3);
- let index = Some(store.set(&index)?);
-
- let mut tex_albedo = None;
- let mut tex_alpha = None;
- if let Some(tex) = p.material().pbr_metallic_roughness().base_color_texture() {
- let r = load_texture(
- "albedo",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?;
- tex_albedo = Some(r.clone());
- tex_alpha = Some(r.clone());
- }
- let mut tex_normal = None;
- if let Some(tex) = p.material().normal_texture() {
- tex_normal = Some(load_texture(
- "normal",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?);
- }
- let mut tex_emission = None;
- if let Some(tex) = p.material().emissive_texture() {
- tex_emission = Some(load_texture(
- "emission",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?);
- }
- let mut tex_transmission = None;
- if let Some(tex) = p
- .material()
- .transmission()
- .and_then(|t| t.transmission_texture())
- {
- tex_transmission = Some(load_texture(
- "transmission",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?);
- }
- let mut tex_thickness = None;
- if let Some(tex) = p.material().volume().and_then(|t| t.thickness_texture()) {
- tex_thickness = Some(load_texture(
- "thickness",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?);
- }
- let mut tex_occlusion = None;
- if let Some(tex) = p.material().occlusion_texture() {
- tex_occlusion = Some(load_texture(
- "occlusion",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?);
- }
- let mut tex_roughness = None;
- let mut tex_metallic = None;
- if let Some(tex) = p
- .material()
- .pbr_metallic_roughness()
- .metallic_roughness_texture()
- {
- let r = load_texture(
- "metallic+roughness",
- store,
- path_base,
- buffers,
- &tex.texture().source().source(),
- args.webp,
- texture_cache,
- )?;
- tex_roughness = Some(r.clone());
- tex_metallic = Some(r.clone());
- }
-
- let g_metallic = Some(p.material().pbr_metallic_roughness().metallic_factor());
- let g_roughness = Some(p.material().pbr_metallic_roughness().roughness_factor());
-
- let base_color = p.material().pbr_metallic_roughness().base_color_factor();
-
- let g_albedo = if base_color[0] != 1. || base_color[1] != 1. || base_color[2] != 1. {
- debug!(
- "albedo is r={},g={},b={}",
- base_color[0], base_color[1], base_color[2]
- );
- Some(Vec3A::new(base_color[0], base_color[1], base_color[2]))
- } else {
- debug!("albedo pruned");
- None
- };
- let g_alpha = if base_color[3] != 1. {
- debug!("alpha is {}", base_color[3]);
- Some(base_color[3])
- } else {
- debug!("alpha pruned");
- None
- };
-
- let emission = p.material().emissive_factor();
- let g_emission = if emission[0] != 0. || emission[1] != 0. || emission[2] != 0. {
- debug!(
- "emission is r={},g={},b={}",
- base_color[0], base_color[1], base_color[2]
- );
- Some(Vec3A::new(emission[0], emission[1], emission[2]))
- } else {
- debug!("emission pruned");
- None
- };
-
- let transmission = p
- .material()
- .transmission()
- .map(|t| t.transmission_factor())
- .unwrap_or(0.);
-
- let g_transmission = if transmission != 0. {
- debug!("transmission is {transmission}");
- Some(transmission)
- } else {
- debug!("transmission pruned");
- None
- };
-
- let g_dispersion = p
- .material()
- .extension_value("KHR_materials_dispersion")
- .and_then(|e| e.get("dispersion"))
- .and_then(|e| e.as_f64())
- .map(|e| e as f32);
- if let Some(d) = g_dispersion {
- debug!("dispersion is {d}");
- }
-
- // if node.name() == Some("fog") {
- // eprintln!("{:#?}", p.material().volume().is_some());
- // eprintln!("{:#?}", p.material().ior());
- // eprintln!("{:#?}", p.material().transmission().is_some());
- // }
-
- let g_attenuation = p.material().volume().map(|v| {
- let ref_dist = v.attenuation_distance();
- let att = Vec3A::from_array(v.attenuation_color().map(
- // manually derived from attenuation coefficient formula. i hope this is correct.
- |factor| -(factor.powf(1. / ref_dist)).ln(),
- ));
- debug!("attenuation is {att}");
- att
- });
- let g_refractive_index = p.material().ior();
- if let Some(i) = g_refractive_index {
- debug!("refractive index is {i}");
- }
- let g_thickness = p.material().volume().map(|v| v.thickness_factor());
-
- let g_unlit = bool_to_opt(
- p.material()
- .extension_value("KHR_materials_unlit")
- .is_some(),
- "unlit",
- );
-
- let g_double_sided = bool_to_opt(p.material().double_sided(), "double sided");
-
- let hint_volume = bool_to_opt(
- g_attenuation.is_some_and(|a| a.length() > 0.01),
- "volume hint",
- );
-
- let hint_hide_first_person = bool_to_opt(
- many_head_bones | vrm.hide_first_person.contains(&node.index()),
- "hide first person hint",
- );
-
- let hint_mirror = bool_to_opt(
- node.name().unwrap_or_default().ends_with("-mirror"),
- "mirror hint",
- );
-
- let armature = node.skin().map(|_| 0);
-
- let mesh = MeshPart {
- name,
- index,
- armature,
- g_albedo,
- g_alpha,
- g_metallic,
- g_roughness,
- g_emission,
- g_transmission,
- g_attenuation,
- g_thickness,
- g_refractive_index,
- g_dispersion,
- g_unlit,
- g_double_sided,
- va_position,
- va_normal,
- va_tangent,
- va_texcoord,
- va_albedo,
- va_alpha,
- va_joint_index,
- va_joint_weight,
- tex_albedo,
- tex_normal,
- tex_roughness,
- tex_metallic,
- tex_alpha,
- tex_emission,
- tex_transmission,
- tex_thickness,
- tex_occlusion,
- hint_hide_first_person,
- hint_mirror,
- hint_volume,
- // not supported by gltf
- hint_static: None, // TODO Set when instancing
- va_transmission: None,
- va_emission: None,
- va_metallic: None,
- va_roughness: None,
- };
- meshes.push((node.index(), trans, store.set(&mesh)?))
- }
- Ok(meshes)
-}
-
-fn bool_to_opt(b: bool, log: &str) -> Option<()> {
- if b {
- debug!("{log}");
- Some(())
- } else {
- None
- }
-}