def Li(self, scene, renderer: Renderer, r: Ray, intersection: Intersection, sample: Sample) -> Spectrum: # Declare common path integration variables pathThroughput = Spectrum(1.0) L = Spectrum(0.0) ray = deepcopy(r) specularBounce = False localIsect = Intersection() isectp = intersection bounces = 0 while True: # Possibly add emitted light at path vertex if bounces == 0 or specularBounce: L += pathThroughput * isectp.Le(-ray.direction) # Sample illumination from lights to find path contribution bsdf = isectp.get_bsdf(ray) p = bsdf.dgShading.point n = bsdf.dgShading.normal wo = -ray.direction if bounces < self.maxDepth: L += pathThroughput * UniformSampleOneLight(scene, renderer, p, n, wo, ray.time, bsdf, sample, self.lightSampleOffsets[bounces], self.bsdfSampleOffsets[bounces], self.lightNumOffset[bounces]) else: L += pathThroughput * UniformSampleOneLight(scene, renderer, p, n, wo, ray.time, bsdf, sample) # Sample BSDF to get new path direction # Get _outgoingBSDFSample_ for sampling new path direction if bounces < self.maxDepth: outgoingBSDFSample = BSDFSample.create_from_sample(sample, self.pathSampleOffsets[bounces], 0) else: outgoingBSDFSample = BSDFSample.create_from_random() wi, pdf, flags, f = bsdf.Sample_f(wo, outgoingBSDFSample, BxDFType.BSDF_ALL) if f.get_is_black() or pdf == 0.0: break specularBounce = (flags & BxDFType.BSDF_SPECULAR) != 0 pathThroughput *= f * math.fabs(Vector3d.dot(wi, n)) / pdf ray = Ray(p, wi, 0.01, ray.max_t) # Possibly terminate the path if bounces > 3: continueProbability = min(0.5, pathThroughput.y()) if random() > continueProbability: break pathThroughput /= continueProbability if bounces == self.maxDepth: break # Find next vertex of path if not scene.get_intersection(ray, localIsect): if specularBounce: for i in range(scene.lights.size()): L += pathThroughput * scene.lights[i].get_Le(ray) break # pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); isectp = localIsect bounces += 1 return L
def run(self): """Execute the task.""" print "executing task %d/%d" % (self.task_num, self.task_count) # get sub-sampler for SamplerRendererTask sampler = self.main_sampler.get_sub_sampler(self.task_num, self.task_count) if not sampler: return # Declare local variables used for rendering loop rng = RNG(self.task_num) # allocate space for samples and intersections max_samples = sampler.maximum_sample_count() samples = self.orig_sample.duplicate(max_samples) rays = [None] * max_samples Ls = [None] * max_samples Ts = [None] * max_samples isects = [] # Intersection[max_samples] for i in range(max_samples): isects.append(Intersection()) # get samples from Sampler and update image while True: sample_count = sampler.get_more_samples(samples, rng) # if no more samples to compute, exit if sample_count <= 0: break # generate camera rays and compute radiance along rays for i in range(sample_count): # find camera ray for samples[i] ray_weight, ray_diff = self.camera.generate_ray_differential( samples[i]) rays[i] = ray_diff coeff = 1.0 / math.sqrt(sampler.samples_per_pixel) ray_diff.scale_differentials(coeff) # evaluate radiance along camera ray if ray_weight > 0.0: radiance, intersection, Ts_i = \ self.renderer.Li(self.scene, ray_diff, samples[i], rng, isects[i]) Ls_i = ray_weight * radiance else: Ls_i = Spectrum(0.0) Ts_i = Spectrum(1.0) Ls[i] = Ls_i Ts[i] = Ts_i # check for unexpected radiance values if Ls_i.has_nan(): logger.error( "Not-a-number radiance value returned for image sample. Setting to black." ) Ls_i = Spectrum(0.0) elif Ls_i.y() < -1e-5: logger.error( "Negative luminance value, %f, returned for image sample. Setting to black." % Ls_i.y()) Ls_i = Spectrum(0.0) elif Ls_i.y() == float('inf'): logger.error( "Infinite luminance value returned for image sample. Setting to black." ) Ls_i = Spectrum(0.0) # report sample results to Sampler, add contributions to image if sampler.report_results(samples, rays, Ls, isects, sample_count): for i in range(sample_count): self.camera.film.add_sample(samples[i], Ls[i]) # clean up after SamplerRendererTask is done with its image region pass
def run(self): """Execute the task.""" print "executing task %d/%d" % (self.task_num, self.task_count) # get sub-sampler for SamplerRendererTask sampler = self.main_sampler.get_sub_sampler(self.task_num, self.task_count) if not sampler: return # Declare local variables used for rendering loop rng = RNG(self.task_num) # allocate space for samples and intersections max_samples = sampler.maximum_sample_count() samples = self.orig_sample.duplicate(max_samples) rays = [None] * max_samples Ls = [None] * max_samples Ts = [None] * max_samples isects = [] # Intersection[max_samples] for i in range(max_samples): isects.append(Intersection()) # get samples from Sampler and update image while True: sample_count = sampler.get_more_samples(samples, rng) # if no more samples to compute, exit if sample_count <= 0: break # generate camera rays and compute radiance along rays for i in range(sample_count): # find camera ray for samples[i] ray_weight, ray_diff = self.camera.generate_ray_differential(samples[i]) rays[i] = ray_diff coeff = 1.0 / math.sqrt(sampler.samples_per_pixel) ray_diff.scale_differentials(coeff) # evaluate radiance along camera ray if ray_weight > 0.0: radiance, intersection, Ts_i = \ self.renderer.Li(self.scene, ray_diff, samples[i], rng, isects[i]) Ls_i = ray_weight * radiance else: Ls_i = Spectrum(0.0) Ts_i = Spectrum(1.0) Ls[i] = Ls_i Ts[i] = Ts_i # check for unexpected radiance values if Ls_i.has_nan(): logger.error( "Not-a-number radiance value returned for image sample. Setting to black.") Ls_i = Spectrum(0.0) elif Ls_i.y() < -1e-5: logger.error( "Negative luminance value, %f, returned for image sample. Setting to black." % Ls_i.y()) Ls_i = Spectrum(0.0) elif Ls_i.y() == float('inf'): logger.error( "Infinite luminance value returned for image sample. Setting to black.") Ls_i = Spectrum(0.0) # report sample results to Sampler, add contributions to image if sampler.report_results(samples, rays, Ls, isects, sample_count): for i in range(sample_count): self.camera.film.add_sample(samples[i], Ls[i]) # clean up after SamplerRendererTask is done with its image region pass