pbrt_r3/core/shape/
shape.rs

1use crate::core::base::*;
2use crate::core::geometry::*;
3use crate::core::interaction::*;
4use crate::core::lowdiscrepancy::*;
5
6pub trait Shape {
7    fn object_bound(&self) -> Bounds3f;
8    fn world_bound(&self) -> Bounds3f;
9    /* pbrt-r3:
10    The below functions - intersect/intersect_p had an argument variable "bool testAlphaTexture" in the original code,
11    but since alpha masking has been changed to the responsibility of the class AlphaMaskShape, this variable has been removed. */
12    fn intersect(&self, r: &Ray) -> Option<(Float, SurfaceInteraction)>;
13    fn intersect_p(&self, r: &Ray) -> bool;
14    fn area(&self) -> Float;
15    fn sample(&self, u: &Point2f) -> Option<(Interaction, Float)>;
16    fn pdf(&self, _inter: &Interaction) -> Float {
17        Float::recip(self.area())
18    }
19
20    fn sample_from(&self, ref_: &Interaction, u: &Point2f) -> Option<(Interaction, Float)> {
21        let (intr, pdf) = self.sample(u)?;
22        assert!(intr.is_surface_interaction());
23        let wi = intr.get_p() - ref_.get_p();
24        if wi.length_squared() <= 0.0 {
25            return None;
26        } else {
27            assert!(intr.get_n().length() > 0.0);
28            let wi = wi.normalize();
29            // Convert from area measure, as returned by the Sample() call
30            // above, to solid angle measure.
31            let pdf = pdf * Vector3f::distance_squared(&ref_.get_p(), &intr.get_p())
32                / Vector3f::abs_dot(&intr.get_n(), &-wi);
33            if pdf <= 0.0 || pdf.is_infinite() {
34                return None;
35            }
36            return Some((intr, pdf));
37        }
38    }
39
40    fn pdf_from(&self, inter: &Interaction, wi: &Vector3f) -> Float {
41        let ray = inter.spawn_ray(wi);
42        if let Some((_, isect_light)) = self.intersect(&ray) {
43            assert!(isect_light.n.length() > 0.0);
44
45            let pdf = Vector3f::distance_squared(&inter.get_p(), &isect_light.p)
46                / (Vector3f::abs_dot(&isect_light.n, &(-*wi)) * self.area());
47            if pdf.is_infinite() {
48                return 0.0;
49            }
50            return pdf;
51        } else {
52            return 0.0;
53        }
54    }
55
56    fn solid_angle(&self, p: &Point3f, n_samples: i32) -> Float {
57        let mut it = BaseInteraction::default();
58        it.p = *p;
59        it.wo = Vector3f::new(0.0, 0.0, 1.0);
60        let inter = Interaction::from(it);
61        let mut solid_angle = 0.0;
62        for i in 0..n_samples {
63            let u = Point2f::new(radical_inverse(0, i as u64), radical_inverse(1, i as u64));
64            if let Some((p_shape, pdf)) = self.sample_from(&inter, &u) {
65                let r = Ray::new(p, &(p_shape.get_p() - *p), 0.999, 0.0);
66                if !self.intersect_p(&r) {
67                    solid_angle += 1.0 / pdf
68                }
69            }
70        }
71        return solid_angle / n_samples as Float;
72    }
73}