-
Notifications
You must be signed in to change notification settings - Fork 0
/
material.py
71 lines (48 loc) · 2.4 KB
/
material.py
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
from abc import ABC, abstractmethod
import math
import vector
import util
import hittable
class Material(ABC):
@abstractmethod
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord):
pass
class Lambertian(Material):
def __init__(self, albedo):
self.albedo = albedo
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord):
scatter_direction = hit_record.normal + vector.random_unit_vector()
scattered = vector.Ray(hit_record.position, scatter_direction, ray_in.time)
return True, self.albedo, scattered
class Metal(Material):
def __init__(self, color, fuzz):
self.color = color
self.fuzz = fuzz
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord):
reflected = vector.reflect(vector.unit_vector(ray_in.direction), hit_record.normal)
scattered = vector.Ray(hit_record.position, reflected + vector.random_in_unit_sphere().times(self.fuzz), ray_in.time)
didscatter = (vector.dot(scattered.direction, hit_record.normal) > 0)
return didscatter, self.color, scattered
class Dielectric(Material):
def __init__(self, refractive_index):
self.ref_idx = refractive_index
def scatter(self, ray_in: vector.Ray, hit_record: hittable.HitRecord):
attenuation = vector.Vec3(1.0, 1.0, 1.0)
etai_over_etat = self.ref_idx
if hit_record.front_face:
etai_over_etat = 1.0 / self.ref_idx
unit_direction = vector.unit_vector(ray_in.direction)
cos_theta = min(vector.dot(-unit_direction, hit_record.normal), 1.0)
sin_theta = math.sqrt(1.0 - cos_theta*cos_theta)
if etai_over_etat * sin_theta > 1.0:
reflected = vector.reflect(unit_direction, hit_record.normal)
scattered = vector.Ray(hit_record.position, reflected, ray_in.time)
return True, attenuation, scattered
reflect_prob = vector.schlick(cos_theta, etai_over_etat)
if util.random_double() < reflect_prob:
reflected = vector.reflect(unit_direction, hit_record.normal)
scattered = vector.Ray(hit_record.position, reflected, ray_in.time)
return True, attenuation, scattered
refracted = vector.refract(unit_direction, hit_record.normal, etai_over_etat)
scattered = vector.Ray(hit_record.position, refracted, ray_in.time)
return True, attenuation, scattered