def generateSample(self, intersection, scene, camera, ray, depth=0): sample = Irradiance_Sample(intersection.pos, intersection.n) minSamples = 64 l = np.array([0., 0., 0.]) # generate a sample for irradiance if (depth > 0): numSample = np.max( [minSamples, self.directLightSampleCount / (2**depth)]) for i in range(int(numSample)): h2Vec = self.getCosineWeightedPointH2() d = self.transformH2toR3(h2Vec, intersection.n) r = Ray(intersection.pos + 0.001 * intersection.n, d) ni = Intersection() if (scene.intersect(r, ni)): if r.t <= 0: print( "\033[34mWARNING\033[30m: ray intersects with t <= 0" ) if (sample.minHitDist > r.t): sample.minHitDist = r.t procData = Irradiance_ProcessData(ni.pos, ni.n, self.minWeight, self.maxCosAngleDiff) intVal = self.getInterpolatedValue(procData, depth - 1) # if interpolation is successful if (intVal >= 0).all(): lightval = ni.color * intVal * ni.BSDF( procData.avgLightDir, d, ni.n) """ if lightval < 0: print("\033[34mWARNING\033[30m: Interpolation lead to a negative light value") """ l += lightval sample.avgLightDir += d * np.linalg.norm(lightval) v = self.transformH2toR3( np.array([ h2Vec[0], (h2Vec[1] - np.pi / 4) % (2 * np.pi) ]), intersection.n) sample.rotGrad += -v * np.tan( h2Vec[0]) * np.linalg.norm(lightval) # else make a new sample und use its irradiance else: s = self.generateSample(ni, scene, camera, r, depth - 1) lightval = ni.color * s.irradiance * ni.BSDF( s.avgLightDir, d, ni.n) if (lightval < 0).any(): print( "\033[31mERROR\033[30m: Generating a new sample lead to a negative light value" ) l += lightval sample.avgLightDir += d * np.linalg.norm( lightval) #s.avgLightDir v = self.transformH2toR3( np.array([ h2Vec[0], (h2Vec[1] - np.pi / 4) % (2 * np.pi) ]), intersection.n) sample.rotGrad += -v * np.tan( h2Vec[0]) * np.linalg.norm(lightval) if np.dot(sample.avgLightDir, sample.normal) < 0: print( "\033[34mWARNING\033[30m: The average Light direction points temporally in the wrong half space" ) l *= np.pi / numSample sample.rotGrad *= np.pi / numSample else: # generate a sample for direct light l = self.MonteCarlo(intersection, scene, self.directLightSampleCount, sample) #+ intersection.ell pixelSpacing = self.computeIntersectionPixelSpacing( camera, ray, intersection) sample.irradiance = l sample.computeSampleMaxContribution(self.minPixelDist, self.maxPixelDist, pixelSpacing) norm = np.linalg.norm(sample.avgLightDir) if (norm > 0): sample.avgLightDir /= norm if ((self.showSamples) & (depth == self.maxBounceDepth)): camera.imageDepths[-1][ray.pixel[0], ray.pixel[1], :] = [1., 0., 0.] if np.dot(sample.avgLightDir, sample.normal) < 0: print( "\033[31mERROR\033[30m: Sample was generated with avgLightDir pointing in the wrong half space" ) self.cache[depth].addObj(sample) return sample
def ell(self, scene, ray, camera): #very first call for ell() means the cache has to be filled cameraImageCount = self.maxBounceDepth + 1 + (1 if self.showSamples else 0) if len(camera.imageDepths) < cameraImageCount: for i in range(len(camera.imageDepths), cameraImageCount): camera.addImage() if ((ray.pixel[0] == 0) & (ray.pixel[1] == 0)): start = time.perf_counter() if self.completelyFillCache: self.FillCacheComplete(camera, scene) else: self.fillCache(camera, scene) end = time.perf_counter() s = end - start m = int(s / 60) s = s % 60 h = int(m / 60) m = m % 60 print("filling cache took:", h, "h ", m, "min ", s, "s") for i in range(len(self.cache)): print("In cache depth: ", i, "are ", self.cache[i].objCount, "samples") intersection = Intersection() val = np.array([0.0, 0., 0.]) if (scene.intersect(ray, intersection)): #interpolate indirect light for i in range(self.maxBounceDepth, 0, -1): interpolatedPoint = Irradiance_ProcessData( intersection.pos, intersection.n, self.minWeight, self.maxCosAngleDiff) interpval = self.getInterpolatedValue(interpolatedPoint, i) e = 0 if (interpval >= 0).all(): e += interpval * intersection.BSDF( interpolatedPoint.avgLightDir, -ray.d, intersection.n) #if interpolation failed, compute new sample else: #print("new sample generated at ", ray.pixel) s = self.generateSample(intersection, scene, camera, ray, i) e += s.irradiance * intersection.BSDF( s.avgLightDir, -ray.d, s.normal) if (e < 0).any(): print(e) camera.imageDepths[i][ray.pixel[0], ray.pixel[1], :] = e val += e #compute direct light if self.renderDirectLight: sample = Irradiance_Sample(intersection.pos, intersection.n) self.MonteCarlo(intersection, scene, sampleCount=self.directLightSampleCount, sample=sample) camera.imageDepths[0][ ray.pixel[0], ray.pixel[1], :] = intersection.color * ( sample.irradiance * intersection.BSDF( sample.avgLightDir, -ray.d, intersection.n) + intersection.ell) val += sample.irradiance * intersection.BSDF( sample.avgLightDir, -ray.d, intersection.n) val += intersection.ell if (val < 0).any(): print("light value is negative :", val) return val * intersection.color