Example #1
0
def render_photon_map(t: ti.i32, offset_x: ti.f32, offset_y: ti.f32):
  for i in range(n_grid):  # Parallelized over GPU threads
    for j in range(n_grid):
      grad = height_gradient[i, j] * (1 - offset_x) * (1 - offset_y) + \
             height_gradient[i + 1, j] * offset_x * (1 - offset_y) + \
             height_gradient[i, j + 1] * (1 - offset_x) * offset_y + \
             height_gradient[i + 1, j + 1] * offset_x * offset_y
      
      scale = 5.0
      sample_x = i - grad[0] * scale + offset_x
      sample_y = j - grad[1] * scale + offset_y
      sample_x = ti.min(n_grid - 1, ti.max(0, sample_x))
      sample_y = ti.min(n_grid - 1, ti.max(0, sample_y))
      sample_xi = ti.cast(ti.floor(sample_x), ti.i32)
      sample_yi = ti.cast(ti.floor(sample_y), ti.i32)
      
      frac_x = sample_x - sample_xi
      frac_y = sample_y - sample_yi
      
      x = sample_xi
      y = sample_yi
      
      ti.atomic_add(rendered[x, y], (1 - frac_x) * (1 - frac_y))
      ti.atomic_add(rendered[x, y + 1], (1 - frac_x) * frac_y)
      ti.atomic_add(rendered[x + 1, y], frac_x * (1 - frac_y))
      ti.atomic_add(rendered[x + 1, y + 1], frac_x * frac_y)
Example #2
0
def advect(field: ti.template(), field_out: ti.template(),
           t_offset: ti.template(), t: ti.i32):
    """Move field smoke according to x and y velocities (vx and vy)
     using an implicit Euler integrator."""
    for y in range(n_grid):
        for x in range(n_grid):
            center_x = y - v[t + t_offset, y, x][0]
            center_y = x - v[t + t_offset, y, x][1]

            # Compute indices of source cell
            left_ix = ti.cast(ti.floor(center_x), ti.i32)
            top_ix = ti.cast(ti.floor(center_y), ti.i32)

            rw = center_x - left_ix  # Relative weight of right-hand cell
            bw = center_y - top_ix  # Relative weight of bottom cell

            # Wrap around edges
            # TODO: implement mod (%) operator
            left_ix = imod(left_ix, n_grid)
            right_ix = inc_index(left_ix)
            top_ix = imod(top_ix, n_grid)
            bot_ix = inc_index(top_ix)

            # Linearly-weighted sum of the 4 surrounding cells
            field_out[t, y, x] = (1 - rw) * (
                (1 - bw) * field[t - 1, left_ix, top_ix] +
                bw * field[t - 1, left_ix, bot_ix]) + rw * (
                    (1 - bw) * field[t - 1, right_ix, top_ix] +
                    bw * field[t - 1, right_ix, bot_ix])
Example #3
0
def render_refract(t: ti.i32):
  for i in range(n_grid):  # Parallelized over GPU threads
    for j in range(n_grid):
      grad = height_gradient[i, j]
      
      scale = 2.0
      sample_x = i - grad[0] * scale
      sample_y = j - grad[1] * scale
      sample_x = ti.min(n_grid - 1, ti.max(0, sample_x))
      sample_y = ti.min(n_grid - 1, ti.max(0, sample_y))
      sample_xi = ti.cast(ti.floor(sample_x), ti.i32)
      sample_yi = ti.cast(ti.floor(sample_y), ti.i32)
      
      frac_x = sample_x - sample_xi
      frac_y = sample_y - sample_yi
      
      for k in ti.static(range(3)):
        refracted_image[i, j, k] = (1.0 - frac_x) * (
            (1 - frac_y) * bottom_image[sample_xi, sample_yi, k] + frac_y *
            bottom_image[
              sample_xi, sample_yi + 1, k]) + frac_x * (
                                       (1 - frac_y) * bottom_image[
                                     sample_xi + 1, sample_yi, k] + frac_y *
                                       bottom_image[
                                         sample_xi + 1, sample_yi + 1, k]
                                   )
