aboutsummaryrefslogtreecommitdiff
path: root/exporter/src
diff options
context:
space:
mode:
Diffstat (limited to 'exporter/src')
-rw-r--r--exporter/src/bin/gltf.rs151
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)
+}