Create a material type for loading materials

This commit is contained in:
SeanOMik 2023-09-29 13:00:33 -04:00
parent dabc051b58
commit 792596078d
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
6 changed files with 82 additions and 6 deletions

View File

@ -10,7 +10,7 @@ anyhow = "1.0.75"
base64 = "0.21.4" base64 = "0.21.4"
edict = "0.5.0" edict = "0.5.0"
glam = "0.24.1" glam = "0.24.1"
gltf = "1.3.0" gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness"] }
image = "0.24.7" image = "0.24.7"
percent-encoding = "2.3.0" percent-encoding = "2.3.0"
thiserror = "1.0.48" thiserror = "1.0.48"

View File

@ -12,3 +12,6 @@ pub use loader::*;
pub mod model; pub mod model;
pub use model::*; pub use model::*;
pub mod material;
pub use material::*;

View File

@ -2,7 +2,7 @@ use std::sync::Arc;
use base64::Engine; use base64::Engine;
use crate::{ResourceLoader, LoaderError, Mesh, Model, MeshVertexAttribute, VertexAttributeData, Resource}; use crate::{ResourceLoader, LoaderError, Mesh, Model, MeshVertexAttribute, VertexAttributeData, Resource, Material, PbrRoughness};
impl From<gltf::Error> for LoaderError { impl From<gltf::Error> for LoaderError {
fn from(value: gltf::Error) -> Self { fn from(value: gltf::Error) -> Self {
@ -30,7 +30,7 @@ impl ModelLoader {
} }
} }
fn process_node(&self, buffers: &Vec<Vec<u8>>, node: gltf::Node<'_>) -> Vec<Mesh> { fn process_node(&self, buffers: &Vec<Vec<u8>>, materials: &Vec<Material>, node: gltf::Node<'_>) -> Vec<Mesh> {
let mut meshes = vec![]; let mut meshes = vec![];
if let Some(mesh) = node.mesh() { if let Some(mesh) = node.mesh() {
for prim in mesh.primitives() { for prim in mesh.primitives() {
@ -73,12 +73,14 @@ impl ModelLoader {
new_mesh.indices = Some(indices); new_mesh.indices = Some(indices);
} }
prim.material().
meshes.push(new_mesh); meshes.push(new_mesh);
} }
} }
for child in node.children() { for child in node.children() {
let mut child_meshes = self.process_node(buffers, child); let mut child_meshes = self.process_node(buffers, materials, child);
meshes.append(&mut child_meshes); meshes.append(&mut child_meshes);
} }
@ -109,10 +111,18 @@ impl ResourceLoader for ModelLoader {
// TODO: Read in multiple scenes // TODO: Read in multiple scenes
let scene = gltf.scenes().next().unwrap(); let scene = gltf.scenes().next().unwrap();
// TODO: materials // Load the materials
let materials: Vec<Material> = gltf.materials()
.map(|mat| Material {
double_sided: mat.double_sided(),
name: mat.name().map(|s| s.to_string()),
shader_uuid: None,
pbr: Some(PbrRoughness::from(mat.pbr_metallic_roughness())),
texture: None
}).collect();
let meshes: Vec<Mesh> = scene.nodes() let meshes: Vec<Mesh> = scene.nodes()
.map(|node| self.process_node(&buffers, node)) .map(|node| self.process_node(&buffers, &materials, node))
.flatten().collect(); .flatten().collect();
Ok(Arc::new(Resource::with_data(path, Model::new(meshes)))) Ok(Arc::new(Resource::with_data(path, Model::new(meshes))))

View File

@ -0,0 +1,51 @@
use crate::{Texture, ResHandle};
/// PBR metallic roughness
#[derive(Clone, Debug, Default)]
pub struct PbrRoughness {
/// The rgba base color of the PBR material
pub base_color: [f32; 4],
/// The metalness of the material
/// From 0.0 (non-metal) to 1.0 (metal)
pub metallic: f32,
/// The roughness of the material
/// From 0.0 (smooth) to 1.0 (rough)
pub roughness: f32,
// TODO: base_color_texture and metallic_roughness_texture
}
impl From<gltf::material::PbrMetallicRoughness<'_>> for PbrRoughness {
fn from(value: gltf::material::PbrMetallicRoughness) -> Self {
PbrRoughness {
base_color: value.base_color_factor(),
metallic: value.metallic_factor(),
roughness: value.roughness_factor(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct PbrGlossiness {
/// The rgba diffuse color of the material
pub diffuse_color: [f32; 4],
// The base color texture
// pub diffuse_texture // TODO
pub specular: [f32; 3],
/// The glossiness factor of the material.
/// From 0.0 (no glossiness) to 1.0 (full glossiness)
pub glossiness: f32,
// pub glossiness_texture // TODO
}
#[derive(Clone, Default)]
pub struct Material {
pub shader_uuid: Option<u64>,
pub name: Option<String>,
pub double_sided: bool,
pub pbr_roughness: PbrRoughness,
pub pbr_glossiness: Option<PbrGlossiness>,
pub alpha_cutoff: Option<f32>,
pub alpha_mode: gltf::material::AlphaMode,
pub texture: Option<ResHandle<Texture>>,
}

View File

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{Material, ResHandle};
#[repr(C)] #[repr(C)]
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum VertexAttributeData { pub enum VertexAttributeData {
@ -35,6 +37,8 @@ pub enum MeshVertexAttribute {
TexCoords, TexCoords,
Weights, // TODO: Animation Weights, // TODO: Animation
MorphTargets, // TODO: Animation MorphTargets, // TODO: Animation
/// Used during loading of the Mesh to process the materials taht it
MaterialRef,
Other(String), Other(String),
} }
@ -42,6 +46,7 @@ pub enum MeshVertexAttribute {
pub struct Mesh { pub struct Mesh {
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>, pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
pub indices: Option<Vec<u32>>, pub indices: Option<Vec<u32>>,
material: Option<ResHandle<Material>>,
} }
impl Mesh { impl Mesh {
@ -70,6 +75,10 @@ impl Mesh {
self.attributes.get(&MeshVertexAttribute::TexCoords) self.attributes.get(&MeshVertexAttribute::TexCoords)
.map(|p| p.as_vec2()) .map(|p| p.as_vec2())
} }
pub fn material(&self) -> ResHandle<Material> {
self.material.clone().expect("This mesh is missing a material!")
}
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]

View File

@ -16,6 +16,9 @@ pub struct Resource<T: Send + Sync + 'static> {
pub state: ResourceState, pub state: ResourceState,
} }
/// A helper type to make it easier to use resources
pub type ResHandle<T> = Arc<Resource<T>>;
impl<T: Send + Sync + 'static> Resource<T> { impl<T: Send + Sync + 'static> Resource<T> {
/// Create the resource with data, its assumed the state is `Ready` /// Create the resource with data, its assumed the state is `Ready`
pub fn with_data(path: &str, data: T) -> Self { pub fn with_data(path: &str, data: T) -> Self {