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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
use crate::camera::Camera;
use crate::hittable::Hittable;
use crate::ray::Ray;
use crate::scene::Scene;
use crate::utils::print_colour;
use cgmath::prelude::*;
use cgmath::{vec3, Vector3};
use rand::prelude::*;
use rayon::prelude::*;
use std::f64::INFINITY;
fn ray_colour(rng: &mut ThreadRng, ray: &Ray, scene: &Scene, depth: i32) -> Vector3<f64> {
if depth <= 0 {
return vec3(0.0, 0.0, 0.0);
}
if let Some(t) = scene.is_hit(ray, 0.001, INFINITY) {
if let Some(nray) = t.material.scatter(rng, ray, &t) {
ray_colour(rng, &nray.ray, scene, depth - 1).mul_element_wise(nray.attenuation)
} else {
vec3(0.0, 0.0, 0.0)
}
} else {
let t = 0.5 * (ray.dir.normalize().y + 1.0);
(1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0)
}
}
pub fn thread_render(
world: &Scene,
camera: &Camera,
rng: &mut ThreadRng,
image_height: i32,
image_width: i32,
samples: i32,
max_depth: i32,
i: i32,
j: i32,
) -> Vector3<f64> {
let mut colour = vec3(0.0, 0.0, 0.0);
for _ in 0..samples {
let ru: f64 = rng.gen();
let rv: f64 = rng.gen();
let u = (i as f64 + ru) / image_width as f64;
let v = ((image_height - 1 - j) as f64 + rv) / image_height as f64;
let ray = camera.get_ray(rng, u, v);
colour += ray_colour(rng, &ray, &world, max_depth);
}
colour
}
pub fn render(
world: &Scene,
camera: &Camera,
image_height: i32,
image_width: i32,
samples: i32,
max_depth: i32,
threads: i32,
) {
for j in 0..image_height {
eprint!("\rScanlines: {:3} / {:3}", j + 1, image_height);
for i in 0..image_width {
let colours = (0..threads).into_par_iter().map(|_| {
let mut trng = thread_rng();
thread_render(
world,
camera,
&mut trng,
image_height,
image_width,
samples / threads,
max_depth,
i,
j,
)
});
let colour = colours.sum::<Vector3<f64>>();
print_colour(&colour, samples);
}
}
}
|