# Homework 0: 2D光线追踪 vs JavaScript

Taichi版：

``````# -*- coding: utf-8 -*-
import taichi as ti

# Javascript:         0.1  FPS
# i7-6820HQ     CPU:  2.70 FPS
# Quadro M1000M CUDA: 2.03 FPS
ti.init(arch=ti.cpu)

# 把场景写进kernel导致编译时间太长，故关掉高级优化

W = 720; H = 480;
MAGNIFY_DISP = 4
color_buffer     = ti.Vector(3, dt=ti.f32, shape=(W, H));
gui = ti.GUI('Haha', (W, H))
# Taichi's coordinate system is different from Processing's
#
#     Taichi                   Processing
#
# ^ (0, 480)                +------------> (720,0
# |                         |
# |                         |
# +----------> (720, 0)     V (0, 480)

@ti.func
def Perp(v):
return ti.Vector([-v[1], v[0], 0.0])

# 返回：[t, tact]
@ti.func
def IntersectLineWithRay(l, r):
p1 = l[0]; p2 = l[1]; o = r[0]; d = ti.normalized(r[1]);
p1p2 = p2 - p1
n = ti.normalized(Perp(p1p2))
op1 = p1 - o;
dist = ti.dot(n, op1);
ddn  = ti.dot(n, d);
t    = dist / ddn;
tact = ti.Vector([0.0, 0.0, 0.0]);
if t > 0:
tact = o + t * d
t0 = ti.dot((tact - p1), p1p2)
t1 = ti.dot((p2 - tact), p1p2)
completion = t0 / (t0+t1)
if completion >= 0 and completion <= 1:
pass
else:
t = -1
return t, tact

@ti.kernel
def Clear():
for i, j in color_buffer:
color_buffer[i, j] = ti.Vector([0,0,0]);

@ti.func
def Diffuse(l, d):
n = Perp(l[1]-l[0]);
if (ti.dot(n, d) > 0): n = n*(-1)
theta = ti.random(ti.f32) * 3.14159*2
ret = ti.Vector([ti.cos(theta), ti.sin(theta), 0.0]);
for x in range(0, 4):
theta = ti.random(ti.f32) * 3.14159*2
ret = ti.Vector([ti.cos(theta), ti.sin(theta), 0.0]);
if ti.dot(n, ret) < 0:
break
return ret

NSAMP = 4;

x0 = 0.2*W; x1 = 0.25*W; x2 = 0.3*W; y1 = 0.7*H; y2 = 0.55*H; y0 = 0.85*H;
g1 = [ti.Vector([x1,y1,0]), ti.Vector([x2,y1,0])]
g2 = [ti.Vector([x2,y1,0]), ti.Vector([x2,y2,0])]
g3 = [ti.Vector([x0,y2,0]), ti.Vector([x2,y2,0])]
g4 = [ti.Vector([x0,y2,0]), ti.Vector([x0,y0,0])]
g5 = [ti.Vector([x0,y0,0]), ti.Vector([x2,y0,0])]

#####
#
# ###
#   #
#####
@ti.func
def IntersectG(o, d, t_, this_intensity_, done_):
d_out = d;
t = t_;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(g1, [o, d]);
if t1 > 0 and t>t1:
t = t1;
this_intensity = ti.Vector([0.5, 0.0, 0.0]);
done = True
t1, _ = IntersectLineWithRay(g2, [o, d]);
if t1 > 0 and t>t1: t = t1; d_out = Diffuse(g2, d); done = False;
t1, _ = IntersectLineWithRay(g3, [o, d]);
if t1 > 0 and t>t1: t = t1; this_intensity = ti.Vector([0.5, 0.0, 0.0]); done = True
t1, _ = IntersectLineWithRay(g4, [o, d]);
if t1 > 0 and t>t1: t = t1; d_out = Diffuse(g4, d); done = False
t1, _ = IntersectLineWithRay(g5, [o, d]);
if t1 > 0 and t>t1: t = t1; this_intensity = ti.Vector([0.5, 0.0, 0.0]); done = True
return t, d_out, this_intensity, done

