pbrt_r3/core/shape/
shape.rs1use 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 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 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}