Example #4
0
def grid_to_particles():
    for p in particles.velocity:
        pos = particles.position[p]

        pos[0] = max(epsilon,min(grid_size_x*cell_size-epsilon,pos[0]))
        pos[1] = max(epsilon,min(grid_size_y*cell_size-epsilon,pos[1]))

        x = ti.cast(ti.floor(pos[0] / cell_size),ti.i32)
        y = ti.cast(ti.floor(pos[1] / cell_size),ti.i32)

        vel = ti.Vector([0.0,0.0])
        cx = ti.Vector([0.0,0.0])
        cy = ti.Vector([0.0,0.0])
        sum_weights = ti.Vector([0.0,0.0])

        for i,j in ti.ndrange(3,3):
            this_x = x+i-1
            this_y = y+j-1

            if this_x < 0 or this_x >= grid_size_x+1 or this_y < 0 or this_y >= grid_size_y+1:
                continue

            x_vel_pos = ti.Vector([this_x,this_y+0.5]) * cell_size
            y_vel_pos = ti.Vector([this_x+0.5,this_y]) * cell_size

            x_weight = kernel_2d(x_vel_pos-pos,cell_size)
            y_weight = kernel_2d(y_vel_pos-pos,cell_size)

            if y_vel_pos[0] >  grid_size_x*cell_size:
                y_weight = 0
            if x_vel_pos[1] >  grid_size_y*cell_size:
                x_weight = 0

            weights = ti.Vector([x_weight,y_weight])
            velocity_contribution = grid.velocity[this_x,this_y] * weights

            #cx += grid.velocity[this_x,this_y][0] * x_weight * (x_vel_pos-pos)  / (cell_size ** 2)
            #cy += grid.velocity[this_x,this_y][1] * y_weight * (y_vel_pos-pos)  / (cell_size ** 2)

            cx += grid.velocity[this_x,this_y][0] * kernel_grad(x_vel_pos-pos,cell_size) * -1
            cy += grid.velocity[this_x,this_y][1] * kernel_grad(y_vel_pos-pos,cell_size) * -1
            

            vel += velocity_contribution
            sum_weights += weights

        if sum_weights[0] > 0:
            vel[0] /= sum_weights[0]
            cx /= sum_weights[0]
        if sum_weights[1] > 0:
            vel[1] /= sum_weights[1]
            cy /= sum_weights[1]


        particles.velocity[p] = vel
        particles.cx[p] = cx
        particles.cy[p] = cy
def sample_minmax(vf, p):  # 2d case
    u, v = p
    s, t = u - 0.5, v - 0.5
    iu, iv = ti.floor(s), ti.floor(t)
    a = sample(vf, iu, iv)
    b = sample(vf, iu + 1, iv)
    c = sample(vf, iu, iv + 1)
    d = sample(vf, iu + 1, iv + 1)
    return min(a, b, c, d), max(a, b, c, d)
Example #6
0
    def voxelize_triangles(self, num_triangles: ti.i32,
                           triangles: ti.ext_arr()):
        for i in range(num_triangles):
            jitter_scale = ti.cast(0, self.precision)
            if ti.static(self.precision is ti.f32):
                jitter_scale = 1e-4
            else:
                jitter_scale = 1e-8
            # We jitter the vertices to prevent voxel samples from lying precicely at triangle edges
            jitter = ti.Vector([-0.057616723909439505, -0.25608986292614977, 0.06716309129743714]) * jitter_scale
            a = ti.Vector([triangles[i, 0], triangles[i, 1], triangles[i, 2]]) + jitter
            b = ti.Vector([triangles[i, 3], triangles[i, 4], triangles[i, 5]]) + jitter
            c = ti.Vector([triangles[i, 6], triangles[i, 7], triangles[i, 8]]) + jitter

            bound_min = ti.Vector.zero(self.precision, 3)
            bound_max = ti.Vector.zero(self.precision, 3)
            for k in ti.static(range(3)):
                bound_min[k] = min(a[k], b[k], c[k])
                bound_max[k] = max(a[k], b[k], c[k])

            p_min = int(ti.floor(bound_min[0] * self.inv_dx))
            p_max = int(ti.floor(bound_max[0] * self.inv_dx)) + 1
            
            p_min = max(self.padding, p_min)
            p_max = min(self.res[0] - self.padding, p_max)

            q_min = int(ti.floor(bound_min[1] * self.inv_dx))
            q_max = int(ti.floor(bound_max[1] * self.inv_dx)) + 1
            
            q_min = max(self.padding, q_min)
            q_max = min(self.res[1] - self.padding, q_max)

            normal = ti.normalized(ti.cross(b - a, c - a))
            
            if abs(normal[2]) < 1e-10:
                continue

            a_proj = ti.Vector([a[0], a[1]])
            b_proj = ti.Vector([b[0], b[1]])
            c_proj = ti.Vector([c[0], c[1]])

            for p in range(p_min, p_max):
                for q in range(q_min, q_max):
                    pos2d = ti.Vector([(p + 0.5) * self.dx, (q + 0.5) * self.dx])
                    if inside_ccw(pos2d, a_proj, b_proj, c_proj) or inside_ccw(pos2d, a_proj, c_proj, b_proj):
                        base_voxel = ti.Vector([pos2d[0], pos2d[1], 0])
                        height = int(
                            -ti.dot(normal, base_voxel - a) /
                            normal[2] * self.inv_dx + 0.5)
                        height = min(height, self.res[1] - self.padding)
                        inc = 0
                        if normal[2] > 0:
                            inc = 1
                        else:
                            inc = -1
                        self.fill(p, q, height, inc)
