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); } } }
int GenerateCameraSubpath(const Scene &scene, Sampler &sampler, MemoryArena &arena, int maxDepth, const Camera &camera, Point2f &pFilm, Vertex *path) { if (maxDepth == 0) return 0; // Sample initial ray for camera subpath CameraSample cameraSample; cameraSample.pFilm = pFilm; cameraSample.time = sampler.Get1D(); cameraSample.pLens = sampler.Get2D(); RayDifferential ray; Spectrum beta = camera.GenerateRayDifferential(cameraSample, &ray); ray.ScaleDifferentials(1 / std::sqrt(sampler.samplesPerPixel)); // Generate first vertex on camera subpath and start random walk Float pdfPos, pdfDir; path[0] = Vertex::CreateCamera(&camera, ray, beta); camera.Pdf_We(ray, &pdfPos, &pdfDir); return RandomWalk(scene, ray, sampler, arena, beta, pdfDir, maxDepth - 1, TransportMode::Radiance, path + 1) + 1; }
int GenerateCameraSubpath(const Scene &scene, Sampler &sampler, MemoryArena &arena, int maxdepth, const Camera &camera, Point2f &rasterPos, Vertex *path) { if (maxdepth == 0) return 0; // Sample initial ray for camera subpath CameraSample cameraSample; cameraSample.pFilm = rasterPos; cameraSample.time = sampler.Get1D(); cameraSample.pLens = sampler.Get2D(); RayDifferential ray; Spectrum rayWeight(camera.GenerateRayDifferential(cameraSample, &ray)); ray.ScaleDifferentials(1.f / std::sqrt(sampler.samplesPerPixel)); // Generate first vertex on camera subpath and start random walk path[0] = Vertex(VertexType::Camera, EndpointInteraction(&camera, ray), Spectrum(1.0f)); return RandomWalk(scene, ray, sampler, arena, rayWeight, camera.Pdf(path[0].ei, ray.d), maxdepth - 1, TransportMode::Radiance, path + 1) + 1; }
// SamplerIntegrator Method Definitions void SamplerIntegrator::Render(const Scene &scene) { ProfilePhase p(Prof::IntegratorRender); Preprocess(scene, *sampler); // Render image tiles in parallel // Compute number of tiles, _nTiles_, to use for parallel rendering Bounds2i sampleBounds = camera->film->GetSampleBounds(); Vector2i sampleExtent = sampleBounds.Diagonal(); const int tileSize = 16; Point2i nTiles((sampleExtent.x + tileSize - 1) / tileSize, (sampleExtent.y + tileSize - 1) / tileSize); ProgressReporter reporter(nTiles.x * nTiles.y, "Rendering"); { StatTimer timer(&renderingTime); ParallelFor2D([&](Point2i tile) { // Render section of image corresponding to _tile_ // Allocate _MemoryArena_ for tile MemoryArena arena; // Get sampler instance for tile int seed = tile.y * nTiles.x + tile.x; std::unique_ptr<Sampler> tileSampler = sampler->Clone(seed); // Compute sample bounds for tile int x0 = sampleBounds.pMin.x + tile.x * tileSize; int x1 = std::min(x0 + tileSize, sampleBounds.pMax.x); int y0 = sampleBounds.pMin.y + tile.y * tileSize; int y1 = std::min(y0 + tileSize, sampleBounds.pMax.y); Bounds2i tileBounds(Point2i(x0, y0), Point2i(x1, y1)); // Get _FilmTile_ for tile std::unique_ptr<FilmTile> filmTile = camera->film->GetFilmTile(tileBounds); // Loop over pixels in tile to render them for (Point2i pixel : tileBounds) { { ProfilePhase pp(Prof::StartPixel); tileSampler->StartPixel(pixel); } do { // Initialize _CameraSample_ for current sample CameraSample cameraSample = tileSampler->GetCameraSample(pixel); // Generate camera ray for current sample RayDifferential ray; Float rayWeight = camera->GenerateRayDifferential(cameraSample, &ray); ray.ScaleDifferentials( 1 / std::sqrt((Float)tileSampler->samplesPerPixel)); ++nCameraRays; // Evaluate radiance along camera ray Spectrum L(0.f); if (rayWeight > 0) L = Li(ray, scene, *tileSampler, arena); // Issue warning if unexpected radiance value returned if (L.HasNaNs()) { Error( "Not-a-number radiance value returned " "for image sample. Setting to black."); L = Spectrum(0.f); } else if (L.y() < -1e-5) { Error( "Negative luminance value, %f, returned " "for image sample. Setting to black.", L.y()); L = Spectrum(0.f); } else if (std::isinf(L.y())) { Error( "Infinite luminance value returned " "for image sample. Setting to black."); L = Spectrum(0.f); } // Add camera ray's contribution to image filmTile->AddSample(cameraSample.pFilm, L, rayWeight); // Free _MemoryArena_ memory from computing image sample // value arena.Reset(); } while (tileSampler->StartNextSample()); } // Merge image tile into _Film_ camera->film->MergeFilmTile(std::move(filmTile)); reporter.Update(); }, nTiles); reporter.Done(); } // Save final image after rendering camera->film->WriteImage(); }