Ejemplo n.º 1
0
    def render_func(self, pos, normal, dir, light_dir):
        color = ts.vec3(0.0)

        shineness = self.shineness
        half_lambert = ts.dot(normal, light_dir) * 0.5 + 0.5
        lambert = max(0, ts.dot(normal, light_dir))
        blinn_phong = ts.dot(normal, ts.mix(light_dir, -dir, 0.5))
        blinn_phong = pow(max(blinn_phong, 0), shineness)
        refl_dir = ts.reflect(light_dir, normal)
        phong = -ts.dot(normal, refl_dir)
        phong = pow(max(phong, 0), shineness)

        strength = 0.0
        if ti.static(self.lambert != 0.0):
            strength += lambert * self.lambert
        if ti.static(self.half_lambert != 0.0):
            strength += half_lambert * self.half_lambert
        if ti.static(self.blinn_phong != 0.0):
            strength += blinn_phong * self.blinn_phong
        if ti.static(self.phong != 0.0):
            strength += phong * self.phong
        color = ts.vec3(strength)

        if ti.static(self.is_normal_map):
            color = normal * 0.5 + 0.5

        return color
Ejemplo n.º 2
0
 def render_floor(self, camera):
     scene = camera.scene
     c_floor = ts.vec3(*self.floor_color)
     c_sky = ts.vec3(*self.sky_color)
     for X in ti.grouped(camera.img):
         W = ti.cast(ti.Vector([X.x, X.y, 1]), ti.f32)
         x = cook_coord(camera, W)
         world_dir = camera.trans_dir(ts.normalize(x))
         if world_dir[1] > 0 or camera.pos[None][1] < floor_y:
             camera.img[X] = c_sky
         else:
             f = min(1, -world_dir[1] * 50)
             n = camera.untrans_dir(ts.vec3(0, 1, 0))
             pos = camera.pos[None] + world_dir * (
                 camera.pos[None][1] - floor_y) / abs(world_dir[1])
             #print(pos)
             pos = camera.untrans_pos(pos)
             #print(pos)
             color = ambient * c_sky * c_floor
             for light in ti.static(scene.lights):
                 light_color = scene.opt.render_func(pos, n, \
                     ts.normalize(pos), light, c_floor)
                 color += light_color
             camera.img[X] = c_sky * (1 - f) + color * f
             camera.nbuf[X] = n
             camera.zbuf[X] = 1 / pos.z
Ejemplo n.º 3
0
def render_particle(model, camera, index):
    scene = model.scene
    a = (model.L2C[None] @ ts.vec4(model.pos[index], 1)).xyz
    r = model.radius[index]
    A = camera.uncook(a)

    rad = camera.uncook(ts.vec3(r, r, a.z), False)

    M = int(ti.floor(A - rad))
    N = int(ti.ceil(A + rad))
    M = ts.clamp(M, 0, ti.Vector(camera.res))
    N = ts.clamp(N, 0, ti.Vector(camera.res))

    for X in ti.grouped(ti.ndrange((M.x, N.x), (M.y, N.y))):
        pos = camera.cook(float(ts.vec3(X, a.z)))
        dp = pos - a
        dp2 = dp.norm_sqr()

        if dp2 > r**2:
            continue

        dz = ti.sqrt(r**2 - dp2)
        if camera.fb.atomic_depth(X, a.z - dz):
            continue

        n = ts.vec3(dp.xy, -dz)
        normal = ts.normalize(n)
        view = ts.normalize(a + n)

        color = model.colorize(pos, normal)
        camera.fb['img'][X] = color
        camera.fb['normal'][X] = normal
Ejemplo n.º 4
0
    def pixel_shader(self, pos, texcoor, normal, tangent, bitangent):
        ndir = self.sample('normal', texcoor, ts.vec3(0.0, 0.0, 1.0))
        normal = ti.Matrix.cols([tangent, bitangent, normal]) @ ndir
        normal = normal.normalized()

        color = self.sample('color', texcoor, ts.vec3(1.0))
        color = self.colorize(pos, texcoor, normal, color)
        return dict(img=color, normal=normal,
                    tangent=tangent, bitangent=bitangent)
