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
use crate::{Attribute, Input};
use arctk::{geom::Ray, phys::Crossing};
#[inline]
#[must_use]
pub fn occlusion(input: &Input, mut ray: Ray, mut dist: f64) -> f64 {
debug_assert!(dist > 0.0);
let bump_dist = input.sett.bump_dist();
let loop_limit = input.sett.loop_limit();
let min_weight = input.sett.min_weight();
let mut vis = 1.0;
let mut num_loops = 0;
while let Some(hit) = input.tree.scan(ray.clone(), bump_dist, dist) {
if num_loops >= loop_limit {
println!("[WARN] : Terminating shadower: loop limit reached.");
return 0.0;
}
num_loops += 1;
dist -= hit.dist();
if dist < 0.0 {
return vis;
}
if vis < min_weight {
return 0.0;
}
match *hit.tag() {
Attribute::Opaque(..) => {
return vis / dist.mul_add(input.shader.fall_off(), 1.0);
}
Attribute::Mirror(.., abs_frac) => {
ray.travel(dist);
vis *= 1.0 - abs_frac;
*ray.dir_mut() = Crossing::calc_ref_dir(ray.dir(), hit.side().norm());
ray.travel(bump_dist);
}
Attribute::Transparent(.., abs_frac) => {
ray.travel(dist + bump_dist);
vis *= 1.0 - abs_frac;
}
Attribute::Refractive(.., abs_frac, [_inside, _outside]) => {
ray.travel(dist + bump_dist);
vis *= 1.0 - abs_frac;
}
Attribute::Luminous(.., bright_mult) => {
return (vis * bright_mult) / dist.mul_add(input.shader.fall_off(), 1.0);
}
}
}
vis
}