pbrt_r3/core/reflection/
math.rs

1use crate::core::base::*;
2
3// BSDF Inline Functions
4#[inline]
5pub fn cos_theta(w: &Vector3f) -> Float {
6    return w.z;
7}
8
9#[inline]
10pub fn cos_2_theta(w: &Vector3f) -> Float {
11    return w.z * w.z;
12}
13
14#[inline]
15pub fn abs_cos_theta(w: &Vector3f) -> Float {
16    return Float::abs(w.z);
17}
18
19#[inline]
20pub fn sin_2_theta(w: &Vector3f) -> Float {
21    return Float::max(0.0, 1.0 - cos_2_theta(w));
22}
23
24#[inline]
25pub fn sin_theta(w: &Vector3f) -> Float {
26    return Float::sqrt(sin_2_theta(w));
27}
28
29#[inline]
30pub fn tan_theta(w: &Vector3f) -> Float {
31    return sin_theta(w) / cos_theta(w);
32}
33
34#[inline]
35pub fn tan_2_theta(w: &Vector3f) -> Float {
36    return sin_2_theta(w) / cos_2_theta(w);
37}
38
39#[inline]
40pub fn cos_phi(w: &Vector3f) -> Float {
41    let sin = sin_theta(w);
42    return if sin == 0.0 {
43        1.0
44    } else {
45        Float::clamp(w.x / sin, -1.0, 1.0)
46    };
47}
48
49#[inline]
50pub fn sin_phi(w: &Vector3f) -> Float {
51    let sin = sin_theta(w);
52    return if sin == 0.0 {
53        0.0
54    } else {
55        Float::clamp(w.y / sin, -1.0, 1.0)
56    };
57}
58
59#[inline]
60pub fn cos_2_phi(w: &Vector3f) -> Float {
61    return cos_phi(w) * cos_phi(w);
62}
63
64#[inline]
65pub fn sin_2_phi(w: &Vector3f) -> Float {
66    return sin_phi(w) * sin_phi(w);
67}
68
69#[inline]
70pub fn cos_d_phi(wa: &Vector3f, wb: &Vector3f) -> Float {
71    let waxy = wa.x * wa.x + wa.y * wa.y;
72    let wbxy = wb.x * wb.x + wb.y * wb.y;
73    if waxy <= 0.0 || wbxy <= 0.0 {
74        return 1.0;
75    }
76    return Float::clamp(
77        (wa.x * wb.x + wa.y * wb.y) / Float::sqrt(waxy * wbxy),
78        -1.0,
79        1.0,
80    );
81}
82
83#[inline]
84pub fn reflect(wo: &Vector3f, n: &Vector3f) -> Vector3f {
85    let a = 2.0 * Vector3f::dot(wo, n) * *n;
86    let b = -*wo;
87    return a + b;
88}
89
90#[inline]
91pub fn refract(wi: &Vector3f, n: &Vector3f, eta: Float) -> Option<Vector3f> {
92    // Compute $\cos \theta_\roman{t}$ using Snell's law
93    let cos_theta_i = Vector3f::dot(n, wi);
94    let sin2_theta_i = Float::max(0.0, 1.0 - cos_theta_i * cos_theta_i);
95    let sin2_theta_t = eta * eta * sin2_theta_i;
96    // Handle total internal reflection for transmission
97    if sin2_theta_t >= 1.0 {
98        return None;
99    } else {
100        let cos_theta_t = Float::sqrt(1.0 - sin2_theta_t);
101        let a = eta * -*wi;
102        let b = (eta * cos_theta_i - cos_theta_t) * *n;
103        let wt = a + b;
104        return Some(wt);
105    }
106}
107
108#[inline]
109pub fn same_hemisphere(w: &Vector3f, wp: &Vector3f) -> bool {
110    return w.z * wp.z > 0.0;
111}