-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhittable.pi
More file actions
121 lines (99 loc) · 3.26 KB
/
hittable.pi
File metadata and controls
121 lines (99 loc) · 3.26 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use raytracepl::ray::Ray;
use raytracepl::vec3::Vec3;
use raytracepl::interval::Interval;
use raytracepl::material::*;
use raytracepl::utils::*;
pub trait Material {
fn scatter(r_in:Ray, rec:HitRecord, attenuation:* Vec3, scattered:*Ray) bool;
}
pub struct HitRecord {
pub p:Vec3;
pub normal:Vec3;
pub t:f64;
pub front_face:bool;
pub mat:Material;
}
pub trait Hittable {
fn hit(r:Ray, ray_t:Interval, rec:*HitRecord) bool;
}
impl HitRecord {
pub fn set_face_normal(r:Ray, outward_normal:Vec3) void {
// Sets the hit record normal vector.
// NOTE: the parameter `outward_normal` is assumed to have unit length.
self.front_face = r.direction().dot(outward_normal) < 0.0;
if self.front_face {
self.normal = outward_normal;
} else {
self.normal = outward_normal.neg();
}
return;
}
}
impl Material for Mat {
fn scatter(r_in:Ray, rec:HitRecord, attenuation:* Vec3, scattered:*Ray) bool {
let re = false;
let m = *self;
match m {
Lambertian(a) => {
re = a.scatter(r_in, rec, attenuation, scattered);
}
Metal(a) => {
re = a.scatter(r_in, rec, attenuation, scattered);
}
Dielectric(a) => {
re = a.scatter(r_in, rec, attenuation, scattered);
}
}
return re;
}
}
impl Material for Lambertian {
fn scatter(_r_in: Ray, rec: HitRecord, attenuation: * Vec3, scattered: * Ray) bool {
let scatter_direction = rec.normal.add( vec3::ranndom_unit_vector());
// Catch degenerate scatter direction
if scatter_direction.near_zero() {
scatter_direction = rec.normal;
}
*scattered = ray::new(rec.p, scatter_direction);
*attenuation = self.albedo;
return true;
}
}
impl Material for Metal {
fn scatter(r_in: Ray, rec: HitRecord, attenuation: * Vec3, scattered: * Ray) bool {
let reflected = r_in.direction().unit_vector().reflect(rec.normal);
*scattered = ray::new(
rec.p,
reflected.add(
vec3::ranndom_unit_vector().mul(self.fuzz)
)
);
*attenuation = self.albedo;
return true;
}
}
impl Material for Dielectric {
fn scatter(r_in: Ray, rec: HitRecord, attenuation: * Vec3, scattered: * Ray) bool {
*attenuation = vec3::new(1.0, 1.0, 1.0);
let refraction_ration;
if rec.front_face {
refraction_ration = 1.0 / self.ir;
} else {
refraction_ration = self.ir;
}
let unit_direction = r_in.direction().unit_vector();
let cos_theta = fmin(unit_direction.neg().dot(rec.normal), 1.0);
let sin_theta = sqrt_64(1.0 - cos_theta * cos_theta);
let cannot_refract = refraction_ration * sin_theta > 1.0;
let direction;
if cannot_refract || self.reflectance(
cos_theta, refraction_ration) > random_f64(){
direction = unit_direction.reflect(rec.normal);
} else {
direction = unit_direction.refract(
rec.normal, refraction_ration);
}
*scattered = ray::new(rec.p, direction);
return true;
}
}