From 3ac853862b5965c1ebfb10b12fb35cf5c671232f Mon Sep 17 00:00:00 2001 From: metamuffin Date: Fri, 10 Jan 2025 20:06:01 +0100 Subject: physics extension and fixes --- client/src/shader.wgsl | 23 +++----- doc/resources.md | 14 ++--- server/src/main.rs | 2 +- shared/src/helper.rs | 140 +++++++++++++++++++++++++++++++++++++++++++ shared/src/lib.rs | 4 +- shared/src/resources.rs | 154 +++++++++++++++++++----------------------------- world/src/main.rs | 8 +++ world/src/mesh.rs | 95 ++++++++++------------------- world/src/physics.rs | 73 +++++++++++++++++++++++ 9 files changed, 330 insertions(+), 183 deletions(-) create mode 100644 world/src/physics.rs diff --git a/client/src/shader.wgsl b/client/src/shader.wgsl index eb5530c..3f93223 100644 --- a/client/src/shader.wgsl +++ b/client/src/shader.wgsl @@ -14,19 +14,14 @@ // along with this program. If not, see . struct VertexIn { - @location(0) x: f32, - @location(1) y: f32, - @location(2) z: f32, - @location(3) nx: f32, - @location(4) ny: f32, - @location(5) nz: f32, - @location(6) u: f32, - @location(7) v: f32, + @location(0) position: vec3, + @location(1) normal: vec3, + @location(2) texcoord: vec2, } struct VertexOut { @builtin(position) clip: vec4, @location(0) normal: vec3, - @location(1) uv: vec2, + @location(1) texcoord: vec2, } @group(0) @binding(0) var tex_albedo: texture_2d; @@ -35,15 +30,11 @@ var project: mat4x4; @vertex fn vs_main(vi: VertexIn) -> VertexOut { - var clip = project * vec4(vi.x, vi.y, vi.z, 1.); - let vo = VertexOut( - clip, - vec3(vi.nx, vi.ny, vi.nz), - vec2(vi.u, vi.v), - ); + var clip = project * vec4(vi.position, 1.); + let vo = VertexOut(clip, vi.normal, vi.texcoord); return vo; } @fragment fn fs_main(vo: VertexOut) -> @location(0) vec4 { - return textureSample(tex_albedo, tex_albedo_sampler, vo.uv); + return textureSample(tex_albedo, tex_albedo_sampler, vo.texcoord); } diff --git a/doc/resources.md b/doc/resources.md index 86f874a..d3d33eb 100644 --- a/doc/resources.md +++ b/doc/resources.md @@ -22,7 +22,7 @@ | Key | Value Type | | | ------------- | -------------------------------------- | --------- | | `mesh` | `Matrix3`, `Vec3`, `Res` | Multi key | -| `collider` | `Matrix3`, `Vec3`, `Res` | Multi key | +| `collision` | `Matrix3`, `Vec3`, `Res` | Multi key | | `light` | `Vec3`, `Res` | Multi key | | `environment` | `Res` | | @@ -51,12 +51,12 @@ white except normals are zero. | `va_position` | `Res<[Vec3]>` | | | `va_normal` | `Res<[Vec3]>` | | | `va_texcoord` | `Res<[Vec2]>` | | -| `va_roughness` | `Res` | | -| `va_metallic` | `Res` | | +| `va_roughness` | `Res<[Float]>` | | +| `va_metallic` | `Res<[Float]>` | | | `va_albedo` | `Res<[Vec3]>` | | -| `va_alpha` | `Res` | | -| `va_transmission` | `Res` | | -| `va_emission` | `Res` | | +| `va_alpha` | `Res<[Float]>` | | +| `va_transmission` | `Res<[Float]>` | | +| `va_emission` | `Res<[Vec3]>` | | | `tex_normal` | `Res` | Use color channels | | `tex_roughness` | `Res` | Use green channel | | `tex_metallic` | `Res` | Use blue channel | @@ -107,7 +107,7 @@ white except normals are zero. WebP -## ColliderPart +## CollisionPart Only one key for shape should be set. diff --git a/server/src/main.rs b/server/src/main.rs index a599efa..bb99edd 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -28,7 +28,7 @@ use std::{ use weareshared::{ packets::{Data, Packet, Resource}, resources::{Prefab, PrefabIndex}, - store::{ResourceStore, sha256}, + store::ResourceStore, tree::SceneTree, }; diff --git a/shared/src/helper.rs b/shared/src/helper.rs index 706e36b..61e149f 100644 --- a/shared/src/helper.rs +++ b/shared/src/helper.rs @@ -16,6 +16,7 @@ */ use crate::packets::{Data, Object, Resource}; use anyhow::Result; +use glam::{Affine3A, Vec2, Vec3A}; use std::{ io::{Read, Write}, marker::PhantomData, @@ -65,6 +66,81 @@ impl ReadWrite for Vec { Ok(buf) } } +impl ReadWrite for Vec { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for e in self { + e.write(w)?; + } + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(buf + .into_iter() + .array_chunks::<4>() + .map(f32::from_be_bytes) + .array_chunks::<3>() + .map(Vec3A::from_array) + .collect()) + } +} +impl ReadWrite for Vec { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for e in self { + e.write(w)?; + } + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(buf + .into_iter() + .array_chunks::<4>() + .map(f32::from_be_bytes) + .array_chunks::<2>() + .map(Vec2::from_array) + .collect()) + } +} +impl ReadWrite for Vec<[u16; 3]> { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for e in self { + w.write_all(&e[0].to_be_bytes())?; + w.write_all(&e[1].to_be_bytes())?; + w.write_all(&e[2].to_be_bytes())?; + } + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(buf + .into_iter() + .array_chunks::<2>() + .map(u16::from_be_bytes) + .array_chunks::<3>() + .collect()) + } +} +impl ReadWrite for Vec { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for e in self { + e.write(w)?; + } + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut buf = Vec::new(); + r.read_to_end(&mut buf)?; + Ok(buf + .into_iter() + .array_chunks::<4>() + .map(f32::from_be_bytes) + .collect()) + } +} impl ReadWrite for String { fn write(&self, w: &mut dyn Write) -> Result<()> { w.write_all(self.as_bytes())?; @@ -134,3 +210,67 @@ impl ReadWrite for () { Ok(()) } } +impl ReadWrite for Vec2 { + fn write(&self, w: &mut dyn Write) -> Result<()> { + self.x.write(w)?; + self.y.write(w)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + Ok(Self::new(f32::read(r)?, f32::read(r)?)) + } +} +impl ReadWrite for Vec3A { + fn write(&self, w: &mut dyn Write) -> Result<()> { + self.x.write(w)?; + self.y.write(w)?; + self.z.write(w)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + Ok(Self::new(f32::read(r)?, f32::read(r)?, f32::read(r)?)) + } +} +impl ReadWrite for Affine3A { + fn write(&self, w: &mut dyn Write) -> Result<()> { + for v in self.to_cols_array() { + v.write(w)? + } + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + Ok(Self::from_cols_array(&[(); 12].try_map(|()| f32::read(r))?)) + } +} +impl ReadWrite for (A, B) { + fn write(&self, w: &mut dyn Write) -> Result<()> { + self.0.write(w)?; + self.1.write(w)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + Ok((A::read(r)?, B::read(r)?)) + } +} +impl ReadWrite for (A, B, C) { + fn write(&self, w: &mut dyn Write) -> Result<()> { + self.0.write(w)?; + self.1.write(w)?; + self.2.write(w)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + Ok((A::read(r)?, B::read(r)?, C::read(r)?)) + } +} +impl ReadWrite for u8 { + fn write(&self, w: &mut dyn Write) -> Result<()> { + w.write_all(&[*self])?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut buf = [0u8; 1]; + r.read_exact(&mut buf)?; + Ok(buf[0]) + } +} diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 951683c..11ed2ce 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -16,10 +16,10 @@ */ #![feature(iter_array_chunks, array_try_map)] +pub mod helper; pub mod packets; pub mod resources; pub mod store; pub mod tree; -pub mod helper; -pub use glam::{Affine3A, Mat3A, Vec3A, vec3a}; +pub use glam::{Affine3A, Mat3A, Vec2, Vec3A, vec2, vec3a}; diff --git a/shared/src/resources.rs b/shared/src/resources.rs index 772a140..f422611 100644 --- a/shared/src/resources.rs +++ b/shared/src/resources.rs @@ -16,7 +16,7 @@ */ use crate::{helper::ReadWrite, packets::Resource}; use anyhow::Result; -use glam::{Affine3A, Vec3A}; +use glam::{Affine3A, Vec2, Vec3A}; use log::warn; use std::{ collections::BTreeMap, @@ -27,6 +27,7 @@ use std::{ pub struct Prefab { pub name: Option, pub mesh: Vec<(Affine3A, Resource)>, + pub collision: Vec<(Affine3A, Resource)>, pub light: Vec<(Vec3A, Resource)>, pub environment: Option>, } @@ -46,7 +47,7 @@ pub struct EnvironmentPart { #[derive(Debug, Default, Clone)] pub struct MeshPart { pub name: Option, - pub index: Option>, + pub index: Option>>, pub g_metallic: Option, pub g_roughness: Option, pub g_albedo: Option, @@ -58,15 +59,15 @@ pub struct MeshPart { pub g_attenuation: Option, pub g_dispersion: Option, pub g_unlit: Option<()>, - pub va_position: Option<[Resource; 3]>, - pub va_normal: Option<[Resource; 3]>, - pub va_texcoord: Option<[Resource; 2]>, - pub va_roughness: Option>, - pub va_metallic: Option>, - pub va_albedo: Option<[Resource; 3]>, - pub va_transmission: Option>, - pub va_alpha: Option>, - pub va_emission: Option<[Resource; 3]>, + pub va_position: Option>>, + pub va_normal: Option>>, + pub va_texcoord: Option>>, + pub va_roughness: Option>>, + pub va_metallic: Option>>, + pub va_albedo: Option>>, + pub va_transmission: Option>>, + pub va_alpha: Option>>, + pub va_emission: Option>>, pub tex_normal: Option>, pub tex_roughness: Option>, pub tex_metallic: Option>, @@ -79,12 +80,20 @@ pub struct MeshPart { } #[derive(Debug, Default, Clone)] -pub struct PrefabIndex(pub BTreeMap>); +pub struct CollisionPart { + pub restitution_coeff: Option, + pub friction_kinetic: Option, + pub friction_static: Option, + pub sh_box: Option, + pub sh_sphere: Option, + pub sh_cylinder: Option<(f32, f32, f32)>, + pub sh_capsule: Option<(f32, f32, f32)>, + pub sh_convex_hull: Option, + pub sh_mesh: Option<(Resource>, Resource>)>, +} #[derive(Debug, Default, Clone)] -pub struct AttributeArray(pub Vec); -#[derive(Debug, Default, Clone)] -pub struct IndexArray(pub Vec<[u16; 3]>); +pub struct PrefabIndex(pub BTreeMap>); #[derive(Debug, Clone)] pub struct Image(pub Vec); @@ -109,12 +118,48 @@ impl ReadWrite for PrefabIndex { } } +impl ReadWrite for CollisionPart { + fn write(&self, w: &mut dyn Write) -> Result<()> { + write_kv_opt(w, b"restitution_coeff", &self.restitution_coeff)?; + write_kv_opt(w, b"friction_kinetic", &self.friction_kinetic)?; + write_kv_opt(w, b"friction_static", &self.friction_static)?; + write_kv_opt(w, b"sh_box", &self.sh_box)?; + write_kv_opt(w, b"sh_sphere", &self.sh_sphere)?; + write_kv_opt(w, b"sh_cylinder", &self.sh_cylinder)?; + write_kv_opt(w, b"sh_capsule", &self.sh_capsule)?; + write_kv_opt(w, b"sh_convex_hull", &self.sh_convex_hull)?; + write_kv_opt(w, b"sh_mesh", &self.sh_mesh)?; + Ok(()) + } + fn read(r: &mut dyn Read) -> Result { + let mut s = Self::default(); + read_kv_iter(r, |k, v| match k { + b"restitution_coeff" => Ok(s.restitution_coeff = Some(read_slice(v)?)), + b"friction_kinetic" => Ok(s.friction_kinetic = Some(read_slice(v)?)), + b"friction_static" => Ok(s.friction_static = Some(read_slice(v)?)), + b"sh_box" => Ok(s.sh_box = Some(read_slice(v)?)), + b"sh_sphere" => Ok(s.sh_sphere = Some(read_slice(v)?)), + b"sh_cylinder" => Ok(s.sh_cylinder = Some(read_slice(v)?)), + b"sh_capsule" => Ok(s.sh_capsule = Some(read_slice(v)?)), + b"sh_convex_hull" => Ok(s.sh_convex_hull = Some(read_slice(v)?)), + b"sh_mesh" => Ok(s.sh_mesh = Some(read_slice(v)?)), + x => Ok(warn!( + "unknown prefab key: {:?}", + String::from_utf8_lossy(x) + )), + })?; + Ok(s) + } +} impl ReadWrite for Prefab { fn write(&self, w: &mut dyn Write) -> Result<()> { write_kv_opt(w, b"name", &self.name)?; for x in &self.mesh { write_kv_opt(w, b"mesh", &Some(x.clone()))?; } + for x in &self.collision { + write_kv_opt(w, b"collision", &Some(x.clone()))?; + } for x in &self.light { write_kv_opt(w, b"light", &Some(x.clone()))?; } @@ -126,6 +171,7 @@ impl ReadWrite for Prefab { read_kv_iter(r, |k, v| match k { b"name" => Ok(s.name = Some(read_slice(v)?)), b"mesh" => Ok(s.mesh.push(read_slice(v)?)), + b"collision" => Ok(s.collision.push(read_slice(v)?)), b"light" => Ok(s.light.push(read_slice(v)?)), b"environment" => Ok(s.environment = Some(read_slice(v)?)), x => Ok(warn!( @@ -284,84 +330,6 @@ fn write_kv(w: &mut dyn Write, key: &[u8], value: &[u8]) -> Result<()> { Ok(()) } -impl ReadWrite for u8 { - fn write(&self, w: &mut dyn Write) -> Result<()> { - w.write_all(&[*self])?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - let mut buf = [0u8; 1]; - r.read_exact(&mut buf)?; - Ok(buf[0]) - } -} - -impl ReadWrite for Vec3A { - fn write(&self, w: &mut dyn Write) -> Result<()> { - self.x.write(w)?; - self.y.write(w)?; - self.z.write(w)?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - Ok(Self::new(f32::read(r)?, f32::read(r)?, f32::read(r)?)) - } -} -impl ReadWrite for Affine3A { - fn write(&self, w: &mut dyn Write) -> Result<()> { - for v in self.to_cols_array() { - v.write(w)? - } - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - Ok(Self::from_cols_array(&[(); 12].try_map(|()| f32::read(r))?)) - } -} -impl ReadWrite for IndexArray { - fn write(&self, w: &mut dyn Write) -> Result<()> { - for x in self.0.clone() { - w.write_all(x.map(|x| x.to_be_bytes()).as_flattened())?; - } - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - let mut s = Self(Vec::new()); - let mut g = Vec::new(); - r.read_to_end(&mut g)?; - for x in g.iter().array_chunks::<2>().array_chunks::<3>() { - s.0.push(x.map(|x| u16::from_be_bytes(x.map(|x| *x)))) - } - Ok(s) - } -} -impl ReadWrite for AttributeArray { - fn write(&self, w: &mut dyn Write) -> Result<()> { - for x in self.0.clone() { - w.write_all(&x.to_be_bytes())?; - } - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - let mut s = Self(Vec::new()); - let mut g = Vec::new(); - r.read_to_end(&mut g)?; - for x in g.iter().array_chunks::<4>() { - s.0.push(f32::from_be_bytes(x.map(|x| *x))) - } - Ok(s) - } -} -impl ReadWrite for (A, B) { - fn write(&self, w: &mut dyn Write) -> Result<()> { - self.0.write(w)?; - self.1.write(w)?; - Ok(()) - } - fn read(r: &mut dyn Read) -> Result { - Ok((A::read(r)?, B::read(r)?)) - } -} impl ReadWrite for Image { fn write(&self, w: &mut dyn Write) -> Result<()> { self.0.write(w) diff --git a/world/src/main.rs b/world/src/main.rs index 5dbfd06..c90ff0c 100644 --- a/world/src/main.rs +++ b/world/src/main.rs @@ -16,6 +16,7 @@ */ #![feature(iter_array_chunks)] pub mod mesh; +pub mod physics; use anyhow::{Result, bail}; use clap::Parser; @@ -23,6 +24,7 @@ use gltf::{Gltf, image::Source, import_buffers}; use image::{ImageReader, codecs::webp::WebPEncoder}; use log::info; use mesh::import_mesh; +use physics::import_physics; use rand::random; use std::{ fs::File, @@ -93,6 +95,7 @@ fn main() -> Result<()> { for node in gltf.nodes() { if let Some(mesh) = node.mesh() { + info!("--- MESH ---"); import_mesh( mesh, &buffers, @@ -105,7 +108,11 @@ fn main() -> Result<()> { } let (position, _, _) = node.transform().decomposed(); if let Some(light) = node.light() { + info!("--- LIGHT ---"); let emission = Some(Vec3A::from_array(light.color()) * light.intensity()); + if let Some(e) = emission { + info!("emission is {e}"); + } prefab.light.push(( Vec3A::from_array(position), store.set(&LightPart { @@ -114,6 +121,7 @@ fn main() -> Result<()> { })?, )); } + import_physics(&gltf, &node, &mut prefab, &store, &buffers)?; } if let Some(skybox) = args.skybox { diff --git a/world/src/mesh.rs b/world/src/mesh.rs index c621753..67f86ad 100644 --- a/world/src/mesh.rs +++ b/world/src/mesh.rs @@ -21,8 +21,9 @@ use log::{debug, info}; use std::path::Path; use weareshared::{ Affine3A, Vec3A, - resources::{AttributeArray, IndexArray, MeshPart, Prefab}, + resources::{MeshPart, Prefab}, store::ResourceStore, + vec2, vec3a, }; pub fn import_mesh( @@ -40,77 +41,39 @@ pub fn import_mesh( let va_position = reader .read_positions() .map(|iter| { - let mut pos_x = vec![]; - let mut pos_y = vec![]; - let mut pos_z = vec![]; - for p in iter { - pos_x.push(p[0]); - pos_y.push(p[1]); - pos_z.push(p[2]); - } - info!("{} vertex positions", pos_x.len()); - Ok::<_, anyhow::Error>([ - store.set(&AttributeArray(pos_x))?, - store.set(&AttributeArray(pos_y))?, - store.set(&AttributeArray(pos_z))?, - ]) + let a = iter.map(|[x, y, z]| vec3a(x, y, z)).collect::>(); + info!("{} vertex positions", a.len()); + Ok::<_, anyhow::Error>(store.set(&a)?) }) .transpose()?; let va_normal = reader .read_normals() .map(|iter| { - let mut normal_x = vec![]; - let mut normal_y = vec![]; - let mut normal_z = vec![]; - for p in iter { - normal_x.push(p[0]); - normal_y.push(p[1]); - normal_z.push(p[2]); - } - info!("{} vertex normals", normal_x.len()); - Ok::<_, anyhow::Error>([ - store.set(&AttributeArray(normal_x))?, - store.set(&AttributeArray(normal_y))?, - store.set(&AttributeArray(normal_z))?, - ]) + let a = iter.map(|[x, y, z]| vec3a(x, y, z)).collect::>(); + info!("{} vertex normals", a.len()); + Ok::<_, anyhow::Error>(store.set(&a)?) }) .transpose()?; let va_texcoord = reader .read_tex_coords(0) .map(|iter| { - let mut texcoord_u = vec![]; - let mut texcoord_v = vec![]; - for p in iter.into_f32() { - texcoord_u.push(p[0]); - texcoord_v.push(p[1]); - } - info!("{} vertex texture coordinates", texcoord_u.len()); - Ok::<_, anyhow::Error>([ - store.set(&AttributeArray(texcoord_u))?, - store.set(&AttributeArray(texcoord_v))?, - ]) + let a = iter.into_f32().map(|[x, y]| vec2(x, y)).collect::>(); + info!("{} vertex texture coordinates", a.len()); + Ok::<_, anyhow::Error>(store.set(&a)?) }) .transpose()?; let va_albedo = reader .read_colors(0) .map(|iter| { - let mut color_r = vec![]; - let mut color_g = vec![]; - let mut color_b = vec![]; - for p in iter.into_rgb_f32() { - color_r.push(p[0]); - color_g.push(p[1]); - color_b.push(p[2]); - } - info!("{} vertex colors", color_r.len()); - Ok::<_, anyhow::Error>([ - store.set(&AttributeArray(color_r))?, - store.set(&AttributeArray(color_g))?, - store.set(&AttributeArray(color_b))?, - ]) + let a = iter + .into_rgb_f32() + .map(|[x, y, z]| vec3a(x, y, z)) + .collect::>(); + info!("{} vertex colors", a.len()); + Ok::<_, anyhow::Error>(store.set(&a)?) }) .transpose()?; @@ -123,7 +86,7 @@ pub fn import_mesh( } let o = if color_a.iter().any(|x| *x != 1.) { info!("{} vertex transmissions", color_a.len()); - Some(store.set(&AttributeArray(color_a))?) + Some(store.set(&color_a)?) } else { debug!("vertex transmission pruned"); None @@ -141,7 +104,7 @@ pub fn import_mesh( .array_chunks::<3>() .collect::>(); info!("{} indecies", index.len() * 3); - let index = Some(store.set(&IndexArray(index))?); + let index = Some(store.set(&index)?); let mut tex_albedo = None; let mut tex_alpha = None; @@ -370,13 +333,17 @@ pub fn import_mesh( va_metallic: None, va_roughness: None, })?; - let mat = node.transform().matrix(); - let aff = Affine3A::from_cols_array_2d(&[ - [mat[0][0], mat[0][1], mat[0][2]], - [mat[1][0], mat[1][1], mat[1][2]], - [mat[2][0], mat[2][1], mat[2][2]], - [mat[3][0], mat[3][1], mat[3][2]], - ]); - prefab.mesh.push((aff, mesh)) + + prefab.mesh.push((node_transform_to_affine(node), mesh)) }) } + +pub fn node_transform_to_affine(node: &Node) -> Affine3A { + let mat = node.transform().matrix(); + Affine3A::from_cols_array_2d(&[ + [mat[0][0], mat[0][1], mat[0][2]], + [mat[1][0], mat[1][1], mat[1][2]], + [mat[2][0], mat[2][1], mat[2][2]], + [mat[3][0], mat[3][1], mat[3][2]], + ]) +} diff --git a/world/src/physics.rs b/world/src/physics.rs new file mode 100644 index 0000000..82bb28f --- /dev/null +++ b/world/src/physics.rs @@ -0,0 +1,73 @@ +use anyhow::{Result, anyhow}; +use gltf::{Gltf, Node, buffer::Data, json::Value}; +use log::info; +use weareshared::{ + resources::{CollisionPart, Prefab}, + store::ResourceStore, + vec3a, +}; + +use crate::mesh::node_transform_to_affine; + +pub fn import_physics( + gltf: &Gltf, + node: &Node, + prefab: &mut Prefab, + store: &ResourceStore, + buffers: &[Data], +) -> Result<()> { + if let Some(physics) = node + .extensions() + .map(|e| e.get("KHR_physics_rigid_bodies")) + .flatten() + { + info!("--- COLLISION ---"); + if let Some(collider) = physics.get("collider") { + if let Some(geometry) = collider.get("geometry") { + if geometry.get("convexHull") == Some(&Value::Bool(true)) { + let node = geometry + .get("node") + .map(|n| n.as_u64()) + .flatten() + .ok_or(anyhow!("convexHull node missing"))?; + let node = gltf + .nodes() + .nth(node as usize) + .ok_or(anyhow!("convexHull node reference invalid"))?; + let mesh = node.mesh().ok_or(anyhow!("convexHull node has no mesh"))?; + for p in mesh.primitives() { + let reader = p.reader(|buf| Some(&buffers[buf.index()])); + + let index = reader + .read_indices() + .ok_or(anyhow!("convexHull no index buffer"))? + .into_u32() + .map(|e| e as u16) + .array_chunks::<3>() + .collect::>(); + let position = reader + .read_positions() + .ok_or(anyhow!("convexHull no positions"))? + .map(|[x, y, z]| vec3a(x, y, z)) + .collect::>(); + + info!( + "convex hull has {} indecies and {} positions", + index.len(), + position.len() + ); + + prefab.collision.push(( + node_transform_to_affine(&node), + store.set(&CollisionPart { + sh_mesh: Some((store.set(&index)?, store.set(&position)?)), + ..Default::default() + })?, + )); + } + } + } + } + } + Ok(()) +} -- cgit v1.2.3-70-g09d2