diff options
Diffstat (limited to 'exporter/src/bin/gltf.rs')
-rw-r--r-- | exporter/src/bin/gltf.rs | 151 |
1 files changed, 143 insertions, 8 deletions
diff --git a/exporter/src/bin/gltf.rs b/exporter/src/bin/gltf.rs index fb6b72d..86f48b4 100644 --- a/exporter/src/bin/gltf.rs +++ b/exporter/src/bin/gltf.rs @@ -1,13 +1,20 @@ #![feature(array_chunks)] -use anyhow::anyhow; +use anyhow::{Result, anyhow}; use glam::{Affine3A, Mat4}; -use gltf::Glb; +use gltf::{Glb, Semantic, mesh::Mode}; +use gltf_json::{ + Accessor, Index, Node, Root, Scene, + accessor::GenericComponentType, + mesh::Primitive, + validation::{Checked, USize64}, +}; use log::warn; -use std::{borrow::Cow, env::args, fs::File, io::BufReader}; +use std::{borrow::Cow, collections::BTreeMap, env::args, fs::File, io::BufReader}; use unity_tools::{ classes::{ gameobject::GameObject, - mesh_renderer::{MeshRenderer, SkinnedMeshRenderer}, + mesh::{Mesh, VertexDataChannel}, + mesh_renderer::SkinnedMeshRenderer, transform::Transform, }, serialized_file::SerializedFile, @@ -40,12 +47,14 @@ fn main() -> anyhow::Result<()> { // eprintln!("{root_tr:?}"); let mut root = gltf_json::Root::default(); + let mut nodes = Vec::new(); + let mut buffer = Vec::new(); for ob in gameobjects { let go = file.read_object(ob)?.parse::<GameObject>()?; + let mut global_transform = Affine3A::default(); for comp in go.components { let ob = comp.load(&mut file)?; - let mut global_transform = Affine3A::default(); match ob.class_name().unwrap().as_str() { "Transform" => { let mut tr = ob.parse::<Transform>()?; @@ -66,15 +75,30 @@ fn main() -> anyhow::Result<()> { Affine3A::from_mat4(transforms.into_iter().reduce(|a, b| a * b).unwrap()) } "SkinnedMeshRenderer" => { - let mr = ob.parse::<SkinnedMeshRenderer>()?; + let smr = ob.parse::<SkinnedMeshRenderer>()?; + let mesh = import_mesh( + &mut root, + &mut buffer, + smr.mesh_renderer.mesh.load(&mut file)?, + )?; + nodes.push(root.push(Node { + mesh: Some(mesh), + ..Default::default() + })); } "MeshRenderer" => { - let mr = ob.parse::<MeshRenderer>()?; + // let mr = ob.parse::<MeshRenderer>()?; } x => warn!("unknown component {x:?}"), } } } + root.push(Scene { + extensions: Default::default(), + extras: Default::default(), + name: None, + nodes, + }); let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error"); let mut json_offset = json_string.len(); @@ -85,7 +109,7 @@ fn main() -> anyhow::Result<()> { version: 2, length: json_offset as u32, }, - bin: None, + bin: Some(Cow::Owned(buffer)), json: Cow::Owned(json_string.into_bytes()), }; let writer = std::fs::File::create("triangle.glb").expect("I/O error"); @@ -97,3 +121,114 @@ fn main() -> anyhow::Result<()> { fn align_to_multiple_of_four(n: &mut usize) { *n = (*n + 3) & !3; } + +pub fn import_mesh( + root: &mut Root, + buffer: &mut Vec<u8>, + mesh: Mesh, +) -> Result<Index<gltf_json::Mesh>> { + let indicies = mesh.read_indecies(); + let (pdim, positions) = mesh + .vertex_data + .read_channel(VertexDataChannel::Position) + .ok_or(anyhow!("mesh has no positions"))?; + assert_eq!(pdim, 3); + + let positions = { + let buffer_length = positions.len() * size_of::<[f32; 3]>(); + let buffer = root.push(gltf_json::Buffer { + byte_length: USize64::from(buffer_length), + name: None, + uri: None, + extensions: Default::default(), + extras: Default::default(), + }); + let buffer_view = root.push(gltf_json::buffer::View { + buffer, + byte_length: USize64::from(buffer_length), + byte_offset: None, + byte_stride: Some(gltf_json::buffer::Stride(size_of::<[f32; 3]>())), + name: None, + target: Some(Checked::Valid(gltf_json::buffer::Target::ArrayBuffer)), + extensions: Default::default(), + extras: Default::default(), + }); + root.push(Accessor { + buffer_view: Some(buffer_view), + byte_offset: Some(USize64(0)), + count: USize64::from(positions.len()), + component_type: Checked::Valid(GenericComponentType( + gltf_json::accessor::ComponentType::F32, + )), + extensions: Default::default(), + extras: Default::default(), + type_: Checked::Valid(gltf_json::accessor::Type::Vec3), + max: None, + min: None, + name: None, + normalized: false, + sparse: None, + }) + }; + let indices = { + let offset = buffer.len(); + let num_indices = indicies.len(); + buffer.extend(indicies.into_iter().flatten().flat_map(u32::to_le_bytes)); + let buffer_length = num_indices * size_of::<u32>() * 3; + let buffer = root.push(gltf_json::Buffer { + byte_length: USize64::from(buffer_length), + name: None, + uri: None, + extensions: Default::default(), + extras: Default::default(), + }); + let buffer_view = root.push(gltf_json::buffer::View { + buffer, + byte_length: USize64::from(buffer_length), + byte_offset: Some(USize64::from(offset)), + byte_stride: Some(gltf_json::buffer::Stride(size_of::<u32>())), + name: None, + target: Some(Checked::Valid(gltf_json::buffer::Target::ArrayBuffer)), + extensions: Default::default(), + extras: Default::default(), + }); + root.push(Accessor { + buffer_view: Some(buffer_view), + byte_offset: Some(USize64(0)), + count: USize64::from(num_indices * 3), + component_type: Checked::Valid(GenericComponentType( + gltf_json::accessor::ComponentType::U32, + )), + extensions: Default::default(), + extras: Default::default(), + type_: Checked::Valid(gltf_json::accessor::Type::Vec3), + max: None, + min: None, + name: None, + normalized: false, + sparse: None, + }) + }; + + let primitive = Primitive { + attributes: { + let mut map = BTreeMap::new(); + map.insert(Checked::Valid(Semantic::Positions), positions); + map + }, + extensions: Default::default(), + extras: Default::default(), + indices: Some(indices), + material: None, + mode: Checked::Valid(Mode::Triangles), + targets: None, + }; + let mesh = root.push(gltf_json::Mesh { + extensions: Default::default(), + extras: Default::default(), + name: None, + primitives: vec![primitive], + weights: None, + }); + Ok(mesh) +} |