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
83
84
85
86
87
use crate::prelude::*;
#[allow(unused)]
pub trait Scene : Sync + Send {
fn new() -> Self where Self: Sized;
fn background(&self, ray: &Ray) -> F3;
fn closest_hit(&self, ray: &Ray, state: &mut State, light: &mut LightSampleRec) -> bool;
fn any_hit(&self, ray: &Ray, max_dist: F) -> bool;
fn camera(&self) -> &Box<dyn Camera3D>;
fn number_of_lights(&self) -> usize;
fn light_at(&self, index: usize) -> &AnalyticalLight;
fn recursion_depth(&self) -> u16 {
4
}
fn to_linear(&self, c: F3) -> F3 {
F3::new(c.x.powf(2.2), c.y.powf(2.2), c.z.powf(2.2))
}
fn sample_lights(&self, ray: &Ray, state: &mut State, light_sample: &mut LightSampleRec, lights: &Vec<AnalyticalLight>) -> bool {
fn sphere(ray: &Ray, center: F3, radius: F) -> Option<F> {
let l = center - ray.origin;
let tca = l.dot(&ray.direction);
let d2 = l.dot(&l) - tca * tca;
let radius2 = radius * radius;
if d2 > radius2 {
return None;
}
let thc = (radius2 - d2).sqrt();
let mut t0 = tca - thc;
let mut t1 = tca + thc;
if t0 > t1 {
std::mem::swap(&mut t0, &mut t1);
}
if t0 < 0.0 {
t0 = t1;
if t0 < 0.0 {
return None;
}
}
Some(t0)
}
let mut hit = false;
let mut dist = state.hit_dist;
for light in lights {
if light.light.light_type == LightType::Spherical {
if let Some(d) = sphere(ray, light.light.position, light.light.radius) {
if d < dist {
dist = d;
let hit_point = ray.at(&d);
let cos_theta = dot(&-ray.direction, &normalize(&(hit_point - light.light.position)));
light_sample.pdf = (dist * dist) / (light.light.area * cos_theta * 0.5);
light_sample.emission = light.light.emission;
state.is_emitter = true;
state.hit_dist = d;
hit = true;
}
}
}
}
hit
}
}