rs_pbrt/materials/
mixmat.rs

1//std
2use std::sync::Arc;
3// pbrt
4use crate::core::bssrdf::SeparableBssrdfAdapter;
5use crate::core::interaction::SurfaceInteraction;
6use crate::core::material::{Material, TransportMode};
7use crate::core::microfacet::{
8    BeckmannDistribution, MicrofacetDistribution, TrowbridgeReitzDistribution,
9};
10use crate::core::pbrt::{Float, Spectrum};
11use crate::core::reflection::{
12    Bxdf, FourierBSDF, Fresnel, FresnelBlend, FresnelConductor, FresnelDielectric, FresnelNoOp,
13    FresnelSpecular, LambertianReflection, LambertianTransmission, MicrofacetReflection,
14    MicrofacetTransmission, OrenNayar, SpecularReflection, SpecularTransmission,
15};
16use crate::core::texture::Texture;
17use crate::materials::disney::{
18    DisneyClearCoat, DisneyDiffuse, DisneyFakeSS, DisneyMicrofacetDistribution, DisneyRetro,
19    DisneySheen,
20};
21use crate::materials::hair::HairBSDF;
22
23// see mixmat.h
24
25/// The mix material takes two other materials and a texture and uses
26/// the value returned by the texture to blend between the two
27/// materials at the point being shaded.
28pub struct MixMaterial {
29    pub m1: Arc<Material>,
30    pub m2: Arc<Material>,
31    pub scale: Arc<dyn Texture<Spectrum> + Sync + Send>, // default: 0.5
32}
33
34impl MixMaterial {
35    pub fn new(
36        m1: Arc<Material>,
37        m2: Arc<Material>,
38        scale: Arc<dyn Texture<Spectrum> + Send + Sync>,
39    ) -> Self {
40        MixMaterial { m1, m2, scale }
41    }
42    // Material
43    pub fn compute_scattering_functions(
44        &self,
45        si: &mut SurfaceInteraction,
46        // arena: &mut Arena,
47        mode: TransportMode,
48        allow_multiple_lobes: bool,
49        _material: Option<Arc<Material>>,
50        _scale: Option<Spectrum>,
51    ) {
52        let s1: Spectrum = self
53            .scale
54            .evaluate(si)
55            .clamp(0.0 as Float, std::f32::INFINITY as Float);
56        let s2: Spectrum =
57            (Spectrum::new(1.0 as Float) - s1).clamp(0.0 as Float, std::f32::INFINITY as Float);
58        let mut si2: SurfaceInteraction = SurfaceInteraction::new(
59            &si.common.p,
60            &si.common.p_error,
61            si.uv,
62            &si.common.wo,
63            &si.dpdu,
64            &si.dpdv,
65            &si.dndu,
66            &si.dndv,
67            si.common.time,
68            si.shape,
69        );
70        self.m1
71            .compute_scattering_functions(si, mode, allow_multiple_lobes, None, Some(s1));
72        self.m2
73            .compute_scattering_functions(&mut si2, mode, allow_multiple_lobes, None, Some(s2));
74        if let Some(bsdf1) = &mut si.bsdf {
75            if let Some(bsdf2) = &si2.bsdf {
76                // get Bxdfs from si2 before it gets out of scope
77                for bxdf2 in bsdf2.bxdfs.as_slice() {
78                    match bxdf2 {
79                        Bxdf::Empty(_bxdf) => break,
80                        Bxdf::SpecRefl(bxdf) => {
81                            let fresnel = match &bxdf.fresnel {
82                                Fresnel::Conductor(fresnel) => {
83                                    Fresnel::Conductor(FresnelConductor {
84                                        eta_i: fresnel.eta_i,
85                                        eta_t: fresnel.eta_t,
86                                        k: fresnel.k,
87                                    })
88                                }
89                                Fresnel::Dielectric(fresnel) => {
90                                    Fresnel::Dielectric(FresnelDielectric {
91                                        eta_i: fresnel.eta_i,
92                                        eta_t: fresnel.eta_t,
93                                    })
94                                }
95                                _ => Fresnel::NoOp(FresnelNoOp {}),
96                            };
97                            bsdf1.add(Bxdf::SpecRefl(SpecularReflection::new(
98                                bxdf.r,
99                                fresnel,
100                                bxdf.sc_opt,
101                            )))
102                        }
103                        Bxdf::SpecTrans(bxdf) => {
104                            bsdf1.add(Bxdf::SpecTrans(SpecularTransmission::new(
105                                bxdf.t,
106                                bxdf.eta_a,
107                                bxdf.eta_b,
108                                bxdf.mode,
109                                bxdf.sc_opt,
110                            )))
111                        }
112                        Bxdf::FresnelSpec(bxdf) => {
113                            bsdf1.add(Bxdf::FresnelSpec(FresnelSpecular::new(
114                                bxdf.r,
115                                bxdf.t,
116                                bxdf.eta_a,
117                                bxdf.eta_b,
118                                bxdf.mode,
119                                bxdf.sc_opt,
120                            )))
121                        }
122                        Bxdf::LambertianRefl(bxdf) => bsdf1.add(Bxdf::LambertianRefl(
123                            LambertianReflection::new(bxdf.r, bxdf.sc_opt),
124                        )),
125                        Bxdf::LambertianTrans(bxdf) => bsdf1.add(Bxdf::LambertianTrans(
126                            LambertianTransmission::new(bxdf.t, bxdf.sc_opt),
127                        )),
128                        Bxdf::OrenNayarRefl(bxdf) => bsdf1.add(Bxdf::OrenNayarRefl(OrenNayar {
129                            r: bxdf.r,
130                            a: bxdf.a,
131                            b: bxdf.b,
132                            sc_opt: bxdf.sc_opt,
133                        })),
134                        Bxdf::MicrofacetRefl(bxdf) => {
135                            let distribution = match &bxdf.distribution {
136                                MicrofacetDistribution::Beckmann(distribution) => {
137                                    MicrofacetDistribution::Beckmann(BeckmannDistribution {
138                                        alpha_x: distribution.alpha_x,
139                                        alpha_y: distribution.alpha_y,
140                                        sample_visible_area: distribution.sample_visible_area,
141                                    })
142                                }
143                                MicrofacetDistribution::TrowbridgeReitz(distribution) => {
144                                    MicrofacetDistribution::TrowbridgeReitz(
145                                        TrowbridgeReitzDistribution {
146                                            alpha_x: distribution.alpha_x,
147                                            alpha_y: distribution.alpha_y,
148                                            sample_visible_area: distribution.sample_visible_area,
149                                        },
150                                    )
151                                }
152                                MicrofacetDistribution::DisneyMicrofacet(distribution) => {
153                                    MicrofacetDistribution::DisneyMicrofacet(
154                                        DisneyMicrofacetDistribution::new(
155                                            distribution.inner.alpha_x,
156                                            distribution.inner.alpha_y,
157                                        ),
158                                    )
159                                }
160                            };
161                            let fresnel = match &bxdf.fresnel {
162                                Fresnel::Conductor(fresnel) => {
163                                    Fresnel::Conductor(FresnelConductor {
164                                        eta_i: fresnel.eta_i,
165                                        eta_t: fresnel.eta_t,
166                                        k: fresnel.k,
167                                    })
168                                }
169                                Fresnel::Dielectric(fresnel) => {
170                                    Fresnel::Dielectric(FresnelDielectric {
171                                        eta_i: fresnel.eta_i,
172                                        eta_t: fresnel.eta_t,
173                                    })
174                                }
175                                _ => Fresnel::NoOp(FresnelNoOp {}),
176                            };
177                            bsdf1.add(Bxdf::MicrofacetRefl(MicrofacetReflection::new(
178                                bxdf.r,
179                                distribution,
180                                fresnel,
181                                bxdf.sc_opt,
182                            )))
183                        }
184                        Bxdf::MicrofacetTrans(bxdf) => {
185                            let distribution = match &bxdf.distribution {
186                                MicrofacetDistribution::Beckmann(distribution) => {
187                                    MicrofacetDistribution::Beckmann(BeckmannDistribution {
188                                        alpha_x: distribution.alpha_x,
189                                        alpha_y: distribution.alpha_y,
190                                        sample_visible_area: distribution.sample_visible_area,
191                                    })
192                                }
193                                MicrofacetDistribution::TrowbridgeReitz(distribution) => {
194                                    MicrofacetDistribution::TrowbridgeReitz(
195                                        TrowbridgeReitzDistribution {
196                                            alpha_x: distribution.alpha_x,
197                                            alpha_y: distribution.alpha_y,
198                                            sample_visible_area: distribution.sample_visible_area,
199                                        },
200                                    )
201                                }
202                                MicrofacetDistribution::DisneyMicrofacet(distribution) => {
203                                    MicrofacetDistribution::DisneyMicrofacet(
204                                        DisneyMicrofacetDistribution::new(
205                                            distribution.inner.alpha_x,
206                                            distribution.inner.alpha_y,
207                                        ),
208                                    )
209                                }
210                            };
211                            bsdf1.add(Bxdf::MicrofacetTrans(MicrofacetTransmission::new(
212                                bxdf.t,
213                                distribution,
214                                bxdf.eta_a,
215                                bxdf.eta_b,
216                                bxdf.mode,
217                                bxdf.sc_opt,
218                            )))
219                        }
220                        Bxdf::FresnelBlnd(bxdf) => {
221                            let mut distrib: Option<MicrofacetDistribution> = None;
222                            if let Some(distribution) = &bxdf.distribution {
223                                distrib = match &distribution {
224                                    MicrofacetDistribution::Beckmann(distribution) => Some(
225                                        MicrofacetDistribution::Beckmann(BeckmannDistribution {
226                                            alpha_x: distribution.alpha_x,
227                                            alpha_y: distribution.alpha_y,
228                                            sample_visible_area: distribution.sample_visible_area,
229                                        }),
230                                    ),
231                                    MicrofacetDistribution::TrowbridgeReitz(distribution) => {
232                                        Some(MicrofacetDistribution::TrowbridgeReitz(
233                                            TrowbridgeReitzDistribution {
234                                                alpha_x: distribution.alpha_x,
235                                                alpha_y: distribution.alpha_y,
236                                                sample_visible_area: distribution
237                                                    .sample_visible_area,
238                                            },
239                                        ))
240                                    }
241                                    MicrofacetDistribution::DisneyMicrofacet(distribution) => {
242                                        Some(MicrofacetDistribution::DisneyMicrofacet(
243                                            DisneyMicrofacetDistribution::new(
244                                                distribution.inner.alpha_x,
245                                                distribution.inner.alpha_y,
246                                            ),
247                                        ))
248                                    }
249                                }
250                            }
251                            bsdf1.add(Bxdf::FresnelBlnd(FresnelBlend::new(
252                                bxdf.rd,
253                                bxdf.rs,
254                                distrib,
255                                bxdf.sc_opt,
256                            )))
257                        }
258                        Bxdf::Fourier(bxdf) => bsdf1.add(Bxdf::Fourier(FourierBSDF::new(
259                            bxdf.bsdf_table.clone(),
260                            bxdf.mode,
261                            bxdf.sc_opt,
262                        ))),
263                        Bxdf::Bssrdf(bxdf) => bsdf1.add(Bxdf::Bssrdf(SeparableBssrdfAdapter {
264                            bssrdf: bxdf.bssrdf.clone(),
265                            mode: bxdf.mode,
266                            eta2: bxdf.eta2,
267                        })),
268                        Bxdf::DisDiff(bxdf) => {
269                            bsdf1.add(Bxdf::DisDiff(DisneyDiffuse::new(bxdf.r, bxdf.sc_opt)))
270                        }
271                        Bxdf::DisSS(bxdf) => bsdf1.add(Bxdf::DisSS(DisneyFakeSS::new(
272                            bxdf.r,
273                            bxdf.roughness,
274                            bxdf.sc_opt,
275                        ))),
276                        Bxdf::DisRetro(bxdf) => bsdf1.add(Bxdf::DisRetro(DisneyRetro::new(
277                            bxdf.r,
278                            bxdf.roughness,
279                            bxdf.sc_opt,
280                        ))),
281                        Bxdf::DisSheen(bxdf) => {
282                            bsdf1.add(Bxdf::DisSheen(DisneySheen::new(bxdf.r, bxdf.sc_opt)))
283                        }
284                        Bxdf::DisClearCoat(bxdf) => bsdf1.add(Bxdf::DisClearCoat(
285                            DisneyClearCoat::new(bxdf.weight, bxdf.gloss, bxdf.sc_opt),
286                        )),
287                        Bxdf::Hair(bxdf) => bsdf1.add(Bxdf::Hair(HairBSDF {
288                            h: bxdf.h,
289                            gamma_o: bxdf.gamma_o,
290                            eta: bxdf.eta,
291                            sigma_a: bxdf.sigma_a,
292                            beta_m: bxdf.beta_m,
293                            beta_n: bxdf.beta_n,
294                            v: bxdf.v,
295                            s: bxdf.s,
296                            sin_2k_alpha: bxdf.sin_2k_alpha,
297                            cos_2k_alpha: bxdf.cos_2k_alpha,
298                            sc_opt: bxdf.sc_opt,
299                        })),
300                    };
301                }
302            }
303        }
304    }
305}