1use std::f32;
2use std::sync::Arc;
3
4use num::Zero;
5
6use crate::core::geometry::{spherical_direction, vec3_abs_dot_vec3f, vec3_dot_vec3f};
7use crate::core::geometry::{Point2f, Vector3f, XYEnum};
8use crate::core::interaction::SurfaceInteraction;
9use crate::core::material::{Material, TransportMode};
10use crate::core::microfacet::{MicrofacetDistribution, TrowbridgeReitzDistribution};
11use crate::core::paramset::TextureParams;
12use crate::core::pbrt::{clamp_t, lerp};
13use crate::core::pbrt::{Float, Spectrum};
14use crate::core::reflection::reflect;
15use crate::core::reflection::{abs_cos_theta, fr_schlick, vec3_same_hemisphere_vec3};
16use crate::core::reflection::{
17 Bsdf, Bxdf, BxdfType, DisneyFresnel, Fresnel, LambertianTransmission, MicrofacetReflection,
18 MicrofacetTransmission, SpecularTransmission,
19};
20use crate::core::texture::Texture;
21
22pub struct DisneyMaterial {
23 color: Arc<dyn Texture<Spectrum> + Send + Sync>,
24 metallic: Arc<dyn Texture<Float> + Send + Sync>,
26 eta: Arc<dyn Texture<Float> + Send + Sync>,
27 roughness: Arc<dyn Texture<Float> + Send + Sync>,
28 specular_tint: Arc<dyn Texture<Float> + Send + Sync>,
29 anisotropic: Arc<dyn Texture<Float> + Send + Sync>,
30 sheen: Arc<dyn Texture<Float> + Send + Sync>,
31 sheen_tint: Arc<dyn Texture<Float> + Send + Sync>,
32 clearcoat: Arc<dyn Texture<Float> + Send + Sync>,
33 clearcoat_gloss: Arc<dyn Texture<Float> + Send + Sync>,
34 spec_trans: Arc<dyn Texture<Float> + Send + Sync>,
35 scatter_distance: Arc<dyn Texture<Spectrum> + Send + Sync>,
36 flatness: Arc<dyn Texture<Float> + Send + Sync>,
37 diff_trans: Arc<dyn Texture<Float> + Send + Sync>,
38 bump_map: Option<Arc<dyn Texture<Float> + Send + Sync>>,
39 thin: bool,
40}
41
42impl DisneyMaterial {
43 pub fn create(mp: &mut TextureParams) -> Arc<Material> {
44 let color = mp.get_spectrum_texture("color", Spectrum::from(0.5));
45 let metallic = mp.get_float_texture("metallic", 0.0);
46 let eta = mp.get_float_texture("eta", 1.5);
47 let roughness = mp.get_float_texture("roughness", 0.5);
48 let specular_tint = mp.get_float_texture("speculartint", 0.0);
49 let anisotropic = mp.get_float_texture("anisotropic", 0.0);
50 let sheen = mp.get_float_texture("sheen", 0.0);
51 let sheen_tint = mp.get_float_texture("sheentint", 0.5);
52 let clearcoat = mp.get_float_texture("clearcoat", 0.0);
53 let clearcoat_gloss = mp.get_float_texture("clearcoatgloss", 1.0);
54 let spec_trans = mp.get_float_texture("spectrans", 0.0);
55 let scatter_distance = mp.get_spectrum_texture("scatterdistance", Spectrum::from(0.0));
56 let thin = mp.find_bool("thin", false);
57 let flatness = mp.get_float_texture("flatness", 0.0);
58 let diff_trans = mp.get_float_texture("difftrans", 1.0);
59 let bump_map = mp.get_float_texture_or_null("bumpmap");
60
61 Arc::new(Material::Disney(Box::new(DisneyMaterial {
62 color,
63 metallic,
64 eta,
65 roughness,
66 specular_tint,
67 anisotropic,
68 sheen,
69 sheen_tint,
70 clearcoat,
71 clearcoat_gloss,
72 spec_trans,
73 scatter_distance,
74 flatness,
75 diff_trans,
76 bump_map,
77 thin,
78 })))
79 }
80 pub fn compute_scattering_functions(
82 &self,
83 si: &mut SurfaceInteraction,
84 mode: TransportMode,
85 _allow_multiple_lobes: bool,
86 _material: Option<Arc<Material>>,
87 scale_opt: Option<Spectrum>,
88 ) {
89 let mut use_scale: bool = false;
90 let mut sc: Spectrum = Spectrum::default();
91 if let Some(scale) = scale_opt {
92 use_scale = true;
93 sc = scale;
94 }
95 if let Some(ref bump) = self.bump_map {
96 Material::bump(bump, si);
97 }
98 let c = self.color.evaluate(si).clamp(0.0, f32::INFINITY);
100 let metallic_weight = self.metallic.evaluate(si);
101 let e = self.eta.evaluate(si);
102 let strans = self.spec_trans.evaluate(si);
103 let diffuse_weight = (1.0 - metallic_weight) * (1.0 - strans);
104 let dt = self.diff_trans.evaluate(si) / 2.0; let rough = self.roughness.evaluate(si);
106 let lum = c.y();
107 let c_tint = if lum > 0.0 {
109 c / lum
110 } else {
111 Spectrum::new(1.0)
112 };
113 let sheen_weight = self.sheen.evaluate(si);
114 let c_sheen = if sheen_weight > 0.0 {
115 let stint = self.sheen_tint.evaluate(si);
116 lerp(stint, Spectrum::new(1.0), c_tint)
117 } else {
118 Spectrum::zero()
119 };
120 let flat = self.flatness.evaluate(si);
121 let sd = self.scatter_distance.evaluate(si);
122 let aspect = Float::sqrt(1.0 - self.anisotropic.evaluate(si) * 0.9);
123 let spec_tint = self.specular_tint.evaluate(si);
124 let cc = self.clearcoat.evaluate(si);
125 let gloss: Float = lerp(self.clearcoat_gloss.evaluate(si), 0.1, 0.001);
126 si.bsdf = Some(Bsdf::new(si, 1.0));
127 if let Some(bsdf) = &mut si.bsdf {
128 if diffuse_weight > 0.0 {
129 if self.thin {
130 if use_scale {
133 bsdf.add(Bxdf::DisDiff(DisneyDiffuse::new(
134 diffuse_weight * (1.0 - flat) * (1.0 - dt) * c,
135 Some(sc),
136 )));
137 bsdf.add(Bxdf::DisSS(DisneyFakeSS::new(
138 diffuse_weight * flat * (1.0 - dt) * c,
139 rough,
140 Some(sc),
141 )));
142 } else {
143 bsdf.add(Bxdf::DisDiff(DisneyDiffuse::new(
144 diffuse_weight * (1.0 - flat) * (1.0 - dt) * c,
145 None,
146 )));
147 bsdf.add(Bxdf::DisSS(DisneyFakeSS::new(
148 diffuse_weight * flat * (1.0 - dt) * c,
149 rough,
150 None,
151 )));
152 }
153 } else if sd.is_black() {
154 if use_scale {
156 bsdf.add(Bxdf::DisDiff(DisneyDiffuse::new(
157 diffuse_weight * c,
158 Some(sc),
159 )));
160 } else {
161 bsdf.add(Bxdf::DisDiff(DisneyDiffuse::new(diffuse_weight * c, None)));
162 }
163 } else {
164 if use_scale {
166 bsdf.add(Bxdf::SpecTrans(SpecularTransmission::new(
167 Spectrum::from(1.0),
168 1.0,
169 e,
170 mode,
171 Some(sc),
172 )));
173 } else {
174 bsdf.add(Bxdf::SpecTrans(SpecularTransmission::new(
175 Spectrum::from(1.0),
176 1.0,
177 e,
178 mode,
179 None,
180 )));
181 }
182 }
184
185 if use_scale {
187 bsdf.add(Bxdf::DisRetro(DisneyRetro::new(
188 diffuse_weight * c,
189 rough,
190 Some(sc),
191 )));
192 } else {
193 bsdf.add(Bxdf::DisRetro(DisneyRetro::new(
194 diffuse_weight * c,
195 rough,
196 None,
197 )));
198 }
199 if sheen_weight > 0.0 {
201 if use_scale {
202 bsdf.add(Bxdf::DisSheen(DisneySheen::new(
203 diffuse_weight * sheen_weight * c_sheen,
204 Some(sc),
205 )));
206 } else {
207 bsdf.add(Bxdf::DisSheen(DisneySheen::new(
208 diffuse_weight * sheen_weight * c_sheen,
209 None,
210 )));
211 }
212 }
213 }
214
215 let ax = Float::max(0.001, sqr(rough) / aspect);
217 let ay = Float::max(0.001, sqr(rough) * aspect);
218 let distrib =
219 MicrofacetDistribution::DisneyMicrofacet(DisneyMicrofacetDistribution::new(ax, ay));
220
221 let cspec0 = lerp(
223 metallic_weight,
224 schlick_r0_from_eta(e) * lerp(spec_tint, Spectrum::new(1.0), c_tint),
225 c,
226 );
227 let fresnel = Fresnel::Disney(DisneyFresnel::new(cspec0, metallic_weight, e));
228 if use_scale {
229 bsdf.add(Bxdf::MicrofacetRefl(MicrofacetReflection::new(
230 c,
231 distrib,
232 fresnel,
233 Some(sc),
234 )));
235 } else {
236 bsdf.add(Bxdf::MicrofacetRefl(MicrofacetReflection::new(
237 c, distrib, fresnel, None,
238 )));
239 }
240 if cc > 0.0 {
242 if use_scale {
243 bsdf.add(Bxdf::DisClearCoat(DisneyClearCoat::new(
244 cc,
245 gloss,
246 Some(sc),
247 )));
248 } else {
249 bsdf.add(Bxdf::DisClearCoat(DisneyClearCoat::new(cc, gloss, None)));
250 }
251 }
252
253 if strans > 0.0 {
255 let t = strans * c.sqrt();
258 if self.thin {
259 let rscaled = (0.65 * e - 0.35) * rough;
261 let ax = Float::max(0.001, sqr(rscaled) / aspect);
262 let ay = Float::max(0.001, sqr(rscaled) * aspect);
263 let scaled_distrib = MicrofacetDistribution::TrowbridgeReitz(
264 TrowbridgeReitzDistribution::new(ax, ay, true),
265 );
266 if use_scale {
267 bsdf.add(Bxdf::MicrofacetTrans(MicrofacetTransmission::new(
268 t,
269 scaled_distrib,
270 1.0,
271 e,
272 mode,
273 Some(sc),
274 )));
275 } else {
276 bsdf.add(Bxdf::MicrofacetTrans(MicrofacetTransmission::new(
277 t,
278 scaled_distrib,
279 1.0,
280 e,
281 mode,
282 None,
283 )));
284 }
285 } else {
286 let distrib = MicrofacetDistribution::DisneyMicrofacet(
287 DisneyMicrofacetDistribution::new(ax, ay),
288 );
289 if use_scale {
290 bsdf.add(Bxdf::MicrofacetTrans(MicrofacetTransmission::new(
291 t,
292 distrib,
293 1.0,
294 e,
295 mode,
296 Some(sc),
297 )));
298 } else {
299 bsdf.add(Bxdf::MicrofacetTrans(MicrofacetTransmission::new(
300 t, distrib, 1.0, e, mode, None,
301 )));
302 }
303 }
304 }
305
306 if self.thin {
307 if use_scale {
309 bsdf.add(Bxdf::LambertianTrans(LambertianTransmission::new(
310 dt * c,
311 Some(sc),
312 )));
313 } else {
315 bsdf.add(Bxdf::LambertianTrans(LambertianTransmission::new(
316 dt * c,
317 None,
318 )));
319 }
321 }
322 }
323 }
324}
325#[derive(Debug, Clone, Copy)]
328pub struct DisneyDiffuse {
329 pub r: Spectrum,
330 pub sc_opt: Option<Spectrum>,
331}
332
333impl DisneyDiffuse {
334 pub fn new(r: Spectrum, sc_opt: Option<Spectrum>) -> Self {
335 DisneyDiffuse { r, sc_opt }
336 }
337 pub fn f(&self, wo: &Vector3f, wi: &Vector3f) -> Spectrum {
338 let fo = schlick_weight(abs_cos_theta(wo));
339 let fi = schlick_weight(abs_cos_theta(wi));
340
341 if let Some(sc) = self.sc_opt {
344 sc * self.r * f32::consts::FRAC_1_PI * (1.0 - fo / 2.0) * (1.0 - fi / 2.0)
345 } else {
346 self.r * f32::consts::FRAC_1_PI * (1.0 - fo / 2.0) * (1.0 - fi / 2.0)
347 }
348 }
349 pub fn get_type(&self) -> u8 {
350 BxdfType::BsdfReflection as u8 | BxdfType::BsdfDiffuse as u8
351 }
352}
353
354#[derive(Debug, Clone, Copy)]
357pub struct DisneyFakeSS {
358 pub r: Spectrum,
359 pub roughness: Float,
360 pub sc_opt: Option<Spectrum>,
361}
362
363impl DisneyFakeSS {
364 pub fn new(r: Spectrum, roughness: Float, sc_opt: Option<Spectrum>) -> Self {
365 DisneyFakeSS {
366 r,
367 roughness,
368 sc_opt,
369 }
370 }
371 pub fn f(&self, wo: &Vector3f, wi: &Vector3f) -> Spectrum {
372 let mut wh = *wi + *wo;
373 if wh.x == 0.0 && wh.y == 0.0 && wh.z == 0.0 {
374 return Spectrum::from(0.0);
375 }
376 wh = wh.normalize();
377 let cos_theta_d = vec3_dot_vec3f(wi, &wh);
378
379 let fss90 = cos_theta_d * cos_theta_d * self.roughness;
381 let fo = schlick_weight(abs_cos_theta(wo));
382 let fi = schlick_weight(abs_cos_theta(wi));
383 let fss = lerp(fo, 1.0, fss90) * lerp(fi, 1.0, fss90);
384 let ss = 1.25 * (fss * (1.0 / (abs_cos_theta(wo) + abs_cos_theta(wi)) - 0.5) + 0.5);
386
387 if let Some(sc) = self.sc_opt {
388 sc * self.r * f32::consts::FRAC_1_PI * ss
389 } else {
390 self.r * f32::consts::FRAC_1_PI * ss
391 }
392 }
393 pub fn get_type(&self) -> u8 {
394 BxdfType::BsdfReflection as u8 | BxdfType::BsdfDiffuse as u8
395 }
396}
397
398#[derive(Debug, Clone, Copy)]
401pub struct DisneyRetro {
402 pub r: Spectrum,
403 pub roughness: Float,
404 pub sc_opt: Option<Spectrum>,
405}
406
407impl DisneyRetro {
408 pub fn new(r: Spectrum, roughness: Float, sc_opt: Option<Spectrum>) -> Self {
409 DisneyRetro {
410 r,
411 roughness,
412 sc_opt,
413 }
414 }
415 pub fn f(&self, wo: &Vector3f, wi: &Vector3f) -> Spectrum {
416 let mut wh = *wi + *wo;
417 if wh.x == 0.0 && wh.y == 0.0 && wh.z == 0.0 {
418 return Spectrum::from(0.0);
419 }
420 wh = wh.normalize();
421 let cos_theta_d = vec3_dot_vec3f(wi, &wh);
422 let fo = schlick_weight(abs_cos_theta(wo));
423 let fi = schlick_weight(abs_cos_theta(wi));
424 let rr = 2.0 * self.roughness * cos_theta_d * cos_theta_d;
425
426 if let Some(sc) = self.sc_opt {
428 sc * self.r * f32::consts::FRAC_1_PI * rr * (fo + fi + fo * fi * (rr - 1.0))
429 } else {
430 self.r * f32::consts::FRAC_1_PI * rr * (fo + fi + fo * fi * (rr - 1.0))
431 }
432 }
433 pub fn get_type(&self) -> u8 {
434 BxdfType::BsdfReflection as u8 | BxdfType::BsdfDiffuse as u8
435 }
436}
437
438#[derive(Debug, Clone, Copy)]
441pub struct DisneySheen {
442 pub r: Spectrum,
443 pub sc_opt: Option<Spectrum>,
444}
445
446impl DisneySheen {
447 pub fn new(r: Spectrum, sc_opt: Option<Spectrum>) -> Self {
448 DisneySheen { r, sc_opt }
449 }
450 pub fn f(&self, wo: &Vector3f, wi: &Vector3f) -> Spectrum {
451 let mut wh = *wi + *wo;
452 if wh.x == 0.0 && wh.y == 0.0 && wh.z == 0.0 {
453 return Spectrum::from(0.0);
454 }
455 wh = wh.normalize();
456 let cos_theta_d = vec3_dot_vec3f(wi, &wh);
457
458 if let Some(sc) = self.sc_opt {
459 sc * self.r * schlick_weight(cos_theta_d)
460 } else {
461 self.r * schlick_weight(cos_theta_d)
462 }
463 }
464 pub fn get_type(&self) -> u8 {
465 BxdfType::BsdfReflection as u8 | BxdfType::BsdfDiffuse as u8
466 }
467}
468
469#[derive(Debug, Clone, Copy)]
472pub struct DisneyClearCoat {
473 pub weight: Float,
474 pub gloss: Float,
475 pub sc_opt: Option<Spectrum>,
476}
477
478impl DisneyClearCoat {
479 pub fn new(weight: Float, gloss: Float, sc_opt: Option<Spectrum>) -> Self {
480 DisneyClearCoat {
481 weight,
482 gloss,
483 sc_opt,
484 }
485 }
486 pub fn f(&self, wo: &Vector3f, wi: &Vector3f) -> Spectrum {
487 let mut wh = *wi + *wo;
488 if wh.x == 0.0 && wh.y == 0.0 && wh.z == 0.0 {
489 return Spectrum::from(0.0);
490 }
491 wh = wh.normalize();
492
493 let dr = gtr1(abs_cos_theta(&wh), self.gloss);
497 let fr = fr_schlick(0.04, vec3_dot_vec3f(wo, &wh));
498 let gr = smith_g_ggx(abs_cos_theta(wo), 0.25) * smith_g_ggx(abs_cos_theta(wi), 0.25);
500
501 if let Some(sc) = self.sc_opt {
502 sc * Spectrum::from(self.weight * gr * fr * dr / 4.0)
503 } else {
504 Spectrum::from(self.weight * gr * fr * dr / 4.0)
505 }
506 }
507 pub fn sample_f(
508 &self,
509 wo: &Vector3f,
510 wi: &mut Vector3f,
511 u: &Point2f,
512 pdf: &mut Float,
513 _sampled_type: &mut u8,
514 ) -> Spectrum {
515 if wo.z == 0.0 {
516 return Spectrum::zero();
517 }
518
519 let alpha2 = self.gloss * self.gloss;
520 let cos_theta = Float::sqrt(Float::max(
521 0.0,
522 (1.0 - Float::powf(alpha2, 1.0 - u[XYEnum::X])) / (1.0 - alpha2),
523 ));
524 let sin_theta = Float::sqrt(Float::max(0.0, 1.0 - cos_theta * cos_theta));
525 let phi = 2.0 * f32::consts::PI * u[XYEnum::Y];
526 let mut wh = spherical_direction(sin_theta, cos_theta, phi);
527 if !vec3_same_hemisphere_vec3(wo, &wh) {
528 wh = -wh;
529 }
530 *wi = reflect(wo, &wh);
531
532 if !vec3_same_hemisphere_vec3(wo, wi) {
533 return Spectrum::zero();
534 }
535
536 *pdf = self.pdf(wo, wi);
537
538 if let Some(sc) = self.sc_opt {
539 sc * self.f(wo, wi)
540 } else {
541 self.f(wo, wi)
542 }
543 }
544 pub fn pdf(&self, wo: &Vector3f, wi: &Vector3f) -> Float {
545 if !vec3_same_hemisphere_vec3(wo, wi) {
546 return 0.0;
547 }
548
549 let mut wh = *wo + *wi;
550 if wh.x == 0.0 && wh.y == 0.0 && wh.z == 0.0 {
551 return 0.0;
552 }
553 wh = wh.normalize();
554
555 let dr = gtr1(abs_cos_theta(&wh), self.gloss);
560 dr * abs_cos_theta(&wh) / (4.0 * vec3_dot_vec3f(wo, &wh))
561 }
562 pub fn get_type(&self) -> u8 {
563 BxdfType::BsdfReflection as u8 | BxdfType::BsdfGlossy as u8
564 }
565}
566
567#[derive(Default, Clone, Copy)]
568pub struct DisneyMicrofacetDistribution {
569 pub inner: TrowbridgeReitzDistribution,
570}
571
572impl DisneyMicrofacetDistribution {
573 pub fn new(alphax: Float, alphay: Float) -> DisneyMicrofacetDistribution {
574 DisneyMicrofacetDistribution {
575 inner: TrowbridgeReitzDistribution::new(alphax, alphay, true),
576 }
577 }
578 pub fn d(&self, wh: &Vector3f) -> Float {
579 self.inner.d(wh)
580 }
581 pub fn lambda(&self, wh: &Vector3f) -> Float {
582 self.inner.lambda(wh)
583 }
584 pub fn g1(&self, w: &Vector3f) -> Float {
585 1.0 as Float / (1.0 as Float + self.lambda(w))
586 }
587 pub fn g(&self, wi: &Vector3f, wo: &Vector3f) -> Float {
588 self.g1(wi) * self.g1(wo)
590 }
591 pub fn pdf(&self, wo: &Vector3f, wh: &Vector3f) -> Float {
592 if self.get_sample_visible_area() {
593 self.d(wh) * self.g1(wo) * vec3_abs_dot_vec3f(wo, wh) / abs_cos_theta(wo)
594 } else {
595 self.d(wh) * abs_cos_theta(wh)
596 }
597 }
598 pub fn sample_wh(&self, wo: &Vector3f, u: &Point2f) -> Vector3f {
599 self.inner.sample_wh(wo, u)
600 }
601 pub fn get_sample_visible_area(&self) -> bool {
602 self.inner.get_sample_visible_area()
603 }
604}
605
606fn schlick_weight(cos_theta: Float) -> Float {
614 let m = clamp_t(1.0 - cos_theta, 0.0, 1.0);
615 (m * m) * (m * m) * m
616}
617
618fn schlick_r0_from_eta(eta: Float) -> Float {
621 sqr(eta - 1.0) / sqr(eta + 1.0)
622}
623
624fn gtr1(cos_theta: Float, alpha: Float) -> Float {
625 let alpha2 = alpha * alpha;
626
627 (alpha2 - 1.0)
628 / (f32::consts::PI * Float::log10(alpha2) * (1.0 + (alpha2 - 1.0) * cos_theta * cos_theta))
629}
630
631fn smith_g_ggx(cos_theta: Float, alpha: Float) -> Float {
632 let alpha2 = alpha * alpha;
633 let cos_theta2 = cos_theta * cos_theta;
634
635 1.0 / (cos_theta + Float::sqrt(alpha2 + cos_theta2 - alpha2 * cos_theta2))
636}
637
638fn sqr(x: Float) -> Float {
639 x * x
640}