pbrt_r3/shapes/
alphamask.rs

1use crate::core::prelude::*;
2
3use std::sync::Arc;
4
5#[derive(Clone)]
6pub enum AlphaMaskInfo {
7    Texture { texture: Arc<dyn Texture<Float>> },
8    Value { value: Float },
9}
10
11pub struct AlphaMaskShape {
12    shape: Arc<dyn Shape>,
13    test_intersection: bool,
14    test_intersection_p: bool,
15    alpha_mask_texture: Option<Arc<dyn Texture<Float>>>,
16    shadow_alpha_mask_texture: Option<Arc<dyn Texture<Float>>>,
17}
18
19impl AlphaMaskShape {
20    pub fn new(
21        shape: &Arc<dyn Shape>,
22        alpha_mask_info: &Option<AlphaMaskInfo>,
23        shadow_alpha_mask_info: &Option<AlphaMaskInfo>,
24    ) -> Self {
25        let mut test_intersection = true;
26        let mut test_intersection_p = true;
27        let mut alpha_mask_texture = None;
28        let mut shadow_alpha_mask_texture = None;
29        if let Some(info) = alpha_mask_info.as_ref() {
30            match info {
31                AlphaMaskInfo::Texture { texture } => {
32                    alpha_mask_texture = Some(Arc::clone(texture));
33                }
34                AlphaMaskInfo::Value { value: alpha } => {
35                    if *alpha <= 0.0 {
36                        test_intersection = false;
37                        test_intersection_p = false;
38                    }
39                }
40            }
41        }
42        if let Some(info) = shadow_alpha_mask_info.as_ref() {
43            match info {
44                AlphaMaskInfo::Texture { texture } => {
45                    shadow_alpha_mask_texture = Some(Arc::clone(texture));
46                }
47                AlphaMaskInfo::Value { value: alpha } => {
48                    if *alpha <= 0.0 {
49                        test_intersection_p = false;
50                    }
51                }
52            }
53        }
54        AlphaMaskShape {
55            shape: Arc::clone(shape),
56            test_intersection,
57            test_intersection_p,
58            alpha_mask_texture,
59            shadow_alpha_mask_texture,
60        }
61    }
62}
63
64impl Shape for AlphaMaskShape {
65    fn object_bound(&self) -> Bounds3f {
66        let shape = self.shape.as_ref();
67        return shape.object_bound();
68    }
69    fn world_bound(&self) -> Bounds3f {
70        let shape = self.shape.as_ref();
71        return shape.world_bound();
72    }
73    fn intersect(&self, r: &Ray) -> Option<(Float, SurfaceInteraction)> {
74        if self.test_intersection {
75            let shape = self.shape.as_ref();
76            let t_max = r.t_max.get();
77            if let Some((t, si)) = shape.intersect(r) {
78                if let Some(mask) = self.alpha_mask_texture.as_ref() {
79                    let a = mask.evaluate(&si);
80                    if a <= 0.0 {
81                        r.t_max.set(t_max);
82                        return None;
83                    }
84                }
85                return Some((t, si));
86            }
87        }
88        return None;
89    }
90
91    fn intersect_p(&self, r: &Ray) -> bool {
92        if self.test_intersection_p {
93            let shape = self.shape.as_ref();
94            let t_max = r.t_max.get();
95            if let Some((_, si)) = shape.intersect(r) {
96                r.t_max.set(t_max);
97                if let Some(mask) = self.alpha_mask_texture.as_ref() {
98                    let a = mask.evaluate(&si);
99                    if a <= 0.0 {
100                        return false;
101                    }
102                }
103                if let Some(mask) = self.shadow_alpha_mask_texture.as_ref() {
104                    let a = mask.evaluate(&si);
105                    if a <= 0.0 {
106                        return false;
107                    }
108                }
109                return true;
110            }
111        }
112        return false;
113    }
114
115    fn area(&self) -> Float {
116        let shape = self.shape.as_ref();
117        return shape.area();
118    }
119
120    fn pdf(&self, inter: &Interaction) -> Float {
121        // Ignore any alpha textures used for trimming the shape when performing
122        // this intersection. Hack for the "San Miguel" scene, where this is used
123        // to make an invisible area light.
124        let shape = self.shape.as_ref();
125        return shape.pdf(inter);
126    }
127
128    fn pdf_from(&self, inter: &Interaction, wi: &Vector3f) -> Float {
129        let shape = self.shape.as_ref();
130        return shape.pdf_from(inter, wi);
131    }
132
133    fn sample(&self, u: &Point2f) -> Option<(Interaction, Float)> {
134        let shape = self.shape.as_ref();
135        return shape.sample(u);
136    }
137
138    fn sample_from(&self, inter: &Interaction, u: &Point2f) -> Option<(Interaction, Float)> {
139        let shape = self.shape.as_ref();
140        return shape.sample_from(inter, u);
141    }
142
143    fn solid_angle(&self, p: &Point3f, n_samples: i32) -> Float {
144        let shape = self.shape.as_ref();
145        return shape.solid_angle(p, n_samples);
146    }
147}