ursus_materials/strategies/
pbr.rs1use crate::error::MaterialError;
2use crate::field::{FieldDesc, FieldType};
3use crate::material::Material;
4use crate::requirements::Requirements;
5use crate::strategies::properties::*;
6use crate::strategy::ShadingStrategy;
7use crate::value::{MaterialValue, PropertyId};
8
9const FIELDS: &[FieldDesc] = &[
13 FieldDesc::new("base_color", FieldType::Vec4),
14 FieldDesc::new("emissive", FieldType::Vec4),
15 FieldDesc::new("metallic", FieldType::Float),
16 FieldDesc::new("roughness", FieldType::Float),
17 FieldDesc::new("tex_indices0", FieldType::UVec4),
18 FieldDesc::new("tex_indices1", FieldType::UVec4),
19];
20
21pub struct PbrStrategy {
22 requirements: Requirements,
23}
24
25impl Default for PbrStrategy {
26 fn default() -> Self {
27 let requirements = Requirements::new()
28 .optional(BASE_COLOR, MaterialValue::Color(glam::Vec4::ONE))
29 .optional(EMISSIVE, MaterialValue::Color(glam::Vec4::new(0.0, 0.0, 0.0, 1.0)))
30 .optional(METALLIC, MaterialValue::Float(0.0))
31 .optional(ROUGHNESS, MaterialValue::Float(1.0));
32 Self { requirements }
33 }
34}
35
36impl PbrStrategy {
37 fn texture_slot(material: &Material, id: PropertyId) -> u32 {
40 material.get(id).and_then(MaterialValue::as_texture).map(|t| t.0).unwrap_or(0)
41 }
42}
43
44impl ShadingStrategy for PbrStrategy {
45 fn name(&self) -> &'static str {
46 "pbr"
47 }
48
49 fn requirements(&self) -> &Requirements {
50 &self.requirements
51 }
52
53 fn fields(&self) -> &[FieldDesc] {
54 FIELDS
55 }
56
57 fn resolve(&self, material: &Material) -> Result<Vec<MaterialValue>, MaterialError> {
58 let get = |id| {
59 self.requirements.get_or_default(material, id).copied().ok_or_else(|| MaterialError::MissingProperty {
60 material: material.name.clone(),
61 strategy: self.name(),
62 property: id,
63 })
64 };
65
66 let tex_indices0 = MaterialValue::UVec4([
67 Self::texture_slot(material, DIFFUSE_TEXTURE),
68 Self::texture_slot(material, NORMAL_TEXTURE),
69 Self::texture_slot(material, METALLIC_ROUGHNESS_TEXTURE),
70 Self::texture_slot(material, EMISSIVE_TEXTURE),
71 ]);
72 let tex_indices1 = MaterialValue::UVec4([Self::texture_slot(material, OCCLUSION_TEXTURE), 0, 0, 0]);
73
74 Ok(vec![
75 get(BASE_COLOR)?,
76 get(EMISSIVE)?,
77 get(METALLIC)?,
78 get(ROUGHNESS)?,
79 tex_indices0,
80 tex_indices1,
81 ])
82 }
83}