Ejemplo n.º 5
0
 def trace(self, orig, dir):
     pos = orig
     color = ts.vec3(0.0)
     normal = ts.vec3(0.0)
     for s in range(100):
         t = self.calc_sdf(pos)
         if t <= 0:
             normal = ts.normalize(self.calc_grad(pos) - t)
             break
         pos += dir * t
     return pos, normal
Ejemplo n.º 6
0
def normal(pos):
    eps = 0.005
    v1 = ts.vec3(1.0, -1.0, -1.0)
    v2 = ts.vec3(-1.0, -1.0, 1.0)
    v3 = ts.vec3(-1.0, 1.0, -1.0)
    v4 = ts.vec3(1.0, 1.0, 1.0)

    return ts.normalize(v1 * scene(pos + v1 * eps) +
                        v2 * scene(pos + v2 * eps) +
                        v3 * scene(pos + v3 * eps) +
                        v4 * scene(pos + v4 * eps))
Ejemplo n.º 7
0
 def get_volume_normal(self, pos):
     delta = 1e-3
     x_delta = tl.vec3(delta, 0.0, 0.0)
     y_delta = tl.vec3(0.0, delta, 0.0)
     z_delta = tl.vec3(0.0, 0.0, delta)
     dx = self.sample_volume_trilinear(pos + x_delta) \
          - self.sample_volume_trilinear(pos - x_delta)
     dy = self.sample_volume_trilinear(pos + y_delta) \
          - self.sample_volume_trilinear(pos - y_delta)
     dz = self.sample_volume_trilinear(pos + z_delta) \
          - self.sample_volume_trilinear(pos - z_delta)
     return tl.vec3(dx, dy, dz).normalized()
Ejemplo n.º 8
0
def get_ambient(camera, normal, view):
    c_floor = ts.vec3(0.75)
    c_sky = ts.vec3(0.8, 0.9, 0.95)
    refl_dir = -ts.reflect(-view, normal)
    refl_dir = ts.normalize(camera.trans_dir(refl_dir))
    color = ts.vec3(ambient)
    if refl_dir[1] > 0:
        color *= c_sky
    else:
        f = min(1.0, -refl_dir[1] * 25.0)
        color *= c_sky * (1 - f) + c_floor * f
    return color
Ejemplo n.º 9
0
 def pixel_shader(self, mid: ti.template(), pos, tex, nrm, tan, bitan):
     if ti.static(isinstance(mid, int)):
         return ti.static(self.materials[mid]).pixel_shader(
             pos, tex, nrm, tan, bitan)
     color = ts.vec3(0.0)
     if mid != 0:
         color = ts.vec3(1.0, 0.0,
                         1.0)  # magenta, for debugging missing materials
     for i, material in ti.static(self.materials.items()):
         if mid == i:
             color = material.pixel_shader(pos, tex, nrm, tan, bitan)
     return color
Ejemplo n.º 10
0
def compute_tangent(dp1, dp2, duv1, duv2):
    if ti.static(0):
        return ts.vec3(0.0), ts.vec3(0.0)
    IDUV = ti.Matrix([[duv1.x, duv1.y], [duv2.x, duv2.y]]).inverse()
    DPx = ti.Vector([dp1.x, dp2.x])
    DPy = ti.Vector([dp1.y, dp2.y])
    DPz = ti.Vector([dp1.z, dp2.z])
    T = ti.Vector([0.0, 0.0, 0.0])
    B = ti.Vector([0.0, 0.0, 0.0])
    T.x, B.x = IDUV @ DPx
    T.y, B.y = IDUV @ DPy
    T.z, B.z = IDUV @ DPz
    return T, B
