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; }
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 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; }
Spectrum IGIIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const { Spectrum L(0.); Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; L += UniformSampleAllLights(scene, renderer, arena, p, n, wo, isect.rayEpsilon, ray.time, bsdf, sample, rng, lightSampleOffsets, bsdfSampleOffsets); // Compute indirect illumination with virtual lights uint32_t lSet = min(uint32_t(sample->oneD[vlSetOffset][0] * nLightSets), nLightSets-1); for (uint32_t i = 0; i < virtualLights[lSet].size(); ++i) { const VirtualLight &vl = virtualLights[lSet][i]; // Compute virtual light's tentative contribution _Llight_ float d2 = DistanceSquared(p, vl.p); Vector wi = Normalize(vl.p - p); float G = AbsDot(wi, n) * AbsDot(wi, vl.n) / d2; G = min(G, gLimit); Spectrum f = bsdf->f(wo, wi); if (G == 0.f || f.IsBlack()) continue; Spectrum Llight = f * G * vl.pathContrib / nLightPaths; RayDifferential connectRay(p, wi, ray, isect.rayEpsilon, sqrtf(d2) * (1.f - vl.rayEpsilon)); Llight *= renderer->Transmittance(scene, connectRay, NULL, rng, arena); // Possibly skip virtual light shadow ray with Russian roulette if (Llight.y() < rrThreshold) { float continueProbability = .1f; if (rng.RandomFloat() > continueProbability) continue; Llight /= continueProbability; } // Add contribution from _VirtualLight_ _vl_ if (!scene->IntersectP(connectRay)) L += Llight; } if (ray.depth < maxSpecularDepth) { // Do bias compensation for bounding geometry term int nSamples = (ray.depth == 0) ? nGatherSamples : 1; for (int i = 0; i < nSamples; ++i) { Vector wi; float pdf; BSDFSample bsdfSample = (ray.depth == 0) ? BSDFSample(sample, gatherSampleOffset, i) : BSDFSample(rng); Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &pdf, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)); if (!f.IsBlack() && pdf > 0.f) { // Trace ray for bias compensation gather sample float maxDist = sqrtf(AbsDot(wi, n) / gLimit); RayDifferential gatherRay(p, wi, ray, isect.rayEpsilon, maxDist); Intersection gatherIsect; Spectrum Li = renderer->Li(scene, gatherRay, sample, rng, arena, &gatherIsect); if (Li.IsBlack()) continue; // Add bias compensation ray contribution to radiance sum float Ggather = AbsDot(wi, n) * AbsDot(-wi, gatherIsect.dg.nn) / DistanceSquared(p, gatherIsect.dg.p); if (Ggather - gLimit > 0.f && !isinf(Ggather)) { float gs = (Ggather - gLimit) / Ggather; L += f * Li * (AbsDot(wi, n) * gs / (nSamples * pdf)); } } } } if (ray.depth + 1 < maxSpecularDepth) { Vector wi; // Trace rays for specular reflection and refraction L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample, arena); L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample, arena); } return L; }
void PhotonShootingTask::Run() { // Declare local variables for _PhotonShootingTask_ MemoryArena arena; RNG rng(31 * taskNum); vector<Photon> localDirectPhotons, localIndirectPhotons, localCausticPhotons; vector<RadiancePhoton> localRadiancePhotons; uint32_t totalPaths = 0; bool causticDone = (integrator->nCausticPhotonsWanted == 0); bool indirectDone = (integrator->nIndirectPhotonsWanted == 0); PermutedHalton halton(6, rng); vector<Spectrum> localRpReflectances, localRpTransmittances; while (true) { // Follow photon paths for a block of samples const uint32_t blockSize = 4096; for (uint32_t i = 0; i < blockSize; ++i) { float u[6]; halton.Sample(++totalPaths, u); // Choose light to shoot photon from float lightPdf; int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); const Light *light = scene->lights[lightNum]; // Generate _photonRay_ from light source and initialize _alpha_ RayDifferential photonRay; float pdf; LightSample ls(u[1], u[2], u[3]); Normal Nl; Spectrum Le = light->Sample_L(scene, ls, u[4], u[5], time, &photonRay, &Nl, &pdf); if (pdf == 0.f || Le.IsBlack()) continue; Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); if (!alpha.IsBlack()) { // Follow photon path through scene and record intersections PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); bool specularPath = true; Intersection photonIsect; int nIntersections = 0; while (scene->Intersect(photonRay, &photonIsect)) { ++nIntersections; // Handle photon/surface intersection alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena); BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); BxDFType specularType = BxDFType(BSDF_REFLECTION | BSDF_TRANSMISSION | BSDF_SPECULAR); bool hasNonSpecular = (photonBSDF->NumComponents() > photonBSDF->NumComponents(specularType)); Vector wo = -photonRay.d; if (hasNonSpecular) { // Deposit photon at surface Photon photon(photonIsect.dg.p, alpha, wo); bool depositedPhoton = false; if (specularPath && nIntersections > 1) { if (!causticDone) { PBRT_PHOTON_MAP_DEPOSITED_CAUSTIC_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localCausticPhotons.push_back(photon); } } else { // Deposit either direct or indirect photon // stop depositing direct photons once indirectDone is true; don't // want to waste memory storing too many if we're going a long time // trying to get enough caustic photons desposited. if (nIntersections == 1 && !indirectDone && integrator->finalGather) { PBRT_PHOTON_MAP_DEPOSITED_DIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localDirectPhotons.push_back(photon); } else if (nIntersections > 1 && !indirectDone) { PBRT_PHOTON_MAP_DEPOSITED_INDIRECT_PHOTON(&photonIsect.dg, &alpha, &wo); depositedPhoton = true; localIndirectPhotons.push_back(photon); } } // Possibly create radiance photon at photon intersection point if (depositedPhoton && integrator->finalGather && rng.RandomFloat() < .125f) { Normal n = photonIsect.dg.nn; n = Faceforward(n, -photonRay.d); localRadiancePhotons.push_back(RadiancePhoton(photonIsect.dg.p, n)); Spectrum rho_r = photonBSDF->rho(rng, BSDF_ALL_REFLECTION); localRpReflectances.push_back(rho_r); Spectrum rho_t = photonBSDF->rho(rng, BSDF_ALL_TRANSMISSION); localRpTransmittances.push_back(rho_t); } } if (nIntersections >= integrator->maxPhotonDepth) break; // Sample new photon ray direction Vector wi; float pdf; BxDFType flags; Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (fr.IsBlack() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf; // Possibly terminate photon path with Russian roulette float continueProb = min(1.f, anew.y() / alpha.y()); if (rng.RandomFloat() > continueProb) break; alpha = anew / continueProb; specularPath &= ((flags & BSDF_SPECULAR) != 0); if (indirectDone && !specularPath) break; photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, photonIsect.rayEpsilon); } PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); } arena.FreeAll(); } // Merge local photon data with data in _PhotonIntegrator_ { MutexLock lock(mutex); // Give up if we're not storing enough photons if (abortTasks) return; if (nshot > 500000 && (unsuccessful(integrator->nCausticPhotonsWanted, causticPhotons.size(), blockSize) || unsuccessful(integrator->nIndirectPhotonsWanted, indirectPhotons.size(), blockSize))) { Error("Unable to store enough photons. Giving up.\n"); causticPhotons.erase(causticPhotons.begin(), causticPhotons.end()); indirectPhotons.erase(indirectPhotons.begin(), indirectPhotons.end()); radiancePhotons.erase(radiancePhotons.begin(), radiancePhotons.end()); abortTasks = true; return; } progress.Update(localIndirectPhotons.size() + localCausticPhotons.size()); nshot += blockSize; // Merge indirect photons into shared array if (!indirectDone) { integrator->nIndirectPaths += blockSize; for (uint32_t i = 0; i < localIndirectPhotons.size(); ++i) indirectPhotons.push_back(localIndirectPhotons[i]); localIndirectPhotons.erase(localIndirectPhotons.begin(), localIndirectPhotons.end()); if (indirectPhotons.size() >= integrator->nIndirectPhotonsWanted) indirectDone = true; nDirectPaths += blockSize; for (uint32_t i = 0; i < localDirectPhotons.size(); ++i) directPhotons.push_back(localDirectPhotons[i]); localDirectPhotons.erase(localDirectPhotons.begin(), localDirectPhotons.end()); } // Merge direct, caustic, and radiance photons into shared array if (!causticDone) { integrator->nCausticPaths += blockSize; for (uint32_t i = 0; i < localCausticPhotons.size(); ++i) causticPhotons.push_back(localCausticPhotons[i]); localCausticPhotons.erase(localCausticPhotons.begin(), localCausticPhotons.end()); if (causticPhotons.size() >= integrator->nCausticPhotonsWanted) causticDone = true; } for (uint32_t i = 0; i < localRadiancePhotons.size(); ++i) radiancePhotons.push_back(localRadiancePhotons[i]); localRadiancePhotons.erase(localRadiancePhotons.begin(), localRadiancePhotons.end()); for (uint32_t i = 0; i < localRpReflectances.size(); ++i) rpReflectances.push_back(localRpReflectances[i]); localRpReflectances.erase(localRpReflectances.begin(), localRpReflectances.end()); for (uint32_t i = 0; i < localRpTransmittances.size(); ++i) rpTransmittances.push_back(localRpTransmittances[i]); localRpTransmittances.erase(localRpTransmittances.begin(), localRpTransmittances.end()); } // Exit task if enough photons have been found if (indirectDone && causticDone) break; } }
Spectrum PathIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &r, const Intersection &isect, const Sample *sample, MemoryArena &arena) const { // Declare common path integration variables Spectrum pathThroughput = 1., L = 0.; RayDifferential ray(r); bool specularBounce = false; Intersection localIsect; const Intersection *isectp = &isect; for (int pathLength = 0; ; ++pathLength) { // Possibly add emitted light at path vertex if (pathLength == 0 || specularBounce) L += pathThroughput * isectp->Le(-ray.d); // Sample illumination from lights to find path contribution BSDF *bsdf = isectp->GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; const Normal &n = bsdf->dgShading.nn; Vector wo = -ray.d; if (pathLength < SAMPLE_DEPTH) L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isectp->RayEpsilon, bsdf, sample, lightNumOffset[pathLength], &lightSampleOffsets[pathLength], &bsdfSampleOffsets[pathLength]); else L += pathThroughput * UniformSampleOneLight(scene, renderer, arena, p, n, wo, isectp->RayEpsilon, bsdf, sample); // Sample BSDF to get new path direction // Get _outgoingBSDFSample_ for sampling new path direction BSDFSample outgoingBSDFSample; if (pathLength < SAMPLE_DEPTH) outgoingBSDFSample = BSDFSample(sample, pathSampleOffsets[pathLength], 0); else outgoingBSDFSample = BSDFSample(*sample->rng); 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; pathThroughput *= f * AbsDot(wi, n) / pdf; ray = RayDifferential(p, wi, ray, isectp->RayEpsilon); // Possibly terminate the path if (pathLength > 3) { float continueProbability = min(.5f, pathThroughput.y()); if (sample->rng->RandomFloat() > continueProbability) break; pathThroughput /= continueProbability; } if (pathLength == maxDepth) break; // Find next vertex of path if (!scene->Intersect(ray, &localIsect)) { if (specularBounce) { for (u_int i = 0; i < scene->lights.size(); ++i) L += pathThroughput * scene->lights[i]->Le(ray); } break; } if (pathLength > 1) pathThroughput *= renderer->Transmittance(scene, ray, NULL, arena, sample->rng); isectp = &localIsect; } return L; }
void RefractShader::generateDir(const SurfacePoint & sp, const glm::vec3 & out, unsigned numSamples, BSDFSamples & samples) const { samples.resize (numSamples); // assume refraction index 1.0 for outer medium glm::float_t n1 = 1.0f; glm::float_t n2 = m_index; // normal should point to medium n1 glm::vec3 normal = sp.normal; const glm::vec3 incident = -out; // Flip normal and count new n if the ray is coming from // inside the surface (ie. from n2 to n1) if (sp.cos_theta(out) < 0) { normal = -normal; std::swap(n1, n2); } // n = n1 / n2 where ray comes from n1 to n2 /*const glm::float_t n = n1 / n2; const glm::float_t cosI = glm::dot(normal, -incident);*/ for (unsigned i = 0; i < numSamples; ++i) { glm::vec3 result, value; glm::vec3 refracted; glm::float_t refl; if(refract(n1, n2, normal, incident, refracted, refl)) { // always reflect //refl = 1.0f; // always transmit //refl = 0.0f; assert(0 <= refl && refl <= 1); // choose between refracted and reflected rays based on fresnel term const glm::float_t roulette = Sampling::uniform(); if(roulette < refl) { // reflect result = reflect(normal, incident); value = (1 / refl) * (refl) * m_reflectance / sp.cos_theta(result); } else { const real cos_theta = glm::dot(normal, result); // transmit result = refracted; value = (1 / (1 - refl)) * (1 - refl) * m_transmittance / sp.cos_theta(result); } } else { result = reflect(normal, incident); value = m_reflectance / sp.cos_theta(result); } samples[i] = BSDFSample(result, value, 1); } }
Spectrum GlossyPRTIntegrator::Li(const Scene *scene, const Renderer *, const RayDifferential &ray, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const { Spectrum L = 0.f; Vector wo = -ray.d; // Compute emitted light if ray hit an area light source L += isect.Le(wo); // Evaluate BSDF at hit point BSDF *bsdf = isect.GetBSDF(ray, arena); const Point &p = bsdf->dgShading.p; // Compute reflected radiance with glossy PRT at point // Compute SH radiance transfer matrix at point and SH coefficients Spectrum *c_t = arena.Alloc<Spectrum>(SHTerms(lmax)); Spectrum *T = arena.Alloc<Spectrum>(SHTerms(lmax)*SHTerms(lmax)); SHComputeTransferMatrix(p, isect.rayEpsilon, scene, rng, nSamples, lmax, T); SHMatrixVectorMultiply(T, c_in, c_t, lmax); // Rotate incident SH lighting to local coordinate frame Vector r1 = bsdf->LocalToWorld(Vector(1,0,0)); Vector r2 = bsdf->LocalToWorld(Vector(0,1,0)); Normal nl = Normal(bsdf->LocalToWorld(Vector(0,0,1))); Matrix4x4 rot(r1.x, r2.x, nl.x, 0, r1.y, r2.y, nl.y, 0, r1.z, r2.z, nl.z, 0, 0, 0, 0, 1); Spectrum *c_l = arena.Alloc<Spectrum>(SHTerms(lmax)); SHRotate(c_t, c_l, rot, lmax, arena); #if 0 // Sample BSDF and integrate against direct SH coefficients float *Ylm = ALLOCA(float, SHTerms(lmax)); int ns = 1024; for (int i = 0; i < ns; ++i) { Vector wi; float pdf; Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf); if (pdf > 0.f && !f.IsBlack() && !scene->IntersectP(Ray(p, wi))) { f *= fabsf(Dot(wi, n)) / (pdf * ns); SHEvaluate(bsdf->WorldToLocal(wi), lmax, Ylm); Spectrum Li = 0.f; for (int j = 0; j < SHTerms(lmax); ++j) Li += Ylm[j] * c_l[j] * f; L += Li.Clamp(); } } #else // Compute final coefficients _c\_o_ using BSDF matrix Spectrum *c_o = arena.Alloc<Spectrum>(SHTerms(lmax)); SHMatrixVectorMultiply(B, c_l, c_o, lmax); // Evaluate outgoing radiance function for $\wo$ and add to _L_ Vector woLocal = bsdf->WorldToLocal(wo); float *Ylm = ALLOCA(float, SHTerms(lmax)); SHEvaluate(woLocal, lmax, Ylm); Spectrum Li = 0.f; for (int i = 0; i < SHTerms(lmax); ++i) Li += Ylm[i] * c_o[i]; L += Li.Clamp(); #endif return L; }
void LightShootingTask::Run() { // tady by mel byt kod z photon mappingu MemoryArena arena; uint32_t totalPaths = 0; RNG rng(seed); PermutedHalton halton(6, rng); while (true) { // Follow photon paths for a block of samples const uint32_t blockSize = 4096; for (uint32_t i = 0; i < blockSize; ++i) { float u[6]; halton.Sample(++totalPaths, u); // Choose light to shoot photon from float lightPdf; int lightNum = lightDistribution->SampleDiscrete(u[0], &lightPdf); const Light *light = scene->lights[lightNum]; // Generate _photonRay_ from light source and initialize _alpha_ RayDifferential photonRay; float pdf; LightSample ls(u[1], u[2], u[3]); Normal Nl; Spectrum Le = light->Sample_L(scene, ls, u[4], u[5],time, &photonRay, &Nl, &pdf); if (pdf == 0.f || Le.IsBlack()) continue; Spectrum alpha = (AbsDot(Nl, photonRay.d) * Le) / (pdf * lightPdf); if (!alpha.IsBlack()) { // Follow photon path through scene and record intersections PBRT_PHOTON_MAP_STARTED_RAY_PATH(&photonRay, &alpha); bool specularPath = true; Intersection photonIsect; int nIntersections = 0; while (scene->Intersect(photonRay, &photonIsect)) { ++nIntersections; //MC tady by mel byt i kod pro volumetriku // Handle photon/surface intersection // alpha *= renderer->Transmittance(scene, photonRay, NULL, rng, arena); BSDF *photonBSDF = photonIsect.GetBSDF(photonRay, arena); Vector wo = -photonRay.d; //MC tady se ukladaly photony takze tady bych mel ukladat samples do filmu kamery // // Deposit photon at surface //Photon photon(photonIsect.dg.p, alpha, wo); //tuhle metodu chci pouzit //filmAddSample() if (nIntersections >= maxDepth) break; // Sample new photon ray direction Vector wi; float pdf; BxDFType flags; Spectrum fr = photonBSDF->Sample_f(wo, &wi, BSDFSample(rng), &pdf, BSDF_ALL, &flags); if (fr.IsBlack() || pdf == 0.f) break; Spectrum anew = alpha * fr * AbsDot(wi, photonBSDF->dgShading.nn) / pdf; // Possibly terminate photon path with Russian roulette float continueProb = min(1.f, anew.y() / alpha.y()); if (rng.RandomFloat() > continueProb) break; alpha = anew / continueProb; specularPath &= ((flags & BSDF_SPECULAR) != 0); photonRay = RayDifferential(photonIsect.dg.p, wi, photonRay, photonIsect.rayEpsilon); } PBRT_PHOTON_MAP_FINISHED_RAY_PATH(&photonRay, &alpha); } arena.FreeAll(); } //termination criteria ??? if (totalPaths==maxPathCount) { break; } } }