HW0 Ray marching 以及一些问题

Hello! 我最近才有时间，所以有些赶。作业也比较糙

1. Taichi 以后会支持类或者结构体嘛？就像GLSL一样支持struct?
2. Taichi 为什么在Taichi-scope里面不支持while-loop呢？
3. 什么时候能够支持多个return呢？
4. 什么时候能够支持loop里面的’break’呢？

import taichi as ti
import numpy as np

# Questions: 1. Can we declare class or struct in Taichi? 2. It doesn't have a 'while-loop' in Taichi? 3. When can we get double 'return' in the loop? 4. 'Break' in loop.

ti.init(arch=ti.gpu)

# Canvas
nx = 640
ny = 320
pixels = ti.Vector(3, dt=ti.f32, shape=(nx, ny))

RAY_STEPS = 256
FOVY = 3.141569*0.25

SPHERE_1_ID = 1
SPHERE_2_ID = 2

@ti.func
def distance(p1, p2):
return ti.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + (p1[2] - p2[2]) ** 2)

@ti.func
def sphere(p, r, c):
return distance(p, c) - r

@ti.func
def rotateY(p, a):
return [ti.cos(a) * p[0] + ti.sin(a) * p[2], p[1], -ti.sin(a) * p[0] + ti.cos(a) * p[2]]

@ti.func
def rayCast(eye, ref, ndc):
F = ref - eye
R = F.cross(ti.Vector([0.0, 1.0, 0.0])).normalized()
U = R.cross(F).normalized()
V = U * F.norm() * np.tan(FOVY * 0.5)
H = R * F.norm() * np.tan(FOVY * 0.5) * (nx / ny)
p = ref + ndc[0] * H + ndc[1] * V

return (p - eye).normalized()

@ti.func
def sceneMap3D(pos):
t = sphere(pos, 1.0, ti.Vector([-2.0, 0.0, 0.0]))
obj = SPHERE_1_ID
t2 = sphere(pos, 2.0, ti.Vector([4.0, 2.0, 0.0]))
if t2 < t:
t = t2
obj = SPHERE_2_ID
return t, obj

@ti.func
def secneMap3D_1(pos):
t = sphere(pos, 1.0, ti.Vector([-2.0, 0.0, 0.0]))
t2 = sphere(pos, 2.0, ti.Vector([4.0, 2.0, 0.0]))
if t2 < t:
t = t2
return t

@ti.func
def computeNormal(pos):
return ti.Vector([secneMap3D_1(pos + ti.Vector([0.001, 0.0, 0.0])) - secneMap3D_1(pos - ti.Vector([0.001, 0.0, 0.0])),
secneMap3D_1(pos + ti.Vector([0.0, 0.001, 0.0])) - secneMap3D_1(pos - ti.Vector([0.0, 0.001, 0.0])),
secneMap3D_1(pos + ti.Vector([0.0, 0.0, 0.001])) - secneMap3D_1(pos - ti.Vector([0.0, 0.0, 0.001]))]).normalized()

@ti.func
def march(origin, dir):
t = 0.001
m = -1
hitObj = -1
for iStep in range(20):
pos = origin + t * dir
m, hitObj = sceneMap3D(pos)
t += m
# Didn't hit
if m > 0.01:
t = 1.0
hitObj = -1
return t, hitObj

@ti.func
def computeMaterial(hitObj, p, n, lightVec, view):
lambert = view.dot(n)
cColor = ti.Vector([0.0, 0.0, 0.0])
if hitObj == SPHERE_1_ID:
cColor = ti.Vector([1.0, 0.5, 0.25]) * lambert
elif hitObj == SPHERE_2_ID:
cColor = ti.Vector([0.25, 1.0, 0.5]) * lambert

return cColor

@ti.func
def sdf3D(dir, eye):
t, hitObj = march(eye, dir)
isect = eye + t * dir
nor = computeNormal(isect)
lightDir = ti.Vector([0.0, 0.0, 0.0])
surfaceColor = computeMaterial(hitObj, isect, nor, lightDir, (eye - isect).normalized())
return t, surfaceColor, hitObj, isect

# main
@ti.kernel
def mainImage(t: ti.f32):
for i, j in pixels:
uv = ti.Vector([i/nx, j/ny])
uv = uv * 2.0 - ti.Vector([1.0, 1.0])
eye = rotateY(ti.Vector([0, 2, -20]), t)
ref = ti.Vector([0.0, 0.0, 0.0])
rayDir = rayCast(eye, ref, uv)
dis_t, surfaceColor, hitObj, isect = sdf3D(rayDir, eye)
pixels[i, j] = surfaceColor

gui = ti.GUI("Simple Ray Marcher", res=(nx, ny))
for i in range(1000000):
mainImage(i * 0.03)
gui.set_image(pixels)
gui.show()

（当然，Taichi是面向数据的语言，所以即使用了class，数据层级也是平的。）

while-loop 和 break的话，我刚刚试了下，确实是可以的。

ODOP的话之前看文档也好像是忽略了

1 Like