Example #7
0
 def insert():
     ti.block_dim(256)
     for i in x:
         # It is important to ensure insert and p2g uses the exact same way to compute the base
         # coordinates. Otherwise there might be coordinate mismatch due to float-point errors.
         base = ti.Vector([
             int(ti.floor(x[i][0] * N) - grid_offset[0]),
             int(ti.floor(x[i][1] * N) - grid_offset[1])
         ])
         ti.append(pid.parent(), base, i)
Example #8
0
def make_nested(f):
    f = f * 40
    i = int(f)
    if f < 0:
        if i % 2 == 1:
            f -= ti.floor(f)
        else:
            f = ti.floor(f) + 1 - f
    f = (f - 0.2) / 40
    return f
def bilerp(vf, p):
    u, v = p
    s, t = u - 0.5, v - 0.5
    iu, iv = ti.floor(s), ti.floor(t)
    #frac
    fu, fv = s - iu, t - iv
    a = sample(vf, iu, iv)
    b = sample(vf, iu + 1, iv)
    c = sample(vf, iu, iv + 1)
    d = sample(vf, iu + 1, iv + 1)
    return lerp(lerp(a, b, fu), lerp(c, d, fu), fv)
Example #10
0
def bilerp(vf, p):
    u, v = p
    s, t = u - 0.5, v - 0.5
    # floor
    iu, iv = ti.floor(s), ti.floor(t)
    # fract
    fu, fv = s - iu, t - iv
    a = sample(vf, iu + 0.5, iv + 0.5)
    b = sample(vf, iu + 1.5, iv + 0.5)
    c = sample(vf, iu + 0.5, iv + 1.5)
    d = sample(vf, iu + 1.5, iv + 1.5)
    return lerp(lerp(a, b, fu), lerp(c, d, fu), fv)
Example #11
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
Example #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
Example #13
0
def paintArrow(img: ti.template(),
               orig,
               dir,
               color=1,
               width=3,
               max_size=12,
               min_scale=0.4):
    res = ts.vec(*img.shape)
    I = orig * res
    D = dir * res
    J = I + D
    DL = ts.length(D)
    S = min(max_size, DL * min_scale)
    DS = D / (DL + 1e-4) * S
    SW = S + width
    D1 = ti.Matrix.rotation2d(+math.pi * 3 / 4) @ DS
    D2 = ti.Matrix.rotation2d(-math.pi * 3 / 4) @ DS
    bmin, bmax = ti.floor(max(0,
                              min(I, J) - SW)), ti.ceil(
                                  min(res - 1,
                                      max(I, J) + SW))
    for P in ti.grouped(ti.ndrange((bmin.x, bmax.x), (bmin.y, bmax.y))):
        c0 = ts.smoothstep(abs(sdLine(I, J, P)), width, width / 2)
        c1 = ts.smoothstep(abs(sdLine(J, J + D1, P)), width, width / 2)
        c2 = ts.smoothstep(abs(sdLine(J, J + D2, P)), width, width / 2)
        ti.atomic_max(img[P], max(c0, c1, c2) * color)
Example #14
0
def fract(x):
    """
    Дробная часть числа
    :param x: значение
    :return: дробная часть
    """
    return x - ti.floor(x)
