1use crate::prelude::*;
2
3use rhai::{Engine, FnPtr};
4
5#[derive(PartialEq, Copy, Clone, Debug)]
8pub enum MediumType {
9 None,
10 Absorb,
11 Scatter,
12 Emissive
13}
14
15#[derive(PartialEq, Copy, Clone, Debug)]
17pub struct Medium {
18 pub medium_type : MediumType,
19 pub density : F,
20 pub color : F3,
21 pub anisotropy : F,
22}
23
24impl Medium {
25
26 pub fn new() -> Self {
27 Self {
28 medium_type : MediumType::None,
29 density : 0.0,
30 color : F3::new(0.0, 0.0, 0.0),
31 anisotropy : 0.0,
32 }
33 }
34}
35
36#[derive(PartialEq, Copy, Clone, Debug)]
39pub enum AlphaMode
40{
41 Opaque,
42 Blend,
43 Mask
44}
45
46#[derive(Clone, Debug)]
48pub struct Material {
49 pub rgb : F3,
50 pub anisotropic : F,
51 pub emission : F3,
52
53 pub metallic : F,
54 pub roughness : F,
55 pub subsurface : F,
56 pub specular_tint : F,
57
58 pub sheen : F,
59 pub sheen_tint : F,
60 pub clearcoat : F,
61 pub clearcoat_gloss : F,
62 pub clearcoat_roughness : F,
64
65 pub spec_trans : F,
66 pub ior : F,
67
68 pub opacity : F,
69 pub alpha_mode : AlphaMode,
70 pub alpha_cutoff : F,
71
72 pub ax : F,
73 pub ay : F,
74
75 pub medium : Medium,
76
77 pub procedural : Option<FnPtr>,
78}
79
80impl Material {
81
82 pub fn new() -> Self {
83
84 Self {
85 rgb : F3::new(1.5, 1.5, 1.5),
86 emission : F3::new(0.0, 0.0, 0.0),
87
88 anisotropic : 0.0,
89 metallic : 0.0,
90 roughness : 0.5,
91 subsurface : 0.0,
92 specular_tint : 0.0,
93
94 sheen : 0.0,
95 sheen_tint : 0.0,
96
97 clearcoat : 0.0,
98 clearcoat_gloss : 0.0,
99 clearcoat_roughness : 0.0,
100 spec_trans : 0.0,
101 ior : 1.45,
102
103 opacity : 1.0,
104 alpha_mode : AlphaMode::Opaque,
105 alpha_cutoff : 0.0,
106
107 medium : Medium::new(),
108
109 ax : 0.0,
110 ay : 0.0,
111
112 procedural : None,
113 }
114 }
115
116 pub fn finalize(&mut self) {
118
119 self.roughness = self.roughness.max(0.01);
120
121 fn mix_ptf(a: &F, b: &F, v: F) -> F {
122 (1.0 - v) * a + b * v
123 }
124
125 self.clearcoat_roughness = mix_ptf(&0.1, &0.001, self.clearcoat_gloss); self.medium.anisotropy = self.medium.anisotropy.clamp(-0.9, 0.9);
127
128 let aspect = (1.0 - self.anisotropic * 0.9).sqrt();
129 self.ax = (self.roughness / aspect).max(0.001);
130 self.ay = (self.roughness * aspect).max(0.001);
131 }
132
133 pub fn mix(&self, other: &Material, v: F) -> Material {
135 let mut m = Material::new();
136
137 m.rgb = mix(&self.rgb, &other.rgb, &v);
138 m.emission = mix(&self.emission, &other.emission, &v);
139
140 m.anisotropic = mix_f(&self.anisotropic, &other.anisotropic, &v);
141 m.metallic = mix_f(&self.metallic, &other.metallic, &v);
142 m.roughness = mix_f(&self.roughness, &other.roughness, &v);
143 m.subsurface = mix_f(&self.subsurface, &other.subsurface, &v);
144 m.specular_tint = mix_f(&self.specular_tint, &other.specular_tint, &v);
145
146 m.sheen = mix_f(&self.sheen, &other.sheen, &v);
147 m.sheen_tint = mix_f(&self.sheen_tint, &other.sheen_tint, &v);
148
149 m.clearcoat = mix_f(&self.clearcoat, &other.clearcoat, &v);
150 m.clearcoat_gloss = mix_f(&self.clearcoat_gloss, &other.clearcoat_gloss, &v);
151 m.spec_trans = mix_f(&self.spec_trans, &other.spec_trans, &v);
152 m.ior = mix_f(&self.ior, &other.ior, &v);
153
154 m
155 }
156
157 pub fn get_rgb(&mut self) -> F3 {
160 self.rgb
161 }
162
163 pub fn set_rgb(&mut self, new_val: F3) {
164 self.rgb = new_val;
165 }
166
167 pub fn get_emission(&mut self) -> F3 {
168 self.emission
169 }
170
171 pub fn set_emission(&mut self, new_val: F3) {
172 self.emission = new_val;
173 }
174
175 pub fn get_anisotropic(&mut self) -> F {
176 self.anisotropic
177 }
178
179 pub fn set_anisotropic(&mut self, new_val: F) {
180 self.anisotropic = new_val;
181 }
182
183 pub fn get_metallic(&mut self) -> F {
184 self.metallic
185 }
186
187 pub fn set_metallic(&mut self, new_val: F) {
188 self.metallic = new_val;
189 }
190
191 pub fn get_roughness(&mut self) -> F {
192 self.roughness
193 }
194
195 pub fn set_roughness(&mut self, new_val: F) {
196 self.roughness = new_val;
197 }
198
199 pub fn get_subsurface(&mut self) -> F {
200 self.subsurface
201 }
202
203 pub fn set_subsurface(&mut self, new_val: F) {
204 self.subsurface = new_val;
205 }
206
207 pub fn get_specular_tint(&mut self) -> F {
208 self.specular_tint
209 }
210
211 pub fn set_specular_tint(&mut self, new_val: F) {
212 self.specular_tint = new_val;
213 }
214
215 pub fn get_sheen(&mut self) -> F {
216 self.sheen
217 }
218
219 pub fn set_sheen(&mut self, new_val: F) {
220 self.sheen = new_val;
221 }
222
223 pub fn get_sheen_tint(&mut self) -> F {
224 self.sheen_tint
225 }
226
227 pub fn set_sheen_tint(&mut self, new_val: F) {
228 self.sheen_tint = new_val;
229 }
230
231 pub fn get_clearcoat(&mut self) -> F {
232 self.clearcoat
233 }
234
235 pub fn set_clearcoat(&mut self, new_val: F) {
236 self.clearcoat = new_val;
237 }
238
239 pub fn get_clearcoat_gloss(&mut self) -> F {
240 self.clearcoat_gloss
241 }
242
243 pub fn set_clearcoat_gloss(&mut self, new_val: F) {
244 self.clearcoat_gloss = new_val;
245 }
246
247 pub fn get_spec_trans(&mut self) -> F {
248 self.spec_trans
249 }
250
251 pub fn set_spec_trans(&mut self, new_val: F) {
252 self.spec_trans = new_val;
253 }
254
255 pub fn get_ior(&mut self) -> F {
256 self.ior
257 }
258
259 pub fn set_ior(&mut self, new_val: F) {
260 self.ior = new_val;
261 }
262
263 pub fn get_procedural(&mut self) -> FnPtr {
264 if let Some(procedural) = &self.procedural {
265 procedural.clone()
266 } else {
267 FnPtr::new("empty").ok().unwrap()
268 }
269 }
270
271 pub fn set_procedural(&mut self, new_val: FnPtr) {
272 self.procedural = Some(new_val)
273 }
274
275 pub fn register(engine: &mut Engine) {
277 engine.register_type_with_name::<Material>("Material")
278 .register_fn("Material", Material::new)
279
280 .register_get_set("rgb", Material::get_rgb, Material::set_rgb)
281 .register_get_set("emission", Material::get_emission, Material::set_emission)
282
283 .register_get_set("anisotropic", Material::get_anisotropic, Material::set_anisotropic)
284 .register_get_set("roughness", Material::get_roughness, Material::set_roughness)
285 .register_get_set("metallic", Material::get_metallic, Material::set_metallic)
286 .register_get_set("subsurface", Material::get_subsurface, Material::set_subsurface)
287 .register_get_set("specular_tint", Material::get_specular_tint, Material::set_specular_tint)
288
289 .register_get_set("sheen", Material::get_sheen, Material::set_sheen)
290 .register_get_set("sheen_tint", Material::get_sheen_tint, Material::set_sheen_tint)
291 .register_get_set("clearcoat", Material::get_clearcoat, Material::set_clearcoat)
292 .register_get_set("clearcoat_gloss", Material::get_clearcoat_gloss, Material::set_clearcoat_gloss)
293
294 .register_get_set("transmission", Material::get_spec_trans, Material::set_spec_trans)
295 .register_get_set("ior", Material::get_ior, Material::set_ior)
296
297 .register_get_set("procedural", Material::get_procedural, Material::set_procedural);
298 }
299}