vkobject_rs/
material.rs

1
2use crate::prelude::*;
3use std::{
4	any::Any,
5	collections::{HashMap, BTreeSet},
6	fmt::Debug,
7	sync::Arc,
8};
9
10/// The material component
11#[derive(Debug, Clone)]
12pub enum MaterialComponent {
13	Texture(Arc<VulkanTexture>),
14	Color(Vec4),
15	Luminance(f32),
16}
17
18impl MaterialComponent {
19	/// Convert an `ObjMaterialComponent` into `MaterialComponent`, the texture will be loaded after the command buffer is submitted. The load command will be issued immediately.
20	pub fn from_obj(device: Arc<VulkanDevice>, cmdbuf: VkCommandBuffer, obj_comp: &ObjMaterialComponent) -> Result<Self, VulkanError> {
21		match obj_comp {
22			ObjMaterialComponent::Texture(path) => Ok(MaterialComponent::Texture(Arc::new(VulkanTexture::new_from_path(device, cmdbuf, path, true, Some(VkFilter::VK_FILTER_LINEAR), VkImageUsageFlagBits::VK_IMAGE_USAGE_SAMPLED_BIT as VkImageUsageFlags)?))),
23			ObjMaterialComponent::Color(color) => Ok(MaterialComponent::Color(*color)),
24			ObjMaterialComponent::Luminance(lum) => Ok(MaterialComponent::Luminance(*lum)),
25		}
26	}
27}
28
29/// The legacy illumination model material
30#[derive(Default, Debug, Clone)]
31pub struct MaterialLegacy {
32	/// Base brightness
33	pub ambient: MaterialComponent,
34
35	/// Base color
36	pub diffuse: MaterialComponent,
37
38	/// Specular color
39	pub specular: MaterialComponent,
40
41	/// Specular power
42	pub specular_power: MaterialComponent,
43
44	/// Normal map
45	pub normal: MaterialComponent,
46
47	/// Emissive, self-lighting
48	pub emissive: MaterialComponent,
49
50	/// The other type of components
51	pub others: HashMap<String, MaterialComponent>,
52}
53
54/// The physically based rendering illumination model material
55#[derive(Default, Debug, Clone)]
56pub struct MaterialPbr {
57	/// Base color
58	pub albedo: MaterialComponent,
59
60	/// Normal map
61	pub normal: MaterialComponent,
62
63	/// Ambient occlusion
64	pub ao: MaterialComponent,
65
66	/// A.k.a. Height map. The renderer must render this map by extruding the mesh, or use ray-marching to cast the protrusions of the map
67	pub displacement: MaterialComponent,
68
69	/// Roughness, something sort of the legacy specular-key map
70	pub roughness: MaterialComponent,
71
72	/// Metalness, something sort of the legacy specular map
73	pub metalness: MaterialComponent,
74
75	/// Emissive, self-lighting
76	pub emissive: MaterialComponent,
77
78	/// The other type of components
79	pub others: HashMap<String, MaterialComponent>,
80}
81
82impl Default for MaterialComponent {
83	fn default() -> Self {
84		Self::Color(Vec4::new(0.5, 0.5, 0.5, 1.0))
85	}
86}
87
88/// The `Material` trait helps the `MaterialLegacy` struct or the `MaterialPbr` struct to be able to turn into an object
89pub trait Material: Debug + Any {
90	/// Get the ambient color
91	fn get_ambient(&self) -> Option<&MaterialComponent>;
92
93	/// Get the diffuse color
94	fn get_diffuse(&self) -> Option<&MaterialComponent>;
95
96	/// Get the specular color
97	fn get_specular(&self) -> Option<&MaterialComponent>;
98
99	/// Get the specular power
100	fn get_specular_power(&self) -> Option<&MaterialComponent>;
101
102	/// Get the base color (PBR)
103	fn get_albedo(&self) -> Option<&MaterialComponent>;
104
105	/// Get the ambient occlusion (PBR)
106	fn get_ao(&self) -> Option<&MaterialComponent>;
107
108	/// Get the displacement map (A.k.a. height map) (PBR)
109	fn get_displacement(&self) -> Option<&MaterialComponent>;
110
111	/// Get the roughness map (PBR)
112	fn get_roughness(&self) -> Option<&MaterialComponent>;
113
114	/// Get the metalness map (PBR)
115	fn get_metalness(&self) -> Option<&MaterialComponent>;
116
117	/// Get the normal map
118	fn get_normal(&self) -> Option<&MaterialComponent>;
119
120	/// Get the emissive color
121	fn get_emissive(&self) -> Option<&MaterialComponent>;
122
123	/// Get all of the component names exists in this material
124	fn get_names(&self) -> BTreeSet<String>;
125
126	/// Get a component by the name of the component
127	fn get_by_name(&self, name: &str) -> Option<&MaterialComponent>;
128
129	/// Set a componnet by the name of the component
130	fn set_by_name(&mut self, name: &str, texture: MaterialComponent);
131}
132
133/// Convert `&dyn ObjMaterial` into the `Arc<dyn Material>`, all textures were loaded and constants were also converted
134pub fn create_material_from_obj_material(device: Arc<VulkanDevice>, cmdbuf: VkCommandBuffer, objmat: &dyn ObjMaterial) -> Result<Arc<dyn Material>, VulkanError> {
135	let mut ret: Box<dyn Material> = if (objmat as &dyn Any).downcast_ref::<ObjMaterialLegacy>().is_some() {
136		Box::new(MaterialLegacy::default())
137	} else {
138		Box::new(MaterialPbr::default())
139	};
140	for entry in objmat.get_names().iter() {
141		ret.set_by_name(entry, MaterialComponent::from_obj(device.clone(), cmdbuf, objmat.get_by_name(entry).unwrap())?);
142	}
143	Ok(Arc::from(ret))
144}
145
146impl Material for MaterialLegacy {
147	fn get_ambient(&self) ->		Option<&MaterialComponent> {Some(&self.ambient)}
148	fn get_diffuse(&self) ->		Option<&MaterialComponent> {Some(&self.diffuse)}
149	fn get_specular(&self) ->		Option<&MaterialComponent> {Some(&self.specular)}
150	fn get_specular_power(&self) ->	Option<&MaterialComponent> {Some(&self.specular_power)}
151	fn get_normal(&self) ->			Option<&MaterialComponent> {Some(&self.normal)}
152	fn get_emissive(&self) ->		Option<&MaterialComponent> {Some(&self.emissive)}
153
154	fn get_albedo(&self) ->			Option<&MaterialComponent> {Some(&self.diffuse)}
155	fn get_ao(&self) ->				Option<&MaterialComponent> {Some(&self.ambient)}
156	fn get_displacement(&self) ->	Option<&MaterialComponent> {None}
157	fn get_roughness(&self) ->		Option<&MaterialComponent> {None}
158	fn get_metalness(&self) ->		Option<&MaterialComponent> {None}
159
160	fn get_names(&self) -> BTreeSet<String> {
161		let mut ret = BTreeSet::new();
162		ret.insert("ambient".to_owned());
163		ret.insert("diffuse".to_owned());
164		ret.insert("specular".to_owned());
165		ret.insert("specular_power".to_owned());
166		ret.insert("normal".to_owned());
167		ret.insert("emissive".to_owned());
168		for (name, _) in self.others.iter() {
169			ret.insert(name.clone());
170		}
171		ret
172	}
173
174	fn get_by_name(&self, name: &str) -> Option<&MaterialComponent> {
175		match self.others.get(name) {
176			Some(data) => Some(data),
177			None => {
178				match name {
179					"ambient" =>		self.get_ambient(),
180					"diffuse" =>		self.get_diffuse(),
181					"specular" =>		self.get_specular(),
182					"specular_power" =>	self.get_specular_power(),
183					"normal" =>			self.get_normal(),
184					"emissive" =>		self.get_emissive(),
185					_ => None,
186				}
187			}
188		}
189	}
190
191	fn set_by_name(&mut self, name: &str, texture: MaterialComponent) {
192		match name {
193			"ambient" =>		self.ambient = texture,
194			"diffuse" =>		self.diffuse = texture,
195			"specular" =>		self.specular = texture,
196			"specular_power" =>	self.specular_power = texture,
197			"normal" =>			self.normal = texture,
198			"emissive" =>		self.emissive = texture,
199			others =>{
200				self.others.insert(others.to_owned(), texture);
201			}
202		}
203	}
204}
205
206impl Material for MaterialPbr {
207	fn get_albedo(&self) ->			Option<&MaterialComponent> {Some(&self.albedo)}
208	fn get_ao(&self) ->				Option<&MaterialComponent> {Some(&self.ao)}
209	fn get_displacement(&self) ->	Option<&MaterialComponent> {Some(&self.displacement)}
210	fn get_roughness(&self) ->		Option<&MaterialComponent> {Some(&self.roughness)}
211	fn get_metalness(&self) ->		Option<&MaterialComponent> {Some(&self.metalness)}
212	fn get_normal(&self) ->			Option<&MaterialComponent> {Some(&self.normal)}
213	fn get_emissive(&self) ->		Option<&MaterialComponent> {Some(&self.emissive)}
214
215	fn get_ambient(&self) ->		Option<&MaterialComponent> {Some(&self.ao)}
216	fn get_diffuse(&self) ->		Option<&MaterialComponent> {Some(&self.albedo)}
217	fn get_specular(&self) ->		Option<&MaterialComponent> {None}
218	fn get_specular_power(&self) ->	Option<&MaterialComponent> {None}
219
220	fn get_names(&self) -> BTreeSet<String> {
221		let mut ret = BTreeSet::new();
222		ret.insert("albedo".to_owned());
223		ret.insert("ao".to_owned());
224		ret.insert("displacement".to_owned());
225		ret.insert("roughness".to_owned());
226		ret.insert("metalness".to_owned());
227		ret.insert("normal".to_owned());
228		ret.insert("emissive".to_owned());
229		for (name, _) in self.others.iter() {
230			ret.insert(name.clone());
231		}
232		ret
233	}
234
235	fn get_by_name(&self, name: &str) -> Option<&MaterialComponent> {
236		match self.others.get(name) {
237			Some(data) => Some(data),
238			None => {
239				match name {
240					"albedo" =>			self.get_albedo(),
241					"ao" =>				self.get_ao(),
242					"displacement" =>	self.get_displacement(),
243					"roughness" =>		self.get_roughness(),
244					"metalness" =>		self.get_metalness(),
245					"normal" =>			self.get_normal(),
246					"emissive" =>		self.get_emissive(),
247					_ => None,
248				}
249			}
250		}
251	}
252
253	fn set_by_name(&mut self, name: &str, texture: MaterialComponent) {
254		match name {
255			"albedo" =>			self.albedo = texture,
256			"ao" =>				self.ao = texture,
257			"displacement" =>	self.displacement = texture,
258			"roughness" =>		self.roughness = texture,
259			"metalness" =>		self.metalness = texture,
260			"normal" =>			self.normal = texture,
261			"emissive" =>		self.emissive = texture,
262			others =>{
263				self.others.insert(others.to_owned(), texture);
264			}
265		}
266	}
267}