Ejemplo n.º 11
0
 def calc_gi(self, camera):
     scene = camera.scene
     for X in ti.grouped(camera.img):
         if self.enable_gi[None] == 0:
             continue
         # use an additional normal buffer at this time
         if camera.zbuf[X] > 0:
             z = 1 / camera.zbuf[X]
             pos = cook_coord(camera,
                              ti.cast(ti.Vector([X.x, X.y, z]), ti.f32))
             pos_world = camera.trans_pos(pos)
             norm_world = camera.trans_dir(camera.nbuf[X])
             dy = pos_world[1] - floor_y
             ftot = 0.0
             if dy > 0:
                 ftot = form_factor_floor(norm_world, dy, self.radius)
             gtot = ts.vec3(0.0)
             if ti.static(self.grid is not None):
                 base = self.grid.grid_index(pos_world)
                 for dI in ti.grouped(ti.ndrange((-4, 5), (-4, 5),
                                                 (-4, 5))):
                     I = max(0, min(base + dI, self.grid.gridsize - 1))
                     for p in range(self.grid_n[I + dI]):
                         i = self.grid_list[I + dI, p]
                         if (self.particles[i] - pos_world).norm_sqr() \
                                 > (self.gi_cutoff * self.boxlength) ** 2:
                             continue
                         f, gi = get_gi_factors(camera, scene,
                                                self.particles[i],
                                                pos_world, norm_world,
                                                self.radius,
                                                self.colors[self.type[i]])
                         ftot += f
                         gtot += gi
             else:
                 for i in range(self.particles.shape[0]):
                     # don't compute for particles behind the normal
                     if ti.dot(self.particles[i] - pos_world,
                               norm_world) < 0:
                         continue
                     f, gi = get_gi_factors(camera, scene,
                                            self.particles[i], pos_world,
                                            norm_world, self.radius,
                                            self.colors[self.type[i]])
                     ftot += f
                     gtot += gi
             camera.img[X] = camera.img[X] * ts.vec3(max(1 - ftot,
                                                         0)) + gtot * 0.3
Ejemplo n.º 12
0
def render_line(model, camera, face, w0=0, w1=1):
    posa, posb = face.pos   # Position
    texa, texb = face.tex   # TexCoord
    nrma, nrmb = face.nrm   # Normal

    clra = [posa, texa, nrma]
    clrb = [posb, texb, nrmb]

    A = camera.uncook(posa)
    B = camera.uncook(posb)

    M = int(ti.floor(min(A, B) - 1))
    N = int(ti.ceil(max(A, B) + 1))
    M = ts.clamp(M, 0, ti.Vector(camera.fb.res))
    N = ts.clamp(N, 0, ti.Vector(camera.fb.res))

    B_A = (B - A).normalized()

    for X in ti.grouped(ti.ndrange((M.x, N.x), (M.y, N.y))):
        udf = abs((X - A).cross(B_A))
        if udf >= w1:
            continue

        strength = ts.smoothstep(udf, w1, w0)
        color = ts.vec3(strength)
        camera.img[X] += color
Ejemplo n.º 13
0
    def sample_volume_trilinear(self, pos):
        ''' Samples volume data at `pos` and trilinearly interpolates the value

        Args:
            pos (tl.vec3): Position to sample the volume in [-1, 1]^3

        Returns:
            float: Sampled interpolated intensity
        '''
        pos = tl.clamp(((0.5 * pos) + 0.5), 0.0, 1.0) \
              * ti.static(tl.vec3(*self.volume.shape) - 1.0 - 1e-4)
        x_low, x_high, x_frac = low_high_frac(pos.x)
        y_low, y_high, y_frac = low_high_frac(pos.y)
        z_low, z_high, z_frac = low_high_frac(pos.z)

        x_high = min(x_high, ti.static(self.volume.shape[0] - 1))
        y_high = min(y_high, ti.static(self.volume.shape[1] - 1))
        z_high = min(z_high, ti.static(self.volume.shape[2] - 1))
        # on z_low
        v000 = self.volume[x_low, y_low, z_low]
        v100 = self.volume[x_high, y_low, z_low]
        x_val_y_low = tl.mix(v000, v100, x_frac)
        v010 = self.volume[x_low, y_high, z_low]
        v110 = self.volume[x_high, y_high, z_low]
        x_val_y_high = tl.mix(v010, v110, x_frac)
        xy_val_z_low = tl.mix(x_val_y_low, x_val_y_high, y_frac)
        # on z_high
        v001 = self.volume[x_low, y_low, z_high]
        v101 = self.volume[x_high, y_low, z_high]
        x_val_y_low = tl.mix(v001, v101, x_frac)
        v011 = self.volume[x_low, y_high, z_high]
        v111 = self.volume[x_high, y_high, z_high]
        x_val_y_high = tl.mix(v011, v111, x_frac)
        xy_val_z_high = tl.mix(x_val_y_low, x_val_y_high, y_frac)
        return tl.mix(xy_val_z_low, xy_val_z_high, z_frac)
