ray_tracing_core/
random.rs

1use crate::types::{ColorRGB, FSize, Point3, TextureCoordinate, Vector3};
2use core::f64::consts::PI;
3use rand::Rng;
4use std::ops::Range;
5
6/// Generate random axis
7pub fn generate_axis() -> usize {
8    rand::thread_rng().gen_range(0..3)
9}
10
11/// Generate random axis
12pub fn generate_from_range(range: Range<usize>) -> usize {
13    rand::thread_rng().gen_range(range)
14}
15
16/// Generate a single floating point value in the range [0.0, 1.0]
17pub fn generate_size() -> FSize {
18    let value: FSize = rand::thread_rng().gen();
19    value
20}
21
22/// Generate a single floating point value in a specific range
23pub fn generate_range(range: Range<FSize>) -> FSize {
24    let value: FSize = rand::thread_rng().gen_range(range);
25    value
26}
27
28/// Generate a floating point tuple in a specific range
29pub fn generate_range2d(range: &Range<(FSize, FSize)>) -> (FSize, FSize) {
30    (
31        generate_range(range.start.0..range.end.0),
32        generate_range(range.start.1..range.end.1),
33    )
34}
35
36/// Generate a single floating point value in range [-1.0, 1.0]
37pub fn generate_unit() -> FSize {
38    let value: FSize = rand::thread_rng().gen();
39    value * 2.0 - 1.0
40}
41
42/// Generate a single floating point value in range [0.0, 1.0]
43pub fn generate_unit_abs() -> FSize {
44    let value: FSize = rand::thread_rng().gen();
45    value
46}
47
48/// Generate a random vector, whose length is less than or equal 1.0
49pub fn generate_unit_sphere() -> Vector3 {
50    loop {
51        let v = generate_vector3();
52        if glm::dot(v, v) < 1.0 {
53            break v;
54        }
55    }
56}
57
58/// Generate a random vector
59pub fn generate_cosine_direction() -> Vector3 {
60    let r1 = generate_size();
61    let r2 = generate_size();
62    let z = FSize::sqrt(1.0 - r2);
63    let phi = 2.0 * PI * r1;
64    let x = FSize::cos(phi) * 2.0 * FSize::sqrt(r2);
65    let y = FSize::sin(phi) * 2.0 * FSize::sqrt(r2);
66    Vector3::new(x, y, z)
67}
68
69/// Generate a random vector
70pub fn generate_to_sphere(radius: FSize, distance_squared: FSize) -> Vector3 {
71    let r1 = generate_size();
72    let r2 = generate_size();
73    let z = 1.0 + r2 * (FSize::sqrt(1.0 - radius * radius / distance_squared) - 1.0);
74    let phi = 2.0 * PI * r1;
75    let x = FSize::cos(phi) * FSize::sqrt(1.0 - z * z);
76    let y = FSize::sin(phi) * FSize::sqrt(1.0 - z * z);
77    Vector3::new(x, y, z)
78}
79
80/// Generate a random RGB color
81pub fn generate_rgb() -> ColorRGB {
82    ColorRGB::new(
83        generate_unit_abs(),
84        generate_unit_abs(),
85        generate_unit_abs(),
86    )
87}
88
89/// Generate a random vector
90pub fn generate_vector3() -> Vector3 {
91    Vector3::new(generate_unit(), generate_unit(), generate_unit())
92}
93
94/// Generate a random point
95pub fn generate_point3() -> Point3 {
96    Point3::new(generate_unit(), generate_unit(), generate_unit())
97}
98
99/// Generate a texture coordinate
100pub fn generate_uv() -> TextureCoordinate {
101    TextureCoordinate::from_uv(generate_unit_abs(), generate_unit_abs())
102}
103
104#[cfg(test)]
105mod random_test {
106    use super::*;
107    use crate::test;
108
109    #[test]
110    fn generate_size_test() {
111        let value = generate_size();
112        test::assert_in_range(value, 0.0..1.0);
113    }
114
115    #[test]
116    fn generate_range_test() {
117        let value = generate_range(-1.0..1.0);
118        test::assert_in_range(value, -1.0..1.0);
119    }
120
121    #[test]
122    fn generate_unit_test() {
123        let value = generate_unit();
124        test::assert_in_range(value, -1.0..1.0);
125    }
126
127    #[test]
128    fn generate_unit_abs_test() {
129        let value = generate_unit_abs();
130        test::assert_in_range(value, 0.0..1.0);
131    }
132
133    #[test]
134    fn generate_unit_sphere_test() {
135        let v = generate_unit_sphere();
136        for i in 0..3 {
137            test::assert_in_range(v[i], -1.0..1.0);
138        }
139        assert!(glm::length(v) <= 1.0);
140    }
141
142    #[test]
143    fn generate_rgb_test() {
144        let c = generate_rgb();
145        for i in 0..3 {
146            test::assert_in_range(c[i], 0.0..1.0);
147        }
148    }
149
150    #[test]
151    fn generate_vector_test() {
152        let v = generate_vector3();
153        for i in 0..3 {
154            test::assert_in_range(v[i], -1.0..1.0);
155        }
156    }
157
158    #[test]
159    fn generate_point_test() {
160        let p = generate_point3();
161        for i in 0..3 {
162            test::assert_in_range(p[i], -1.0..1.0);
163        }
164    }
165
166    #[test]
167    fn generate_uv_test() {
168        let uv = generate_uv();
169        test::assert_in_range(uv.u, 0.0..1.0);
170        test::assert_in_range(uv.v, 0.0..1.0);
171    }
172}