// KdSubsurfaceMaterial Method Definitions void KdSubsurfaceMaterial::ComputeScatteringFunctions( SurfaceInteraction *si, MemoryArena &arena, TransportMode mode, bool allowMultipleLobes) const { // Perform bump mapping with _bumpMap_, if present if (bumpMap) Bump(bumpMap, si); si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, eta); Spectrum R = Kr->Evaluate(*si).Clamp(); Spectrum T = Kt->Evaluate(*si).Clamp(); if (allowMultipleLobes && (!R.IsBlack() || !T.IsBlack())) si->bsdf->Add( ARENA_ALLOC(arena, FresnelSpecular)(1., 1., 1.f, eta, mode)); else { if (!R.IsBlack()) si->bsdf->Add(ARENA_ALLOC(arena, SpecularReflection)( R, ARENA_ALLOC(arena, FresnelDielectric)(1.f, eta))); if (!T.IsBlack()) si->bsdf->Add( ARENA_ALLOC(arena, SpecularTransmission)(T, 1.f, eta, mode)); } Spectrum sig_t = scale * sigma_t->Evaluate(*si).Clamp(); Spectrum kd = Kd->Evaluate(*si).Clamp(); Spectrum sig_a, sig_s; SubsurfaceFromDiffuse(table, kd, sig_t, &sig_a, &sig_s); si->bssrdf = ARENA_ALLOC(arena, TabulatedBSSRDF)(*si, this, mode, eta, sig_a, sig_s, table); }
// PlasticMaterial Method Definitions BSDF *PlasticMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum kd = Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()) { BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); bsdf->Add(diff); } Spectrum ks = Ks->Evaluate(dgs).Clamp(); if (!ks.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(1.5f, 1.f); float rough = roughness->Evaluate(dgs); BxDF *spec = BSDF_ALLOC(arena, Microfacet) (ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)); bsdf->Add(spec); } return bsdf; }
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; }
// UberMaterial Method Definitions void UberMaterial::ComputeScatteringFunctions(SurfaceInteraction *si, MemoryArena &arena, TransportMode mode, bool allowMultipleLobes) const { // Perform bump mapping with _bumpMap_, if present if (bumpMap) Bump(bumpMap, si); Float e = eta->Evaluate(*si); Spectrum op = opacity->Evaluate(*si).Clamp(); if (op != Spectrum(1.f)) { si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, 1.f); BxDF *tr = ARENA_ALLOC(arena, SpecularTransmission)(-op + Spectrum(1.f), 1.f, 1.f, mode); si->bsdf->Add(tr); } else si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, e); Spectrum kd = op * Kd->Evaluate(*si).Clamp(); if (!kd.IsBlack()) { BxDF *diff = ARENA_ALLOC(arena, LambertianReflection)(kd); si->bsdf->Add(diff); } Spectrum ks = op * Ks->Evaluate(*si).Clamp(); if (!ks.IsBlack()) { Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.f, e); Float roughu, roughv; if (roughnessu) roughu = roughnessu->Evaluate(*si); else roughu = roughness->Evaluate(*si); if (roughnessv) roughv = roughnessv->Evaluate(*si); else roughv = roughu; if (remapRoughness) { roughu = TrowbridgeReitzDistribution::RoughnessToAlpha(roughu); roughv = TrowbridgeReitzDistribution::RoughnessToAlpha(roughv); } MicrofacetDistribution *distrib = ARENA_ALLOC(arena, TrowbridgeReitzDistribution)(roughu, roughv); BxDF *spec = ARENA_ALLOC(arena, MicrofacetReflection)(ks, distrib, fresnel); si->bsdf->Add(spec); } Spectrum kr = op * Kr->Evaluate(*si).Clamp(); if (!kr.IsBlack()) { Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.f, e); si->bsdf->Add(ARENA_ALLOC(arena, SpecularReflection)(kr, fresnel)); } Spectrum kt = op * Kt->Evaluate(*si).Clamp(); if (!kt.IsBlack()) si->bsdf->Add( ARENA_ALLOC(arena, SpecularTransmission)(kt, 1.f, e, mode)); }
// KdSubsurfaceMaterial Method Definitions void KdSubsurfaceMaterial::ComputeScatteringFunctions( SurfaceInteraction *si, MemoryArena &arena, TransportMode mode, bool allowMultipleLobes) const { // Perform bump mapping with _bumpMap_, if present if (bumpMap) Bump(bumpMap, si); Spectrum R = Kr->Evaluate(*si).Clamp(); Spectrum T = Kt->Evaluate(*si).Clamp(); Float urough = uRoughness->Evaluate(*si); Float vrough = vRoughness->Evaluate(*si); // Initialize _bsdf_ for smooth or rough dielectric si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, eta); if (R.IsBlack() && T.IsBlack()) return; bool isSpecular = urough == 0 && vrough == 0; if (isSpecular && allowMultipleLobes) { si->bsdf->Add( ARENA_ALLOC(arena, FresnelSpecular)(R, T, 1.f, eta, mode)); } else { if (remapRoughness) { urough = TrowbridgeReitzDistribution::RoughnessToAlpha(urough); vrough = TrowbridgeReitzDistribution::RoughnessToAlpha(vrough); } MicrofacetDistribution *distrib = isSpecular ? nullptr : ARENA_ALLOC(arena, TrowbridgeReitzDistribution)( urough, vrough); if (!R.IsBlack()) { Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.f, eta); if (isSpecular) si->bsdf->Add( ARENA_ALLOC(arena, SpecularReflection)(R, fresnel)); else si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetReflection)( R, distrib, fresnel)); } if (!T.IsBlack()) { if (isSpecular) si->bsdf->Add(ARENA_ALLOC(arena, SpecularTransmission)( T, 1.f, eta, mode)); else si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetTransmission)( T, distrib, 1.f, eta, mode)); } } Spectrum mfree = scale * mfp->Evaluate(*si).Clamp(); Spectrum kd = Kd->Evaluate(*si).Clamp(); Spectrum sig_a, sig_s; SubsurfaceFromDiffuse(table, kd, Spectrum(1.f) / mfree, &sig_a, &sig_s); si->bssrdf = ARENA_ALLOC(arena, TabulatedBSSRDF)(*si, this, mode, eta, sig_a, sig_s, table); }
// TranslucentMaterial Method Definitions BSDF *TranslucentMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { float ior = 1.5f; DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn, ior); Spectrum r = reflect->Evaluate(dgs).Clamp(); Spectrum t = transmit->Evaluate(dgs).Clamp(); if (r.IsBlack() && t.IsBlack()) return bsdf; Spectrum kd = Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()) { if (!r.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, Lambertian)(r * kd)); if (!t.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Lambertian)(t * kd))); } Spectrum ks = Ks->Evaluate(dgs).Clamp(); if (!ks.IsBlack()) { float rough = roughness->Evaluate(dgs); if (!r.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); bsdf->Add(BSDF_ALLOC(arena, Microfacet)(r * ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough))); } if (!t.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(ior, 1.f); bsdf->Add(BSDF_ALLOC(arena, BRDFToBTDF)(BSDF_ALLOC(arena, Microfacet)(t * ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)))); } } return bsdf; }
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; }
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; light->Sample_L(p, rayEpsilon, lightSample, time, &wi, &lightPdf, &visibility); Spectrum Li(1.); 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 * (AbsDot(wi, n) / lightPdf); else { bsdfPdf = bsdf->Pdf(wo, wi, flags); float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf); Ld += f * (AbsDot(wi, n) * weight / lightPdf); } } } return Ld; }
void Light::SHProject(const PbrtPoint &p, float pEpsilon, int lmax, const Scene *scene, bool computeLightVisibility, float time, RNG &rng, Spectrum *coeffs) const { for (int i = 0; i < SHTerms(lmax); ++i) coeffs[i] = 0.f; uint32_t ns = RoundUpPow2(nSamples); uint32_t scramble1D = rng.RandomUInt(); uint32_t scramble2D[2] = { rng.RandomUInt(), rng.RandomUInt() }; float *Ylm = ALLOCA(float, SHTerms(lmax)); for (uint32_t i = 0; i < ns; ++i) { // Compute incident radiance sample from _light_, update SH _coeffs_ float u[2], pdf; Sample02(i, scramble2D, u); LightSample lightSample(u[0], u[1], VanDerCorput(i, scramble1D)); Vector wi; VisibilityTester vis; Spectrum Li = Sample_L(p, pEpsilon, lightSample, time, &wi, &pdf, &vis); if (!Li.IsBlack() && pdf > 0.f && (!computeLightVisibility || vis.Unoccluded(scene))) { // Add light sample contribution to MC estimate of SH coefficients SHEvaluate(wi, lmax, Ylm); for (int j = 0; j < SHTerms(lmax); ++j) coeffs[j] += Li * Ylm[j] / (pdf * ns); } } }
// MirrorMaterial Method Definitions BSDF *MirrorMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum R = Kr->Evaluate(dgs).Clamp(); if (!R.IsBlack()) { float x,y,z; x = dgs.p.x; y = dgs.p.y; z = dgs.p.z; float rad = sqrt((x-(-4))*(x-(-4)) + (y-1)*(y-1) + (z-15)*(z-15)); float c = 15.f; // if (rad < c) {// 11->20, 14 bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelNoOp)())); // } else { // bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, // BSDF_ALLOC(arena, FresnelNoOp)())); // } } return bsdf; }
// GlassMaterial Method Definitions void GlassMaterial::ComputeScatteringFunctions(SurfaceInteraction *si, MemoryArena &arena, TransportMode mode, bool allowMultipleLobes) const { // Perform bump mapping with _bumpMap_, if present if (bumpMap) Bump(bumpMap, si); Float eta = index->Evaluate(*si); si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, eta); Spectrum R = Kr->Evaluate(*si).Clamp(); Spectrum T = Kt->Evaluate(*si).Clamp(); if (R.IsBlack() && T.IsBlack()) return; Float urough = uRoughness->Evaluate(*si); Float vrough = vRoughness->Evaluate(*si); bool isSpecular = urough == 0 && vrough == 0; if (isSpecular && allowMultipleLobes) { si->bsdf->Add( ARENA_ALLOC(arena, FresnelSpecular)(R, T, 1.f, eta, mode)); } else { if (remapRoughness) { urough = TrowbridgeReitzDistribution::RoughnessToAlpha(urough); vrough = TrowbridgeReitzDistribution::RoughnessToAlpha(vrough); } MicrofacetDistribution *distrib = isSpecular ? nullptr : ARENA_ALLOC(arena, TrowbridgeReitzDistribution)( urough, vrough); if (!R.IsBlack()) { Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.f, eta); if (isSpecular) si->bsdf->Add( ARENA_ALLOC(arena, SpecularReflection)(R, fresnel)); else si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetReflection)( R, distrib, fresnel)); } if (!T.IsBlack()) { if (isSpecular) si->bsdf->Add(ARENA_ALLOC(arena, SpecularTransmission)( T, 1.f, eta, mode)); else si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetTransmission)( T, distrib, 1.f, eta, mode)); } } }
Spectrum MetropolisRenderer::PathL(const MLTSample &sample, const Scene *scene, MemoryArena &arena, const Camera *camera, const Distribution1D *lightDistribution, PathVertex *cameraPath, PathVertex *lightPath, RNG &rng) const { // Generate camera path from camera path samples PBRT_STARTED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample)); RayDifferential cameraRay; float cameraWt = camera->GenerateRayDifferential(sample.cameraSample, &cameraRay); cameraRay.ScaleDifferentials(1.f / sqrtf(nPixelSamples)); PBRT_FINISHED_GENERATING_CAMERA_RAY((CameraSample *)(&sample.cameraSample), &cameraRay, cameraWt); RayDifferential escapedRay; Spectrum escapedAlpha; uint32_t cameraLength = GeneratePath(cameraRay, cameraWt, scene, arena, sample.cameraPathSamples, cameraPath, &escapedRay, &escapedAlpha); if (!bidirectional) { // Compute radiance along path using path tracing return Lpath(scene, cameraPath, cameraLength, arena, sample.lightingSamples, rng, sample.cameraSample.time, lightDistribution, escapedRay, escapedAlpha); } else { // Sample light ray and apply bidirectional path tracing // Choose light and sample ray to start light path PBRT_MLT_STARTED_SAMPLE_LIGHT_FOR_BIDIR(); float lightPdf, lightRayPdf; uint32_t lightNum = lightDistribution->SampleDiscrete(sample.lightNumSample, &lightPdf); const Light *light = scene->lights[lightNum]; Ray lightRay; Normal Nl; LightSample lrs(sample.lightRaySamples[0], sample.lightRaySamples[1], sample.lightRaySamples[2]); Spectrum lightWt = light->Sample_L(scene, lrs, sample.lightRaySamples[3], sample.lightRaySamples[4], sample.cameraSample.time, &lightRay, &Nl, &lightRayPdf); PBRT_MLT_FINISHED_SAMPLE_LIGHT_FOR_BIDIR(); if (lightWt.IsBlack() || lightRayPdf == 0.f) { // Compute radiance along path using path tracing return Lpath(scene, cameraPath, cameraLength, arena, sample.lightingSamples, rng, sample.cameraSample.time, lightDistribution, escapedRay, escapedAlpha); } else { // Compute radiance along paths using bidirectional path tracing lightWt *= AbsDot(Normalize(Nl), lightRay.d) / (lightPdf * lightRayPdf); uint32_t lightLength = GeneratePath(RayDifferential(lightRay), lightWt, scene, arena, sample.lightPathSamples, lightPath, NULL, NULL); return Lbidir(scene, cameraPath, cameraLength, lightPath, lightLength, arena, sample.lightingSamples, rng, sample.cameraSample.time, lightDistribution, escapedRay, escapedAlpha); } } }
// WhittedIntegrator Method Definitions Spectrum WhittedIntegrator::Li(const RayDifferential &ray, const Scene &scene, Sampler &sampler, MemoryArena &arena, int depth) const { Spectrum L(0.); // Find closest ray intersection or return background radiance SurfaceInteraction isect; if (!scene.Intersect(ray, &isect)) { for (const auto &light : scene.lights) L += light->Le(ray); return L; } // Compute emitted and reflected light at ray intersection point // Initialize common variables for Whitted integrator const Normal3f &n = isect.shading.n; Vector3f wo = isect.wo; // Compute scattering functions for surface interaction isect.ComputeScatteringFunctions(ray, arena); if (!isect.bsdf) return Li(isect.SpawnRay(ray.d), scene, sampler, arena, depth); // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Add contribution of each light source for (const auto &light : scene.lights) { Vector3f wi; Float pdf; VisibilityTester visibility; Spectrum Li = light->Sample_Li(isect, sampler.Get2D(), &wi, &pdf, &visibility); if (Li.IsBlack() || pdf == 0) continue; Spectrum f = isect.bsdf->f(wo, wi); if (!f.IsBlack() && visibility.Unoccluded(scene)) L += f * Li * AbsDot(wi, n) / pdf; } if (depth + 1 < maxDepth) { // Trace rays for specular reflection and refraction L += SpecularReflect(ray, isect, scene, sampler, arena, depth); L += SpecularTransmit(ray, isect, scene, sampler, arena, depth); } return L; }
// Metropolis Method Definitions static uint32_t GeneratePath(const RayDifferential &r, const Spectrum &a, const Scene *scene, MemoryArena &arena, const vector<PathSample> &samples, PathVertex *path, RayDifferential *escapedRay, Spectrum *escapedAlpha) { PBRT_MLT_STARTED_GENERATE_PATH(); RayDifferential ray = r; Spectrum alpha = a; if (escapedAlpha) *escapedAlpha = 0.f; uint32_t length = 0; for (; length < samples.size(); ++length) { // Try to generate next vertex of ray path PathVertex &v = path[length]; if (!scene->Intersect(ray, &v.isect)) { // Handle ray that leaves the scene during path generation if (escapedAlpha) *escapedAlpha = alpha; if (escapedRay) *escapedRay = ray; break; } // Record information for current path vertex v.alpha = alpha; BSDF *bsdf = v.isect.GetBSDF(ray, arena); v.bsdf = bsdf; v.wPrev = -ray.d; // Sample direction for outgoing Metropolis path direction float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(-ray.d, &v.wNext, samples[length].bsdfSample, &pdf, BSDF_ALL, &flags); v.specularBounce = (flags & BSDF_SPECULAR) != 0; v.nSpecularComponents = bsdf->NumComponents(BxDFType(BSDF_SPECULAR | BSDF_REFLECTION | BSDF_TRANSMISSION)); if (f.IsBlack() || pdf == 0.f) { PBRT_MLT_FINISHED_GENERATE_PATH(); return length+1; } // Terminate path with RR or prepare for finding next vertex const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Spectrum pathScale = f * AbsDot(v.wNext, n) / pdf; float rrSurviveProb = min(1.f, pathScale.y()); if (samples[length].rrSample > rrSurviveProb) { PBRT_MLT_FINISHED_GENERATE_PATH(); return length+1; } alpha *= pathScale / rrSurviveProb; //alpha *= renderer->Transmittance(scene, ray, NULL, rng, arena); ray = RayDifferential(p, v.wNext, ray, v.isect.rayEpsilon); } PBRT_MLT_FINISHED_GENERATE_PATH(); return length; }
// WhittedIntegrator Method Definitions Spectrum WhittedIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, const Sample *sample, MemoryArena &arena) const { Spectrum L(0.); // Compute emitted and reflected light at ray intersection point // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); // Initialize common variables for Whitted integrator const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Add contribution of each light source Vector wi; for (u_int i = 0; i < scene->lights.size(); ++i) { VisibilityTester visibility; float pdf; Spectrum Li = scene->lights[i]->Sample_L(p, isect.rayEpsilon, LightSample(*sample->rng), sample->time, &wi, &pdf, &visibility); if (Li.IsBlack() || pdf == 0.f) continue; Li /= pdf; Spectrum f = bsdf->f(wo, wi); if (!f.IsBlack() && visibility.Unoccluded(scene)) L += f * Li * AbsDot(wi, n) * visibility.Transmittance(scene, renderer, sample, NULL, arena); } if (ray.depth + 1 < maxDepth) { // Trace rays for specular reflection and refraction L += SpecularReflect(ray, bsdf, *sample->rng, isect, renderer, scene, sample, arena); L += SpecularTransmit(ray, bsdf, *sample->rng, isect, renderer, scene, sample, arena); } return L; }
// UberMaterial Method Definitions BSDF *UberMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum op = opacity->Evaluate(dgs).Clamp(); if (op != Spectrum(1.)) { BxDF *tr = BSDF_ALLOC(arena, SpecularTransmission)(-op + Spectrum(1.), 1., 1.); bsdf->Add(tr); } Spectrum kd = op * Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()) { BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); bsdf->Add(diff); } float e = eta->Evaluate(dgs); Spectrum ks = op * Ks->Evaluate(dgs).Clamp(); if (!ks.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(e, 1.f); float rough = roughness->Evaluate(dgs); BxDF *spec = BSDF_ALLOC(arena, Microfacet)(ks, fresnel, BSDF_ALLOC(arena, Blinn)(1.f / rough)); bsdf->Add(spec); } Spectrum kr = op * Kr->Evaluate(dgs).Clamp(); if (!kr.IsBlack()) { Fresnel *fresnel = BSDF_ALLOC(arena, FresnelDielectric)(e, 1.f); bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(kr, fresnel)); } Spectrum kt = op * Kt->Evaluate(dgs).Clamp(); if (!kt.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularTransmission)(kt, e, 1.f)); return bsdf; }
Spectrum IrradianceCacheIntegrator::pathL(Ray &r, const Scene *scene, const Renderer *renderer, const Sample *sample, MemoryArena &arena) const { Spectrum L(0.f); Spectrum pathThroughput = 1.; RayDifferential ray(r); bool specularBounce = false; for (int pathLength = 0; ; ++pathLength) { // Find next vertex of path Intersection isect; if (!scene->Intersect(ray, &isect)) break; if (pathLength == 0) r.maxt = ray.maxt; else if (pathLength == 1) pathThroughput *= renderer->Transmittance(scene, ray, sample, arena, NULL); else pathThroughput *= renderer->Transmittance(scene, ray, NULL, arena, sample->rng); // Possibly add emitted light at path vertex if (specularBounce) L += pathThroughput * isect.Le(-ray.d); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); // Sample illumination from lights to find path contribution const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isect.rayEpsilon, bsdf, sample); if (pathLength+1 == maxIndirectDepth) break; // Sample BSDF to get new path direction // Get random numbers for sampling new direction, \mono{bs1}, \mono{bs2}, and \mono{bcs} Vector wi; float pdf; BxDFType flags; Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(*sample->rng), &pdf, BSDF_ALL, &flags); if (f.IsBlack() || pdf == 0.) break; specularBounce = (flags & BSDF_SPECULAR) != 0; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isect.rayEpsilon); // Possibly terminate the path if (pathLength > 2) { float rrProb = min(1.f, pathThroughput.y()); if (sample->rng->RandomFloat() > rrProb) break; pathThroughput /= rrProb; } } return L; }
Spectrum SeparableBSSRDF::Sample_S(const Scene &scene, Float u1, const Point2f &u2, MemoryArena &arena, SurfaceInteraction *si, Float *pdf) const { ProfilePhase pp(Prof::BSSRDFEvaluation); Spectrum Sp = Sample_Sp(scene, u1, u2, arena, si, pdf); if (!Sp.IsBlack()) { // Initialize material model at sampled surface interaction si->bsdf = ARENA_ALLOC(arena, BSDF)(*si); si->bsdf->Add(ARENA_ALLOC(arena, SeparableBSSRDFAdapter)(this)); si->wo = Vector3f(si->shading.n); } return Sp; }
// SubsurfaceMaterial Method Definitions BSDF *SubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ DifferentialGeometry dgs; // Trisha: This is a hack-y way to determine if we should use the NormalMap over the BumpMap. If the NormalMap is zero at this pixel value, we skip over it. Spectrum normalSpectrum = normalMap->Evaluate(dgShading); if (!normalSpectrum.IsBlack()) NormalMap(normalMap, dgGeom, dgShading, &dgs); else if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum R = Kr->Evaluate(dgs).Clamp(); float e = eta->Evaluate(dgs); if (!R.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelDielectric)(1., e))); return bsdf; }
// GlassMaterial Method Definitions BSDF *GlassMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { DifferentialGeometry dgs; // Trisha: This is a hack-y way to determine if we should use the NormalMap over the BumpMap. If the NormalMap is zero at this pixel value, we skip over it. Spectrum normalSpectrum = normalMap->Evaluate(dgShading); if (!normalSpectrum.IsBlack()) NormalMap(normalMap, dgGeom, dgShading, &dgs); else if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; float ior = index->Evaluate(dgs); BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn, ior); Spectrum R = Kr->Evaluate(dgs).Clamp(); Spectrum T = Kt->Evaluate(dgs).Clamp(); if (!R.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelDielectric)(1., ior))); if (!T.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularTransmission)(T, 1., ior)); return bsdf; }
// TranslucentMaterial Method Definitions void TranslucentMaterial::ComputeScatteringFunctions( SurfaceInteraction *si, MemoryArena &arena, TransportMode mode, bool allowMultipleLobes) const { // Perform bump mapping with _bumpMap_, if present if (bumpMap) Bump(bumpMap, si); Float eta = 1.5f; si->bsdf = ARENA_ALLOC(arena, BSDF)(*si, eta); Spectrum r = reflect->Evaluate(*si).Clamp(); Spectrum t = transmit->Evaluate(*si).Clamp(); if (r.IsBlack() && t.IsBlack()) return; Spectrum kd = Kd->Evaluate(*si).Clamp(); if (!kd.IsBlack()) { if (!r.IsBlack()) si->bsdf->Add(ARENA_ALLOC(arena, LambertianReflection)(r * kd)); if (!t.IsBlack()) si->bsdf->Add(ARENA_ALLOC(arena, LambertianTransmission)(t * kd)); } Spectrum ks = Ks->Evaluate(*si).Clamp(); if (!ks.IsBlack() && (!r.IsBlack() || !t.IsBlack())) { Float rough = roughness->Evaluate(*si); if (remapRoughness) rough = TrowbridgeReitzDistribution::RoughnessToAlpha(rough); MicrofacetDistribution *distrib = ARENA_ALLOC(arena, TrowbridgeReitzDistribution)(rough, rough); if (!r.IsBlack()) { Fresnel *fresnel = ARENA_ALLOC(arena, FresnelDielectric)(1.f, eta); si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetReflection)( r * ks, distrib, fresnel)); } if (!t.IsBlack()) si->bsdf->Add(ARENA_ALLOC(arena, MicrofacetTransmission)( t * ks, distrib, 1.f, eta, mode)); } }
Spectrum SamplerIntegrator::SpecularTransmit( const RayDifferential &ray, const SurfaceInteraction &isect, const Scene &scene, Sampler &sampler, MemoryArena &arena, int depth) const { Vector3f wo = isect.wo, wi; Float pdf; const Point3f &p = isect.p; const Normal3f &ns = isect.shading.n; const BSDF &bsdf = *isect.bsdf; Spectrum f = bsdf.Sample_f(wo, &wi, sampler.Get2D(), &pdf, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)); Spectrum L = Spectrum(0.f); if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, ns) != 0.f) { // Compute ray differential _rd_ for specular transmission RayDifferential rd = isect.SpawnRay(wi); if (ray.hasDifferentials) { rd.hasDifferentials = true; rd.rxOrigin = p + isect.dpdx; rd.ryOrigin = p + isect.dpdy; Float eta = bsdf.eta; Vector3f w = -wo; if (Dot(wo, ns) < 0) eta = 1.f / eta; Normal3f dndx = isect.shading.dndu * isect.dudx + isect.shading.dndv * isect.dvdx; Normal3f dndy = isect.shading.dndu * isect.dudy + isect.shading.dndv * isect.dvdy; Vector3f dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo; Float dDNdx = Dot(dwodx, ns) + Dot(wo, dndx); Float dDNdy = Dot(dwody, ns) + Dot(wo, dndy); Float mu = eta * Dot(w, ns) - Dot(wi, ns); Float dmudx = (eta - (eta * eta * Dot(w, ns)) / Dot(wi, ns)) * dDNdx; Float dmudy = (eta - (eta * eta * Dot(w, ns)) / Dot(wi, ns)) * dDNdy; rd.rxDirection = wi + eta * dwodx - Vector3f(mu * dndx + dmudx * ns); rd.ryDirection = wi + eta * dwody - Vector3f(mu * dndy + dmudy * ns); } L = f * Li(rd, scene, sampler, arena, depth + 1) * AbsDot(wi, ns) / pdf; } return L; }
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; }
// KdSubsurfaceMaterial Method Definitions BSDF *KdSubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { // Allocate _BSDF_, possibly doing bump mapping with _bumpMap_ DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum R = Kr->Evaluate(dgs).Clamp(); float ior = index->Evaluate(dgs); if (!R.IsBlack()) bsdf->Add(BSDF_ALLOC(arena, SpecularReflection)(R, BSDF_ALLOC(arena, FresnelDielectric)(1., ior))); return bsdf; }
Spectrum SpecularTransmit(const RayDifferential &ray, BSDF *bsdf, RNG &rng, const Intersection &isect, const Renderer *renderer, const Scene *scene, const Sample *sample, MemoryArena &arena) { Vector wo = -ray.d, wi; float pdf; const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BxDFType(BSDF_TRANSMISSION | BSDF_SPECULAR)); Spectrum L = 0.f; if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, n) != 0.f) { // Compute ray differential _rd_ for specular transmission RayDifferential rd(p, wi, ray, isect.rayEpsilon); if (ray.hasDifferentials) { rd.hasDifferentials = true; rd.rxOrigin = p + isect.dg.dpdx; rd.ryOrigin = p + isect.dg.dpdy; float eta = bsdf->eta; Vector w = -wo; if (Dot(wo, n) < 0) eta = 1.f / eta; Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx + bsdf->dgShading.dndv * bsdf->dgShading.dvdx; Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy + bsdf->dgShading.dndv * bsdf->dgShading.dvdy; Vector dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo; float dDNdx = Dot(dwodx, n) + Dot(wo, dndx); float dDNdy = Dot(dwody, n) + Dot(wo, dndy); float mu = eta * Dot(w, n) - Dot(wi, n); float dmudx = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdx; float dmudy = (eta - (eta*eta*Dot(w,n))/Dot(wi, n)) * dDNdy; rd.rxDirection = wi + eta * dwodx - Vector(mu * dndx + dmudx * n); rd.ryDirection = wi + eta * dwody - Vector(mu * dndy + dmudy * n); } PBRT_STARTED_SPECULAR_REFRACTION_RAY(const_cast<RayDifferential *>(&rd)); Spectrum Li = renderer->Li(scene, rd, sample, rng, arena); L = f * Li * AbsDot(wi, n) / pdf; PBRT_FINISHED_SPECULAR_REFRACTION_RAY(const_cast<RayDifferential *>(&rd)); } return L; }
int GenerateLightSubpath( const Scene &scene, Sampler &sampler, MemoryArena &arena, int maxDepth, Float time, const Distribution1D &lightDistr, const std::unordered_map<const Light *, size_t> &lightToIndex, Vertex *path) { if (maxDepth == 0) return 0; // Sample initial ray for light subpath Float lightPdf; int lightNum = lightDistr.SampleDiscrete(sampler.Get1D(), &lightPdf); const std::shared_ptr<Light> &light = scene.lights[lightNum]; RayDifferential ray; Normal3f nLight; Float pdfPos, pdfDir; Spectrum Le = light->Sample_Le(sampler.Get2D(), sampler.Get2D(), time, &ray, &nLight, &pdfPos, &pdfDir); if (pdfPos == 0 || pdfDir == 0 || Le.IsBlack()) return 0; // Generate first vertex on light subpath and start random walk path[0] = Vertex::CreateLight(light.get(), ray, nLight, Le, pdfPos * lightPdf); Spectrum beta = Le * AbsDot(nLight, ray.d) / (lightPdf * pdfPos * pdfDir); VLOG(2) << "Starting light subpath. Ray: " << ray << ", Le " << Le << ", beta " << beta << ", pdfPos " << pdfPos << ", pdfDir " << pdfDir; int nVertices = RandomWalk(scene, ray, sampler, arena, beta, pdfDir, maxDepth - 1, TransportMode::Importance, path + 1); // Correct subpath sampling densities for infinite area lights if (path[0].IsInfiniteLight()) { // Set spatial density of _path[1]_ for infinite area light if (nVertices > 0) { path[1].pdfFwd = pdfPos; if (path[1].IsOnSurface()) path[1].pdfFwd *= AbsDot(ray.d, path[1].ng()); } // Set spatial density of _path[0]_ for infinite area light path[0].pdfFwd = InfiniteLightDensity(scene, lightDistr, lightToIndex, ray.d); } return nVertices + 1; }
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; }
int GenerateLightSubpath(const Scene &scene, Sampler &sampler, MemoryArena &arena, int maxdepth, Float time, const Distribution1D &lightDistr, Vertex *path) { if (maxdepth == 0) return 0; // Sample initial ray for light subpath Float lightPdf; int lightNum = lightDistr.SampleDiscrete(sampler.Get1D(), &lightPdf); const std::shared_ptr<Light> &light = scene.lights[lightNum]; RayDifferential ray; Normal3f Nl; Float pdfPos, pdfDir; Spectrum Le = light->Sample_L(sampler.Get2D(), sampler.Get2D(), time, &ray, &Nl, &pdfPos, &pdfDir); if (pdfPos == 0.f || pdfDir == 0.f || Le.IsBlack()) return 0; // Generate first vertex on light subpath and start random walk Spectrum weight = Le * AbsDot(Nl, ray.d) / (lightPdf * pdfPos * pdfDir); path[0] = Vertex(VertexType::Light, EndpointInteraction(light.get(), ray, Nl), Le); path[0].pdfFwd = pdfPos * lightPdf; int nvertices = RandomWalk(scene, ray, sampler, arena, weight, pdfDir, maxdepth - 1, TransportMode::Importance, path + 1); // Correct sampling densities for infinite area lights if (path[0].IsInfiniteLight()) { // Set positional density of _path[1]_ if (nvertices > 0) { path[1].pdfFwd = pdfPos; if (path[1].IsOnSurface()) path[1].pdfFwd *= AbsDot(ray.d, path[1].GetGeoNormal()); } // Set positional density of _path[0]_ path[0].pdfFwd = InfiniteLightDensity(scene, lightDistr, ray.d); } return nvertices + 1; }
BSDF *SkinSubsurfaceMaterial::GetBSDF(const DifferentialGeometry &dgGeom, const DifferentialGeometry &dgShading, MemoryArena &arena) const { DifferentialGeometry dgs; if (bumpMap) Bump(bumpMap, dgGeom, dgShading, &dgs); else dgs = dgShading; BSDF *bsdf = BSDF_ALLOC(arena, BSDF)(dgs, dgGeom.nn); Spectrum kd = Kd->Evaluate(dgs).Clamp(); if (!kd.IsBlack()){ BxDF *diff = BSDF_ALLOC(arena, Lambertian)(kd); bsdf->Add(diff); } float e = eta->Evaluate(dgs); Fresnel *fresnel = BSDF_ALLOC(arena,FresnelDielectric)(1.,e); float rough = 0.35f; BxDF *spec = BSDF_ALLOC(arena,Microfacet)(rho_s, fresnel, BSDF_ALLOC(arena, Beckmann)(rough)); bsdf->Add(spec); return bsdf; }
Spectrum SamplerIntegrator::SpecularReflect( const RayDifferential &ray, const SurfaceInteraction &isect, const Scene &scene, Sampler &sampler, MemoryArena &arena, int depth) const { // Compute specular reflection direction _wi_ and BSDF value Vector3f wo = isect.wo, wi; Float pdf; BxDFType type = BxDFType(BSDF_REFLECTION | BSDF_SPECULAR); Spectrum f = isect.bsdf->Sample_f(wo, &wi, sampler.Get2D(), &pdf, type); // Return contribution of specular reflection const Normal3f &ns = isect.shading.n; if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, ns) != 0.f) { // Compute ray differential _rd_ for specular reflection RayDifferential rd = isect.SpawnRay(wi); if (ray.hasDifferentials) { rd.hasDifferentials = true; rd.rxOrigin = isect.p + isect.dpdx; rd.ryOrigin = isect.p + isect.dpdy; // Compute differential reflected directions Normal3f dndx = isect.shading.dndu * isect.dudx + isect.shading.dndv * isect.dvdx; Normal3f dndy = isect.shading.dndu * isect.dudy + isect.shading.dndv * isect.dvdy; Vector3f dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo; Float dDNdx = Dot(dwodx, ns) + Dot(wo, dndx); Float dDNdy = Dot(dwody, ns) + Dot(wo, dndy); rd.rxDirection = wi - dwodx + 2.f * Vector3f(Dot(wo, ns) * dndx + dDNdx * ns); rd.ryDirection = wi - dwody + 2.f * Vector3f(Dot(wo, ns) * dndy + dDNdy * ns); } return f * Li(rd, scene, sampler, arena, depth + 1) * AbsDot(wi, ns) / pdf; } else return Spectrum(0.f); }