forked from erizmr/taichi_ray_tracing
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy path2_0_lambertian_reflection.py
93 lines (81 loc) · 3.46 KB
/
2_0_lambertian_reflection.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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import taichi as ti
import numpy as np
import argparse
from ray_tracing_models import Ray, Camera, Hittable_list, Sphere, PI
ti.init(arch=ti.gpu)
PI = 3.14159265
# Canvas
aspect_ratio = 1.0
image_width = 800
image_height = int(image_width / aspect_ratio)
canvas = ti.Vector.field(3, dtype=ti.f32, shape=(image_width, image_height))
# Rendering parameters
samples_per_pixel = 4
max_depth = 10
@ti.kernel
def render():
for i, j in canvas:
u = (i + ti.random()) / image_width
v = (j + ti.random()) / image_height
color = ti.Vector([0.0, 0.0, 0.0])
for n in range(samples_per_pixel):
ray = camera.get_ray(u, v)
color += ray_color(ray)
color /= samples_per_pixel
canvas[i, j] += color
@ti.func
def to_light_source(hit_point, light_source):
return light_source - hit_point
# Lambertian reflection model
@ti.func
def ray_color(ray):
default_color = ti.Vector([1.0, 1.0, 1.0])
scattered_origin = ray.origin
scattered_direction = ray.direction
is_hit, hit_point, hit_point_normal, front_face, material, color = scene.hit(Ray(scattered_origin, scattered_direction))
if is_hit:
if material == 0:
default_color = color
else:
hit_point_to_source = to_light_source(hit_point, ti.Vector([0, 5.4 - 3.0, -1]))
default_color = color * ti.max(hit_point_to_source.dot(hit_point_normal) / (hit_point_to_source.norm() * hit_point_normal.norm()), 0.0)
return default_color
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Naive Ray Tracing')
parser.add_argument(
'--max_depth', type=int, default=10, help='max depth (default: 10)')
parser.add_argument(
'--samples_per_pixel', type=int, default=4, help='samples_per_pixel (default: 4)')
args = parser.parse_args()
max_depth = args.max_depth
samples_per_pixel = args.samples_per_pixel
scene = Hittable_list()
# Light source
scene.add(Sphere(center=ti.Vector([0, 5.4, -1]), radius=3.0, material=0, color=ti.Vector([10.0, 10.0, 10.0])))
# Ground
scene.add(Sphere(center=ti.Vector([0, -100.5, -1]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
# ceiling
scene.add(Sphere(center=ti.Vector([0, 102.5, -1]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
# back wall
scene.add(Sphere(center=ti.Vector([0, 1, 101]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
# right wall
scene.add(Sphere(center=ti.Vector([-101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.6, 0.0, 0.0])))
# left wall
scene.add(Sphere(center=ti.Vector([101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.0, 0.6, 0.0])))
# Diffuse ball
scene.add(Sphere(center=ti.Vector([0, -0.2, -1.5]), radius=0.3, material=1, color=ti.Vector([0.8, 0.3, 0.3])))
# Metal ball
scene.add(Sphere(center=ti.Vector([-0.8, 0.2, -1]), radius=0.7, material=2, color=ti.Vector([0.6, 0.8, 0.8])))
# Glass ball
scene.add(Sphere(center=ti.Vector([0.7, 0, -0.5]), radius=0.5, material=3, color=ti.Vector([1.0, 1.0, 1.0])))
# Metal ball-2
scene.add(Sphere(center=ti.Vector([0.6, -0.3, -2.0]), radius=0.2, material=2, color=ti.Vector([0.8, 0.6, 0.2])))
camera = Camera()
gui = ti.GUI("Ray Tracing", res=(image_width, image_height))
canvas.fill(0)
cnt = 0
while gui.running:
render()
cnt += 1
gui.set_image(np.sqrt(canvas.to_numpy() / cnt))
gui.show()