Ejemplo n.º 14
0
 def intersect(self, orig, dir):
     ret, normal = INF, ts.vec3(0.0)
     for b in ti.static(self.balls):
         t, n = b.intersect(orig, dir)
         if t < ret:
             ret, normal = t, n
     return ret, normal
Ejemplo n.º 15
0
 def intersect(self, orig, dir):
     ret, normal = INF, ts.vec3(0.0)
     for I in ti.grouped(ti.ndrange(*self.pos.shape())):
         t, n = self.make_one(I).do_intersect(orig, dir)
         if t < ret:
             ret, normal = t, n
     return ret, normal
Ejemplo n.º 16
0
def cal_look_at_mat(ro, ta, roll):
    ww = (ta - ro).normalized()
    uu = ts.cross(ww, ts.vec3(ts.sin(roll), ts.cos(roll), 0.0)).normalized()
    vv = ts.cross(uu, ww).normalized()

    return ts.mat([uu[0], vv[0], ww[0]], [uu[1], vv[1], ww[1]],
                  [uu[2], vv[2], ww[2]])
Ejemplo n.º 17
0
def intersect_triangle(model, orig, dir, face):
    posa, posb, posc = face.pos
    texa, texb, texc = face.tex
    nrma, nrmb, nrmc = face.nrm

    L2C = model.L2W[None]
    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
    tan, bitan = compute_tangent(posb - posa, posc - posa, texb - texa, texc - texa)

    hit = 1e6
    clr = ts.vec3(0.0)
    sa, sb, sc = plucker_bcoor(orig, orig + dir, posa, posb, posc)
    if (sa >= 0 and sb >= 0 and sc >= 0) or (sa <= 0 and sb <= 0 and sc <= 0):
        snorm = sa + sb + sc
        sa /= snorm
        sb /= snorm
        sc /= snorm
        pos = posa * sa + posb * sb + posc * sc
        tex = texa * sa + texb * sb + texc * sc
        nrm = nrma * sa + nrmb * sb + nrmc * sc
        if dir.dot(pos - orig) > 1e-4:
            hit = (pos - orig).norm()
            orig, dir, clr = model.material.radiance(model, pos, dir, tex, nrm, tan, bitan)

    return hit, orig, dir, clr
Ejemplo n.º 18
0
 def _render(self):
     for I in ti.grouped(self.img):
         self.img[I] = ts.vec3(0.0)
         self.zbuf[I] = 0.0
     if ti.static(len(self.models)):
         for model in ti.static(self.models):
             model.render()
