def integrator_sample(scene, sampler, rays, medium, active=True): si = scene.ray_intersect(rays) active = si.is_valid() & active # Visible emitters emitter_vis = si.emitter(scene, active) result = ek.select(active, Emitter.eval_vec(emitter_vis, si, active), Vector3f(0.0)) ctx = BSDFContext() bsdf = si.bsdf(rays) # Emitter sampling sample_emitter = active & has_flag(BSDF.flags_vec(bsdf), BSDFFlags.Smooth) ds, emitter_val = scene.sample_emitter_direction(si, sampler.next_2d(sample_emitter), True, sample_emitter) active_e = sample_emitter & ek.neq(ds.pdf, 0.0) wo = si.to_local(ds.d) bsdf_val = BSDF.eval_vec(bsdf, ctx, si, wo, active_e) bsdf_pdf = BSDF.pdf_vec(bsdf, ctx, si, wo, active_e) mis = ek.select(ds.delta, Float(1), mis_weight(ds.pdf, bsdf_pdf)) result += ek.select(active_e, emitter_val * bsdf_val * mis, Vector3f(0)) # BSDF sampling active_b = active bs, bsdf_val = BSDF.sample_vec(bsdf, ctx, si, sampler.next_1d(active), sampler.next_2d(active), active_b) si_bsdf = scene.ray_intersect(si.spawn_ray(si.to_world(bs.wo)), active_b) emitter = si_bsdf.emitter(scene, active_b) active_b &= ek.neq(emitter, 0) emitter_val = Emitter.eval_vec(emitter, si_bsdf, active_b) delta = has_flag(bs.sampled_type, BSDFFlags.Delta) ds = DirectionSample3f(si_bsdf, si) ds.object = emitter emitter_pdf = ek.select(delta, Float(0), scene.pdf_emitter_direction(si, ds, active_b)) result += ek.select(active_b, bsdf_val * emitter_val * mis_weight(bs.pdf, emitter_pdf), Vector3f(0)) return result, si.is_valid(), ek.select(si.is_valid(), si.t, Float(0.0))
def __init__(self, props): BSDF.__init__(self, props) self.m_retro_transmittance = \ load_string('''<spectrum version='2.2.0' type='srgb' name="reflectance"> <rgb name="color" value="1.0, 1.0, 1.0"/> </spectrum>''') self.m_flags = BSDFFlags.DeltaReflection self.m_components = [self.m_flags]
def __init__(self, props): BSDF.__init__(self, props) self.m_reflectance \ = load_string('''<spectrum version='2.0.0' type='srgb' name="reflectance"> <rgb name="color" value="0.45, 0.90, 0.90"/> </spectrum>''') self.m_flags = BSDFFlags.DiffuseReflection | BSDFFlags.FrontSide self.m_components = [self.m_flags]
def __init__(self, props): BSDF.__init__(self, props) # BTDFFのzipファイルのパス self.m_filename = props["filename"] # 逆ガンマ補正をかけるかどうか if props.has_property("apply_inv_gamma"): self.m_apply_inv_gamma = props["apply_inv_gamma"] else: self.m_apply_inv_gamma = True # 反射率 if props.has_property("reflectance"): self.m_reflectance = Float(props["reflectance"]) else: self.m_reflectance = Float(1.0) # Power parameter if props.has_property("power_parameter"): self.m_power_parameter = Float(props["power_parameter"]) else: self.m_power_parameter = Float(4.0) # Wrap mode if props.has_property("wrap_mode"): self.m_wrap_mode = str(props["wrap_mode"]) else: self.m_wrap_mode = "repeat" # UVマップの変換 self.m_transform = Transform3f(props["to_uv"].extract()) # 読み込んだBTF self.btf = BtfInterpolator(self.m_filename, p=self.m_power_parameter) self.m_flags = BSDFFlags.DiffuseReflection | BSDFFlags.FrontSide self.m_components = [self.m_flags]
def sample_bssrdf(self, scene, bsdf, bs, si, bdata, heightmap_pybind, channel, active): """ Get projected sample position and absorption probability form VAE BSSRDF Args: scene: rendered scene object bsdf: BSDF information of each ray bs: BSDF Sample object of each ray si: Surface interaction object of each ray bdata: BSSRDF data object in scene data from data_pipeline.py channel: RGB channel of interest TODO: Support multi channel sampling active: Mask data whether a ray needs to process BSSRDF or not Returns: projected_si: Projected surface interaction object from BSSRDF proj_suc: Mask data indicating projection succeed or not abs_recon: absorption probability from BSSRDF """ # Get ID of BSSDRF mesh for each sur face interactions mesh_id = BSDF.mesh_id_vec(bsdf, active) # Convert incident position into local coordinates of mesh of interested as tensor in_pos = ek.select(active, si.to_mesh_local(bs), Vector3f(0)) # Get properties, e.g., medium params and incident angle as tensor props, sigma_n = get_props(bs, si, channel) # Get height map around incident position as tensor im_bind = heightmap_pybind.get_height_map(in_pos.torch().cpu(), mesh_id.torch().cpu()) im = torch.tensor(im_bind) # Estimate position and absorption probability with VAE as mitsuba types recon_pos_local, abs_recon = self.estimate(in_pos.torch(), im, props, sigma_n, active) # Convert from mesh coordinates to world coordinates recon_pos_world = si.to_mesh_world(bs, recon_pos_local) # Project estimated position onto nearest mesh projected_si, proj_suc = si.project_to_mesh_normal( scene, recon_pos_world, bs, channel, active) return projected_si, proj_suc, abs_recon
def render_sample(scene, sampler, rays, bdata, heightmap_pybind, bssrdf=None): """ Sample RTE TODO: Support multi channel sampling Args: scene: Target scene object sampler: Sampler object for random number rays: Given rays for sampling bdata: BSSRDF Data object heightmap_pybind: Object for getting height map around incident position. Refer src/librender/python/heightmap.cpp Returns: result: Sampling RTE result valid_rays: Mask data whether rays are valid or not scatter: Scatter components of Sampling RTE result non_scatter: Non scatter components of Sampling RTE result invalid_sample: Sampling RTE result with invalid sampled data by VAEBSSRDF """ eta = Float(1.0) emission_weight = Float(1.0) throughput = Spectrum(1.0) result = Spectrum(0.0) scatter = Spectrum(0.0) non_scatter = Spectrum(0.0) invalid_sample = Spectrum(0.0) active = True is_bssrdf = False ##### First interaction ##### si = scene.ray_intersect(rays, active) active = si.is_valid() & active valid_rays = si.is_valid() emitter = si.emitter(scene, active) depth = 0 # Set channel # At and after evaluating BSSRDF, a ray consider only this one channel n_channels = 3 channel = UInt32( ek.min(sampler.next_1d(active) * n_channels, n_channels - 1)) d_out_local = Vector3f().zero() d_out_pdf = Float(0) sss = Mask(False) while (True): depth += 1 if config.aovs and depth == 2: sss = is_bssrdf ##### Interaction with emitters ##### emission_val = emission_weight * throughput * Emitter.eval_vec( emitter, si, active) result += ek.select(active, emission_val, Spectrum(0.0)) invalid_sample += ek.select(active, emission_val, Spectrum(0.0)) scatter += ek.select(active & sss, emission_val, Spectrum(0.0)) non_scatter += ek.select(active & ~sss, emission_val, Spectrum(0.0)) active = active & si.is_valid() # Process russian roulette if depth > config.rr_depth: q = ek.min(ek.hmax(throughput) * ek.sqr(eta), 0.95) active = active & (sampler.next_1d(active) < q) throughput *= ek.rcp(q) # Stop if the number of bouces exceeds the given limit bounce, or # all rays are invalid. latter check is done only when the limit # bounce is infinite if depth >= config.max_depth: break ##### Emitter sampling ##### bsdf = si.bsdf(rays) ctx = BSDFContext() active_e = active & has_flag(BSDF.flags_vec(bsdf), BSDFFlags.Smooth) ds, emitter_val = scene.sample_emitter_direction( si, sampler.next_2d(active_e), True, active_e) active_e &= ek.neq(ds.pdf, 0.0) # Query the BSDF for that emitter-sampled direction wo = si.to_local(ds.d) bsdf_val = BSDF.eval_vec(bsdf, ctx, si, wo, active_e) # Determine density of sampling that same direction using BSDF sampling bsdf_pdf = BSDF.pdf_vec(bsdf, ctx, si, wo, active_e) mis = ek.select(ds.delta, Float(1), mis_weight(ds.pdf, bsdf_pdf)) emission_val = mis * throughput * bsdf_val * emitter_val result += ek.select(active, emission_val, Spectrum(0.0)) invalid_sample += ek.select(active, emission_val, Spectrum(0.0)) scatter += ek.select(active & sss, emission_val, Spectrum(0.0)) non_scatter += ek.select(active & ~sss, emission_val, Spectrum(0.0)) ##### BSDF sampling ##### bs, bsdf_val = BSDF.sample_vec(bsdf, ctx, si, sampler.next_1d(active), sampler.next_2d(active), active) ##### BSSRDF replacing ##### if (config.enable_bssrdf): # Replace bsdf samples by ones of BSSRDF bs.wo = ek.select(is_bssrdf, d_out_local, bs.wo) bs.pdf = ek.select(is_bssrdf, d_out_pdf, bs.pdf) bs.sampled_component = ek.select(is_bssrdf, UInt32(1), bs.sampled_component) bs.sampled_type = ek.select(is_bssrdf, UInt32(+BSDFFlags.DeltaTransmission), bs.sampled_type) ############################ throughput *= ek.select(is_bssrdf, Float(1.0), bsdf_val) active &= ek.any(ek.neq(throughput, 0)) eta *= bs.eta # Intersect the BSDF ray against the scene geometry rays = RayDifferential3f(si.spawn_ray(si.to_world(bs.wo))) si_bsdf = scene.ray_intersect(rays, active) ##### Checking BSSRDF ##### if (config.enable_bssrdf): # Whether the BSDF is BSS RDF or not? is_bssrdf = (active & has_flag(BSDF.flags_vec(bsdf), BSDFFlags.BSSRDF) & (Frame3f.cos_theta(bs.wo) < Float(0.0)) & (Frame3f.cos_theta(si.wi) > Float(0.0))) # Decide whether we should use 0-scattering or multiple scattering is_zero_scatter = utils_render.check_zero_scatter( sampler, si_bsdf, bs, channel, is_bssrdf) is_bssrdf = is_bssrdf & ~is_zero_scatter throughput *= ek.select(is_bssrdf, ek.sqr(bs.eta), Float(1.0)) ########################### ###### Process for BSSRDF ###### if (config.enable_bssrdf and not ek.none(is_bssrdf)): # Get projected samples from BSSRDF projected_si, project_suc, abs_prob = bssrdf.sample_bssrdf( scene, bsdf, bs, si, bdata, heightmap_pybind, channel, is_bssrdf) if config.visualize_invalid_sample and (depth <= 1): active = active & (~is_bssrdf | project_suc) invalid_sample += ek.select((is_bssrdf & (~project_suc)), Spectrum([100, 0, 0]), Spectrum(0.0)) # Sample outgoing direction from projected position d_out_local, d_out_pdf = utils_render.resample_wo( sampler, is_bssrdf) # Apply absorption probability throughput *= ek.select(is_bssrdf, Spectrum(1) - abs_prob, Spectrum(1)) # Replace interactions by sampled ones from BSSRDF si_bsdf = SurfaceInteraction3f().masked_si(si_bsdf, projected_si, is_bssrdf) ################################ # Determine probability of having sampled that same # direction using emitter sampling emitter = si_bsdf.emitter(scene, active) ds = DirectionSample3f(si_bsdf, si) ds.object = emitter delta = has_flag(bs.sampled_type, BSDFFlags.Delta) emitter_pdf = ek.select(delta, Float(0.0), scene.pdf_emitter_direction(si, ds)) emission_weight = mis_weight(bs.pdf, emitter_pdf) si = si_bsdf return result, valid_rays, scatter, non_scatter, invalid_sample
def sample(self, scene, sampler, ray, medium=None, active=True): result = Vector3f(0.0) si = scene.ray_intersect(ray, active) active = si.is_valid() & active # emitter = si.emitter(scene) # result = ek.select(active, Emitter.eval_vec(emitter, si, active), Vector3f(0.0)) # z_axis = np.array([0, 0, 1]) # vertex = si.p.numpy() # v_count = vertex.shape[0] # vertex = np.expand_dims(vertex, axis=1) # vertex = np.repeat(vertex, self.light.vertex_count(), axis=1) # light_vertices = self.light.vertex_positions_buffer().numpy().reshape(self.light.vertex_count(), 3) # light_vertices = np.expand_dims(light_vertices, axis=0) # light_vertices = np.repeat(light_vertices, v_count, axis=0) # sph_polygons = light_vertices - vertex # sph_polygons = sph_polygons / np.linalg.norm(sph_polygons, axis=2, keepdims=True) # z_axis = np.repeat( np.expand_dims(z_axis, axis=0), v_count, axis=0 ) # result_np = np.zeros(v_count, dtype=np.double) # for idx in range( self.light.vertex_count() ): # idx1 = (idx+1) % self.light.vertex_count() # idx2 = (idx) % self.light.vertex_count() # dp = np.sum( sph_polygons[:, idx1, :] * sph_polygons[:, idx2, :], axis=1 ) # acos = np.arccos(dp) # cp = np.cross( sph_polygons[:, idx1, :], sph_polygons[:, idx2, :] ) # cp = cp / np.linalg.norm(cp, axis=1, keepdims=True) # dp = np.sum( cp * z_axis, axis=1 ) # result_np += acos * dp # result_np *= 0.5 * 1.0/math.pi # result_np = np.repeat( result_np.reshape((v_count, 1)), 3, axis=1 ) # fin = self.light_radiance * Vector3f(result_np) # fin[fin < 0] = 0 # result += ek.select(active, fin, Vector3f(0.0)) ctx = BSDFContext() bsdf = si.bsdf(ray) # bs, bsdf_val = BSDF.sample_vec(bsdf, ctx, si, sampler.next_1d(active), sampler.next_2d(active), active) # pdf = bs.pdf # wo = si.to_world(bs.wo) ds, emitter_val = scene.sample_emitter_direction( si, sampler.next_2d(active), True, active) pdf = ds.pdf active_e = active & ek.neq(ds.pdf, 0.0) wo = ds.d bsdf_val = BSDF.eval_vec(bsdf, ctx, si, wo, active_e) emitter_val[emitter_val > 1.0] = 1.0 bsdf_val *= emitter_val # _, wi_theta, wi_phi = sph_convert(si.to_world(si.wi)) _, wo_theta, wo_phi = sph_convert(wo) y_0_0_ = y_0_0(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_1_n1_ = y_1_n1(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_1_0_ = y_1_0(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_1_p1_ = y_1_p1(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_2_n2_ = y_2_n2(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_2_n1_ = y_2_n1(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_2_0_ = y_2_0(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_2_p1_ = y_2_p1(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) y_2_p2_ = y_2_p2(bsdf_val, wo_theta, wo_phi) / ek.select( pdf > 0, pdf, Float(0.01)) return result, si.is_valid(), [ Float(y_0_0_[0]), Float(y_0_0_[1]), Float(y_0_0_[2]),\ Float(y_1_n1_[0]), Float(y_1_n1_[1]), Float(y_1_n1_[2]),\ Float(y_1_0_[0]), Float(y_1_0_[1]), Float(y_1_0_[2]),\ Float(y_1_p1_[0]), Float(y_1_p1_[1]), Float(y_1_p1_[2]),\ Float(y_2_n2_[0]), Float(y_2_n2_[1]), Float(y_2_n2_[2]),\ Float(y_2_n1_[0]), Float(y_2_n1_[1]), Float(y_2_n1_[2]),\ Float(y_2_0_[0]), Float(y_2_0_[1]), Float(y_2_0_[2]),\ Float(y_2_p1_[0]), Float(y_2_p1_[1]), Float(y_2_p1_[2]),\ Float(y_2_p2_[0]), Float(y_2_p2_[1]), Float(y_2_p2_[2]) ]