Create a material type for loading materials
This commit is contained in:
parent
dabc051b58
commit
792596078d
|
@ -10,7 +10,7 @@ anyhow = "1.0.75"
|
|||
base64 = "0.21.4"
|
||||
edict = "0.5.0"
|
||||
glam = "0.24.1"
|
||||
gltf = "1.3.0"
|
||||
gltf = { version = "1.3.0", features = ["KHR_materials_pbrSpecularGlossiness"] }
|
||||
image = "0.24.7"
|
||||
percent-encoding = "2.3.0"
|
||||
thiserror = "1.0.48"
|
||||
|
|
|
@ -12,3 +12,6 @@ pub use loader::*;
|
|||
|
||||
pub mod model;
|
||||
pub use model::*;
|
||||
|
||||
pub mod material;
|
||||
pub use material::*;
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
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 {
|
||||
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![];
|
||||
if let Some(mesh) = node.mesh() {
|
||||
for prim in mesh.primitives() {
|
||||
|
@ -73,12 +73,14 @@ impl ModelLoader {
|
|||
new_mesh.indices = Some(indices);
|
||||
}
|
||||
|
||||
prim.material().
|
||||
|
||||
meshes.push(new_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -109,10 +111,18 @@ impl ResourceLoader for ModelLoader {
|
|||
// TODO: Read in multiple scenes
|
||||
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()
|
||||
.map(|node| self.process_node(&buffers, node))
|
||||
.map(|node| self.process_node(&buffers, &materials, node))
|
||||
.flatten().collect();
|
||||
|
||||
Ok(Arc::new(Resource::with_data(path, Model::new(meshes))))
|
||||
|
|
|
@ -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>>,
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{Material, ResHandle};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum VertexAttributeData {
|
||||
|
@ -35,6 +37,8 @@ pub enum MeshVertexAttribute {
|
|||
TexCoords,
|
||||
Weights, // TODO: Animation
|
||||
MorphTargets, // TODO: Animation
|
||||
/// Used during loading of the Mesh to process the materials taht it
|
||||
MaterialRef,
|
||||
Other(String),
|
||||
}
|
||||
|
||||
|
@ -42,6 +46,7 @@ pub enum MeshVertexAttribute {
|
|||
pub struct Mesh {
|
||||
pub attributes: HashMap<MeshVertexAttribute, VertexAttributeData>,
|
||||
pub indices: Option<Vec<u32>>,
|
||||
material: Option<ResHandle<Material>>,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
|
@ -70,6 +75,10 @@ impl Mesh {
|
|||
self.attributes.get(&MeshVertexAttribute::TexCoords)
|
||||
.map(|p| p.as_vec2())
|
||||
}
|
||||
|
||||
pub fn material(&self) -> ResHandle<Material> {
|
||||
self.material.clone().expect("This mesh is missing a material!")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
|
|
@ -16,6 +16,9 @@ pub struct Resource<T: Send + Sync + 'static> {
|
|||
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> {
|
||||
/// Create the resource with data, its assumed the state is `Ready`
|
||||
pub fn with_data(path: &str, data: T) -> Self {
|
||||
|
|
Loading…
Reference in New Issue