def tex(self): return [ i / ts.vec2(*self.parent.res) for i in [ self.i + ts.D.__, self.i + ts.D.x_, self.i + ts.D.xx, self.i + ts.D._x ] ]
def render(self): self.src.render() for i in self.kern: self.kern[i] = ts.randUnit3D() * ti.random()**2 * self.radius for i in ti.grouped(self.repa): u = ts.randUnit3D() v = ts.randUnit3D() w = u.cross(v).normalized() v = w.cross(u) self.repa[i] = ti.Matrix.rows([u, v, w]) for i in ti.grouped(self.img): count = 0 normal = self.src['normal'][i] d0 = self.invdep(self.src.idepth[i]) for j in range(self.samples): r = self.repa[i % ts.vec2(*self.repa.shape)] @ self.kern[j] r = v4trans(self.src.camera.L2W.inverse(), r, 0) if r.dot(normal) < 0: r = -r rxy = self.src.camera.uncook(ts.vec3(r.xy, d0), False).xy d1 = self.invdep(ts.bilerp(self.src.idepth, i + rxy)) d1 = d1 - r.z if d1 < d0 - 1e-6: count += 1 ao = 1 - count / self.samples self.img[i] = ao
def velocity(self, P): p = P * self.dx vel = ts.vec2(0.0) for v in range(self.vorts.shape[0]): dis = (p - self.vorts[v]) dis = ts.normalizePow(dis, -1, 0.001) dis = dis.yx * ts.vec(-1, 1) * self.vorty[v] vel += dis return vel * 0.01
def shadow_occlusion(self, wpos, normal): if ti.static(self.shadow is None): return 1 lspos = v4trans(self.shadow.L2W[None].inverse(), wpos, 1) lscoor = self.shadow.uncook(lspos) cur_z = lspos.z # TODO: bend with normal return self._sub_SDlerp(cur_z, lscoor, ts.vec2(0)) '''
def _render(self): for I in ti.grouped(self.img): scale = ti.static(2 / min(*self.img.shape())) coor = (I - ts.vec2(*self.img.shape()) / 2) * scale orig, dir = self.camera.generate(coor) pos, normal = self.trace(orig, dir) light_dir = self.light_dir[None] color = self.opt.render_func(pos, normal, dir, light_dir) color = self.opt.pre_process(color) self.img[I] = color
def uncook(self, pos): if ti.static(self.type == self.ORTHO): pos[0] *= self.intrinsic[None][0, 0] pos[1] *= self.intrinsic[None][1, 1] pos[0] += self.intrinsic[None][0, 2] pos[1] += self.intrinsic[None][1, 2] elif ti.static(self.type == self.TAN_FOV): pos = self.intrinsic[None] @ pos pos[0] /= abs(pos[2]) pos[1] /= abs(pos[2]) else: raise NotImplementedError("Curvilinear projection matrix not implemented!") return ts.vec2(pos[0], pos[1])
def sample(self, dir): I = ts.vec2(0.0) eps = 1e-5 dps = 1 - 12 / self.texture.shape[0] if dir.z >= 0 and dir.z >= abs(dir.y) - eps and dir.z >= abs( dir.x) - eps: I = ts.vec(3 / 8, 3 / 8) + dir.xy / dir.z / 8 * dps if dir.z <= 0 and -dir.z >= abs(dir.y) - eps and -dir.z >= abs( dir.x) - eps: I = ts.vec(7 / 8, 3 / 8) + dir.Xy / -dir.z / 8 * dps if dir.x <= 0 and -dir.x >= abs(dir.y) - eps and -dir.x >= abs( dir.z) - eps: I = ts.vec(1 / 8, 3 / 8) + dir.zy / -dir.x / 8 * dps if dir.x >= 0 and dir.x >= abs(dir.y) - eps and dir.x >= abs( dir.z) - eps: I = ts.vec(5 / 8, 3 / 8) + dir.Zy / dir.x / 8 * dps if dir.y >= 0 and dir.y >= abs(dir.x) - eps and dir.y >= abs( dir.z) - eps: I = ts.vec(3 / 8, 5 / 8) + dir.xZ / dir.y / 8 * dps if dir.y <= 0 and -dir.y >= abs(dir.x) - eps and -dir.y >= abs( dir.z) - eps: I = ts.vec(3 / 8, 1 / 8) + dir.xz / -dir.y / 8 * dps I = ts.vec2(self.texture.shape[0]) * I return ts.bilerp(self.texture, I)
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 * ti.random() 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] = II
def render_triangle(model, camera, face): scene = model.scene L2C = model.L2C[None] # Local to Camera, i.e. ModelView in OpenGL posa, posb, posc = face.pos texa, texb, texc = face.tex nrma, nrmb, nrmc = face.nrm posa = (L2C @ ts.vec4(posa, 1)).xyz posb = (L2C @ ts.vec4(posb, 1)).xyz posc = (L2C @ ts.vec4(posc, 1)).xyz nrma = (L2C @ ts.vec4(nrma, 0)).xyz nrmb = (L2C @ ts.vec4(nrmb, 0)).xyz nrmc = (L2C @ ts.vec4(nrmc, 0)).xyz pos_center = (posa + posb + posc) / 3 if ti.static(camera.type == camera.ORTHO): pos_center = ts.vec3(0.0, 0.0, 1.0) dpab = posa - posb dpac = posa - posc dtab = texa - texb dtac = texa - texc normal = ts.cross(dpab, dpac) # NOTE: the normal computation indicates that a front-facing face should # be COUNTER-CLOCKWISE, i.e., glFrontFace(GL_CCW); # this is to be compatible with obj model loading. if ts.dot(pos_center, normal) <= 0: tan, bitan = compute_tangent(-dpab, -dpac, -dtab, -dtac) # TODO: node-ize this clra = model.vertex_shader( posa, texa, nrma, tan, bitan) # TODO: interpolate tan and bitan? merge with nrm? clrb = model.vertex_shader(posb, texb, nrmb, tan, bitan) clrc = model.vertex_shader(posc, texc, nrmc, tan, bitan) A = camera.uncook(posa) B = camera.uncook(posb) C = camera.uncook(posc) scr_norm = ts.cross(A - C, B - A) if scr_norm != 0: # degenerate to 'line' if zero B_A = (B - A) / scr_norm A_C = (A - C) / scr_norm shake = ts.vec2(0.0) if ti.static(camera.fb.n_taa): for i, s in ti.static( enumerate(map(ti.Vector, TAA_SHAKES[:camera.fb.n_taa]))): if camera.fb.itaa[None] == i: shake = s * 0.5 # screen space bounding box M = int(ti.floor(min(A, B, C) - 1)) N = int(ti.ceil(max(A, B, C) + 1)) M = ts.clamp(M, 0, ti.Vector(camera.fb.res)) N = ts.clamp(N, 0, ti.Vector(camera.fb.res)) for X in ti.grouped(ti.ndrange((M.x, N.x), (M.y, N.y))): # barycentric coordinates using the area method X_A = X - A + shake w_C = ts.cross(B_A, X_A) w_B = ts.cross(A_C, X_A) w_A = 1 - w_C - w_B # draw eps = ti.get_rel_eps() * 0.2 is_inside = w_A >= -eps and w_B >= -eps and w_C >= -eps if not is_inside: continue # https://gitee.com/zxtree2006/tinyrenderer/blob/master/our_gl.cpp if ti.static(camera.type != camera.ORTHO): bclip = ts.vec3(w_A / posa.z, w_B / posb.z, w_C / posc.z) bclip /= bclip.x + bclip.y + bclip.z w_A, w_B, w_C = bclip depth = (posa.z * w_A + posb.z * w_B + posc.z * w_C) if camera.fb.atomic_depth(X, depth): 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))
def get_normal_at(self, i): xa = self.pos[ts.clamp(i + ts.D.x_, 0, ts.vec2(*self.shape))] xb = self.pos[ts.clamp(i + ts.D.X_, 0, ts.vec2(*self.shape))] ya = self.pos[ts.clamp(i + ts.D._x, 0, ts.vec2(*self.shape))] yb = self.pos[ts.clamp(i + ts.D._X, 0, ts.vec2(*self.shape))] return (ya - yb).cross(xa - xb).normalized()
def tex(self): return [i / ts.vec2(*self.parent.res) for i in self.seq]
__import__('sys').path.insert(0, '/home/bate/Develop/glsl_taichi') __import__('sys').path.insert(0, 'external') import numpy as np import taichi as ti import taichi_glsl as tl ts = tl V = lambda *_: tl.vec(*_).cast(float) if ti.impl.inside_kernel() else tl.vec(*_ ) V3 = lambda *_: tl.vec3(*_).cast(float) if ti.impl.inside_kernel( ) else tl.vec3(*_) V2 = lambda *_: tl.vec2(*_).cast(float) if ti.impl.inside_kernel( ) else tl.vec2(*_) EPS = 1e-6 INF = 1e6 @ti.pyfunc def tangent(Z): Y = V(0, 1, 0) if any(abs(Z.xz) >= 1e-2) else V(1, 0, 0) if any( abs(Z.yz) >= 1e-2) else V(0, 0, 1) X = Y.cross(Z).normalized() Y = Z.cross(X) return ti.Matrix([X.entries, Y.entries, Z.entries]).transpose() @ti.pyfunc def spherical(h, phi):
def uncook_coor(self, coor): coor_xy = ts.shuffle(coor, 0, 1) scale = ti.static(min(*self.img.shape()) / 2) I = coor_xy * scale + ts.vec2(*self.img.shape()) / 2 return I
def cook_coor(self, I): scale = ti.static(2 / min(*self.img.shape())) coor = (I - ts.vec2(*self.img.shape()) / 2) * scale return coor
def uncook_coor(self, coor): scale = ti.static(min(*self.img.shape()) / 2) I = coor.xy * scale + ts.vec2(*self.img.shape()) / 2 return I
def render_triangle(model, camera, face): posa, posb, posc = face.pos # Position texa, texb, texc = face.tex # TexCoord nrma, nrmb, nrmc = face.nrm # Normal pos_center = (posa + posb + posc) / 3 if ti.static(camera.type == camera.ORTHO): pos_center = ts.vec3(0.0, 0.0, 1.0) # NOTE: the normal computation indicates that a front-facing face should # be COUNTER-CLOCKWISE, i.e., glFrontFace(GL_CCW); # this is to be compatible with obj model loading. if ts.dot(pos_center, ts.cross(posa - posc, posa - posb)) >= 0: tan, bitan = compute_tangent(posb - posa, posc - posa, texb - texa, texc - texa) # TODO: node-ize this clra = [posa, texa, nrma] # TODO: interpolate tan and bitan? merge with nrm? clrb = [posb, texb, nrmb] clrc = [posc, texc, nrmc] A = camera.uncook(posa) B = camera.uncook(posb) C = camera.uncook(posc) scr_norm = ts.cross(A - C, B - A) if scr_norm != 0: # degenerate to 'line' if zero B_A = (B - A) / scr_norm A_C = (A - C) / scr_norm shake = ts.vec2(0.0) if ti.static(camera.fb.n_taa): for i, s in ti.static(enumerate(map(ti.Vector, TAA_SHAKES[:camera.fb.n_taa]))): if camera.fb.itaa[None] == i: shake = s * 0.5 # screen space bounding box M = int(ti.floor(min(A, B, C) - 1)) N = int(ti.ceil(max(A, B, C) + 1)) M = ts.clamp(M, 0, ti.Vector(camera.fb.res)) N = ts.clamp(N, 0, ti.Vector(camera.fb.res)) for X in ti.grouped(ti.ndrange((M.x, N.x), (M.y, N.y))): # barycentric coordinates using the area method X_A = X - A + shake w_C = ts.cross(B_A, X_A) w_B = ts.cross(A_C, X_A) w_A = 1 - w_C - w_B # draw eps = ti.get_rel_eps() * 0.2 is_inside = w_A >= -eps and w_B >= -eps and w_C >= -eps if not is_inside: continue # https://gitee.com/zxtree2006/tinyrenderer/blob/master/our_gl.cpp if ti.static(camera.type != camera.ORTHO): bclip = ts.vec3(w_A / posa.z, w_B / posb.z, w_C / posc.z) bclip /= bclip.x + bclip.y + bclip.z w_A, w_B, w_C = bclip depth = (posa.z * w_A + posb.z * w_B + posc.z * w_C) if camera.fb.atomic_depth(X, depth): continue posx, texx, nrmx = [a * w_A + b * w_B + c * w_C for a, b, c in zip(clra, clrb, clrc)] color = ti.static(model.material.pixel_shader(model, posx, texx, nrmx, tan, bitan)) if ti.static(isinstance(color, dict)): camera.fb.update(X, color) else: camera.fb.update(X, dict(img=color))
def vgridGradient(field: ti.template(), I): return ts.vec2( sample(field, I + D.xy) - sample(field, I + D.xz), sample(field, I + D.yx) - sample(field, I + D.zx))
def on_render(self): ts.paintArrow(self.img, ts.vec2(0.0), self.iMouse)