Some gltf improvements #4

Merged
SeanOMik merged 13 commits from feature/gltf-scene-fixes into main 2024-03-09 05:46:45 +00:00
7 changed files with 93 additions and 39 deletions
Showing only changes of commit 5861cb8c3f - Show all commits

View File

@ -64,7 +64,7 @@ impl ModelLoader {
} }
} */ } */
fn process_node(ctx: &mut GltfLoadContext, materials: &Vec<Material>, gnode: gltf::Node<'_>) -> GltfNode { fn process_node(ctx: &mut GltfLoadContext, materials: &Vec<ResHandle<Material>>, gnode: gltf::Node<'_>) -> GltfNode {
let mut node = GltfNode::default(); let mut node = GltfNode::default();
node.transform = { node.transform = {
@ -131,7 +131,7 @@ impl ModelLoader {
} }
for child in gnode.children() { for child in gnode.children() {
let mut cmesh = ModelLoader::process_node(ctx, materials, child); let cmesh = ModelLoader::process_node(ctx, materials, child);
node.children.push(cmesh); node.children.push(cmesh);
} }
@ -184,13 +184,13 @@ impl ResourceLoader for ModelLoader {
}; };
let start_inst = Instant::now(); let start_inst = Instant::now();
let materials: Vec<Material> = gltf.materials() let materials: Vec<ResHandle<Material>> = gltf.materials()
.map(|mat| Material::from_gltf(&mut context, mat)) .map(|mat| ResHandle::with_data("", Material::from_gltf(&mut context, mat)))
.collect(); .collect();
let mat_time = Instant::now() - start_inst; let mat_time = Instant::now() - start_inst;
debug!("Loaded {} materials in {}s", materials.len(), mat_time.as_secs_f32()); debug!("Loaded {} materials in {}s", materials.len(), mat_time.as_secs_f32());
for scene in gltf.scenes() { for (idx, scene) in gltf.scenes().enumerate() {
let start_inst = Instant::now(); let start_inst = Instant::now();
let nodes: Vec<GltfNode> = scene.nodes() let nodes: Vec<GltfNode> = scene.nodes()
.map(|node| ModelLoader::process_node(&mut context, &materials, node)) .map(|node| ModelLoader::process_node(&mut context, &materials, node))
@ -199,14 +199,20 @@ impl ResourceLoader for ModelLoader {
debug!("Loaded {} nodes in the scene in {}s", nodes.len(), node_time.as_secs_f32()); debug!("Loaded {} nodes in the scene in {}s", nodes.len(), node_time.as_secs_f32());
/* debug!("Loaded {} nodes (in {}s), and {} materials (in {}s) from '{}'", nodes.len(), for mesh in nodes.iter().map(|n| &n.mesh) {
node_time.as_secs_f32(), materials.len(), mat_time.as_secs_f32(), path); */ if let Some(mesh) = mesh {
gltf_out.meshes.push(mesh.clone());
}
}
let scene = GltfScene { let scene = GltfScene {
nodes, nodes,
}; };
let scene = ResHandle::with_data(&format!("{}:Scene{}", path, idx), scene);
gltf_out.scenes.push(scene); gltf_out.scenes.push(scene);
} }
gltf_out.materials = materials;
Ok(Arc::new(ResHandle::with_data(path, gltf_out))) Ok(Arc::new(ResHandle::with_data(path, gltf_out)))
} }
@ -236,10 +242,11 @@ mod tests {
let loader = ModelLoader::default(); let loader = ModelLoader::default();
let gltf = loader.load(&mut manager, &path).unwrap(); let gltf = loader.load(&mut manager, &path).unwrap();
let gltf = Arc::downcast::<ResHandle<Gltf>>(gltf.as_arc_any()).unwrap(); let gltf = Arc::downcast::<ResHandle<Gltf>>(gltf.as_arc_any()).unwrap();
let gltf = gltf.data_ref(); let gltf = gltf.data_ref().unwrap();
assert_eq!(gltf.scenes.len(), 1); assert_eq!(gltf.scenes.len(), 1);
let scene = &gltf.scenes[0]; let scene = &gltf.scenes[0]
.data_ref().unwrap();
assert_eq!(scene.nodes.len(), 1); assert_eq!(scene.nodes.len(), 1);
let mnode = &scene.nodes[0]; let mnode = &scene.nodes[0];
@ -249,11 +256,11 @@ mod tests {
assert_eq!(mnode.children.len(), 0); assert_eq!(mnode.children.len(), 0);
let mesh = mnode.mesh.as_ref().unwrap(); let mesh = mnode.mesh.as_ref().unwrap();
let mesh = mesh.data_ref(); let mesh = mesh.data_ref().unwrap();
assert!(mesh.position().unwrap().len() > 0); assert!(mesh.position().unwrap().len() > 0);
assert!(mesh.normals().unwrap().len() > 0); assert!(mesh.normals().unwrap().len() > 0);
assert!(mesh.tex_coords().unwrap().len() > 0); assert!(mesh.tex_coords().unwrap().len() > 0);
assert!(mesh.indices.clone().unwrap().len() > 0); assert!(mesh.indices.clone().unwrap().len() > 0);
assert!(mesh.material.as_ref().unwrap().base_color_texture.is_some()); assert!(mesh.material.as_ref().unwrap().data_ref().unwrap().base_color_texture.is_some());
} }
} }

