Skip to content

Commit

Permalink
enhance t3.Accumate with denosing
Browse files Browse the repository at this point in the history
  • Loading branch information
archibate committed Oct 11, 2020
1 parent 369760e commit e45f1b3
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 44 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ Notable changes:
* Framebuffered texcoor - get model surface coordinate by mouse, see `examples/screen_to_texcoor.py`.
* Separate camera control logic from `t3.Camera` to `t3.CameraCtl`.
* Support `t3.AmbientLight` and ambient occulsion.
* Set up the path tracing scheme.
* Set up the basis of path tracing scheme.
* Shadow mapping is broken.

Minor fixes:
* Fix an artifect in perspective mode due to texture coordinate interpolation.
Expand All @@ -94,6 +95,7 @@ Minor fixes:
* Fix color artifects on edges due to interpolation.
* Fix shadow artifects on 90-deg faces.
* Make camera buffer update less ad-hoc.
* Support scaling in ORTHO mode.

Major steps:
* Standardize affine system - L2W, W2C, C2D.
Expand Down
17 changes: 8 additions & 9 deletions examples/path_tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
scene = t3.Scene()
obj = t3.readobj('assets/cube.obj', scale=0.8)
model = t3.Model.from_obj(obj)
model.add_uniform('color', 1.0)
model.shading_type = t3.IdealRT
model.add_uniform('diffuse', 1.0)
model.add_uniform('emission', 0.0)
scene.add_model(model)
light = t3.Model.from_obj(obj)
light.add_uniform('color', 0.0)
light.add_uniform('emission', 64.0)
light.shading_type = t3.IdealRT
light.add_uniform('diffuse', 0.0)
light.add_uniform('emission', 1.0)
light.add_uniform('emission_color', 16.0)
scene.add_model(light)
camera = t3.RTCamera(res=res)
camera.ctl = t3.CameraCtl(pos=[1, 0, -1])
camera.ctl = t3.CameraCtl(pos=[0.4, 0, -3.7])
scene.add_camera(camera)
accumator = t3.Accumator(camera.res)

Expand All @@ -27,10 +30,6 @@
gui.running = not gui.is_pressed(ti.GUI.ESCAPE)
if camera.from_mouse(gui):
accumator.reset()
camera.loadrays()
for s in range(2):
camera.steprays()
camera.applyrays()
accumator.accumate(camera.img)
accumator.render(camera, 2)
gui.set_image(accumator.buf)
gui.show()
8 changes: 4 additions & 4 deletions examples/shadow_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
scene.add_light(light)

gui = ti.GUI('Model', camera.res)
#gui2 = ti.GUI('Depth map', light.shadow.res)
#gui2.fps_limit = None
gui2 = ti.GUI('Depth map', light.shadow.res)
gui2.fps_limit = None
while gui.running:
gui.get_event(None)
gui.running = not gui.is_pressed(ti.GUI.ESCAPE)
Expand All @@ -29,6 +29,6 @@
scene.render_shadows()
scene.render()
gui.set_image(camera.img)
#gui2.set_image(light.shadow.fb['idepth'])
gui2.set_image(light.shadow.img)
gui.show()
#gui2.show()
gui2.show()
3 changes: 2 additions & 1 deletion taichi_three/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ def render_triangle(model, camera, face):
continue

clr = [a * w_A + b * w_B + c * w_C for a, b, c in zip(clra, clrb, clrc)]
camera.fb.update(X, model.pixel_shader(*clr))
#camera.fb.update(X, model.pixel_shader(*clr))
camera.img[X].fill(1)


@ti.func
Expand Down
8 changes: 4 additions & 4 deletions taichi_three/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ def get_dir(self, pos):
def set_view(self, camera):
self.viewdir[None] = (camera.L2W[None].inverse() @ ts.vec4(self.dir[None], 0)).xyz

def make_shadow_camera(self, dis=10, fov=60, **kwargs):
shadow = Camera()
def make_shadow_camera(self, res=(512, 512), dis=10, fov=60, **kwargs):
shadow = Camera(res=res)
shadow.fov = math.radians(fov)
shadow.ctl = CameraCtl(pos=(self.dir[None].value * dis).entries, **kwargs)
@ti.materialize_callback
#shadow.ctl = CameraCtl(pos=(-self.dir[None].value * dis).entries, **kwargs)
#@ti.materialize_callback
def init_camera():
shadow.ctl.apply(shadow)
shadow.type = shadow.ORTHO
Expand Down
63 changes: 52 additions & 11 deletions taichi_three/raycast.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def __init__(self, shape=(512, 512)):
@ti.kernel
def accumate(self, src: ti.template()):
self.count[None] += 1
alpha = max(1 / 256, 1 / self.count[None])
for I in ti.grouped(self.buf):
alpha = 1 / self.count[None]
self.buf[I] = self.buf[I] * (1 - alpha) + src[I] * alpha

@ti.kernel
Expand All @@ -24,6 +24,26 @@ def reset(self):
for I in ti.grouped(self.buf):
self.buf[I] *= 0

