void MLTIntegrator::Render(const Scene &scene) { ProfilePhase p(Prof::IntegratorRender); std::unique_ptr<Distribution1D> lightDistr = ComputeLightPowerDistribution(scene); // Generate bootstrap samples and compute normalization constant $b$ int nBootstrapSamples = nBootstrap * (maxDepth + 1); std::vector<Float> bootstrapWeights(nBootstrapSamples, 0); if (scene.lights.size() > 0) { ProgressReporter progress(nBootstrap / 256, "Generating bootstrap paths"); std::vector<MemoryArena> bootstrapThreadArenas(MaxThreadIndex()); int chunkSize = Clamp(nBootstrap / 128, 1, 8192); ParallelFor([&](int i) { // Generate _i_th bootstrap sample MemoryArena &arena = bootstrapThreadArenas[threadIndex]; for (int depth = 0; depth <= maxDepth; ++depth) { int rngIndex = i * (maxDepth + 1) + depth; MLTSampler sampler(mutationsPerPixel, rngIndex, sigma, largeStepProbability, nSampleStreams); Point2f pRaster; bootstrapWeights[rngIndex] = L(scene, arena, lightDistr, sampler, depth, &pRaster).y(); arena.Reset(); } if ((i + 1 % 256) == 0) progress.Update(); }, nBootstrap, chunkSize); progress.Done(); } Distribution1D bootstrap(&bootstrapWeights[0], nBootstrapSamples); Float b = bootstrap.funcInt * (maxDepth + 1); // Run _nChains_ Markov chains in parallel Film &film = *camera->film; int64_t nTotalMutations = (int64_t)mutationsPerPixel * (int64_t)film.GetSampleBounds().Area(); if (scene.lights.size() > 0) { StatTimer timer(&renderingTime); const int progressFrequency = 32768; ProgressReporter progress(nTotalMutations / progressFrequency, "Rendering"); ParallelFor([&](int i) { int64_t nChainMutations = std::min((i + 1) * nTotalMutations / nChains, nTotalMutations) - i * nTotalMutations / nChains; // Follow {i}th Markov chain for _nChainMutations_ MemoryArena arena; // Select initial state from the set of bootstrap samples RNG rng(i); int bootstrapIndex = bootstrap.SampleDiscrete(rng.UniformFloat()); int depth = bootstrapIndex % (maxDepth + 1); // Initialize local variables for selected state MLTSampler sampler(mutationsPerPixel, bootstrapIndex, sigma, largeStepProbability, nSampleStreams); Point2f pCurrent; Spectrum LCurrent = L(scene, arena, lightDistr, sampler, depth, &pCurrent); // Run the Markov chain for _nChainMutations_ steps for (int64_t j = 0; j < nChainMutations; ++j) { sampler.StartIteration(); Point2f pProposed; Spectrum LProposed = L(scene, arena, lightDistr, sampler, depth, &pProposed); // Compute acceptance probability for proposed sample Float accept = std::min((Float)1, LProposed.y() / LCurrent.y()); // Splat both current and proposed samples to _film_ if (accept > 0) film.AddSplat(pProposed, LProposed * accept / LProposed.y()); film.AddSplat(pCurrent, LCurrent * (1 - accept) / LCurrent.y()); // Accept or reject the proposal if (rng.UniformFloat() < accept) { pCurrent = pProposed; LCurrent = LProposed; sampler.Accept(); ++acceptedMutations; } else sampler.Reject(); ++totalMutations; if ((i * nTotalMutations / nChains + j) % progressFrequency == 0) progress.Update(); arena.Reset(); } }, nChains); progress.Done(); } // Store final image computed with MLT camera->film->WriteImage(b / mutationsPerPixel); }
void MLTIntegrator::Render(const Scene &scene) { lightDistr = std::unique_ptr<Distribution1D>(ComputeLightSamplingCDF(scene)); Film &film = *camera->film; // Generate bootstrap samples and compute $b$ int bootstrapSamples = nBootstrap * (maxDepth + 1); std::unique_ptr<Float[]> bootstrapWeights(new Float[bootstrapSamples]); { ProgressReporter progress(nBootstrap, "Generating bootstrap paths"); ParallelFor([&](int k) { // Generate a single bootstrap sample MemoryArena arena; for (int depth = 0; depth <= maxDepth; ++depth) { uint32_t uIndex = k * (maxDepth + 1) + depth; MLTSampler sampler(mutationsPerPixel, uIndex, sigma, largeStepProb); Point2f samplePos; bootstrapWeights[uIndex] = L(scene, arena, sampler, depth, &samplePos).y(); } progress.Update(); }, nBootstrap); progress.Done(); } Distribution1D bootstrap(bootstrapWeights.get(), bootstrapSamples); Float b = bootstrap.funcInt * (maxDepth + 1); // Run _nChains_ Markov Chains in parallel int64_t nTotalMutations = mutationsPerPixel * (int64_t)film.GetSampleBounds().Area(); { StatTimer timer(&renderingTime); ProgressReporter progress(nTotalMutations / 100, "Rendering"); ParallelFor([&](int k) { int64_t nChainMutations = std::min((k + 1) * nTotalMutations / nChains, nTotalMutations) - k * nTotalMutations / nChains; MemoryArena arena; std::unique_ptr<FilmTile> filmTile = film.GetFilmTile(Bounds2i( film.croppedPixelBounds.pMin, film.croppedPixelBounds.pMin)); // Select initial state from the set of bootstrap samples RNG rng(PCG32_DEFAULT_STATE, k); int bootstrapIndex = bootstrap.SampleDiscrete(rng.UniformFloat()); int depth = bootstrapIndex % (maxDepth + 1); // Initialize local variables for selected state MLTSampler sampler(mutationsPerPixel, bootstrapIndex, sigma, largeStepProb); Point2f currentPos, proposalPos; Spectrum currentL, proposalL; currentL = L(scene, arena, sampler, depth, ¤tPos); // Run the Markov Chain for _nChainMutations_ steps for (int64_t i = 0; i != nChainMutations; ++i) { sampler.Begin(); proposalL = L(scene, arena, sampler, depth, &proposalPos); // Compute the acceptance rate Float accept = std::min((Float)1, proposalL.y() / currentL.y()); // Splat both current and proposed samples to _FilmTile_ if (accept > 0) filmTile->AddSplat(proposalPos, proposalL * accept / proposalL.y()); filmTile->AddSplat(currentPos, currentL * (1 - accept) / currentL.y()); // Accept or reject the proposal if (rng.UniformFloat() < accept) { currentPos = proposalPos; currentL = proposalL; sampler.Accept(); ++acceptedMutations; } else { sampler.Reject(); } ++totalMutations; if (i % 100 == 0) progress.Update(); } film.MergeFilmTile(std::move(filmTile)); }, nChains); progress.Done(); } film.WriteImage(b / mutationsPerPixel); }