1pub mod sampling {
4 use std::f32::consts::TAU;
5
6 use glam::*;
7
8 #[inline(always)]
9 pub fn uhash(x: u32) -> u32 {
10 let mut x = x ^ (x >> 16);
12 x = x.overflowing_mul(0x7feb352d).0;
13 x = x ^ (x >> 15);
14 x = x.overflowing_mul(0x846ca68b).0;
15 x = x ^ (x >> 16);
16 x
17 }
18
19 pub fn hash_f32_vec(v: &[f32]) -> u32 {
20 v.iter()
21 .map(|&f| uhash(f.to_bits()))
22 .fold(0, |acc, h| acc ^ h)
23 }
24
25 pub fn hash_vec3a_vec(v: &[Vec3A]) -> u32 {
26 v.iter()
27 .flat_map(|v| [v.x, v.y, v.z])
28 .map(|f| uhash(f.to_bits()))
29 .fold(0, |acc, h| acc ^ h)
30 }
31
32 #[inline(always)]
33 pub fn uhash2(a: u32, b: u32) -> u32 {
34 uhash((a.overflowing_mul(1597334673).0) ^ (b.overflowing_mul(3812015801).0))
35 }
36
37 #[inline(always)]
38 pub fn unormf(n: u32) -> f32 {
39 n as f32 * (1.0 / 0xffffffffu32 as f32)
40 }
41
42 #[inline(always)]
43 pub fn hash_noise(coord: UVec2, frame: u32) -> f32 {
44 let urnd = uhash2(coord.x, (coord.y << 11) + frame);
45 unormf(urnd)
46 }
47
48 #[inline(always)]
50 pub fn build_orthonormal_basis(n: Vec3A) -> Mat3 {
51 let sign = n.z.signum();
52 let a = -1.0 / (sign + n.z);
53 let b = n.x * n.y * a;
54
55 mat3(
56 vec3(1.0 + sign * n.x * n.x * a, sign * b, -sign * n.x),
57 vec3(b, sign + n.y * n.y * a, -n.y),
58 n.into(),
59 )
60 }
61
62 #[inline(always)]
63 pub fn cosine_sample_hemisphere(urand: Vec2) -> Vec3A {
64 let r = urand.x.sqrt();
65 let theta = urand.y * TAU;
66 vec3a(
67 r * theta.cos(),
68 r * theta.sin(),
69 0.0f32.max(1.0 - urand.x).sqrt(),
70 )
71 }
72
73 #[inline(always)]
74 pub fn uniform_sample_sphere(urand: Vec2) -> Vec3A {
75 let z = 1.0 - 2.0 * urand.x;
76 let r = (1.0 - z * z).sqrt();
77 let theta = urand.y * TAU;
78 vec3a(r * theta.cos(), r * theta.sin(), z)
79 }
80
81 #[inline(always)]
82 pub fn uniform_sample_cone(urand: Vec2, cos_theta_max: f32) -> Vec3A {
83 let cos_theta = (1.0 - urand.x) + urand.x * cos_theta_max;
84 let sin_theta = (1.0 - cos_theta * cos_theta).clamp(0.0, 1.0).sqrt();
85 let phi: f32 = urand.y * TAU;
86 vec3a(sin_theta * phi.cos(), sin_theta * phi.sin(), cos_theta)
87 }
88
89 #[inline(always)]
90 pub fn smoothstep(e0: f32, e1: f32, x: f32) -> f32 {
91 let t = ((x - e0) / (e1 - e0)).clamp(0.0, 1.0);
92 t * t * (3.0 - 2.0 * t)
93 }
94
95 #[inline(always)]
96 fn cubic(v0: f32, v1: f32, v2: f32, v3: f32, x: f32) -> f32 {
97 let p = (v3 - v2) - (v0 - v1);
98 let q = (v0 - v1) - p;
99 let r = v2 - v0;
100 let s = v1;
101 p * x.powi(3) + q * x.powi(2) + r * x + s
102 }
103
104 #[inline(always)]
105 pub fn bicubic_noise(coord: Vec2, seed: u32) -> f32 {
106 let ix = coord.x.floor() as u32;
107 let iy = coord.y.floor() as u32;
108 let fx = coord.x - ix as f32;
109 let fy = coord.y - iy as f32;
110 fn cubic_col(ix: u32, iy: u32, j: u32, seed: u32, fx: f32) -> f32 {
111 cubic(
112 hash_noise(uvec2(ix, iy + j), seed),
113 hash_noise(uvec2(ix + 1, iy + j), seed),
114 hash_noise(uvec2(ix + 2, iy + j), seed),
115 hash_noise(uvec2(ix + 3, iy + j), seed),
116 fx,
117 )
118 }
119 cubic(
120 cubic_col(ix, iy, 0, seed, fx),
121 cubic_col(ix, iy, 1, seed, fx),
122 cubic_col(ix, iy, 2, seed, fx),
123 cubic_col(ix, iy, 3, seed, fx),
124 fy,
125 )
126 }
127
128 pub fn somewhat_boring_display_transform(col: Vec3A) -> Vec3A {
130 fn rgb_to_ycbcr(col: Vec3A) -> Vec3A {
131 Mat3A {
132 x_axis: vec3a(0.2126, -0.1146, 0.5),
133 y_axis: vec3a(0.7152, -0.3854, -0.4542),
134 z_axis: vec3a(0.0722, 0.5, -0.0458),
135 } * col
136 }
137
138 fn tonemap_curve(v: f32) -> f32 {
139 1.0 - (-v).exp()
140 }
141
142 fn tonemap_curve3(v: Vec3A) -> Vec3A {
143 1.0 - (-v).exp()
144 }
145
146 fn tonemapping_luminance(col: Vec3A) -> f32 {
147 col.dot(vec3a(0.2126, 0.7152, 0.0722))
148 }
149
150 let mut col = col;
151 let ycbcr = rgb_to_ycbcr(col);
152
153 let bt = tonemap_curve(ycbcr.yz().length() * 2.4);
154 let mut desat = (bt - 0.7) * 0.8;
155 desat *= desat;
156
157 let desat_col = col.lerp(ycbcr.xxx(), desat);
158
159 let tm_luma = tonemap_curve(ycbcr.x);
160 let tm0 = col * tm_luma / tonemapping_luminance(col).max(1e-5);
161 let final_mult = 0.97;
162 let tm1 = tonemap_curve3(desat_col);
163
164 col = tm0.lerp(tm1, bt * bt);
165
166 col * final_mult
167 }
168}
169
170pub mod geometry {
171 use crate::{Triangle, test_util::sampling::bicubic_noise};
172 use glam::*;
173
174 #[inline(always)]
175 const fn vec(a: f32, b: f32, c: f32) -> Vec3A {
176 Vec3A::new(a, b, c)
177 }
178 #[inline(always)]
179 const fn tri(v0: Vec3A, v1: Vec3A, v2: Vec3A) -> Triangle {
180 Triangle { v0, v1, v2 }
181 }
182
183 pub const CUBE: [Triangle; 12] = [
185 tri(vec(-1., 1., -1.), vec(1., 1., 1.), vec(1., 1., -1.)),
186 tri(vec(1., 1., 1.), vec(-1., -1., 1.), vec(1., -1., 1.)),
187 tri(vec(-1., 1., 1.), vec(-1., -1., -1.), vec(-1., -1., 1.)),
188 tri(vec(1., -1., -1.), vec(-1., -1., 1.), vec(-1., -1., -1.)),
189 tri(vec(1., 1., -1.), vec(1., -1., 1.), vec(1., -1., -1.)),
190 tri(vec(-1., 1., -1.), vec(1., -1., -1.), vec(-1., -1., -1.)),
191 tri(vec(-1., 1., -1.), vec(-1., 1., 1.), vec(1., 1., 1.)),
192 tri(vec(1., 1., 1.), vec(-1., 1., 1.), vec(-1., -1., 1.)),
193 tri(vec(-1., 1., 1.), vec(-1., 1., -1.), vec(-1., -1., -1.)),
194 tri(vec(1., -1., -1.), vec(1., -1., 1.), vec(-1., -1., 1.)),
195 tri(vec(1., 1., -1.), vec(1., 1., 1.), vec(1., -1., 1.)),
196 tri(vec(-1., 1., -1.), vec(1., 1., -1.), vec(1., -1., -1.)),
197 ];
198
199 pub const PLANE: [Triangle; 2] = [
201 tri(vec(1., 0., 1.), vec(-1., 0., -1.), vec(-1., 0., 1.)),
202 tri(vec(1., 0., 1.), vec(1., 0., -1.), vec(-1., 0., -1.)),
203 ];
204
205 pub fn icosphere(subdivisions: u32) -> Vec<Triangle> {
207 let phi = (1.0 + 5.0_f32.sqrt()) / 2.0; let (a, b, c, d, e) = (1.0, -1.0, 0.0, phi, -phi);
209
210 #[rustfmt::skip]
211 let mut p = [vec(b,d,c),vec(a,d,c),vec(b,e,c),vec(a,e,c),vec(c,b,d),vec(c,a,d),vec(c,b,e),vec(c,a,e),vec(d,c,b),vec(d,c,a),vec(e,c,b),vec(e,c,a)];
212 p.iter_mut().for_each(|v| *v = v.normalize());
213
214 let mut tris = vec![
215 tri(p[0], p[11], p[5]),
216 tri(p[0], p[5], p[1]),
217 tri(p[0], p[1], p[7]),
218 tri(p[0], p[7], p[10]),
219 tri(p[0], p[10], p[11]),
220 tri(p[1], p[5], p[9]),
221 tri(p[5], p[11], p[4]),
222 tri(p[11], p[10], p[2]),
223 tri(p[10], p[7], p[6]),
224 tri(p[7], p[1], p[8]),
225 tri(p[3], p[9], p[4]),
226 tri(p[3], p[4], p[2]),
227 tri(p[3], p[2], p[6]),
228 tri(p[3], p[6], p[8]),
229 tri(p[3], p[8], p[9]),
230 tri(p[4], p[9], p[5]),
231 tri(p[2], p[4], p[11]),
232 tri(p[6], p[2], p[10]),
233 tri(p[8], p[6], p[7]),
234 tri(p[9], p[8], p[1]),
235 ];
236
237 (0..subdivisions).for_each(|_| {
238 let mut new_tris = Vec::new();
239 tris.iter().for_each(|t| {
240 let mid01 = ((t.v0 + t.v1) * 0.5).normalize();
241 let mid12 = ((t.v1 + t.v2) * 0.5).normalize();
242 let mid20 = ((t.v2 + t.v0) * 0.5).normalize();
243 new_tris.push(tri(t.v0, mid01, mid20));
244 new_tris.push(tri(t.v1, mid12, mid01));
245 new_tris.push(tri(t.v2, mid20, mid12));
246 new_tris.push(tri(mid01, mid12, mid20));
247 });
248 tris = new_tris;
249 });
250
251 tris
252 }
253
254 pub fn height_to_triangles<F>(
256 height_map: F,
257 x_resolution: usize,
258 z_resolution: usize,
259 ) -> Vec<Triangle>
260 where
261 F: Fn(usize, usize) -> f32,
262 {
263 let mut triangles = Vec::new();
264
265 for z in 0..z_resolution {
267 for x in 0..x_resolution {
268 let fx = (x as f32 / x_resolution as f32) * 2.0 - 1.0;
270 let fz = (z as f32 / z_resolution as f32) * 2.0 - 1.0;
271 let fx2 = ((x + 1) as f32 / x_resolution as f32) * 2.0 - 1.0;
272 let fz2 = ((z + 1) as f32 / z_resolution as f32) * 2.0 - 1.0;
273
274 let v00 = vec(fx, height_map(x, z), fz);
276 let v10 = vec(fx2, height_map(x + 1, z), fz);
277 let v01 = vec(fx, height_map(x, z + 1), fz2);
278 let v11 = vec(fx2, height_map(x + 1, z + 1), fz2);
279
280 triangles.push(tri(v00, v01, v10));
282 triangles.push(tri(v10, v01, v11));
283 }
284 }
285
286 triangles
287 }
288
289 pub fn demoscene(terrain_res: usize, seed: u32) -> Vec<Triangle> {
291 let height_map = |x: usize, y: usize| -> f32 {
292 let coord = vec2(x as f32, y as f32) / terrain_res as f32;
293 let (mut cs, mut ns) = (1.579, 0.579);
294 (1..17)
295 .map(|i| {
296 (cs, ns) = (cs * 1.579, ns * -0.579);
297 bicubic_noise(coord * cs, seed + i) * ns
298 })
299 .sum::<f32>()
300 * (1.0 - coord.y).powf(0.579)
301 + (1.0 - coord.y).powf(1.579) * 0.579
302 };
303 height_to_triangles(height_map, terrain_res, terrain_res)
304 }
305}