// Integrator Utility Functions Spectrum UniformSampleAllLights(const Interaction &it, const Scene &scene, MemoryArena &arena, Sampler &sampler, const std::vector<int> &nLightSamples, bool handleMedia) { ProfilePhase p(Prof::DirectLighting); Spectrum L(0.f); for (size_t j = 0; j < scene.lights.size(); ++j) { // Accumulate contribution of _j_th light to _L_ const std::shared_ptr<Light> &light = scene.lights[j]; int nSamples = nLightSamples[j]; const Point2f *uLightArray = sampler.Get2DArray(nSamples); const Point2f *uScatteringArray = sampler.Get2DArray(nSamples); if (!uLightArray || !uScatteringArray) { // Use a single sample for illumination from _light_ Point2f uLight = sampler.Get2D(); Point2f uScattering = sampler.Get2D(); L += EstimateDirect(it, uScattering, *light, uLight, scene, sampler, arena, handleMedia); } else { // Estimate direct lighting using sample arrays Spectrum Ld(0.f); for (int k = 0; k < nSamples; ++k) Ld += EstimateDirect(it, uScatteringArray[k], *light, uLightArray[k], scene, sampler, arena, handleMedia); L += Ld / nSamples; } } return L; }
Spectrum UniformSampleOneLight(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, BSDF *bsdf, const Sample *sample, RNG &rng, int lightNumOffset, const LightSampleOffsets *lightSampleOffset, const BSDFSampleOffsets *bsdfSampleOffset) { // Randomly choose a single light to sample, _light_ int nLights = int(scene->lights.size()); if (nLights == 0) return Spectrum(0.); int lightNum; if (lightNumOffset != -1) lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * nLights); else lightNum = Floor2Int(rng.RandomFloat() * nLights); lightNum = min(lightNum, nLights-1); Light *light = scene->lights[lightNum]; // Initialize light and bsdf samples for single light sample LightSample lightSample; BSDFSample bsdfSample; if (lightSampleOffset != NULL && bsdfSampleOffset != NULL) { lightSample = LightSample(sample, *lightSampleOffset, 0); bsdfSample = BSDFSample(sample, *bsdfSampleOffset, 0); } else { lightSample = LightSample(rng); bsdfSample = BSDFSample(rng); } return (float)nLights * EstimateDirect(scene, renderer, arena, light, p, n, wo, rayEpsilon, time, bsdf, rng, lightSample, bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); }
// Integrator Utility Functions Spectrum UniformSampleAllLights(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, BSDF *bsdf, const Sample *sample, RNG &rng, const LightSampleOffsets *lightSampleOffsets, const BSDFSampleOffsets *bsdfSampleOffsets) { Spectrum L(0.); for (uint32_t i = 0; i < scene->lights.size(); ++i) { Light *light = scene->lights[i]; int nSamples = lightSampleOffsets ? lightSampleOffsets[i].nSamples : 1; // Estimate direct lighting from _light_ samples Spectrum Ld(0.); for (int j = 0; j < nSamples; ++j) { // Find light and BSDF sample values for direct lighting estimate LightSample lightSample; BSDFSample bsdfSample; if (lightSampleOffsets != NULL && bsdfSampleOffsets != NULL) { lightSample = LightSample(sample, lightSampleOffsets[i], j); bsdfSample = BSDFSample(sample, bsdfSampleOffsets[i], j); } else { lightSample = LightSample(rng); bsdfSample = BSDFSample(rng); } Ld += EstimateDirect(scene, renderer, arena, light, p, n, wo, rayEpsilon, time, bsdf, rng, lightSample, bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); } L += Ld / nSamples; } return L; }
static Spectrum L(const Scene *scene, const Renderer *renderer, const Camera *camera, MemoryArena &arena, RNG &rng, int maxDepth, bool ignoreDirect, const MLTSample &sample) { // Generate camera ray from Metropolis sample RayDifferential ray; float cameraWeight = camera->GenerateRayDifferential(sample.cameraSample, &ray); Spectrum pathThroughput = cameraWeight, L = 0.; bool specularBounce = false, allSpecular = true; for (int pathLength = 0; pathLength < maxDepth; ++pathLength) { // Find next intersection in Metropolis light path Intersection isect; if (!scene->Intersect(ray, &isect)) { bool includeLe = ignoreDirect ? (specularBounce && !allSpecular) : (pathLength == 0 || specularBounce); if (includeLe) for (uint32_t i = 0; i < scene->lights.size(); ++i) L += pathThroughput * scene->lights[i]->Le(ray); break; } if (ignoreDirect ? (specularBounce && !allSpecular) : (specularBounce || pathLength == 0)) L += pathThroughput * isect.Le(-ray.d); BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; const PathSample &ps = sample.pathSamples[pathLength]; // Sample direct illumination for Metropolis path vertex if (!ignoreDirect || pathLength > 0) { LightSample lightSample(ps.lightDir0, ps.lightDir1, ps.lightNum0); BSDFSample bsdfSample(ps.bsdfLightDir0, ps.bsdfLightDir1, ps.bsdfLightComponent); uint32_t lightNum = Floor2Int(ps.lightNum1 * scene->lights.size()); lightNum = min(lightNum, (uint32_t)(scene->lights.size()-1)); const Light *light = scene->lights[lightNum]; L += pathThroughput * EstimateDirect(scene, renderer, arena, light, p, n, wo, isect.rayEpsilon, sample.cameraSample.time, bsdf, rng, lightSample, bsdfSample); } // Sample direction for outgoing Metropolis path direction BSDFSample outgoingBSDFSample(ps.bsdfDir0, ps.bsdfDir1, ps.bsdfComponent); Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, outgoingBSDFSample, &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; allSpecular &= specularBounce; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isect.rayEpsilon); //pathThroughput *= renderer->Transmittance(scene, ray, NULL, rng, arena); } return L; }
COREDLL Spectrum WeightedSampleOneLight(const Scene *scene, const Point &p, const Normal &n, const Vector &wo, BSDF *bsdf, const Sample *sample, int lightSampleOffset, int lightNumOffset, int bsdfSampleOffset, int bsdfComponentOffset, float *&avgY, float *&avgYsample, float *&cdf, float &overallAvgY) { int nLights = int(scene->lights.size()); // Initialize _avgY_ array if necessary if (!avgY) { avgY = new float[nLights]; avgYsample = new float[nLights]; cdf = new float[nLights+1]; for (int i = 0; i < nLights; ++i) avgY[i] = avgYsample[i] = 0.; } Spectrum L(0.); if (overallAvgY == 0.) { // Sample one light uniformly and initialize luminance arrays L = UniformSampleOneLight(scene, p, n, wo, bsdf, sample, lightSampleOffset, lightNumOffset, bsdfSampleOffset, bsdfComponentOffset); float luminance = L.y(); overallAvgY = luminance; for (int i = 0; i < nLights; ++i) avgY[i] = luminance; } else { // Choose _light_ according to average reflected luminance float c, lightSampleWeight; for (int i = 0; i < nLights; ++i) avgYsample[i] = max(avgY[i], .1f * overallAvgY); ComputeStep1dCDF(avgYsample, nLights, &c, cdf); float t = SampleStep1d(avgYsample, cdf, c, nLights, sample->oneD[lightNumOffset][0], &lightSampleWeight); int lightNum = min(Float2Int(nLights * t), nLights-1); Light *light = scene->lights[lightNum]; L = EstimateDirect(scene, light, p, n, wo, bsdf, sample, lightSampleOffset, bsdfSampleOffset, bsdfComponentOffset, 0); // Update _avgY_ array with reflected radiance due to light float luminance = L.y(); avgY[lightNum] = ExponentialAverage(avgY[lightNum], luminance, .99f); overallAvgY = ExponentialAverage(overallAvgY, luminance, .999f); L /= lightSampleWeight; } return L; }
Spectrum UniformSampleOneLight(const Interaction &it, const Scene &scene, MemoryArena &arena, Sampler &sampler, bool handleMedia) { ProfilePhase p(Prof::DirectLighting); // Randomly choose a single light to sample, _light_ int nLights = int(scene.lights.size()); if (nLights == 0) return Spectrum(0.f); int lightNum = std::min((int)(sampler.Get1D() * nLights), nLights - 1); const std::shared_ptr<Light> &light = scene.lights[lightNum]; Point2f uLight = sampler.Get2D(); Point2f uScattering = sampler.Get2D(); return (Float)nLights * EstimateDirect(it, uScattering, *light, uLight, scene, sampler, arena, handleMedia); }
Spectrum MetropolisRenderer::Lpath(const Scene *scene, const PathVertex *cameraPath, int cameraPathLength, MemoryArena &arena, const vector<LightingSample> &samples, RNG &rng, float time, const Distribution1D *lightDistribution, const RayDifferential &eRay, const Spectrum &eAlpha) const { PBRT_MLT_STARTED_LPATH(); Spectrum L = 0.; bool previousSpecular = true, allSpecular = true; for (int i = 0; i < cameraPathLength; ++i) { // Initialize basic variables for camera path vertex const PathVertex &vc = cameraPath[i]; const Point &pc = vc.bsdf->dgShading.p; const Normal &nc = vc.bsdf->dgShading.nn; // Add emitted light from vertex if appropriate if (previousSpecular && (directLighting == NULL || !allSpecular)) L += vc.alpha * vc.isect.Le(vc.wPrev); // Compute direct illumination for Metropolis path vertex Spectrum Ld(0.f); if (directLighting == NULL || !allSpecular) { // Choose light and call _EstimateDirect()_ for Metropolis vertex const LightingSample &ls = samples[i]; float lightPdf; uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, &lightPdf); const Light *light = scene->lights[lightNum]; PBRT_MLT_STARTED_ESTIMATE_DIRECT(); Ld = vc.alpha * EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, vc.isect.rayEpsilon, time, vc.bsdf, rng, NULL, ls.lightSample, ls.bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); } previousSpecular = vc.specularBounce; allSpecular &= previousSpecular; L += Ld; } // Add contribution of escaped ray, if any if (!eAlpha.IsBlack() && previousSpecular && (directLighting == NULL || !allSpecular)) for (uint32_t i = 0; i < scene->lights.size(); ++i) L += eAlpha * scene->lights[i]->Le(eRay); PBRT_MLT_FINISHED_LPATH(); return L; }
COREDLL Spectrum UniformSampleOneLight(const Scene *scene, const Point &p, const Normal &n, const Vector &wo, BSDF *bsdf, const Sample *sample, int lightSampleOffset, int lightNumOffset, int bsdfSampleOffset, int bsdfComponentOffset) { // Randomly choose a single light to sample, _light_ int nLights = int(scene->lights.size()); int lightNum; if (lightNumOffset != -1) lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * nLights); else lightNum = Floor2Int(RandomFloat() * nLights); lightNum = min(lightNum, nLights-1); Light *light = scene->lights[lightNum]; return (float)nLights * EstimateDirect(scene, light, p, n, wo, bsdf, sample, lightSampleOffset, bsdfSampleOffset, bsdfComponentOffset, 0); }
// Integrator Utility Functions COREDLL Spectrum UniformSampleAllLights(const Scene *scene, const Point &p, const Normal &n, const Vector &wo, BSDF *bsdf, const Sample *sample, int *lightSampleOffset, int *bsdfSampleOffset, int *bsdfComponentOffset) { Spectrum L(0.); for (u_int i = 0; i < scene->lights.size(); ++i) { Light *light = scene->lights[i]; int nSamples = (sample && lightSampleOffset) ? sample->n2D[lightSampleOffset[i]] : 1; // Estimate direct lighting from _light_ samples Spectrum Ld(0.); for (int j = 0; j < nSamples; ++j) Ld += EstimateDirect(scene, light, p, n, wo, bsdf, sample, lightSampleOffset[i], bsdfSampleOffset[i], bsdfComponentOffset[i], j); L += Ld / nSamples; } return L; }
Spectrum MetropolisRenderer::Lbidir(const Scene *scene, const PathVertex *cameraPath, int cameraPathLength, const PathVertex *lightPath, int lightPathLength, MemoryArena &arena, const vector<LightingSample> &samples, RNG &rng, float time, const Distribution1D *lightDistribution, const RayDifferential &eRay, const Spectrum &eAlpha) const { PBRT_MLT_STARTED_LBIDIR(); Spectrum L = 0.; bool previousSpecular = true, allSpecular = true; // Compute number of specular vertices for each path length int nVerts = cameraPathLength + lightPathLength + 2; int *nSpecularVertices = ALLOCA(int, nVerts); memset(nSpecularVertices, 0, nVerts * sizeof(int)); for (int i = 0; i < cameraPathLength; ++i) for (int j = 0; j < lightPathLength; ++j) if (cameraPath[i].specularBounce || lightPath[j].specularBounce) ++nSpecularVertices[i+j+2]; for (int i = 0; i < cameraPathLength; ++i) { // Initialize basic variables for camera path vertex const PathVertex &vc = cameraPath[i]; const Point &pc = vc.bsdf->dgShading.p; const Normal &nc = vc.bsdf->dgShading.nn; // Compute reflected light at camera path vertex // Add emitted light from vertex if appropriate if (previousSpecular && (directLighting == NULL || !allSpecular)) L += vc.alpha * vc.isect.Le(vc.wPrev); // Compute direct illumination for Metropolis path vertex Spectrum Ld(0.f); if (directLighting == NULL || !allSpecular) { // Choose light and call _EstimateDirect()_ for Metropolis vertex const LightingSample &ls = samples[i]; float lightPdf; uint32_t lightNum = lightDistribution->SampleDiscrete(ls.lightNum, &lightPdf); const Light *light = scene->lights[lightNum]; PBRT_MLT_STARTED_ESTIMATE_DIRECT(); Ld = vc.alpha * EstimateDirect(scene, this, arena, light, pc, nc, vc.wPrev, vc.isect.rayEpsilon, time, vc.bsdf, rng, NULL, ls.lightSample, ls.bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf; PBRT_MLT_FINISHED_ESTIMATE_DIRECT(); } previousSpecular = vc.specularBounce; allSpecular &= previousSpecular; L += Ld / (i + 1 - nSpecularVertices[i+1]); if (!vc.specularBounce) { // Loop over light path vertices and connect to camera vertex for (int j = 0; j < lightPathLength; ++j) { const PathVertex &vl = lightPath[j]; const Point &pl = vl.bsdf->dgShading.p; const Normal &nl = vl.bsdf->dgShading.nn; if (!vl.specularBounce) { // Compute contribution between camera and light vertices Vector w = Normalize(pl - pc); Spectrum fc = vc.bsdf->f(vc.wPrev, w) * (1 + vc.nSpecularComponents); Spectrum fl = vl.bsdf->f(-w, vl.wPrev) * (1 + vl.nSpecularComponents); if (fc.IsBlack() || fl.IsBlack()) continue; Ray r(pc, pl - pc, 1e-3f, .999f, time); if (!scene->IntersectP(r)) { // Compute weight for bidirectional path, _pathWt_ float pathWt = 1.f / (i + j + 2 - nSpecularVertices[i+j+2]); float G = AbsDot(nc, w) * AbsDot(nl, w) / DistanceSquared(pl, pc); L += (vc.alpha * fc * G * fl * vl.alpha) * pathWt; } } } } } // Add contribution of escaped ray, if any if (!eAlpha.IsBlack() && previousSpecular && (directLighting == NULL || !allSpecular)) for (uint32_t i = 0; i < scene->lights.size(); ++i) L += eAlpha * scene->lights[i]->Le(eRay); PBRT_MLT_FINISHED_LBIDIR(); return L; }