感谢回复, 下面是一个可以执行的代码, 并附带了一个模型, main函数就是最下面那段While(1)
其中FillTriangles类里面的for循环我只让他循环了4次, 不然第一次运行就要等好久.
我曾试图把Hittable_list中的object变量先设置成空的, 在开始运行后再往里面添加, 但在hit()函数中, 好像taichi只能支持static range, 所以以失败告终. - 很好奇各位大佬是怎么在运行时读取物体的?
import taichi as ti
import numpy as np
ti.init(arch=ti.cuda)
#ti.init(arch=[ti.opengl, ti.metal])
import taichi as ti
PI = 3.14159265
@ti.func
def rand3():
return ti.Vector([ti.random(),ti.random(),ti.random()])
#为完全漫反射做的随机向量生成函数
#生成了一个中心在0, 半径为1的球
@ti.func
def rand_sphere_point():
p = 2.0 * rand3() - ti.Vector([1, 1, 1])
while p.norm() >= 1.0:
p = 2.0 * rand3() - ti.Vector([1, 1, 1])#意图返回一个圆, 如果返回值在圆外, 就从新随机
return (p.normalized())
@ti.func
def reflect(v, normal):
return v - 2 * v.dot(normal) * normal
@ti.func
def refract(uv, n, etai_over_etat):
cos_theta = min(n.dot(-uv), 1.0)
r_out_perp = etai_over_etat * (uv + cos_theta * n)
r_out_parallel = -ti.sqrt(abs(1.0 - r_out_perp.dot(r_out_perp))) * n
return r_out_perp + r_out_parallel
@ti.func
def reflectance(cosine, ref_idx):
# Use Schlick's approximation for reflectance.
r0 = (1 - ref_idx) / (1 + ref_idx)
r0 = r0 * r0
return r0 + (1 - r0) * pow((1 - cosine), 5)
#一个存放障碍物的列表
@ti.data_oriented
class Hittable_list:
def __init__(self):
self.objects = []
def add(self, obj):
self.objects.append(obj)
def clear(self):
self.objects = []
@ti.func
def hit(self, ray, t_min=0.001, t_max=10e8):
closest_t = t_max
is_hit = False
front_face = False
hit_point = ti.Vector([0.0, 0.0, 0.0])
hit_point_normal = ti.Vector([0.0, 0.0, 0.0])
color = ti.Vector([0.0, 0.0, 0.0])
material = 1
for index in ti.static(range(len(self.objects))):
is_hit_tmp, root_tmp, hit_point_tmp, hit_point_normal_tmp, front_face_tmp, material_tmp, color_tmp = self.objects[index].Hit(ray, t_min, closest_t)
if is_hit_tmp:
closest_t = root_tmp
is_hit = is_hit_tmp
hit_point = hit_point_tmp
hit_point_normal = hit_point_normal_tmp
front_face = front_face_tmp
material = material_tmp
color = color_tmp
return is_hit, hit_point, hit_point_normal, front_face, material, color,closest_t
#定义射线
@ti.data_oriented
class Ray:
def __init__(self,start,dir) -> None:
self.start = start
self.dir = dir
@ti.func
def at(self,t) -> ti.Vector:
return self.start+self.dir*t
#定义球,三角,三角组成的物体的class
@ti.data_oriented
class Sphere:
def __init__(self,center,radius,material,color):
self.center = center
self.radius = radius
self.material = material
self.color = color
@ti.func
def Hit(self, ray, t_min=0.001, t_max=10e8):
oc = ray.start - self.center #虎书P92
a = ray.dir.dot(ray.dir)
b = 2.0 * oc.dot(ray.dir)
c = oc.dot(oc) - self.radius * self.radius
discriminant = b * b - 4 * a * c
is_hit = False
front_face = False
root = 0.0
hit_point = ti.Vector([0.0, 0.0, 0.0])
hit_point_normal = ti.Vector([0.0, 0.0, 0.0])
if discriminant > 0:
sqrtd = ti.sqrt(discriminant)
root = (-b - sqrtd) / (2 * a)
if root < t_min or root > t_max:
root = (-b + sqrtd) / (2 * a)
if root >= t_min and root <= t_max:
is_hit = True
else:
is_hit = True
if is_hit:
hit_point = ray.at(root)
hit_point_normal = (hit_point - self.center) / self.radius
#总是把法线朝外
if ray.dir.dot(hit_point_normal) < 0:
front_face = True
else:
hit_point_normal = -hit_point_normal
return is_hit, root, hit_point, hit_point_normal, front_face, self.material, self.color
@ti.data_oriented
class Triangle:
def __init__(self,ptA,ptB,ptC,material,color):
self.ptA = ptA
self.ptB = ptB
self.ptC = ptC
self.material = material
self.color = color
@ti.func
def Hit(self, ray, t_min=0.001, t_max=10e8):
is_HitPlane = False
is_hit = False
front_face = False
hit_point = ti.Vector([0.0, 0.0, 0.0])
hit_point_normal = ti.Vector([0.0, 0.0, 0.0])
edgeAB = self.ptA - self.ptB
edgeAC = self.ptA - self.ptC
ptAMinusStart = self.ptA - ray.start
a = edgeAB[0]
b = edgeAB[1]
c = edgeAB[2]
d = edgeAC[0]
e = edgeAC[1]
f = edgeAC[2]
g = ray.dir[0]
h = ray.dir[1]
i = ray.dir[2]
j = ptAMinusStart[0]
k = ptAMinusStart[1]
l = ptAMinusStart[2]
M = a*(e*i-h*f) + b*(g*f-d*i) + c*(d*h-e*g)+0.0000001
#compute t
t = -(f*(a*k-j*b) + e*(j*c-a*l) + d*(b*l-k*c))/M
is_HitPlane = t>t_min and t<t_max
#color = ti.Vector([0.0,0.0,0.0])#重心坐标
if(is_HitPlane):
gamma = (i*(a*k-j*b) + h*(j*c-a*l) + g*(b*l-k*c))/M
if(gamma > 0 and gamma < 1):
beta = (j*(e*i-h*f) + k*(g*f-d*i) + l*(d*h-e*g))/M
if(beta > 0 and beta < 1 - gamma):
is_hit = True
#color = ti.Vector([gamma,beta,1.0-gamma-beta])
#重心坐标
if(is_hit):
hit_point = ray.at(t)
hit_point_normal = ((self.ptC - self.ptB).cross(self.ptA - self.ptC)).normalized()
if ray.dir.dot(hit_point_normal) < 0:
front_face = True
else:
hit_point_normal = -hit_point_normal
return is_hit, t, hit_point, hit_point_normal, front_face, self.material, self.color
#return is_hit, t, hit_point, hit_point_normal, front_face, self.material,color
@ti.data_oriented
class Object:
def __init__(self,boundFrom,boundTo,transform):
boundCenter = (boundFrom + boundTo) /2.0
boundRVector = abs(boundTo - boundCenter)
boundR = max(max(boundRVector[0],boundRVector[1]),boundRVector[2])
self.boundSphere = Sphere(center=boundCenter+transform, radius=boundR, material=1, color=ti.Vector([0,0,0]))
self.triangles = Hittable_list()
self.transform = transform
def FillTriangles(self,ptPos,faceID,material,color):
#for index in range(len(faceID)):
for index in range(1,4):
i = index - 1
self.triangles.add(Triangle(ptA=ptPos[faceID[i][0]-1]+self.transform, ptB=ptPos[faceID[i][1]-1]+self.transform, ptC=ptPos[faceID[i][2]-1]+self.transform, material=material, color=color))
#print("Created",ptPos[faceID[i][0]-1]+self.transform,ptPos[faceID[i][2]-1]+self.transform,ptPos[faceID[i][2]-1]+self.transform)
#print(len(self.triangles.objects))
@ti.func
def Hit(self,ray, t_min, closest_t):
is_hit = False
root = 0.0
hit_point = ti.Vector([0.0, 0.0, 0.0])
hit_point_normal = ti.Vector([0.0, 0.0, 0.0])
front_face = False
color = ti.Vector([0.0, 0.0, 0.0])
material = 1
is_hit, root1, hit_point1, hit_point_normal1, front_face1, material1, color1 = self.boundSphere.Hit(ray, t_min, closest_t)
if is_hit:
is_hit, hit_point, hit_point_normal, front_face, material, color,root = self.triangles.hit(ray,0.00001,closest_t)
return is_hit, root, hit_point, hit_point_normal, front_face, material, color
#######场景物体class定义结束##########
@ti.data_oriented
class Camera:
def __init__(self,lookFrom,lookAt,up,FOV,aspect_ratio):
#先定义好摄像机自身的一些属性, 不固定的值用field
self.lookfrom = ti.Vector.field(3, dtype=ti.f32, shape=())
self.lookat = ti.Vector.field(3, dtype=ti.f32, shape=())
self.up = ti.Vector.field(3, dtype=ti.f32, shape=())
self.fov = FOV
self.aspect_ratio = aspect_ratio
#传参
self.lookfrom[None] = lookFrom
self.lookat[None] = lookAt
self.up[None] = up
#定义屏幕的属性
self.cam_LLC = ti.Vector.field(3, dtype=ti.f32, shape=())#摄像机的左下角
self.cam_horizontal = ti.Vector.field(3, dtype=ti.f32, shape=())
self.cam_vertical = ti.Vector.field(3, dtype=ti.f32, shape=())
self.reset()
@ti.kernel
def reset(self):
#求出平面的宽和高(这里认为屏幕跟摄像机的距离为1)
half_height = ti.tan(self.fov / 2.0)
half_width = self.aspect_ratio * half_height
#算出平面的uvw来确定朝向
w = (self.lookfrom[None] - self.lookat[None]).normalized()
u = (self.up[None].cross(w)).normalized()
v = w.cross(u)
#算出平面边角位置和宽/高向量
self.cam_LLC[None] = self.lookfrom[None] - half_width * u - half_height * v - w
self.cam_horizontal[None] = 2 * half_width * u
self.cam_vertical[None] = 2 * half_height * v
@ti.func
def getRay(self,u,v):
return Ray(self.lookfrom[None],self.cam_LLC[None]+u*self.cam_horizontal[None]+v*self.cam_vertical[None] - self.lookfrom[None])
#返回一个射线, 起点是摄像机, 看向平面的左下角+一定比例的u,v组合, 最后再减去原点
def AddObject(scene):
scene.add(Sphere(center=ti.Vector([-0.9, 0, -2]), radius=0.5, material=3, color=ti.Vector([1, 1, 1])))
scene.add(Sphere(center=ti.Vector([0.8, 1.7, 0.5]), radius=0.4, material=2, color=ti.Vector([0.8, 0.6, 0.2])))
# #添加墙壁
scene.add(Sphere(center=ti.Vector([0, 102.5, -1]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
scene.add(Sphere(center=ti.Vector([0, 1, 101]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
scene.add(Sphere(center=ti.Vector([0, 1, -106]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8])))
scene.add(Sphere(ti.Vector([0, -500.5, -1]),500.0, 1,ti.Vector([0.8, 0.8, 0.8])))
scene.add(Sphere(center=ti.Vector([101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.0, 0.6, 0.0])))
scene.add(Sphere(center=ti.Vector([-101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.6, 0.0, 0.0])))
#添加灯光
scene.add(Sphere(ti.Vector([0, 5.4, -1]),3.0,0, ti.Vector([10.0, 10.0, 10.0])))
#AddTeaPot
teaPot = Object(boundFrom=ti.Vector([-0.995900333, -0.457885206, -0.610513628]),boundTo=ti.Vector([0.927217543, 0.457885206, 0.610513628]),transform=ti.Vector([0,0.2,-0.5]))
teaPotPtPos = [ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([-0.0801299289,-0.228942603,0.610513628]),ti.Vector([-0.538015127,-0.457885206,0]),ti.Vector([-0.0801299289,-0.457885206,0.457885206]),ti.Vector([-0.0801299289,-0.228942603,0.610513628]),ti.Vector([0.530383706,-0.228942603,0]),ti.Vector([-0.0801299289,-0.457885206,0.457885206]),ti.Vector([0.377755284,-0.457885206,0]),ti.Vector([-0.538015127,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.457885206]),ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([-0.0801299289,-0.228942603,0.610513628]),ti.Vector([-0.0801299289,0.228942633,0.457885206]),ti.Vector([0.377755284,0.228942633,0]),ti.Vector([-0.0801299289,-0.228942603,0.610513628]),ti.Vector([0.530383706,-0.228942603,0]),ti.Vector([-0.507489443,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.427359521]),ti.Vector([-0.538015127,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.457885206]),ti.Vector([-0.0801299289,0.228942633,0.427359521]),ti.Vector([0.3472296,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.457885206]),ti.Vector([0.377755284,0.228942633,0]),ti.Vector([-0.0801299289,-0.228942603,-0.610513628]),ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([-0.0801299289,-0.457885206,-0.457885206]),ti.Vector([-0.538015127,-0.457885206,0]),ti.Vector([0.530383706,-0.228942603,0]),ti.Vector([-0.0801299289,-0.228942603,-0.610513628]),ti.Vector([0.377755284,-0.457885206,0]),ti.Vector([-0.0801299289,-0.457885206,-0.457885206]),ti.Vector([-0.0801299289,0.228942633,-0.457885206]),ti.Vector([-0.538015127,0.228942633,0]),ti.Vector([-0.0801299289,-0.228942603,-0.610513628]),ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([0.377755284,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.457885206]),ti.Vector([0.530383706,-0.228942603,0]),ti.Vector([-0.0801299289,-0.228942603,-0.610513628]),ti.Vector([-0.0801299289,0.228942633,-0.427359521]),ti.Vector([-0.507489443,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.457885206]),ti.Vector([-0.538015127,0.228942633,0]),ti.Vector([0.3472296,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.427359521]),ti.Vector([0.377755284,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.457885206]),ti.Vector([-0.0801299289,-0.457885206,-0.457885206]),ti.Vector([-0.538015127,-0.457885206,0]),ti.Vector([0.377755284,-0.457885206,0]),ti.Vector([-0.0801299289,-0.457885206,0.457885206]),ti.Vector([-0.568540871,0.114471316,0]),ti.Vector([-0.538015127,0.183154047,0]),ti.Vector([-0.904323339,0.0457885265,0]),ti.Vector([-0.995900333,0.0457885265,0]),ti.Vector([-0.538015127,0.183154047,0]),ti.Vector([-0.568540871,0.114471316,0]),ti.Vector([-0.995900333,0.0457885265,0]),ti.Vector([-0.904323339,0.0457885265,0]),ti.Vector([-0.904323339,0.0457885265,0]),ti.Vector([-0.995900333,0.0457885265,0]),ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([-0.660117865,-0.320519626,0]),ti.Vector([-0.995900333,0.0457885265,0]),ti.Vector([-0.904323339,0.0457885265,0]),ti.Vector([-0.660117865,-0.320519626,0]),ti.Vector([-0.690643549,-0.228942603,0]),ti.Vector([0.438806653,-0.0686827898,0]),ti.Vector([0.438806653,-0.320519626,0]),ti.Vector([0.744063497,0.228942633,0]),ti.Vector([0.927217543,0.228942633,0]),ti.Vector([0.438806653,-0.320519626,0]),ti.Vector([0.438806653,-0.0686827898,0]),ti.Vector([0.927217543,0.228942633,0]),ti.Vector([0.744063497,0.228942633,0]),ti.Vector([0.744063497,0.228942633,0]),ti.Vector([0.927217543,0.228942633,0]),ti.Vector([0.774589121,0.228942633,0]),ti.Vector([0.896691918,0.228942633,0]),ti.Vector([0.927217543,0.228942633,0]),ti.Vector([0.744063497,0.228942633,0]),ti.Vector([0.896691918,0.228942633,0]),ti.Vector([0.774589121,0.228942633,0]),ti.Vector([0.301441103,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.381571025]),ti.Vector([0.3472296,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.427359521]),ti.Vector([-0.0801299289,0.228942633,0.381571025]),ti.Vector([0.301441103,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.427359521]),ti.Vector([0.3472296,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.381571025]),ti.Vector([-0.461700946,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.427359521]),ti.Vector([-0.507489443,0.228942633,0]),ti.Vector([-0.461700946,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.381571025]),ti.Vector([-0.507489443,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.427359521]),ti.Vector([-0.0190785639,0.320519626,0]),ti.Vector([-0.0801299289,0.320519626,-0.061051365]),ti.Vector([0.316703916,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,-0.396833837]),ti.Vector([-0.0801299289,0.320519626,0.061051365]),ti.Vector([-0.0190785639,0.320519626,0]),ti.Vector([-0.0801299289,0.228942633,0.396833837]),ti.Vector([0.316703916,0.228942633,0]),ti.Vector([-0.0801299289,0.320519626,-0.061051365]),ti.Vector([-0.14118129,0.320519626,0]),ti.Vector([-0.0801299289,0.228942633,-0.396833837]),ti.Vector([-0.476963758,0.228942633,0]),ti.Vector([-0.14118129,0.320519626,0]),ti.Vector([-0.0801299289,0.320519626,0.061051365]),ti.Vector([-0.476963758,0.228942633,0]),ti.Vector([-0.0801299289,0.228942633,0.396833837]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0190785639,0.320519626,0]),ti.Vector([-0.0801299289,0.320519626,-0.061051365]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.320519626,0.061051365]),ti.Vector([-0.0190785639,0.320519626,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.320519626,-0.061051365]),ti.Vector([-0.14118129,0.320519626,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.0801299289,0.457885206,0]),ti.Vector([-0.14118129,0.320519626,0]),ti.Vector([-0.0801299289,0.320519626,0.061051365])]
teaPotFaceID = [ti.Vector([1,2,4]),ti.Vector([5,8,6]),ti.Vector([9,12,10]),ti.Vector([13,16,14]),ti.Vector([17,20,18]),ti.Vector([21,24,22]),ti.Vector([25,28,26]),ti.Vector([29,32,30]),ti.Vector([33,36,34]),ti.Vector([37,40,38]),ti.Vector([41,44,42]),ti.Vector([45,48,46]),ti.Vector([49,52,50]),ti.Vector([53,56,54]),ti.Vector([57,60,58]),ti.Vector([61,64,62]),ti.Vector([65,68,66]),ti.Vector([69,72,70]),ti.Vector([73,76,74]),ti.Vector([77,79,78]),ti.Vector([81,83,82]),ti.Vector([85,88,86]),ti.Vector([89,92,90]),ti.Vector([93,96,94]),ti.Vector([97,100,98]),ti.Vector([101,104,102]),ti.Vector([105,108,106]),ti.Vector([109,112,110]),ti.Vector([113,116,114]),ti.Vector([117,119,118]),ti.Vector([121,123,122]),ti.Vector([125,127,126]),ti.Vector([129,131,130]),ti.Vector([130,131,132]),ti.Vector([126,127,128]),ti.Vector([122,123,124]),ti.Vector([118,119,120]),ti.Vector([116,113,115]),ti.Vector([112,109,111]),ti.Vector([108,105,107]),ti.Vector([104,101,103]),ti.Vector([100,97,99]),ti.Vector([96,93,95]),ti.Vector([92,89,91]),ti.Vector([88,85,87]),ti.Vector([82,83,84]),ti.Vector([78,79,80]),ti.Vector([76,73,75]),ti.Vector([72,69,71]),ti.Vector([68,65,67]),ti.Vector([64,61,63]),ti.Vector([60,57,59]),ti.Vector([56,53,55]),ti.Vector([52,49,51]),ti.Vector([48,45,47]),ti.Vector([44,41,43]),ti.Vector([40,37,39]),ti.Vector([36,33,35]),ti.Vector([32,29,31]),ti.Vector([28,25,27]),ti.Vector([24,21,23]),ti.Vector([20,17,19]),ti.Vector([16,13,15]),ti.Vector([12,9,11]),ti.Vector([8,5,7]),ti.Vector([4,1,3])]
teaPot.FillTriangles(teaPotPtPos,teaPotFaceID,1,ti.Vector([0.0, 0.2, 0.85]))
scene.add(teaPot)
#主要循环
@ti.kernel
def ShootRay():
for i,j in pixels:
u = (i+ti.random())/width
v = (j+ti.random())/height
color = ti.Vector([0.0,0.0,0.0])
for n in range(SPP):
ray = camera.getRay(u,v)
ray.dir = ray.dir
ray.start = ray.start
color += CalRayColor(ray)
color/=SPP
pixels[i,j] += color
#每一条path,照搬Taichi公开课
@ti.func
def CalRayColor(ray):
#为了让TaiChi实现递归, 使用类似Houdini Solver的方法 - While不停修改同一个变量
colorBuffer = ti.Vector([0.0, 0.0, 0.0])
brightness = ti.Vector([1.0, 1.0, 1.0])
scattered_origin = ray.start
scattered_direction = ray.dir
for n in range(depth):
if ti.random()>p_RR: #使用俄罗斯轮盘更快收敛
break
is_hit, hit_point, hit_point_normal, front_face, material, color, root = scene.hit(Ray(scattered_origin,scattered_direction))
if is_hit:
if material == 0:#光源直接返回亮度和颜色
colorBuffer = color * brightness #只有打到灯, brightness的颜色才会传递给buffer
break
else:
if material == 1:#完全漫反射
target = hit_point + hit_point_normal
target += rand_sphere_point() #因为上面加上了normal, 所以这个球不会随机到物体里面. 而且由于这个是个球, 加上后就不用乘上cos来算光照亮度了
scattered_direction = target - hit_point
scattered_origin = hit_point
brightness *= color
elif material == 2 or material == 4:#镜面材质/磨砂材质
fuzz = 0.0
if material == 4:
fuzz = 0.2
scattered_direction = reflect(scattered_direction.normalized(),
hit_point_normal)
scattered_direction += fuzz * rand_sphere_point()
scattered_origin = hit_point
if scattered_direction.dot(hit_point_normal) < 0:
break
else:
brightness *= color
elif material == 3: #介电质(透明物体)
refraction_ratio = 1.5
if front_face:
refraction_ratio = 1 / refraction_ratio
cos_theta = min(-scattered_direction.normalized().dot(hit_point_normal), 1.0)
sin_theta = ti.sqrt(1 - cos_theta * cos_theta)
# total internal reflection
if refraction_ratio * sin_theta > 1.0 or reflectance(cos_theta, refraction_ratio) > ti.random():
scattered_direction = reflect(scattered_direction.normalized(), hit_point_normal)
else:
scattered_direction = refract(scattered_direction.normalized(), hit_point_normal, refraction_ratio)
scattered_origin = hit_point
brightness *= color
brightness /= p_RR #除以RR来弥补能量缺失
return colorBuffer
##移动摄像机方法
def MoveCamera():
pressed = False
for e in gui.get_events(gui.PRESS):
if(e.key == gui.ESCAPE):
gui.running = False
elif(e.key == "s"):
camera.lookfrom[None] += ti.Vector([0.0,0.0,-1.0])*speed.value
camera.lookat[None] += ti.Vector([0.0,0.0,-1.0])*speed.value
pressed = True
elif(e.key == "w"):
camera.lookfrom[None] += ti.Vector([0.0,0.0,1.0])*speed.value
camera.lookat[None] += ti.Vector([0.0,0.0,1.0])*speed.value
pressed = True
elif(e.key == "a"):
camera.lookfrom[None] += ti.Vector([1.0,0.0,0.0])*speed.value
camera.lookat[None] += ti.Vector([1.0,0.0,0.0])*speed.value
pressed = True
elif(e.key == "d"):
camera.lookfrom[None] += ti.Vector([-1.0,0.0,0.0])*speed.value
camera.lookat[None] += ti.Vector([-1.0,0.0,0.0])*speed.value
pressed = True
elif(e.key == "q"):
camera.lookfrom[None] += ti.Vector([0.0,1.0,0.0])*speed.value
camera.lookat[None] += ti.Vector([0.0,1.0,0.0])*speed.value
pressed = True
elif(e.key == "e"):
camera.lookfrom[None] += ti.Vector([0.0,-1.0,0.0])*speed.value
camera.lookat[None] += ti.Vector([0.0,-1.0,0.0])*speed.value
pressed = True
if(pressed):
camera.reset()
pixels.fill(0)
cnt[None] = 0
#定义屏幕参数
aspectRatio = 1
width = 720
height = int(width/aspectRatio)
pixels = ti.Vector.field(3,ti.f32,shape=(width,height))
#定义摄像机参数
FOV = PI/3.0
camera = Camera(ti.Vector([0,1,-5]),ti.Vector([0,1,-1]),ti.Vector([0,1,0]),FOV,aspectRatio)
SPP = 30
depth = 15
p_RR = 0.9
#定义场景
scene = Hittable_list()
AddObject(scene)
#创建画布
gui = ti.GUI("Ray Tracing", res=(width,height))
pixels.fill(0)
cnt = ti.field(dtype=ti.i32,shape=())
cnt[None] = 0
speed = gui.slider('speed', 0, 1.0, step=0.05)
speed.value = 0.2
while(1):
MoveCamera()
ShootRay()
cnt[None] += 1
gui.set_image(np.sqrt(pixels.to_numpy()/cnt[None]))
gui.show()