#
# #
#   #
#####
#   #
x0 = 0.325*W; x1=0.375*W; x2=0.425*W; y1=0.7*H; y2=0.55*H; y0=0.85*H; y3=0.65*H;
a1 = [ti.Vector([x1,y0,0]), ti.Vector([x2,y1,0])]
a2 = [ti.Vector([x1,y0,0]), ti.Vector([x0,y1,0])]
a3 = [ti.Vector([x0,y3,0]), ti.Vector([x2,y3,0])]
a4 = [ti.Vector([x0,y1,0]), ti.Vector([x0,y2,0])]
a5 = [ti.Vector([x2,y1,0]), ti.Vector([x2,y2,0])]

@ti.func
def IntersectA(o, d, t_, this_intensity_, done_):
t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(a1, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(a1, d); done = False;
t1, _ = IntersectLineWithRay(a2, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(a2, d); done = False;
t1, _ = IntersectLineWithRay(a3, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.0, 0.8, 0.0]); done = True
t1, _ = IntersectLineWithRay(a4, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(a4, d); done = False;
t1, _ = IntersectLineWithRay(a5, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(a5, d); done = False;
return t, d_out, this_intensity, done;

#   #
## ##
# # #
#   #
#   #
x0=0.45*W; x1=0.5*W; x2=0.55*W; y1=0.7*H; y2=0.55*H; y0=0.85*H;
m1 = [ti.Vector([x0,y0,0]), ti.Vector([x0,y2,0])]
m2 = [ti.Vector([x0,y0,0]), ti.Vector([x1,y2,0])]
m3 = [ti.Vector([x2,y0,0]), ti.Vector([x1,y2,0])]
m4 = [ti.Vector([x2,y0,0]), ti.Vector([x2,y2,0])]

@ti.func
def IntersectM(o, d, t_, this_intensity_, done_):

d_out = d;
t = t_;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(m1, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(m1, d); done = False;
t1, _ = IntersectLineWithRay(m2, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.4, 0.4, 0.0]); done = True
t1, _ = IntersectLineWithRay(m3, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.4, 0.4, 0.0]); done = True
t1, _ = IntersectLineWithRay(m4, [o, d]);
if t1 > 0 and t > t1: t = t1;  d_out = Diffuse(m4, d); done = False;
return t, d_out, this_intensity, done;

#####
#
#####
#
#####
x0=0.575*W; x1=0.625*W; x2=0.675*W; y1=0.7*H; y2=0.55*H; y0=0.85*H;
e1 = [ti.Vector([x0,y0,0]), ti.Vector([x0,y2,0])]
e2 = [ti.Vector([x0,y0,0]), ti.Vector([x2,y0,0])]
e3 = [ti.Vector([x0,y2,0]), ti.Vector([x2,y2,0])]
e4 = [ti.Vector([x0,y1,0]), ti.Vector([x1,y1,0])]

@ti.func
def IntersectE(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(e1, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(e1, d); done = False;
t1, _ = IntersectLineWithRay(e2, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0, 0.5, 0.5]); done = True
t1, _ = IntersectLineWithRay(e3, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0, 0.5, 0.5]); done = True
t1, _ = IntersectLineWithRay(e4, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0, 0.5, 0.5]); done = True
return t, d_out, this_intensity, done;

#####
#
#####
#
#####
x0=0.70*W; x1=0.75*W; x2=0.80*W; y1=0.7*H; y2=0.55*H; y0=0.85*H;
s1 = [ti.Vector([x0,y0,0]), ti.Vector([x2,y0,0])]
s2 = [ti.Vector([x0,y0,0]), ti.Vector([x0,y1,0])]
s3 = [ti.Vector([x0,y1,0]), ti.Vector([x2,y1,0])]
s4 = [ti.Vector([x2,y1,0]), ti.Vector([x2,y2,0])]
s5 = [ti.Vector([x0,y2,0]), ti.Vector([x2,y2,0])]
@ti.func
def IntersectS(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_
done = done_
t1, _ = IntersectLineWithRay(s1, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.5, 0.2, 0.2]); done = True
t1, _ = IntersectLineWithRay(s2, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(s2, d); done = False;
t1, _ = IntersectLineWithRay(s3, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.5, 0.2, 0.2]); done = True
t1, _ = IntersectLineWithRay(s4, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(s4, d); done = False;
t1, _ = IntersectLineWithRay(s5, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.5, 0.2, 0.2]); done = True
return t, d_out, this_intensity, done;

#####
#
#####
#
#####
x0=0.25*W; x1=0.3*W; x2=0.35*W; y1=0.3*H; y2=0.15*H; y0=0.45*H;
v21 = [ti.Vector([x0,y0,0]), ti.Vector([x2,y0,0])]
v22 = [ti.Vector([x2,y0,0]), ti.Vector([x2,y1,0])]
v23 = [ti.Vector([x0,y1,0]), ti.Vector([x2,y1,0])]
v24 = [ti.Vector([x0,y1,0]), ti.Vector([x0,y2,0])]
v25 = [ti.Vector([x0,y2,0]), ti.Vector([x2,y2,0])]
@ti.func
def Intersect2(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(v21, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v21, d); done = False;
t1, _ = IntersectLineWithRay(v22, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v22, d); done = False;
t1, _ = IntersectLineWithRay(v23, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v23, d); done = False;
t1, _ = IntersectLineWithRay(v24, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v24, d); done = False;
t1, _ = IntersectLineWithRay(v25, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v25, d); done = False;
return t, d_out, this_intensity, done;

#####
#   #
#   #
#   #
#####
x0=0.45*W; x1=0.5*W; x2=0.55*W; y1=0.3*H; y2=0.15*H; y0=0.45*H;
v01 = [ti.Vector([x0,y0,0]), ti.Vector([x2,y0,0])]
v02 = [ti.Vector([x2,y0,0]), ti.Vector([x2,y2,0])]
v03 = [ti.Vector([x2,y2,0]), ti.Vector([x0,y2,0])]
v04 = [ti.Vector([x0,y0,0]), ti.Vector([x0,y2,0])]
@ti.func
def Intersect0(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(v01, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.2, 0.2, 0.4]); done = True
t1, _ = IntersectLineWithRay(v02, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v02, d); done = False;
t1, _ = IntersectLineWithRay(v03, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.2, 0.2, 0.4]); done = True
t1, _ = IntersectLineWithRay(v04, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v04, d); done = False;
return t, d_out, this_intensity, done;

#
##
# #
#
#####
x0=0.65*W; x1=0.7*W; x2=0.75*W; y1=0.3*H; y2=0.15*H; y0=0.45*H;
v11 = [ti.Vector([x1,y0,0]), ti.Vector([x1-0.05*W,y0-0.075*H,0])]
v12 = [ti.Vector([x1,y0,0]), ti.Vector([x1,y2,0])]
v13 = [ti.Vector([x2,y2,0]), ti.Vector([x0,y2,0])]
@ti.func
def Intersect1(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(v11, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.4, 0.4, 0.8]); done = True
t1, _ = IntersectLineWithRay(v12, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v12, d); done = False;
t1, _ = IntersectLineWithRay(v13, [o, d]);
if t1 > 0 and t > t1: t = t1; d_out = Diffuse(v13, d); done = False;
return t, d_out, this_intensity, done;

##############
#            #
#            #

#            #
#            #
##############
vw1 = [ti.Vector([0.15*W,0.5*H,0]), ti.Vector([0.15*W,0.1*H,0])]
vw2 = [ti.Vector([0.85*W,0.5*H,0]), ti.Vector([0.85*W,0.1*H,0])]
vw3 = [ti.Vector([0.15*W,0.05*H,0]), ti.Vector([0.85*W,0.05*H,0])]
vw4 = [ti.Vector([0.15*W,0.95*H,0]), ti.Vector([0.85*W,0.95*H,0])]
vw5 = [ti.Vector([0.15*W,0.9*H,0]), ti.Vector([0.15*W,0.5*H,0])]
vw6 = [ti.Vector([0.85*W,0.9*H,0]), ti.Vector([0.85*W,0.5*H,0])]
@ti.func
def IntersectW(o, d, t_, this_intensity_, done_):

t = t_;
d_out = d;
this_intensity = this_intensity_;
done = done_
t1, _ = IntersectLineWithRay(vw1, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.6, 0.6, 1.4]); done = True
t1, _ = IntersectLineWithRay(vw2, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.6, 0.6, 1.4]); done = True
t1, _ = IntersectLineWithRay(vw3, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.6, 0.6, 1.4]); done = True
t1, _ = IntersectLineWithRay(vw4, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.4, 0.8, 0.8]); done = True
t1, _ = IntersectLineWithRay(vw5, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.1, 0.2, 0.2]); done = True
t1, _ = IntersectLineWithRay(vw6, [o, d]);
if t1 > 0 and t > t1: t = t1; this_intensity = ti.Vector([0.1, 0.2, 0.2]); done = True

