// 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; }
// 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 EstimateDirect(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Light *light, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, const BSDF *bsdf, RNG &rng, const LightSample &lightSample, const BSDFSample &bsdfSample, BxDFType flags) { Spectrum Ld(0.); // Sample light source with multiple importance sampling Vector wi; float lightPdf, bsdfPdf; VisibilityTester visibility; Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time, &wi, &lightPdf, &visibility); if (lightPdf > 0. && !Li.IsBlack()) { Spectrum f = bsdf->f(wo, wi, flags); if (!f.IsBlack() && visibility.Unoccluded(scene)) { // Add light's contribution to reflected radiance Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); if (light->IsDeltaLight()) Ld += f * Li * (AbsDot(wi, n) / lightPdf); else { bsdfPdf = bsdf->Pdf(wo, wi, flags); float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf); Ld += f * Li * (AbsDot(wi, n) * weight / lightPdf); } } } // Sample BSDF with multiple importance sampling if (!light->IsDeltaLight()) { BxDFType sampledType; Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &bsdfPdf, flags, &sampledType); if (!f.IsBlack() && bsdfPdf > 0.) { float weight = 1.f; if (!(sampledType & BSDF_SPECULAR)) { lightPdf = light->Pdf(p, wi); if (lightPdf == 0.) return Ld; weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf); } // Add light contribution from BSDF sampling Intersection lightIsect; Spectrum Li(0.f); RayDifferential ray(p, wi, rayEpsilon, INFINITY, time); if (scene->Intersect(ray, &lightIsect)) { if (lightIsect.primitive->GetAreaLight() == light) Li = lightIsect.Le(-wi); } else //Li = light->Le(ray,); Li = Spectrum(0.); if (!Li.IsBlack()) { Li *= renderer->Transmittance(scene, ray, NULL, rng, arena); Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf; } } } return Ld; }
void testList(int testSize) { printf("\n ==== Test %2d. Generate two lists each of size %d by random insertions\n", testID++, testSize); List<T> La; randomList(La, testSize); PRINT(La); List<T> Lb; randomList(Lb, testSize); PRINT(Lb); printf("\n ==== Test %2d. Call list members by rank (with high complexity)\n", testID++); for (int i = 0; i < La.size(); i++) print(La[i]->data); printf("\n"); for (int i = 0; i < Lb.size(); i++) print(Lb[i]->data); printf("\n"); printf("\n ==== Test %2d. Concatenation\n", testID++); PRINT(La); PRINT(Lb); while (0 < Lb.size()) La.insertAsLast(Lb.remove(Lb.first())); PRINT(La); PRINT(Lb); printf("\n ==== Test %2d. Increase\n", testID++); PRINT(La); increase(La); PRINT(La); printf("\n ==== Test %2d. Copy\n", testID++); PRINT(La); List<T> Ld(La); PRINT(Ld); printf("\n ==== Test %2d. Trim by random deletions\n", testID++); PRINT(Ld); while (testSize/4 < Ld.size()) { int N = rand() % Ld.size(); printf("removing L[%d]=", N); ListNodePosi(T) p = Ld.first(); while (0 < N--) p = p->succ; print(p->data); printf(" ...\n"); Ld.remove(p); PRINT(Ld); } printf("\n ==== Test %2d. Copy\n", testID++); PRINT(La); List<T> Le(La); PRINT(Le); printf("\n ==== Test %2d. FIND in\n", testID++); PRINT(Le); for (int i = 0; i <= testSize*2; i++) { //逐一测试[0, 2n]中的所有可能 ListNodePosi(T) p = Le.find((T) i); printf("Looking for "); print((T)i); printf(": "); if (p) { printf(" found with"); print(p->data); } else printf(" not found"); printf("\n"); } //正确的结构应该是大致(n+1次)失败、(n次)成功相间 printf("\n ==== Test %2d. Sort\n", testID++); PRINT(La); La.sort(); PRINT(La); printf("\n ==== Test %2d. SEARCH in\n", testID++); PRINT(La); for (int i = 0; i <= testSize*2; i++) { //逐一测试[0, 2n]中的所有可能 ListNodePosi(T) p = La.search((T) i); printf("Looking for "); print((T)i); printf(": "); printf(" stopped at"); print(p->data); if ((T) i == p->data) printf(" and found"); printf("\n"); } //正确的结构应该是大致(n+1次)失败、(n次)成功相间 printf("\n ==== Test %2d. Remove redundancy in\n", testID++); PRINT(La); printf("%d node(s) removed\n", La.uniquify()); PRINT(La); printf("\n ==== Test %2d. Remove redundancy in\n", testID++); PRINT(Le); printf("%d node(s) removed\n", Le.deduplicate()); PRINT(Le); printf("\n ==== Test %2d. Sort\n", testID++); PRINT(Le); Le.sort(); PRINT(Le); return; }
glm::vec3 BidirectionalIntegrator::EstimateDirectLight(Intersection &isx, Ray &ray, Geometry* &light) { glm::vec3 Ld(0); Ld = MIS_SampleBRDF(isx,ray,light) + MIS_SampleLight(isx,ray,light); return Ld; }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { //check if a distant disk light is set const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk == nullptr ) return Color3f(0.0f); //sample the distant disk light return distantsDisk->sampleL(ray.d); } //get the radiance of hitten object Color3f Le(0.0f, 0.0f, 0.0f); if (its.mesh->isEmitter() ) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); Le = aEM->sampleL(-ray.d, its.shFrame.n, its); } //get the asigned BSDF const BSDF* curBSDF = its.mesh->getBSDF(); Color3f Ld(0.0f, 0.0f, 0.0f); Color3f f(0.0f, 0.0f, 0.0f); Color3f totalLight(0.0f, 0.0f, 0.0f); //transform to the local frame //create a BRDF Query BSDFQueryRecord query = BSDFQueryRecord(its.toLocal(-ray.d), Vector3f(0.0f), EMeasure::ESolidAngle); //sample the BRDF Color3f mats = curBSDF->sample(query, sampler->next2D()); if(mats.maxCoeff() > 0.0f) { //Check for the light source Vector3f wo = its.toWorld(query.wo); Ray3f shadowRay(its.p, wo); Intersection itsShadow; if (scene->rayIntersect(shadowRay, itsShadow)) { //intersection check if mesh is emitter if(itsShadow.mesh->isEmitter()){ Ld = itsShadow.mesh->getEmitter()->radiance(); } } else { //check for distant disk light const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) Ld = distantsDisk->sampleL(wo); } totalLight += Ld * mats; } return Le + totalLight; }
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; }
// 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 VolumePatIntegrator::EstimateDirectLight(const Scene *scene, const Renderer *renderer, MemoryArena &arena, const Light *light, const Point &p, const Normal &n, const Vector &wo, float rayEpsilon, float time, RNG &rng, const LightSample &lightSample) const { VolumeRegion *vr = scene->volumeRegion; if (!vr) Spectrum(0.); Spectrum Ld(0.); // Sample light source. Vector wi; float lightPdf; VisibilityTester visibility; Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time, &wi, &lightPdf, &visibility); if (lightPdf > 0. && !Li.IsBlack() && visibility.Unoccluded(scene)) { // Add light's contribution to reflected radiance Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); // Li *= PowerHeuristic(1, lightPdf, 1, (1/M_PI_4)); Ld += vr->p(p, -wi, wo, time) * vr->Sigma_s(p, wo, time) * Li / lightPdf; } return Ld; }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &ray) const { /* Find the surface that is visible in the requested direction */ Intersection its; //check if the ray intersects the scene if (!scene->rayIntersect(ray, its)) { //check if a distant disk light is set const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk == nullptr ) return Color3f(0.0f); //sample the distant disk light Vector3f d = ray.d; return distantsDisk->sampleL(d); } //get the Number of lights from the scene const std::vector<Emitter *> lights = scene->getEmitters(); uint32_t nLights = lights.size(); Color3f tp(1.0f, 1.0f, 1.0f); Color3f L(0.0f, 0.0f, 0.0f); Ray3f pathRay(ray.o, ray.d); bool deltaFlag = true; while(true) { if (its.mesh->isEmitter() && deltaFlag) { const Emitter* areaLightEM = its.mesh->getEmitter(); const areaLight* aEM = static_cast<const areaLight *> (areaLightEM); L += tp * aEM->sampleL(-pathRay.d, its.shFrame.n, its); } //Light sampling //randomly select a lightsource uint32_t var = uint32_t(std::min(sampler->next1D()*nLights, float(nLights) - 1.0f)); //init the light color Color3f Li(0.0f, 0.0f, 0.0f); Color3f Ld(1.0f, 1.0f, 1.0f); //create a sample for the light const BSDF* curBSDF = its.mesh->getBSDF(); const Point2f lightSample = sampler->next2D(); VisibilityTester vis; Vector3f wo; float lightpdf; float bsdfpdf; Normal3f n = its.shFrame.n; deltaFlag = curBSDF->isDeltaBSDF(); //sample the light { Li = lights[var]->sampleL(its.p, Epsilon, lightSample , &wo, &lightpdf, &vis); lightpdf /= float(nLights); //check if the pdf of the sample is greater than 0 and if the color is not black if(lightpdf > 0 && Li.maxCoeff() != 0.0f) { //calculate the cosine term wi in my case the vector to the light float cosTerm = std::abs(n.dot(wo)); const BSDFQueryRecord queryEM = BSDFQueryRecord(its.toLocal(- pathRay.d), its.toLocal(wo), EMeasure::ESolidAngle, sampler); Color3f f = curBSDF->eval(queryEM); if(f.maxCoeff() > 0.0f && f.minCoeff() >= 0.0f && vis.Unoccluded(scene)) { bsdfpdf = curBSDF->pdf(queryEM); float weight = BalanceHeuristic(float(1), lightpdf, float(1), bsdfpdf); if(curBSDF->isDeltaBSDF()) weight = 1.0f; if(bsdfpdf > 0.0f) { Ld = (weight * f * Li * cosTerm) / lightpdf; L += tp * Ld; } else { //cout << "bsdfpdf = " << bsdfpdf << endl; //cout << "f = " << f << endl; } } } } //Material part BSDFQueryRecord queryMats = BSDFQueryRecord(its.toLocal(-pathRay.d), Vector3f(0.0f), EMeasure::ESolidAngle, sampler); Color3f fi = curBSDF->sample(queryMats, sampler->next2D()); bsdfpdf = curBSDF->pdf(queryMats); lightpdf = 0.0f; if(fi.maxCoeff() > 0.0f && fi.minCoeff() >= 0.0f) { if(bsdfpdf > 0.0f) { Ray3f shadowRay(its.p, its.toWorld(queryMats.wo)); Intersection lightIsect; if (scene->rayIntersect(shadowRay, lightIsect)) { if(lightIsect.mesh->isEmitter()){ const Emitter* areaLightEMcur = lightIsect.mesh->getEmitter(); const areaLight* aEMcur = static_cast<const areaLight *> (areaLightEMcur); Li = aEMcur->sampleL(-shadowRay.d, lightIsect.shFrame.n, lightIsect); lightpdf = aEMcur->pdf(its.p, (lightIsect.p - its.p).normalized(), lightIsect.p, Normal3f(lightIsect.shFrame.n)); } } else { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //check if THIS is right! Li = distantsDisk->sampleL(lightIsect.toWorld(queryMats.wo)); lightpdf = distantsDisk->pdf(Point3f(0.0f), wo, Point3f(0.0f), Normal3f(0.0f)); } } lightpdf /= float(nLights); //calculate the weights float weight = BalanceHeuristic(float(1), bsdfpdf, float(1), lightpdf); //check if the lightcolor is not black if(Li.maxCoeff() > 0.0f && lightpdf > 0.0f ) { //wo in my case the vector to the light Ld = weight * Li * fi; L += tp * Ld; } } tp *= fi; } else { break; } wo = its.toWorld(queryMats.wo); pathRay = Ray3f(its.p, wo); if (!scene->rayIntersect(pathRay, its)) { const Emitter* distantsDisk = scene->getDistantEmitter(); if(distantsDisk != nullptr ) { //sample the distant disk light Vector3f d = pathRay.d; L += tp * distantsDisk->sampleL(d); } break; } float maxCoeff = tp.maxCoeff(); float q = std::min(0.99f, maxCoeff); if(q < sampler->next1D()){ break; } tp /= q; } 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; }
Spectrum EstimateDirect(const Interaction &it, const Point2f &uScattering, const Light &light, const Point2f &uLight, const Scene &scene, Sampler &sampler, MemoryArena &arena, bool handleMedia, bool specular) { BxDFType bsdfFlags = specular ? BSDF_ALL : BxDFType(BSDF_ALL & ~BSDF_SPECULAR); Spectrum Ld(0.f); // Sample light source with multiple importance sampling Vector3f wi; Float lightPdf = 0, scatteringPdf = 0; VisibilityTester visibility; Spectrum Li = light.Sample_Li(it, uLight, &wi, &lightPdf, &visibility); if (lightPdf > 0 && !Li.IsBlack()) { // Compute BSDF or phase function's value for light sample Spectrum f; if (it.IsSurfaceInteraction()) { // Evaluate BSDF for light sampling strategy const SurfaceInteraction &isect = (const SurfaceInteraction &)it; f = isect.bsdf->f(isect.wo, wi, bsdfFlags) * AbsDot(wi, isect.shading.n); scatteringPdf = isect.bsdf->Pdf(isect.wo, wi, bsdfFlags); } else { // Evaluate phase function for light sampling strategy const MediumInteraction &mi = (const MediumInteraction &)it; Float p = mi.phase->p(mi.wo, wi); f = Spectrum(p); scatteringPdf = p; } if (!f.IsBlack()) { // Compute effect of visibility for light source sample if (handleMedia) Li *= visibility.Tr(scene, sampler); else if (!visibility.Unoccluded(scene)) Li = Spectrum(0.f); // Add light's contribution to reflected radiance if (!Li.IsBlack()) { if (IsDeltaLight(light.flags)) Ld += f * Li / lightPdf; else { Float weight = PowerHeuristic(1, lightPdf, 1, scatteringPdf); Ld += f * Li * weight / lightPdf; } } } } // Sample BSDF with multiple importance sampling if (!IsDeltaLight(light.flags)) { Spectrum f; bool sampledSpecular = false; if (it.IsSurfaceInteraction()) { // Sample scattered direction for surface interactions BxDFType sampledType; const SurfaceInteraction &isect = (const SurfaceInteraction &)it; f = isect.bsdf->Sample_f(isect.wo, &wi, uScattering, &scatteringPdf, bsdfFlags, &sampledType); f *= AbsDot(wi, isect.shading.n); sampledSpecular = sampledType & BSDF_SPECULAR; } else { // Sample scattered direction for medium interactions const MediumInteraction &mi = (const MediumInteraction &)it; Float p = mi.phase->Sample_p(mi.wo, &wi, uScattering); f = Spectrum(p); scatteringPdf = p; } if (!f.IsBlack() && scatteringPdf > 0) { // Account for light contributions along sampled direction _wi_ Float weight = 1; if (!sampledSpecular) { lightPdf = light.Pdf_Li(it, wi); if (lightPdf == 0) return Ld; weight = PowerHeuristic(1, scatteringPdf, 1, lightPdf); } // Find intersection and compute transmittance SurfaceInteraction lightIsect; Ray ray = it.SpawnRay(wi); Spectrum Tr(1.f); bool foundSurfaceInteraction = handleMedia ? scene.IntersectTr(ray, sampler, &lightIsect, &Tr) : scene.Intersect(ray, &lightIsect); // Add light contribution from material sampling Spectrum Li(0.f); if (foundSurfaceInteraction) { if (lightIsect.primitive->GetAreaLight() == &light) Li = lightIsect.Le(-wi); } else Li = light.Le(ray); if (!Li.IsBlack()) Ld += f * Li * Tr * weight / scatteringPdf; } } return Ld; }
Spectrum EstimateDirect(const Scene *scene, const Light *light, const Point &p, const Normal &n, const Vector &wo, BSDF *bsdf, const Sample *sample, int lightSamp, int bsdfSamp, int bsdfComponent, u_int sampleNum) { Spectrum Ld(0.); // Find light and BSDF sample values for direct lighting estimate float ls1, ls2, bs1, bs2, bcs; if (lightSamp != -1 && bsdfSamp != -1 && sampleNum < sample->n2D[lightSamp] && sampleNum < sample->n2D[bsdfSamp]) { ls1 = sample->twoD[lightSamp][2*sampleNum]; ls2 = sample->twoD[lightSamp][2*sampleNum+1]; bs1 = sample->twoD[bsdfSamp][2*sampleNum]; bs2 = sample->twoD[bsdfSamp][2*sampleNum+1]; bcs = sample->oneD[bsdfComponent][sampleNum]; } else { ls1 = RandomFloat(); ls2 = RandomFloat(); bs1 = RandomFloat(); bs2 = RandomFloat(); bcs = RandomFloat(); } // Sample light source with multiple importance sampling Vector wi; float lightPdf, bsdfPdf; VisibilityTester visibility; Spectrum Li = light->Sample_L(p, n, ls1, ls2, &wi, &lightPdf, &visibility); if (lightPdf > 0. && !Li.Black()) { Spectrum f = bsdf->f(wo, wi); if (!f.Black() && visibility.Unoccluded(scene)) { // Add light's contribution to reflected radiance Li *= visibility.Transmittance(scene); if (light->IsDeltaLight()) Ld += f * Li * AbsDot(wi, n) / lightPdf; else { bsdfPdf = bsdf->Pdf(wo, wi); float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf); Ld += f * Li * AbsDot(wi, n) * weight / lightPdf; } } } // Sample BSDF with multiple importance sampling if (!light->IsDeltaLight()) { BxDFType flags = BxDFType(BSDF_ALL & ~BSDF_SPECULAR); Spectrum f = bsdf->Sample_f(wo, &wi, bs1, bs2, bcs, &bsdfPdf, flags); if (!f.Black() && bsdfPdf > 0.) { lightPdf = light->Pdf(p, n, wi); if (lightPdf > 0.) { // Add light contribution from BSDF sampling float weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf); Intersection lightIsect; Spectrum Li(0.f); RayDifferential ray(p, wi); if (scene->Intersect(ray, &lightIsect)) { if (lightIsect.primitive->GetAreaLight() == light) Li = lightIsect.Le(-wi); } else Li = light->Le(ray); if (!Li.Black()) { Li *= scene->Transmittance(ray); Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf; } } } } return Ld; }