1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use crate::algebra::{vec2d, vec3d, Transform, Vec2d, Vec3d};
mod rng;
pub use rng::{rng_pcg32, Pcg32, Rng};
pub fn concentric_sample_disk(u: Vec2d) -> Vec2d {
let u = u * 2.0 - 1.0;
if u.x() == 0.0 && u.y() == 0.0 {
return vec2d(0.0, 0.0);
}
if u.x().abs() > u.y().abs() {
let r = u.x();
let theta = std::f64::consts::FRAC_PI_4 * (u.y() / u.x());
vec2d(theta.cos(), theta.sin()) * r
} else {
let r = u.y();
let theta = std::f64::consts::FRAC_PI_2 - std::f64::consts::FRAC_PI_4 * (u.x() / u.y());
vec2d(theta.cos(), theta.sin()) * r
}
}
pub fn uniform_sample_disk(u: Vec2d) -> Vec2d {
let (u1, u2) = u.to_tuple();
let r = u1.sqrt();
let theta = 2.0 * std::f64::consts::PI * u2;
vec2d(theta.cos() * r, theta.sin() * r)
}
pub fn uniform_sample_sphere(u: Vec2d) -> (Vec3d, f64) {
let (u1, u2) = u.to_tuple();
let z = 1.0 - 2.0 * u1;
let r = 0f64.max(1.0 - z * z).sqrt();
let phi = std::f64::consts::PI * 2.0 * u2;
(
vec3d(phi.cos() * r, phi.sin() * r, z),
1.0 / (4.0 * std::f64::consts::PI),
)
}
pub fn uniform_sample_hemisphere(n: Vec3d, u: Vec2d) -> (Vec3d, f64) {
let (mut result, _) = uniform_sample_sphere(u);
if result.dot(n) < 0.0 {
result = -result;
}
(result, 1.0 / (2.0 * std::f64::consts::PI))
}
pub fn cosine_sample_hemisphere(n: Vec3d, u: Vec2d) -> (Vec3d, f64) {
let d = concentric_sample_disk(u);
let z = 0.0f64.max(1.0 - d.x() * d.x() - d.y() * d.y()).sqrt();
let pdf = z * std::f64::consts::FRAC_1_PI;
if vec3d(0.0, 0.0, -1.0).eq(&n) {
return (vec3d(d.x(), d.y(), -z), pdf);
}
let d = vec3d(d.x(), d.y(), z);
let n0 = vec3d(0.0, 0.0, 1.0);
let axis = n0.cross(n).normalize();
let angle = n0.angle_between(n).to_degrees();
let t = Transform::from_rotation_axis(axis, angle);
let d = t.transform_vector3d(d);
(d.normalize(), pdf)
}