Example #15
0
 def sample_max(self, qf: ti.template(), coord):
     grid = coord * self.inv_dx - ti.Vector([0.5, 0.5, 0.5])
     I = ti.cast(ti.floor(grid), ti.i32)
     max_val = qf[I]
     for i, j, k in ti.ndrange(2, 2, 2):
         max_val = max(max_val, qf[I + ti.Vector([i, j, k])])
     return max_val
 def g2p(self, dt: ti.f32):
     ti.block_dim(256)
     ti.block_local(*self.grid_v.entries)
     ti.no_activate(self.particle)
     for I in ti.grouped(self.pid):
         p = self.pid[I]
         base = ti.floor(self.x[p] * self.inv_dx - 0.5).cast(int)
         for D in ti.static(range(self.dim)):
             base[D] = ti.assume_in_range(base[D], I[D], 0, 1)
         fx = self.x[p] * self.inv_dx - base.cast(float)
         w = [
             0.5 * (1.5 - fx)**2, 0.75 - (fx - 1.0)**2, 0.5 * (fx - 0.5)**2
         ]
         new_v = ti.Vector.zero(ti.f32, self.dim)
         new_C = ti.Matrix.zero(ti.f32, self.dim, self.dim)
         # loop over 3x3 grid node neighborhood
         for offset in ti.static(ti.grouped(self.stencil_range())):
             dpos = offset.cast(float) - fx
             g_v = self.grid_v[base + offset]
             weight = 1.0
             for d in ti.static(range(self.dim)):
                 weight *= w[offset[d]][d]
             new_v += weight * g_v
             new_C += 4 * self.inv_dx * weight * g_v.outer_product(dpos)
         self.v[p], self.C[p] = new_v, new_C
         self.x[p] += dt * self.v[p]  # advection
Example #17
0
    def p2g_naive():
        ti.block_dim(256)
        for p in x:
            u = ti.floor(x[p] * N).cast(ti.i32)

            for offset in ti.static(ti.grouped(ti.ndrange(extend, extend))):
                m3[u + offset] += scatter_weight
Example #18
0
def bilerp(f: ti.template(), pos):
    p = float(pos)
    I = int(ti.floor(p))
    x = p - I
    y = 1 - x
    return (f[I + V(1, 1)] * x[0] * x[1] + f[I + V(1, 0)] * x[0] * y[1] +
            f[I + V(0, 0)] * y[0] * y[1] + f[I + V(0, 1)] * y[0] * x[1])
Example #19
0
    def kernel(angle: ti.f32, view_id: ti.i32):
        for pixel in range(res * res):
            for k in range(marching_steps):
                x = pixel // res
                y = pixel - x * res

                camera_origin = ti.Vector([
                    camera_origin_radius * ti.sin(angle), 0,
                    camera_origin_radius * ti.cos(angle)
                ])
                dir = ti.Vector([
                    fov * (ti.cast(x, ti.f32) /
                           (res_f32 / 2.0) - res_f32 / res_f32),
                    fov * (ti.cast(y, ti.f32) / (res_f32 / 2.0) - 1.0), -1.0
                ])

                length = ti.sqrt(dir[0] * dir[0] + dir[1] * dir[1] +
                                 dir[2] * dir[2])
                dir /= length

                rotated_x = dir[0] * ti.cos(angle) + dir[2] * ti.sin(angle)
                rotated_z = -dir[0] * ti.sin(angle) + dir[2] * ti.cos(angle)
                dir[0] = rotated_x
                dir[2] = rotated_z
                point = camera_origin + (k + 1) * dx * dir

                # Convert to coordinates of the density grid box
                box_x = point[0] + 0.5
                box_y = point[1] + 0.5
                box_z = point[2] + 0.5

                # Density grid location
                index_x = ti.cast(ti.floor(box_x * density_res), ti.i32)
                index_y = ti.cast(ti.floor(box_y * density_res), ti.i32)
                index_z = ti.cast(ti.floor(box_z * density_res), ti.i32)
                index_x = ti.max(0, ti.min(index_x, density_res - 1))
                index_y = ti.max(0, ti.min(index_y, density_res - 1))
                index_z = ti.max(0, ti.min(index_z, density_res - 1))

                flag = 0
                if in_box(point[0], point[1], point[2]):
                    flag = 1

                contribution = density[index_z, index_y, index_x] * flag

                ti.atomic_add(field[view_id, y, x], contribution)
Example #20
0
def halton(b, i):
    r = 0.0
    f = 1.0
    while i > 0:
        f = f / float(b)
        r = r + f * float(i % b)
        i = int(ti.floor(float(i) / float(b)))
    return r
Example #21
0
def bilinearInterpolation(x, y):
    x_floor = ti.floor(x)
    x_dec = x - x_floor
    y_new = y[int(x_floor)] * (1. - x_dec[0]) * (1. - x_dec[1]) \
            + y[int(x_floor) + ti.Vector([1, 0], ti.int32)] * x_dec[0] * (1. - x_dec[1]) \
            + y[int(x_floor) + ti.Vector([0, 1], ti.int32)] * (1. - x_dec[0]) * x_dec[1] \
            + y[int(x_floor) + 1] * x_dec[0] * x_dec[1]
    return y_new
