def max_starred() -> ti.i32: a = ti.Vector([1, 2, 3]) b = ti.Vector([4, 5, 6]) return ti.max(*a, *b)
def max_u16(a: ti.u16, b: ti.u16) -> ti.u16: return ti.max(a, b)
(lambda x: ti.sqrt(x), lambda x: np.sqrt(x)), (lambda x: ti.exp(x), lambda x: np.exp(x)), (lambda x: ti.log(x), lambda x: np.log(x)), ]) @if_has_autograd @test_utils.test() def test_unary(tifunc, npfunc): grad_test(tifunc, npfunc) @pytest.mark.parametrize('tifunc,npfunc', [ (lambda x: ti.min(x, 0), lambda x: np.minimum(x, 0)), (lambda x: ti.min(x, 1), lambda x: np.minimum(x, 1)), (lambda x: ti.min(0, x), lambda x: np.minimum(0, x)), (lambda x: ti.min(1, x), lambda x: np.minimum(1, x)), (lambda x: ti.max(x, 0), lambda x: np.maximum(x, 0)), (lambda x: ti.max(x, 1), lambda x: np.maximum(x, 1)), (lambda x: ti.max(0, x), lambda x: np.maximum(0, x)), (lambda x: ti.max(1, x), lambda x: np.maximum(1, x)), ]) @if_has_autograd @test_utils.test() def test_minmax(tifunc, npfunc): grad_test(tifunc, npfunc) @if_has_autograd @test_utils.test() def test_mod(): x = ti.field(ti.i32) y = ti.field(ti.i32)
def dda_particle(eye_pos, d_, t): grid_res = particle_grid_res bbox_min = bbox[0] bbox_max = bbox[1] hit_pos = ti.Vector([0.0, 0.0, 0.0]) normal = ti.Vector([0.0, 0.0, 0.0]) c = ti.Vector([0.0, 0.0, 0.0]) d = d_ for i in ti.static(range(3)): if ti.abs(d[i]) < 1e-6: d[i] = 1e-6 inter, near, far = ray_aabb_intersection(bbox_min, bbox_max, eye_pos, d) near = ti.max(0, near) closest_intersection = inf if inter: pos = eye_pos + d * (near + eps) rinv = 1.0 / d rsign = ti.Vector([0, 0, 0]) for i in ti.static(range(3)): if d[i] > 0: rsign[i] = 1 else: rsign[i] = -1 o = grid_res * pos ipos = ti.Matrix.floor(o).cast(ti.i32) dis = (ipos - o + 0.5 + rsign * 0.5) * rinv running = 1 while running: inside = inside_particle_grid(ipos) if inside: num_particles = voxel_has_particle[ipos] if num_particles != 0: num_particles = ti.length(pid.parent(), ipos) for k in range(num_particles): p = pid[ipos[0], ipos[1], ipos[2], k] v = particle_v[p] x = particle_x[p] + t * v color = particle_color[p] dist, poss = intersect_sphere(eye_pos, d, x, sphere_radius) hit_pos = poss if dist < closest_intersection and dist > 0: hit_pos = eye_pos + dist * d closest_intersection = dist normal = ti.Matrix.normalized(hit_pos - x) c = [ color // 256**2 / 255.0, color / 256 % 256 / 255.0, color % 256 / 255.0 ] else: running = 0 normal = [0, 0, 0] if closest_intersection < inf: running = 0 else: # hits nothing. Continue ray marching mm = ti.Vector([0, 0, 0]) if dis[0] <= dis[1] and dis[0] <= dis[2]: mm[0] = 1 elif dis[1] <= dis[0] and dis[1] <= dis[2]: mm[1] = 1 else: mm[2] = 1 dis += mm * rsign * rinv ipos += mm * rsign return closest_intersection, normal, c
def max_i64(a: ti.i64, b: ti.i64) -> ti.i64: return ti.max(a, b)
def dot_or_zero(n, l): return ti.max(0.0, n.dot(l))
def max(self): import taichi as ti ret = self.entries[0] for i in range(1, len(self.entries)): ret = ti.max(ret, self.entries[i]) return ret
def max_i32(a: ti.i32, b: ti.i32) -> ti.i32: return ti.max(a, b)
def clamp(x): return ti.max(0, ti.min(1.0, x))
def boxSDF(p, b): q = ti.abs(p) - b return length(ti.max(q, 0.0)) + ti.min(q.max(), 0.0)
ti.init(ti.cpu) scene = t3.Scene() obj = t3.Geometry.cube() model = t3.Model(t3.Mesh.from_obj(obj)) model.material = t3.Material( t3.BlinnPhong( # https://learnopengl.com/img/textures/container2.png color=t3.Texture('docs/_media/container2.png'), specular=t3.Texture('docs/_media/container2_specular.png'), )) scene.add_model(model) camera = t3.Camera() scene.add_camera_d(camera) original = t3.FrameBuffer(camera) filted = t3.ImgUnaryOp(original, lambda x: ti.max(0, x - 1)) blurred = t3.GaussianBlur(filted, radius=21) final = t3.ImgBinaryOp(original, blurred, lambda x, y: x + y) scene.add_buffer(final) light = t3.Light(dir=[-0.2, -0.6, -1.0], color=1.6) scene.add_light(light) gui_original = ti.GUI('Original', filted.res) gui_filted = ti.GUI('Filted', filted.res) gui_blurred = ti.GUI('Blurred', blurred.res) gui_final = ti.GUI('Final', final.res) gui_original.fps_limit = None gui_filted.fps_limit = None gui_blurred.fps_limit = None gui_final.fps_limit = None while gui_final.running and gui_filted.running and gui_blurred.running and gui_original.running:
def saturate(x): return ti.max(0, ti.min(1.0, x))
def SdfCapsule(X, radius, half_length): alpha = ti.min(ti.max((X[0] / half_length + 1.0) * 0.5, 0.0), 1.0) tmp = ti.Vector([X[0], X[1]]) tmp[0] += (1.0 - 2.0 * alpha) * half_length return tmp.norm() - radius
def max_i16(a: ti.i16, b: ti.i16) -> ti.i16: return ti.max(a, b)
def plane(pos): return ts.length(ti.max(ti.abs(pos) - ts.vec(12.0, 0.5, 12.0), 0.0))
def max_u32(a: ti.u32, b: ti.u32) -> ti.u32: return ti.max(a, b)
def sdfBox(p, length): p = ti.abs(p) - length d = ti.max(p, ti.Vector([0., 0., 0.])).norm() d += ti.min(ti.max(p[0], ti.max(p[1], p[2])), 0.) return d
def max_u64(a: ti.u64, b: ti.u64) -> ti.u64: return ti.max(a, b)
def apply_grad(self, lr: float, gamma: float, max_grad: float): for i in self.tf_tex: self.tf_momentum[i] = gamma * self.tf_momentum[i] + \ lr * tl.clamp(self.tf_tex.grad[i], -max_grad, max_grad) self.tf_tex[i] -= self.tf_momentum[i] self.tf_tex[i] = ti.max(self.tf_tex[i], 0)
def fill_color(ipixels: ti.template(), idyef: ti.template()): for i, j in ipixels: density = ti.min(1.0, ti.max(0.0, idyef[i, j])) ipixels[i, j] = density
def computeNormalAndCurvature(): """ Compute the normal and the curvature at all points voxels. Based on the PC limplementation: https://pointclouds.org/documentation/group__features.html """ radius = 50 for i,j in pts: nb_pts = ti.cast(0, ti.f32) accu_0 = ti.cast(0, ti.f32) accu_1 = ti.cast(0, ti.f32) accu_2 = ti.cast(0, ti.f32) accu_3 = ti.cast(0, ti.f32) accu_4 = ti.cast(0, ti.f32) accu_5 = ti.cast(0, ti.f32) accu_6 = ti.cast(0, ti.f32) accu_7 = ti.cast(0, ti.f32) accu_8 = ti.cast(0, ti.f32) z = 0 for x in range(i-radius, i+radius): for y in range(j-radius, j+radius): if ti.is_active(block1, [x,y]): accu_0 += x * x accu_1 += x * y accu_2 += x * z accu_3 += y * y accu_4 += y * z accu_5 += z * z accu_6 += x accu_7 += y accu_8 += z nb_pts += 1 accu_0 /= nb_pts accu_1 /= nb_pts accu_2 /= nb_pts accu_3 /= nb_pts accu_4 /= nb_pts accu_5 /= nb_pts accu_6 /= nb_pts accu_7 /= nb_pts accu_8 /= nb_pts cov_mat_0 = accu_0 - accu_6 * accu_6 cov_mat_1 = accu_1 - accu_6 * accu_7 cov_mat_2 = accu_2 - accu_6 * accu_8 cov_mat_4 = accu_3 - accu_7 * accu_7 cov_mat_5 = accu_4 - accu_7 * accu_8 cov_mat_8 = accu_5 - accu_8 * accu_8 cov_mat_3 = cov_mat_1 cov_mat_6 = cov_mat_2 cov_mat_7 = cov_mat_5 # Compute eigen value and eigen vector # Make sure in [-1, 1] scale = ti.max(1.0, ti.abs(cov_mat_0)) scale = ti.max(scale, ti.abs(cov_mat_1)) scale = ti.max(scale, ti.abs(cov_mat_2)) scale = ti.max(scale, ti.abs(cov_mat_3)) scale = ti.max(scale, ti.abs(cov_mat_4)) scale = ti.max(scale, ti.abs(cov_mat_5)) scale = ti.max(scale, ti.abs(cov_mat_6)) scale = ti.max(scale, ti.abs(cov_mat_7)) scale = ti.max(scale, ti.abs(cov_mat_8)) if scale > 1.0: cov_mat_0 /= scale cov_mat_1 /= scale cov_mat_2 /= scale cov_mat_3 /= scale cov_mat_4 /= scale cov_mat_5 /= scale cov_mat_6 /= scale cov_mat_7 /= scale cov_mat_8 /= scale # Compute roots eigen_val_0 = ti.cast(0, ti.f32) eigen_val_1 = ti.cast(0, ti.f32) eigen_val_2 = ti.cast(0, ti.f32) c0 = cov_mat_0 * cov_mat_4 * cov_mat_8 \ + 2 * cov_mat_3 * cov_mat_6 * cov_mat_7 \ - cov_mat_0 * cov_mat_7 * cov_mat_7 \ - cov_mat_4 * cov_mat_6 * cov_mat_6 \ - cov_mat_8 * cov_mat_3 * cov_mat_3 c1 = cov_mat_0 * cov_mat_4 \ - cov_mat_3 * cov_mat_3 \ + cov_mat_0 * cov_mat_8 \ - cov_mat_6 * cov_mat_6 \ + cov_mat_4 * cov_mat_8 \ - cov_mat_7 * cov_mat_7 c2 = cov_mat_0 + cov_mat_4 + cov_mat_8 if ti.abs(c0) < 0.00001: eigen_val_0 = 0 d = c2 * c2 - 4.0 * c1 if d < 0.0: # no real roots ! THIS SHOULD NOT HAPPEN! d = 0.0 sd = ti.sqrt(d) eigen_val_2 = 0.5 * (c2 + sd) eigen_val_1 = 0.5 * (c2 - sd) else: s_inv3 = ti.cast(1.0 / 3.0, ti.f32) s_sqrt3 = ti.sqrt(3.0) c2_over_3 = c2 * s_inv3 a_over_3 = (c1 - c2 * c2_over_3) * s_inv3 if a_over_3 > 0: a_over_3 = 0 half_b = 0.5 * (c0 + c2_over_3 * (2 * c2_over_3 * c2_over_3 - c1)) q = half_b * half_b + a_over_3 * a_over_3 * a_over_3 if q > 0: q = 0 rho = ti.sqrt(-a_over_3) theta = ti.atan2(ti.sqrt(-q), half_b) * s_inv3 cos_theta = ti.cos(theta) sin_theta = ti.sin(theta) eigen_val_0 = c2_over_3 + 2 * rho * cos_theta eigen_val_1 = c2_over_3 - rho * (cos_theta + s_sqrt3 * sin_theta) eigen_val_2 = c2_over_3 - rho * (cos_theta - s_sqrt3 * sin_theta) temp_swap = ti.cast(0, ti.f32) # Sort in increasing order. if eigen_val_0 >= eigen_val_1: temp_swap = eigen_val_1 eigen_val_1 = eigen_val_0 eigen_val_0 = temp_swap if eigen_val_1 >= eigen_val_2: temp_swap = eigen_val_2 eigen_val_2 = eigen_val_1 eigen_val_1 = temp_swap if eigen_val_0 >= eigen_val_1: temp_swap = eigen_val_1 eigen_val_1 = eigen_val_0 eigen_val_0 = temp_swap if eigen_val_0 <= 0: eigen_val_0 = 0 d = c2 * c2 - 4.0 * c1 if d < 0.0: # no real roots ! THIS SHOULD NOT HAPPEN! d = 0.0 sd = ti.sqrt(d) eigen_val_2 = 0.5 * (c2 + sd) eigen_val_1 = 0.5 * (c2 - sd) # end of compute roots eigen_value = eigen_val_1 * scale # eigen value for 2D SDF # eigen value for 3D SDF #eigen_value = eigen_val_0 * scale #print("eigen_val_0 ", eigen_val_0) #print("eigen_val_1 ", eigen_val_1) #print("eigen_val_2 ", eigen_val_2) # TODO #scaledMat.diagonal ().array () -= eigenvalues (0) #eigenvector = detail::getLargest3x3Eigenvector<Vector> (scaledMat).vector; # Compute normal vector (TODO) #visual_norm[i,j][0] = eigen_val_0 #eigen_vector[0] #visual_norm[i,j][1] = eigen_val_1 #eigen_vector[1] #visual_norm[i,j][2] = eigen_val_2 #eigen_vector[2] # Compute the curvature surface change eig_sum = cov_mat_0 + cov_mat_1 + cov_mat_2 visual_curv[i,j][0] = 0 if eig_sum != 0: visual_curv[i,j][0] = eigen_val_1 # true curvature is: ti.abs(eigen_value / eig_sum)
def point_aabb_distance2(box_min, box_max, o): p = ti.Vector([0.0, 0.0, 0.0]) for i in ti.static(range(3)): p[i] = ti.max(ti.min(o[i], box_max[i]), box_min[i]) return (p - o).norm_sqr()
def util_color_map_value(self, c0, c1, v) -> ti.i32: vl = ti.max(0.0, ti.min(1.0, v)) r = c1 - c0 d = ti.cast(c0 + r * vl, ti.i32) return d
def apply_grad(): # gradient descent for i, j, k in density: density[i, j, k] -= learning_rate * density.grad[i, j, k] density[i, j, k] = ti.max(density[i, j, k], 0)
def substep(): for i, j in grid_m: grid_v[i, j] = [0, 0] grid_m[i, j] = 0 grid_v_int[i, j] = [0, 0] grid_m_int[i, j] = 0 for p in x: # Particle state update and scatter to grid (P2G) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * inv_dx - base.cast(float) # Quadratic kernels [http://mpm.graphics Eqn. 123, with x=fx, fx-1,fx-2] w = [0.5 * (1.5 - fx)**2, 0.75 - (fx - 1)**2, 0.5 * (fx - 0.5)**2] F[p] = (ti.Matrix.identity(float, 2) + dt * C[p]) @ F[p] # deformation gradient update h = ti.exp( 10 * (1.0 - Jp[p]) ) # Hardening coefficient: snow gets harder when compressed if material[p] == 1: # jelly, make it softer h = 0.3 mu, la = mu_0 * h, lambda_0 * h if material[p] == 0: # liquid mu = 0.0 U, sig, V = ti.svd(F[p]) J = 1.0 for d in ti.static(range(2)): new_sig = sig[d, d] if material[p] == 2: # Snow new_sig = ti.min(ti.max(sig[d, d], 1 - 2.5e-2), 1 + 4.5e-3) # Plasticity Jp[p] *= sig[d, d] / new_sig sig[d, d] = new_sig J *= new_sig if material[ p] == 0: # Reset deformation gradient to avoid numerical instability F[p] = ti.Matrix.identity(float, 2) * ti.sqrt(J) elif material[p] == 2: F[p] = U @ sig @ V.transpose( ) # Reconstruct elastic deformation gradient after plasticity stress = 2 * mu * (F[p] - U @ V.transpose()) @ F[p].transpose( ) + ti.Matrix.identity(float, 2) * la * J * (J - 1) stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * stress affine = stress + p_mass * C[p] for i, j in ti.static(ti.ndrange( 3, 3)): # Loop over 3x3 grid node neighborhood offset = ti.Vector([i, j]) dpos = (offset.cast(float) - fx) * dx weight = w[i][0] * w[j][1] grid_v_int[base + offset] += int( ti.floor(0.5 + weight * (p_mass * v[p] + affine @ dpos) * (2.0**v_exp))) grid_m_int[base + offset] += int( ti.floor(0.5 + weight * p_mass * (2.0**m_exp))) for i, j in grid_m: if grid_m_int[i, j] > 0: # No need for epsilon here # grid_v[i, j] = (1.0 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity grid_v[i, j] = (2**(m_exp - v_exp) / grid_m_int[i, j] ) * grid_v_int[i, j] # Momentum to velocity grid_v[i, j][1] -= dt * 50 # gravity if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 # Boundary conditions if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 for p in x: # grid to particle (G2P) base = (x[p] * inv_dx - 0.5).cast(int) fx = x[p] * 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(float, 2) new_C = ti.Matrix.zero(float, 2, 2) for i, j in ti.static(ti.ndrange( 3, 3)): # loop over 3x3 grid node neighborhood dpos = ti.Vector([i, j]).cast(float) - fx g_v = grid_v[base + ti.Vector([i, j])] weight = w[i][0] * w[j][1] new_v += weight * g_v new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) v[p], C[p] = new_v, new_C x[p] += dt * v[p] # advection
def color_f32_to_i8(x): return ti.cast(ti.min(ti.max(x, 0.0), 1.0) * 255, ti.i32)
def trace(sample: ti.u32): for i, j in linear_pixel: o = ti.Vector([camera_pos[0], camera_pos[1], camera_pos[2]]) aperture_size = 0.2 forward = -o.normalized() u = ti.Vector([0.0, 1.0, 0.0]).cross(forward).normalized() v = forward.cross(u).normalized() u = -u # anti aliasing d = ((i + ti.random() - width / 2.0) / width * u * 1.5 + (j + ti.random() - height / 2.0) / width * v * 1.5 + width / width * forward).normalized() focal_point = d * focal_length / d.dot(forward) + o o += d * 0.01 # assuming a circle-like aperture phi = 2.0 * math.pi * ti.random() aperture_radius = ti.random() * aperture_size o += u * aperture_radius * ti.cos(phi) + \ v * aperture_radius * ti.sin(phi) d = (focal_point - o).normalized() uv = cubemap_coord(d) albedo_factor = ti.Vector([1.0, 1.0, 1.0]) radiance = ti.Vector([0.0, 0.0, 0.0]) for step in ti.ndrange(32): sp = spheres.intersect(o, d) uv = cubemap_coord(d) if sp[1] > -1: sp_index = int(sp[1]) p = sp[0] * d + o c_ = spheres.center_radius[sp_index] c = ti.Vector([c_[0], c_[1], c_[2]]) n = (p - c).normalized() wo = -d albedo = spheres.albedos[sp_index] metallic = spheres.metallics[sp_index] ior = spheres.iors[sp_index] roughness = ti.max(0.04, spheres.roughness[sp_index]) f0 = (1.0 - ior) / (1.0 + ior) f0 = f0 * f0 f0 = lerp(f0, luma(albedo), metallic) wi = reflect(-wo, n) radiance += spheres.emissions[sp_index] * albedo_factor view_fresnel = schlick2(wo, n, f0) sample_weights = ti.Vector([1.0 - view_fresnel, view_fresnel]) weight = 0.0 h = (wi + wo).normalized() shaded = ti.Vector([0.0, 0.0, 0.0]) if ti.random() < sample_weights[0]: wi = cosine_sample(n).normalized() h = (wi + wo).normalized() shaded = ti.max(0.00, wi.dot(n) * albedo / math.pi) else: wi = ggx_sample(n, wo, roughness).normalized() h = (wi + wo).normalized() F = schlick2(wi, n, f0) shaded = ti.max(0.0, wi.dot(n) * albedo * ggx_smith_uncorrelated( roughness, h.dot(n), wo.dot(n), wi.dot(n), F)) pdf_lambert = wi.dot(n) / math.pi pdf_ggx = ggx_pdf(roughness, h.dot(n), wo.dot(h)) weight = ti.max(0.0, 1.0 / (sample_weights[0] * pdf_lambert + sample_weights[1] * pdf_ggx)) # russian roule albedo_factor *= shaded * weight if step > 5: if luma(albedo) < ti.random(): break else: albedo_factor /= luma(albedo) d = wi o = p + eps * d else: radiance += albedo_factor * tex2d(skybox.field, uv) / 255 break linear_pixel[i, j] = (linear_pixel[i, j] * (sample - 1) + radiance) / sample pixel[i, j] = ti.sqrt(linear_pixel[i, j])