def UniformSampleOneLight(scene: Scene, renderer: Renderer, p: Point3d, n: Normal, wo: Vector3d, time: float, bsdf: BSDF, sample: Sample, lightSampleOffsets: [LightSampleOffsets]=None, bsdfSampleOffsets: [BSDFSampleOffsets]=None, lightNumOffset: int=-1) -> Spectrum: L = Spectrum(0.0) nLights = int(len(scene.lights)) if nLights == 0: return Spectrum(0.0) if lightNumOffset != -1: lightNum = int((sample.values_array_1d[lightNumOffset][0] * nLights)) # todo floor to int else: lightNum = int((random() * nLights)) # todo floor to int lightNum = min(lightNum, nLights - 1) light = scene.lights[lightNum] # Initialize light and bsdf samples for single light sample if lightSampleOffsets is not None and bsdfSampleOffsets is not None: lightSample = LightSample.create_from_sample(sample, lightSampleOffsets, 0) bsdfSample = BSDFSample.create_from_sample(sample, bsdfSampleOffsets, 0) else: lightSample = LightSample.create_from_random() bsdfSample = BSDFSample.create_from_random() Ld = EstimateDirect(scene, renderer, light, p, n, wo, time, bsdf, lightSample, bsdfSample, BxDFType.BSDF_ALL & ~BxDFType.BSDF_SPECULAR) return Ld * float(nLights)
def UniformSampleAllLights(scene: Scene, renderer: Renderer, p: Point3d, n: Normal, wo: Vector3d, time: float, bsdf: BSDF, sample: Sample, lightSampleOffsets: [LightSampleOffsets], bsdfSampleOffsets: [BSDFSampleOffsets]) -> Spectrum: L = Spectrum(0.0) for i in range(len(scene.lights)): light = scene.lights[i] if lightSampleOffsets is None: nSamples = 1 else: nSamples = lightSampleOffsets[i].nSamples # Estimate direct lighting from _light_ samples Ld = Spectrum(0.0) for j in range(nSamples): # Find light and BSDF sample values for direct lighting estimate if lightSampleOffsets is not None and bsdfSampleOffsets is not None: lightSample = LightSample.create_from_sample(sample, lightSampleOffsets[i], j) bsdfSample = BSDFSample.create_from_sample(sample, bsdfSampleOffsets[i], j) else: lightSample = LightSample.create_from_random() bsdfSample = BSDFSample.create_from_random() Ld += EstimateDirect(scene, renderer, light, p, n, wo, time, bsdf, lightSample, bsdfSample, BxDFType.BSDF_ALL & ~BxDFType.BSDF_SPECULAR) L += Ld / nSamples return L
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