Ejemplo n.º 19
0
    def __init__(self,
                 volume_resolution,
                 render_resolution,
                 max_samples=512,
                 tf_resolution=128,
                 fov=30.0,
                 nearfar=(0.1, 100.0)):
        ''' Initializes Volume Raycaster. Make sure to .set_volume() and .set_tf_tex() after initialization

        Args:
            volume_resolution (3-tuple of int): Resolution of the volume data (w,h,d)
            render_resolution (2-tuple of int): Resolution of the rendering (w,h)
            tf_resolution (int): Resolution of the transfer function texture
            fov (float, optional): Field of view of the camera in degrees. Defaults to 60.0.
            nearfar (2-tuple of float, optional): Near and far plane distance used for perspective projection. Defaults to (0.1, 100.0).
        '''
        self.resolution = render_resolution
        self.aspect = render_resolution[0] / render_resolution[1]
        self.fov_deg = fov
        self.fov_rad = np.radians(fov)
        self.near, self.far = nearfar
        # Taichi Fields
        self.volume = ti.field(ti.f32, needs_grad=True)
        self.tf_tex = ti.Vector.field(4, dtype=ti.f32, needs_grad=True)
        self.render_tape = ti.Vector.field(4, dtype=ti.f32, needs_grad=True)
        self.output_rgba = ti.Vector.field(4, dtype=ti.f32, needs_grad=True)
        self.valid_sample_step_count = ti.field(ti.i32)
        self.sample_step_nums = ti.field(ti.i32)
        self.entry = ti.field(ti.f32)
        self.exit = ti.field(ti.f32)
        self.rays = ti.Vector.field(3, dtype=ti.f32)
        self.max_valid_sample_step_count = ti.field(ti.i32, ())
        self.max_samples = max_samples
        self.ambient = 0.4
        self.diffuse = 0.8
        self.specular = 0.3
        self.shininess = 32.0
        self.light_color = tl.vec3(1.0)
        self.cam_pos = ti.Vector.field(3, dtype=ti.f32)
        volume_resolution = tuple(map(lambda d: d // 4, volume_resolution))
        render_resolution = tuple(map(lambda d: d // 8, render_resolution))
        ti.root.dense(ti.ijk,
                      volume_resolution).dense(ti.ijk,
                                               (4, 4, 4)).place(self.volume)
        ti.root.dense(ti.ijk, (*render_resolution, max_samples)).dense(
            ti.ijk, (8, 8, 1)).place(self.render_tape)
        ti.root.dense(ti.ij, render_resolution).dense(ti.ij, (8, 8)).place(
            self.valid_sample_step_count, self.sample_step_nums)
        ti.root.dense(ti.ij, render_resolution).dense(ti.ij, (8, 8)).place(
            self.output_rgba)
        ti.root.dense(ti.ij, render_resolution).dense(ti.ij, (8, 8)).place(
            self.entry, self.exit)
        ti.root.dense(ti.ij,
                      render_resolution).dense(ti.ij,
                                               (8, 8)).place(self.rays)
        ti.root.dense(ti.i, tf_resolution).place(self.tf_tex)
        ti.root.dense(ti.i, tf_resolution).place(self.tf_tex.grad)
        ti.root.place(self.cam_pos)
        ti.root.lazy_grad()
Ejemplo n.º 20
0
 def radiance(self):
     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(self.indir, self.normal)
     elif ti.random() < self.diffuse:
         clr = ts.vec3(self.diffuse_color)
         outdir = ts.randUnit3D()
         if outdir.dot(self.normal) < 0:
             outdir = -outdir
         #s = ti.random()
         #outdir = ts.vec3(ti.sqrt(1 - s**2) * ts.randUnit2D(), s)
         #outdir = ti.Matrix.cols([self.tangent, self.bitangent, self.normal]) @ outdir
     return self.pos, outdir, clr
Ejemplo n.º 21
0
 def clear_framebuffer(self):
     self.max_valid_sample_step_count[None] = 0
     for i, j, k in self.render_tape:
         self.render_tape[i, j, k] = tl.vec4(0.0)
     for i, j in self.valid_sample_step_count:
         self.valid_sample_step_count[i, j] = 1
         self.output_rgba[i, j] = tl.vec4(0.0)
         self.output_rgb[i, j] = tl.vec3(0.0)
Ejemplo n.º 22
0
 def render_func(self, pos, normal, viewdir, light, color):
     lightdir = light.get_dir(pos)
     costheta = max(0, ti.dot(normal, lightdir))
     l_out = ts.vec3(0.0)
     if costheta > 0:
         l_out = self.brdf(normal, -viewdir, lightdir, color)\
              * costheta * light.get_color(pos)
     return l_out
Ejemplo n.º 23
0
    def generate(self, coor):
        orig = ts.vec3(0.0)
        dir = ts.vec3(0.0, 0.0, 1.0)

        if ti.static(self.type == self.ORTHO):
            orig = ts.vec3(coor, 0.0)
        elif ti.static(self.type == self.TAN_FOV):
            uv = coor * self.fov
            dir = ts.normalize(ts.vec3(uv, 1))
        elif ti.static(self.type == self.COS_FOV):
            uv = coor * self.fov
            dir = ts.vec3(ti.sin(uv), ti.cos(uv.norm()))

        orig = (self.L2W[None] @ ts.vec4(orig, 1)).xyz
        dir = (self.L2W[None] @ ts.vec4(dir, 0)).xyz

        return orig, dir
Ejemplo n.º 24
0
 def flush_taa(self):
     if ti.static(self.n_taa):
         self.ntaa[None] = 0
         self.itaa[None] = 0
         for I in ti.grouped(ti.ndrange(*self.res)):
             r = ts.vec3(0.0)
             for i in ti.static(range(self.n_taa)):
                 self.taa[i, I] *= 0
Ejemplo n.º 25
0
 def render(self, camera):
     for I in ti.grouped(ti.ndrange(*camera.res)):
         if camera.fb.idepth[I] != 0:
             continue
         id = I / ts.vec(*camera.res) * 2 - 1
         dir = ts.vec3(id * ti.tan(camera.fov), 1.0)
         dir = v4trans(self.L2C[None].inverse(), dir, 0).normalized()
         color = self.sample(dir)
         camera.fb.update(I, dict(img=color))
Ejemplo n.º 26
0
def my_render_func(pos, normal, dir, light_dir):
    n = cartoon_level[None]
    refl_dir = ts.reflect(light_dir, normal)
    #refl_dir = ts.mix(light_dir, -dir, 0.5)
    NoL = pow(ts.dot(normal, refl_dir), 12)
    NoL = ts.mix(NoL, ts.dot(normal, light_dir) * 0.5 + 0.5, 0.5)
    strength = 0.2
    if any(normal):
        strength = ti.floor(max(0, NoL * n + 0.5)) / n
    return ts.vec3(strength)
Ejemplo n.º 27
0
 def do_render(self, scene):
     W = 1
     A = scene.uncook_coor(scene.camera.untrans_pos(self.a))
     B = scene.uncook_coor(scene.camera.untrans_pos(self.b))
     M, N = int(ti.floor(min(A, B) - W)), int(ti.ceil(max(A, B) + W))
     for X in ti.grouped(ti.ndrange((M.x, N.x), (M.y, N.y))):
         P = B - A
         udf = (ts.cross(X, P) + ts.cross(B, A))**2 / P.norm_sqr()
         XoP = ts.dot(X, P)
         AoB = ts.dot(A, B)
         if XoP > B.norm_sqr() - AoB:
             udf = (B - X).norm_sqr()
         elif XoP < AoB - A.norm_sqr():
             udf = (A - X).norm_sqr()
         if udf < 0:
             scene.img[X] = ts.vec3(1.0)
         elif udf < W**2:
             t = ts.smoothstep(udf, 0, W**2)
             ti.atomic_min(scene.img[X], ts.vec3(t))
Ejemplo n.º 28
0
 def render_func(self, pos, normal, viewdir, light):  # TODO: move render_func to Light.render_func?
     if ti.static(isinstance(light, AmbientLight)):
         return light.get_color(pos) * self.get_ambient()
     lightdir = light.get_dir(pos)
     NoL = ts.dot(normal, lightdir)
     l_out = ts.vec3(0.0)
     if NoL > EPS:
         l_out = light.get_color(pos)
         l_out *= NoL * self.brdf(normal, lightdir, -viewdir)
     return l_out
Ejemplo n.º 29
0
 def render(self):
     self.src.render()
     for I in ti.grouped(self.img):
         mid = self.src['mid'][I]
         pos = self.src['position'][I]
         texcoor = self.src['texcoord'][I]
         normal = self.src['normal'][I]
         tangent = self.src['tangent'][I]
         bitangent = normal.cross(tangent)
         color = ts.vec3(0.0)
         if mid != 0:
             color = ts.vec3(1.0, 0.0,
                             1.0)  # magenta for debugging missing material
         if ti.static(len(self.mtllib)):
             for i, material in ti.static(enumerate(self.mtllib)):
                 if ti.static(material is not None):
                     if i == mid:
                         color = material.pixel_shader(
                             self, pos, texcoor, normal, tangent, bitangent)
         self.img[I] = color