return t, d_out, this_intensity, done;

@ti.kernel
def Fill():
for i, j in color_buffer:
intensity = ti.Vector([0.0, 0.0, 0.0])
samp = 0
while samp < NSAMP: # 每个像素采这么多次
o = ti.Vector([i*1.0, j*1.0, 0.0]); # 必须是三维的不能是二维的？
theta = ti.random(ti.f32) * 3.14159*2
d = ti.Vector([ti.cos(theta), ti.sin(theta), 0.0])
# obj = None 不能设为none？

t_total = 0.0 # 光走过的距离

level = 0
while level < 3:
d_orig = d;
t = 1000000000.0

# 求交点
# this_intensity = ti.Vector([0,0,0]) # 错误：整型的不能赋浮点值
this_intensity = ti.Vector([0.0, 0.0, 0.0])
done = False
t, d, this_intensity, done = IntersectG(o, d_orig, t, this_intensity, done); # G
t, d, this_intensity, done = IntersectA(o, d_orig, t, this_intensity, done); # A
t, d, this_intensity, done = IntersectM(o, d_orig, t, this_intensity, done); # M
t, d, this_intensity, done = IntersectE(o, d_orig, t, this_intensity, done); # E
t, d, this_intensity, done = IntersectS(o, d_orig, t, this_intensity, done); # S
t, d, this_intensity, done = Intersect2(o, d_orig, t, this_intensity, done); # 2
t, d, this_intensity, done = Intersect0(o, d_orig, t, this_intensity, done); # 0
t, d, this_intensity, done = Intersect1(o, d_orig, t, this_intensity, done); # 1
t, d, this_intensity, done = IntersectW(o, d_orig, t, this_intensity, done); # Walls

# 总结一下求交点结果决定是再发射间接光还是退出
if t != 1000000000.0:
t_total += t
damp = 1 / (1 + ti.exp(t_total/400))
EPS = 0.001;
o = o + d_orig * (t - EPS);
if done: intensity += this_intensity * damp; break
level += 1 # 一次递归结束了
samp += 1; # 一次采样结束了
color_buffer[i, j] += intensity * 1.0 / NSAMP

g_frame_count = 0;
while True:
while gui.get_event(ti.GUI.PRESS):
if gui.event.key == ti.GUI.ESCAPE:
exit()
#Clear();
Fill();
g_frame_count += 1;
img = (color_buffer).to_numpy() * (1.0 / (g_frame_count)) * MAGNIFY_DISP;
gui.set_image(img);
gui.show()
``````
9 Likes

1 Like