HW0 Ray marching 以及一些问题

Hello! 我最近才有时间,所以有些赶。作业也比较糙 :grin:
本来打算是把写过的ShaderToy用Taichi写一遍的,发现这个写码水平还是有点捉急呀
写了这个作业之后感觉有以下这几个问题:

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

十分感谢!

image

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()

可以考虑一下使用ODOP: https://taichi.readthedocs.io/en/v0.6.14/odop.html
(当然,Taichi是面向数据的语言,所以即使用了class,数据层级也是平的。)

这个应该是支持的?可否给出一个例子我们容易复现

这个得过一阵

应该是支持的?

哇!十分感谢
while-loop 和 break的话,我刚刚试了下,确实是可以的。
不好意思,估计是之前debug的时候没仔细整,结果把别的错误归因成这个了 :grin:

ODOP的话之前看文档也好像是忽略了 :grin:
我好好试一下!
谢谢你啦!

1 个赞