def target_surface(self): for I in ti.grouped(self.phi): sign_change = False est = ti.cast(1e20, self.real) for k in ti.static(range(self.dim)): for s in ti.static((-1, 1)): offset = ti.Vector.unit(self.dim, k) * s I1 = I + offset if I1[k] >= 0 and I1[k] < self.res[k] and \ ts.sign(self.phi[I]) != ts.sign(self.phi[I1]): theta = self.phi[I] / (self.phi[I] - self.phi[I1]) est0 = ts.sign(self.phi[I]) * theta * self.dx est = est0 if ti.abs(est0) < ti.abs(est) else est sign_change = True if sign_change: self.phi_temp[I] = est self.valid[I] = 0 else: self.phi_temp[I] = ti.cast( 1e20, self.real) # an upper bound for all possible distances
def target_minus(self): for I in ti.grouped(self.phi): self.phi[I] -= ( 0.99 * self.dx ) # the particle radius r (typically just a little less than the grid cell size dx) for I in ti.grouped(self.phi): sign_change = False for k in ti.static(range(self.dim)): for s in ti.static((-1, 1)): offset = ti.Vector.unit(self.dim, k) * s I1 = I + offset if I1[k] >= 0 and I1[k] < self.res[k] and \ ts.sign(self.phi[I]) != ts.sign(self.phi[I1]): sign_change = True if sign_change and self.phi[I] <= 0: self.valid[I] = 0 self.phi_temp[I] = self.phi[I] elif self.phi[I] <= 0: self.phi_temp[I] = ti.cast(-1, self.real) else: self.phi_temp[I] = self.phi[I] self.valid[I] = 0
def propagate(self): while not self.priority_queue.empty(): I0 = self.priority_queue.top() self.priority_queue.pop() for k in ti.static(range(self.dim)): for s in ti.static((-1, 1)): offset = ti.Vector.unit(self.dim, k) * s I = I0 + offset if I[k] >= 0 and I[k] < self.res[k] and \ self.valid[I] == -1: d = self.update_from_neighbor(I) if d < ti.abs(self.phi_temp[I]): self.phi_temp[I] = d * ts.sign(self.phi[I0]) self.valid[I] = 0 self.priority_queue.push(ti.abs(self.phi_temp[I]), I)
def propagate_update(self, I, s): if self.valid[I] == -1: d = self.update_from_neighbor(I) if ti.abs(d) < ti.abs(self.phi_temp[I]): self.phi_temp[I] = d * ts.sign(self.phi[I]) return s
def render(): for i, j in rt_canvas.hdr: next_origin = rt_canvas.get_ray_origin() next_dir = rt_canvas.get_ray_direction(i, j) depth = 0 pdf = 1.0 perfect_spec = 0 f_or_b = 1.0 brdf = ti.Vector([1.0, 1.0, 1.0]) throughout = ti.Vector([1.0, 1.0, 1.0]) radiance = ti.Vector([0.0, 0.0, 0.0]) while (depth < MAX_DEPTH): origin = next_origin direction = next_dir t, pos, normal, tex, prim_id = bvh.closet_hit( origin, direction, rt_canvas.stack, i, j, Canvas.STACK_SIZE) fnormal = faceforward(normal, -direction, normal) mat_id = UF.get_prim_mindex(bvh.primitive, prim_id) mat_emission = UF.get_material_emission(bvh.material, mat_id) mat_type = UF.get_material_type(bvh.material, mat_id) if t < UF.INF_VALUE: if mat_emission.sum() > Bvh.IS_LIGHT: fCosTheta = direction.dot(normal) if fCosTheta < 0.0: area = bvh.get_prim_area(prim_id) if (perfect_spec == 1) | (depth == 0): radiance += mat_emission #radiance = radiance else: lightPdf = (t * t) / (area * fCosTheta) radiance += powerHeuristic( pdf, lightPdf) * throughout * mat_emission break else: next_origin = offset_ray(pos, fnormal) #btdf if mat_type == 1: perfect_spec = 1 next_dir, f_or_b = glass.sample( direction, normal, t, i, j, bvh.material, mat_id) brdf, pdf = glass.evaluate(normal, next_dir, -direction, bvh.material, mat_id) else: #disney perfect_spec = 0 #direct lighting light_prim_id = bvh.get_random_light_prim_index() light_pos, light_normal = bvh.get_prim_random_point_normal( light_prim_id) light_dir = light_pos - next_origin light_dist = light_dir.norm() light_dir = light_dir / light_dist NdotL_light = -light_normal.dot(light_dir) NdotL_surface = normal.dot(light_dir) ####shadow if (NdotL_light > 0.0) & (NdotL_surface > 0.0): shadow_prim = bvh.closet_hit_shadow( next_origin, light_dir, rt_canvas.stack, i, j, Canvas.STACK_SIZE) shadow_mat = UF.get_prim_mindex( bvh.primitive, shadow_prim) shadow_emission = UF.get_material_emission( bvh.material, shadow_mat) if shadow_emission.sum() > Bvh.IS_LIGHT: brdf, pdf = disney.evaluate( normal, -direction, light_dir, bvh.material, mat_id) if pdf > 0.0: light_emission = UF.get_material_emission( bvh.material, UF.get_prim_mindex( bvh.primitive, light_prim_id)) light_area = bvh.get_prim_area( light_prim_id) lightPdf = light_dist * light_dist / ( light_area * NdotL_light) radiance += powerHeuristic( lightPdf, pdf) * light_emission / max( 0.001, lightPdf) * throughout * brdf next_dir, f_or_b = disney.sample( direction, normal, i, j, bvh.material, mat_id) brdf, pdf = disney.evaluate(normal, next_dir, -direction, bvh.material, mat_id) next_origin = offset_ray(pos, ts.sign(f_or_b) * fnormal) if pdf > 0.0: throughout *= brdf / pdf * abs(f_or_b) depth += 1 else: break #debug code , color map #nl = -normal.dot(direction) #nv = -normal.dot(direction) #radiance = ts.reflect(-direction, normal) #radiance = (next_dir + ti.Vector([1.0, 1.0, 1.0]))*0.5 #radiance = brdf #if depth == 0: # radiance = ti.Vector([1.0, 0.0, 0.0]) #if depth == 1: # radiance = ti.Vector([0.0, 1.0, 0.0]) #if depth == 2: # radiance = ti.Vector([0.0, 0.0, 1.0]) #break else: dis = ti.sqrt(direction.x * direction.x + direction.z * direction.z) tx = (ts.atan(direction.z, direction.x) + 3.1415926) / 3.1415926 / 2.0 ty = (ts.atan(direction.y, dis)) / 3.1415926 + 0.5 radiance += env.teture2D(tx, ty) * throughout break frame = float(rt_canvas.frame_gpu[0]) rt_canvas.hdr[i, j] = (radiance + rt_canvas.hdr[i, j] * frame) / (frame + 1.0)
def faceforward(n, i, nref): return ts.sign(i.dot(nref)) * n