Example #22
0
def noise(p):
    i = ti.floor(p)
    a = i.dot(vec(1.0, 57.0, 21.0)) + vec(0.0, 57.0, 21.0, 78.0)
    f = ti.cos((p - i) * math.acos(-1.0)) * (-0.5) + 0.5
    a = mix(ti.sin(ti.cos(a) * a), ti.sin(ti.cos(1.0 + a) * (1.0 + a)), f[0])
    a[0] = mix(a[0], a[1], f[1])
    a[1] = mix(a[2], a[3], f[1])
    return mix(a[0], a[1], f[2])
Example #23
0
def sample_max(field, p):

	p = clamp(p)

	grid_f = p * n - stagger
	grid_i = ti.cast(ti.floor(grid_f), ti.i32)
	
	return max( field[ grid_i ], field[ grid_i+I(1, 0) ], field[ grid_i+I(0, 1) ], field[ grid_i+I(1, 1) ] )
Example #24
0
def bilerp(f: ti.template(), pos):
    p = float(pos)
    I = int(ti.floor(p))
    x = p - I
    y = 1 - x
    ti.static_assert(len(f.meta.shape) == 2)
    return (f[I + V(1, 1)] * x[0] * x[1] + f[I + V(1, 0)] * x[0] * y[1] +
            f[I + V(0, 0)] * y[0] * y[1] + f[I + V(0, 1)] * y[0] * x[1])
Example #25
0
    def g2p_naive(s: ti.template()):
        ti.block_dim(256)
        for p in x:
            u = ti.floor(x[p] * N).cast(ti.i32)

            tot = 0.0
            for offset in ti.static(ti.grouped(ti.ndrange(extend, extend))):
                tot += m1[u + offset]
            s[p] = tot
Example #26
0
def pos_to_stagger_idx(pos, stagger):
    pos[0] = clamp(pos[0], stagger[0] * grid_x,
                   w - 1e-4 - grid_x + stagger[0] * grid_x)
    pos[1] = clamp(pos[1], stagger[1] * grid_y,
                   h - 1e-4 - grid_y + stagger[1] * grid_y)
    p_grid = pos / vec2(grid_x, grid_y) - stagger
    I = ti.cast(ti.floor(p_grid), ti.i32)

    return I, p_grid
Example #27
0
def noise(p):
    i = ti.floor(p)
    f = fract(p)
    u = f * f * (3.0 - 2.0 * f)
    v1 = mix(hash(i + ti.Vector([0.0, 0.0])), hash(i + ti.Vector([1.0, 0.0])),
             u[0])
    v2 = mix(hash(i + ti.Vector([0.0, 1.0])), hash(i + ti.Vector([1.0, 1.0])),
             u[0])
    v3 = mix(v1, v2, u[1])
    return -1.0 + 2.0 * v3
Example #28
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)
Example #29
0
def sample_bilinear(field, p):

	p = clamp(p)

	grid_f = p * n - stagger
	grid_i = ti.cast(ti.floor(grid_f), ti.i32)

	d = grid_f - grid_i
	
	return field[ grid_i ] * (1-d.x)*(1-d.y) + field[ grid_i+I(1, 0) ] * d.x*(1-d.y) + field[ grid_i+I(0, 1) ] * (1-d.x)*d.y + field[ grid_i+I(1, 1) ] * d.x*d.y
Example #30
0
 def teture2D(self, u, v):
     x = ts.clamp(u * self.wid, 0.0, self.wid - 1.0)
     y = ts.clamp(v * self.hgt, 0.0, self.hgt - 1.0)
     #   lt       rt
     #    *--------*
     #    |   ↑wbt |
     #    | ← *    |
     #    | wlr    |
     #    *--------*
     #   lb       rb
     lt = ti.Vector([ti.floor(x), ti.floor(y)])
     rt = lt + ti.Vector([1, 0])
     lb = lt + ti.Vector([0, 1])
     rb = lt + ti.Vector([1, 1])
     wbt = ts.fract(y)
     wlr = ts.fract(x)
     #print(x,y,lt,wbt,wlr)
     return ts.mix(ts.mix(self.sample(lt), self.sample(rt), wlr),
                   ts.mix(self.sample(lb), self.sample(rb), wlr), wbt)