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); } } }
void AggregateTest::Render(const Scene *scene) { RNG rng; ProgressReporter prog(nIterations, "Aggregate Test"); // Compute bounding box of region used to generate random rays BBox bbox = scene->WorldBound(); bbox.Expand(bbox.pMax[bbox.MaximumExtent()] - bbox.pMin[bbox.MaximumExtent()]); Point lastHit; float lastEps = 0.f; for (int i = 0; i < nIterations; ++i) { // Choose random rays, _rayAccel_ and _rayAll_ for testing // Choose ray origin for testing accelerator Point org(Lerp(rng.RandomFloat(), bbox.pMin.x, bbox.pMax.x), Lerp(rng.RandomFloat(), bbox.pMin.y, bbox.pMax.y), Lerp(rng.RandomFloat(), bbox.pMin.z, bbox.pMax.z)); if ((rng.RandomUInt() % 4) == 0) org = lastHit; // Choose ray direction for testing accelerator Vector dir = UniformSampleSphere(rng.RandomFloat(), rng.RandomFloat()); if ((rng.RandomUInt() % 32) == 0) dir.x = dir.y = 0.f; else if ((rng.RandomUInt() % 32) == 0) dir.x = dir.z = 0.f; else if ((rng.RandomUInt() % 32) == 0) dir.y = dir.z = 0.f; // Choose ray epsilon for testing accelerator float eps = 0.f; if (rng.RandomFloat() < .25) eps = lastEps; else if (rng.RandomFloat() < .25) eps = 1e-3f; Ray rayAccel(org, dir, eps); Ray rayAll = rayAccel; // Compute intersections using accelerator and exhaustive testing Intersection isectAccel, isectAll; bool hitAccel = scene->Intersect(rayAccel, &isectAccel); bool hitAll = false; bool inconsistentBounds = false; for (u_int j = 0; j < primitives.size(); ++j) { if (bboxes[j].IntersectP(rayAll)) hitAll |= primitives[j]->Intersect(rayAll, &isectAll); else if (primitives[j]->Intersect(rayAll, &isectAll)) inconsistentBounds = true; } // Report any inconsistencies between intersections if (!inconsistentBounds && ((hitAccel != hitAll) || (rayAccel.maxt != rayAll.maxt))) Warning("Disagreement: t accel %.16g [%a] t exhaustive %.16g [%a]\n" "Ray: org [%a, %a, %a], dir [%a, %a, %a], mint = %a", rayAccel.maxt, rayAll.maxt, rayAccel.maxt, rayAll.maxt, rayAll.o.x, rayAll.o.y, rayAll.o.z, rayAll.d.x, rayAll.d.y, rayAll.d.z, rayAll.mint); if (hitAll) { lastHit = rayAll(rayAll.maxt); lastEps = isectAll.RayEpsilon; } prog.Update(); } prog.Done(); }
Spectrum IrradianceCacheIntegrator::indirectLo(const Point &p, const Normal &ng, float pixelSpacing, const Vector &wo, float rayEpsilon, BSDF *bsdf, BxDFType flags, RNG &rng, const Scene *scene, const Renderer *renderer, MemoryArena &arena) const { if (bsdf->NumComponents(flags) == 0) return Spectrum(0.); Spectrum E; Vector wi; // Get irradiance _E_ and average incident direction _wi_ at point _p_ if (!interpolateE(scene, p, ng, &E, &wi)) { // Compute irradiance at current point PBRT_IRRADIANCE_CACHE_STARTED_COMPUTING_IRRADIANCE(const_cast<Point *>(&p), const_cast<Normal *>(&ng)); uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; float minHitDistance = INFINITY; Vector wAvg(0,0,0); Spectrum LiSum = 0.f; for (int i = 0; i < nSamples; ++i) { // Sample direction for irradiance estimate ray float u[2]; Sample02(i, scramble, u); Vector w = CosineSampleHemisphere(u[0], u[1]); RayDifferential r(p, bsdf->LocalToWorld(w), rayEpsilon); r.d = Faceforward(r.d, ng); // Trace ray to sample radiance for irradiance estimate PBRT_IRRADIANCE_CACHE_STARTED_RAY(&r); Spectrum L = pathL(r, scene, renderer, rng, arena); LiSum += L; wAvg += r.d * L.y(); minHitDistance = min(minHitDistance, r.maxt); PBRT_IRRADIANCE_CACHE_FINISHED_RAY(&r, r.maxt, &L); } E = (M_PI / float(nSamples)) * LiSum; PBRT_IRRADIANCE_CACHE_FINISHED_COMPUTING_IRRADIANCE(const_cast<Point *>(&p), const_cast<Normal *>(&ng)); // Add computed irradiance value to cache // Compute irradiance sample's contribution extent and bounding box float maxDist = maxSamplePixelSpacing * pixelSpacing; float minDist = minSamplePixelSpacing * pixelSpacing; float contribExtent = Clamp(minHitDistance / 2.f, minDist, maxDist); BBox sampleExtent(p); sampleExtent.Expand(contribExtent); PBRT_IRRADIANCE_CACHE_ADDED_NEW_SAMPLE(const_cast<Point *>(&p), const_cast<Normal *>(&ng), contribExtent, &E, &wAvg, pixelSpacing); // Allocate _IrradianceSample_, get write lock, add to octree IrradianceSample *sample = new IrradianceSample(E, p, ng, wAvg, contribExtent); RWMutexLock lock(*mutex, WRITE); octree->Add(sample, sampleExtent); wi = wAvg; } // Compute reflected radiance due to irradiance and BSDF if (wi.LengthSquared() == 0.f) return Spectrum(0.); return bsdf->f(wo, Normalize(wi), flags) * E; }
// AmbientOcclusionIntegrator Method Definitions Spectrum AmbientOcclusionIntegrator::Li(const Scene *scene, const Renderer *renderer, const RayDifferential &ray, const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena, int wavelength) const { BSDF *bsdf = isect.GetBSDF(ray, arena, wavelength); const Point &p = bsdf->dgShading.p; Normal n = Faceforward(isect.dg.nn, -ray.d); uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; float u[2]; int nClear = 0; for (int i = 0; i < nSamples; ++i) { Sample02(i, scramble, u); Vector w = UniformSampleSphere(u[0], u[1]); if (Dot(w, n) < 0.) w = -w; Ray r(p, w, .01f, maxDist); if (!scene->IntersectP(r)) ++nClear; } return Spectrum(float(nClear) / float(nSamples)); }
void LatinHypercube(float *samples, u_int nSamples, u_int nDim, RNG &rng) { // Generate LHS samples along diagonal float delta = 1.f / nSamples; for (u_int i = 0; i < nSamples; ++i) for (u_int j = 0; j < nDim; ++j) samples[nDim * i + j] = (i + (rng.RandomFloat())) * delta; // Permute LHS samples in each dimension for (u_int i = 0; i < nDim; ++i) { for (u_int j = 0; j < nSamples; ++j) { u_int other = j + (rng.RandomUInt() % (nSamples - j)); swap(samples[nDim * j + i], samples[nDim * other + i]); } } }
void DipoleSubsurfaceIntegrator::Preprocess(const Scene *scene, const Camera *camera, const Renderer *renderer) { if (scene->lights.size() == 0) return; vector<SurfacePoint> pts; // Get _SurfacePoint_s for translucent objects in scene if (filename != "") { // Initialize _SurfacePoint_s from file vector<float> fpts; if (ReadFloatFile(filename.c_str(), &fpts)) { if ((fpts.size() % 8) != 0) Error("Excess values (%d) in points file \"%s\"", int(fpts.size() % 8), filename.c_str()); for (u_int i = 0; i < fpts.size(); i += 8) pts.push_back(SurfacePoint(Point(fpts[i], fpts[i+1], fpts[i+2]), Normal(fpts[i+3], fpts[i+4], fpts[i+5]), fpts[i+6], fpts[i+7])); } } if (pts.size() == 0) { Point pCamera = camera->CameraToWorld(camera->shutterOpen, Point(0, 0, 0)); FindPoissonPointDistribution(pCamera, camera->shutterOpen, minSampleDist, scene, &pts); } // Compute irradiance values at sample points RNG rng; MemoryArena arena; PBRT_SUBSURFACE_STARTED_COMPUTING_IRRADIANCE_VALUES(); ProgressReporter progress(pts.size(), "Computing Irradiances"); for (uint32_t i = 0; i < pts.size(); ++i) { SurfacePoint &sp = pts[i]; Spectrum E(0.f); for (uint32_t j = 0; j < scene->lights.size(); ++j) { // Add irradiance from light at point const Light *light = scene->lights[j]; Spectrum Elight = 0.f; int nSamples = RoundUpPow2(light->nSamples); uint32_t scramble[2] = { rng.RandomUInt(), rng.RandomUInt() }; uint32_t compScramble = rng.RandomUInt(); for (int s = 0; s < nSamples; ++s) { float lpos[2]; Sample02(s, scramble, lpos); float lcomp = VanDerCorput(s, compScramble); LightSample ls(lpos[0], lpos[1], lcomp); Vector wi; float lightPdf; VisibilityTester visibility; Spectrum Li = light->Sample_L(sp.p, sp.rayEpsilon, ls, camera->shutterOpen, &wi, &lightPdf, &visibility); if (Dot(wi, sp.n) <= 0.) continue; if (Li.IsBlack() || lightPdf == 0.f) continue; Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena); if (visibility.Unoccluded(scene)) Elight += Li * AbsDot(wi, sp.n) / lightPdf; } E += Elight / nSamples; } if (E.y() > 0.f) { irradiancePoints.push_back(IrradiancePoint(sp, E)); PBRT_SUBSURFACE_COMPUTED_IRRADIANCE_AT_POINT(&sp, &E); } arena.FreeAll(); progress.Update(); } progress.Done(); PBRT_SUBSURFACE_FINISHED_COMPUTING_IRRADIANCE_VALUES(); // Create octree of clustered irradiance samples octree = octreeArena.Alloc<SubsurfaceOctreeNode>(); for (uint32_t i = 0; i < irradiancePoints.size(); ++i) octreeBounds = Union(octreeBounds, irradiancePoints[i].p); for (uint32_t i = 0; i < irradiancePoints.size(); ++i) octree->Insert(octreeBounds, &irradiancePoints[i], octreeArena); octree->InitHierarchy(); }