ray_tracing_core/
random.rs1use crate::types::{ColorRGB, FSize, Point3, TextureCoordinate, Vector3};
2use core::f64::consts::PI;
3use rand::Rng;
4use std::ops::Range;
5
6pub fn generate_axis() -> usize {
8 rand::thread_rng().gen_range(0..3)
9}
10
11pub fn generate_from_range(range: Range<usize>) -> usize {
13 rand::thread_rng().gen_range(range)
14}
15
16pub fn generate_size() -> FSize {
18 let value: FSize = rand::thread_rng().gen();
19 value
20}
21
22pub fn generate_range(range: Range<FSize>) -> FSize {
24 let value: FSize = rand::thread_rng().gen_range(range);
25 value
26}
27
28pub 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
36pub fn generate_unit() -> FSize {
38 let value: FSize = rand::thread_rng().gen();
39 value * 2.0 - 1.0
40}
41
42pub fn generate_unit_abs() -> FSize {
44 let value: FSize = rand::thread_rng().gen();
45 value
46}
47
48pub 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
58pub 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
69pub 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
80pub fn generate_rgb() -> ColorRGB {
82 ColorRGB::new(
83 generate_unit_abs(),
84 generate_unit_abs(),
85 generate_unit_abs(),
86 )
87}
88
89pub fn generate_vector3() -> Vector3 {
91 Vector3::new(generate_unit(), generate_unit(), generate_unit())
92}
93
94pub fn generate_point3() -> Point3 {
96 Point3::new(generate_unit(), generate_unit(), generate_unit())
97}
98
99pub 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}