Hello! 我最近才有时间,所以有些赶。作业也比较糙
本来打算是把写过的ShaderToy用Taichi写一遍的,发现这个写码水平还是有点捉急呀
写了这个作业之后感觉有以下这几个问题:
- Taichi 以后会支持类或者结构体嘛?就像GLSL一样支持struct?
- Taichi 为什么在Taichi-scope里面不支持while-loop呢?
- 什么时候能够支持多个return呢?
- 什么时候能够支持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()