@ti.kernel
def denoise(self, alpha: ti.template(), throttle: ti.template()):
ti.static_print('denoise', alpha)
for I in ti.grouped(self.buf):
center = ts.clamp(self.buf[I])
around = ts.clamp((self.buf[I + ts.D.x_] + self.buf[I + ts.D.X_] + self.buf[I + ts.D._x] + self.buf[I + ts.D._X]) / 4)
diff = (center - around).norm_sqr()
if diff < throttle**2:
self.buf[I] = center * (1 - alpha) + around * alpha

def render(self, camera, depth, baseres=3, regrate=128):
rate = max(0, baseres - self.count[None] // regrate)
region = camera.res[0] // 2**rate, camera.res[1] // 2**rate
camera.loadrays((0, 0), region, 2**rate)
for step in range(depth):
camera.steprays()
camera.applyrays()
self.accumate(camera.img)
self.denoise(0.5 * (rate / baseres), 0.5)


class RTCamera(Camera):
def __init__(self, res=None):
Expand All @@ -35,9 +55,13 @@ def __init__(self, res=None):
self.rc = ti.Vector.field(3, float, self.N)
self.rI = ti.Vector.field(2, int, self.N)

@ti.kernel
def steprays(self):
for i in self.ro:
nrays = self.region[0] * self.region[1]
self._steprays(nrays)

@ti.kernel
def _steprays(self, nrays: ti.template()):
for i in range(nrays):
hit = 1e6
orig, dir = self.ro[i], self.rd[i]
if self.rd[i].norm_sqr() >= 1e-3:
Expand All @@ -49,22 +73,39 @@ def steprays(self):
self.ro[i], self.rd[i] = orig, dir
self.rc[i] *= clr

def loadrays(self, topleft=None, region=None, skipstep=None):
self.topleft = topleft or (0, 0)
self.region = region or self.res
self.skipstep = skipstep or 1
self._loadrays(self.topleft, self.region, self.skipstep)

@ti.kernel
def loadrays(self):
self.fb.clear_buffer()
for I in ti.grouped(ti.ndrange(*self.res)):
i = I.dot(ts.vec(1, self.res[0]))
def _loadrays(self, topleft: ti.template(), region: ti.template(), skipstep: ti.template()):
ti.static_print('loadrays:', topleft, region, skipstep)
for II in ti.grouped(ti.ndrange(*region)):
I = II * skipstep + topleft
for J in ti.static(ti.grouped(ti.ndrange(skipstep, skipstep))):
self.img[I + J] *= 0
for II in ti.grouped(ti.ndrange(*region)):
i = II.dot(ts.vec(1, region[0]))
I = II * skipstep + topleft + skipstep / 2
coor = ts.vec2((I.x - self.cx) / self.fx, (I.y - self.cy) / self.fy)
orig, dir = self.generate(coor)
self.ro[i] = orig
self.rd[i] = dir
self.rc[i] = ts.vec3(1.0)
self.rI[i] = I
self.rI[i] = II

@ti.kernel
def applyrays(self):
for i in self.ro:
self.img[self.rI[i]] = self.rc[i]
nrays = self.region[0] * self.region[1]
self._applyrays(nrays, self.topleft, self.skipstep)

@ti.kernel
def _applyrays(self, nrays: ti.template(), topleft: ti.template(), skipstep: ti.template()):
for i in range(nrays):
I = self.rI[i] * skipstep + topleft
for J in ti.static(ti.grouped(ti.ndrange(skipstep, skipstep))):
self.img[I + J] = self.rc[i]

@ti.func
def generate(self, coor):
Expand Down
40 changes: 26 additions & 14 deletions taichi_three/shading.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,32 @@ def brdf(self, normal, lightdir, viewdir):
return strength


class IdealRT(Shading):
emission = 0.0
diffuse = 1.0
specular = 0.0
emission_color = 1.0
diffuse_color = 1.0
specular_color = 1.0
parameters = ['emission', 'diffuse', 'specular', 'emission_color', 'diffuse_color', 'specular_color']

@ti.func
def radiance(self, pos, indir, normal):
outdir = ts.vec3(0.0)
clr = ts.vec3(0.0)
if ti.random() < self.emission:
clr = ts.vec3(self.emission_color)
elif ti.random() < self.specular:
clr = ts.vec3(self.specular_color)
outdir = ts.reflect(indir, normal)
elif ti.random() < self.diffuse:
clr = ts.vec3(self.diffuse_color)
outdir = ts.randUnit3D()
if outdir.dot(normal) < 0:
outdir = -outdir
return pos, outdir, clr


# https://zhuanlan.zhihu.com/p/37639418
class CookTorrance(Shading):
color = 1.0
Expand All @@ -136,20 +162,6 @@ class CookTorrance(Shading):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)

@ti.func
def radiance(self, pos, indir, normal):
outdir = ts.vec3(0.0)
clr = ts.vec3(0.0)
if ti.random() < self.emission:
clr = ts.vec3(1.0)
elif ti.random() < self.color:
clr = ts.vec3(1.0)
outdir = ts.reflect(indir, normal)
outdir = ts.randUnit3D()
if outdir.dot(normal) < 0:
outdir = -outdir
return pos, outdir, clr

@ti.func
def ischlick(self, cost):
k = (self.roughness + 1)**2 / 8
Expand Down

0 comments on commit e45f1b3

Please sign in to comment.