View File

@ -1,8 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use lyra_math::Transform; use crate::{lyra_engine, ResHandle};
use crate::lyra_engine;
use super::Material; use super::Material;
@ -89,7 +87,7 @@ pub enum MeshVertexAttribute {
pub struct Mesh { pub struct Mesh {
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>, pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
pub indices: Option<MeshIndices>, pub indices: Option<MeshIndices>,
pub material: Option<Material>, pub material: Option<ResHandle<Material>>,
} }
impl Mesh { impl Mesh {

View File

@ -2,6 +2,7 @@ pub mod loader;
pub use loader::*; pub use loader::*;
pub mod material; pub mod material;
use lyra_math::Transform;
pub use material::*; pub use material::*;
pub mod mesh; pub mod mesh;
@ -10,9 +11,27 @@ pub use mesh::*;
pub mod scene; pub mod scene;
pub use scene::*; pub use scene::*;
use crate::ResHandle;
/// A loaded Gltf file /// A loaded Gltf file
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct Gltf { pub struct Gltf {
pub scenes: Vec<GltfScene>, pub scenes: Vec<ResHandle<GltfScene>>,
pub materials: Vec<Material>, pub materials: Vec<ResHandle<Material>>,
pub meshes: Vec<ResHandle<Mesh>>,
}
impl Gltf {
/// Collects all Gltf meshes and gets their world Transform.
pub fn collect_world_meshes(&self) -> Vec<(ResHandle<Mesh>, Transform)> {
let mut v = vec![];
for scene in self.scenes.iter() {
let mut tmp = scene.data_ref()
.unwrap().collect_world_meshes();
v.append(&mut tmp);
}
v
}
} }

View File

@ -1,10 +1,7 @@
use std::collections::HashMap;
use lyra_ecs::Component;
use lyra_math::Transform; use lyra_math::Transform;
use super::{Material, Mesh}; use super::Mesh;
use crate::{lyra_engine, ResHandle}; use crate::ResHandle;
/// A Node in the Gltf file /// A Node in the Gltf file
#[derive(Clone, Default)] #[derive(Clone, Default)]
@ -19,4 +16,40 @@ pub struct GltfNode {
#[derive(Clone)] #[derive(Clone)]
pub struct GltfScene { pub struct GltfScene {
pub nodes: Vec<GltfNode>, pub nodes: Vec<GltfNode>,
}
impl GltfScene {
fn collect_node(&self, parent_node: &GltfNode, node: &GltfNode) -> Vec<(ResHandle<Mesh>, Transform)> {
let mut v = vec![];
if let Some(mesh) = &node.mesh {
v.push((mesh.clone(), parent_node.transform + node.transform));
}
for child in node.children.iter() {
let mut tmp = self.collect_node(node, child);
v.append(&mut tmp);
}
v
}
/// Collects all Gltf meshes and gets their world Transform.
pub fn collect_world_meshes(&self) -> Vec<(ResHandle<Mesh>, Transform)> {
let mut v = vec![];
// process the root nodes in the scene
for parent_node in self.nodes.iter() {
if let Some(mesh) = &parent_node.mesh {
v.push((mesh.clone(), parent_node.transform));
}
for child in parent_node.children.iter() {
let mut tmp = self.collect_node(parent_node, child);
v.append(&mut tmp);
}
}
v
}
} }

View File

@ -1,6 +1,7 @@
use std::{fs::File, sync::Arc, io::Read}; use std::{fs::File, sync::Arc, io::Read};
use image::ImageError; use image::ImageError;
use tracing::{debug, trace};
use crate::{resource_manager::ResourceStorage, texture::Texture, resource::ResHandle, ResourceManager}; use crate::{resource_manager::ResourceStorage, texture::Texture, resource::ResHandle, ResourceManager};
@ -68,6 +69,8 @@ impl ResourceLoader for ImageLoader {
} }
fn load_bytes(&self, _resource_manager: &mut ResourceManager, bytes: Vec<u8>, offset: usize, length: usize) -> Result<Arc<dyn ResourceStorage>, LoaderError> { fn load_bytes(&self, _resource_manager: &mut ResourceManager, bytes: Vec<u8>, offset: usize, length: usize) -> Result<Arc<dyn ResourceStorage>, LoaderError> {
trace!("Loading {} bytes as an image", length);
let image = image::load_from_memory(&bytes[offset..(length-offset)]) let image = image::load_from_memory(&bytes[offset..(length-offset)])
.map_err(|e| match e { .map_err(|e| match e {
ImageError::IoError(e) => LoaderError::IoError(e), ImageError::IoError(e) => LoaderError::IoError(e),
@ -78,6 +81,8 @@ impl ResourceLoader for ImageLoader {
}; };
let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), texture); let res = ResHandle::with_data(&uuid::Uuid::new_v4().to_string(), texture);
debug!("Finished loading image of {} bytes", length);
Ok(Arc::new(res)) Ok(Arc::new(res))
} }
} }

View File

@ -1,5 +1,7 @@
use std::{any::Any, sync::{Arc, RwLock}}; use std::{any::Any, sync::{Arc, RwLock}};
use lyra_ecs::Component;
use crate::lyra_engine;
use uuid::Uuid; use uuid::Uuid;
use crate::ResourceStorage; use crate::ResourceStorage;
@ -38,7 +40,8 @@ pub struct Resource<T> {
/// This struct has an inner [`RwLock`] to the resource data, so most methods may be blocking. /// This struct has an inner [`RwLock`] to the resource data, so most methods may be blocking.
/// However, the only times it will be blocking is if another thread is reloading the resource /// However, the only times it will be blocking is if another thread is reloading the resource
/// and has a write lock on the data. This means that most of the time, it is not blocking. /// and has a write lock on the data. This means that most of the time, it is not blocking.
pub struct ResHandle<T> { #[derive(Component)]
pub struct ResHandle<T: 'static> {
pub(crate) data: Arc<RwLock<Resource<T>>>, pub(crate) data: Arc<RwLock<Resource<T>>>,
} }
@ -103,18 +106,7 @@ impl<T> ResHandle<T> {
} }
/// Get a reference to the data in the resource /// Get a reference to the data in the resource
/// pub fn data_ref<'a>(&'a self) -> Option<ResourceDataRef<'a, T>> {
/// # Panics
/// Panics if the resource was not loaded yet.
pub fn data_ref<'a>(&'a self) -> ResourceDataRef<'a, T> {
let d = self.data.read().expect("Resource mutex was poisoned!");
ResourceDataRef {
guard: d
}
}
/// Attempt to get a borrow to the resource data. Returns `None` if the resource is not loaded.
pub fn try_data_ref<'a>(&'a self) -> Option<ResourceDataRef<'a, T>> {
if self.is_loaded() { if self.is_loaded() {
let d = self.data.read().expect("Resource mutex was poisoned!"); let d = self.data.read().expect("Resource mutex was poisoned!");
Some(ResourceDataRef { Some(ResourceDataRef {

View File

@ -329,7 +329,7 @@ mod tests {
let mut man = ResourceManager::new(); let mut man = ResourceManager::new();
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap(); let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
assert_eq!(res.state(), ResourceState::Ready); assert_eq!(res.state(), ResourceState::Ready);
let img = res.try_data_ref(); let img = res.data_ref();
img.unwrap(); img.unwrap();
} }
@ -365,7 +365,7 @@ mod tests {
let mut man = ResourceManager::new(); let mut man = ResourceManager::new();
let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap(); let res = man.request::<Texture>(&get_image("squiggles.png")).unwrap();
assert_eq!(res.state(), ResourceState::Ready); assert_eq!(res.state(), ResourceState::Ready);
let img = res.try_data_ref(); let img = res.data_ref();
img.unwrap(); img.unwrap();
println!("Path = {}", res.path()); println!("Path = {}", res.path());
@ -385,7 +385,7 @@ mod tests {
let mut man = ResourceManager::new(); let mut man = ResourceManager::new();
let res = man.request::<Texture>(&image_path).unwrap(); let res = man.request::<Texture>(&image_path).unwrap();
assert_eq!(res.state(), ResourceState::Ready); assert_eq!(res.state(), ResourceState::Ready);
let img = res.try_data_ref(); let img = res.data_ref();
img.unwrap(); img.unwrap();
let recv = man.watch(&image_path, false).unwrap(); let recv = man.watch(&image_path, false).unwrap();