void MLTTask::Run() { PBRT_MLT_STARTED_MLT_TASK(this); // Declare basic _MLTTask_ variables and prepare for sampling PBRT_MLT_STARTED_TASK_INIT(); uint32_t nPixels = (x1-x0) * (y1-y0); uint32_t nPixelSamples = renderer->nPixelSamples; uint32_t largeStepRate = nPixelSamples / renderer->largeStepsPerPixel; Assert(largeStepRate > 1); uint64_t nTaskSamples = uint64_t(nPixels) * uint64_t(largeStepRate); uint32_t consecutiveRejects = 0; uint32_t progressCounter = progressUpdateFrequency; // Declare variables for storing and computing MLT samples MemoryArena arena; RNG rng(taskNum); vector<PathVertex> cameraPath(renderer->maxDepth, PathVertex()); vector<PathVertex> lightPath(renderer->maxDepth, PathVertex()); vector<MLTSample> samples(2, MLTSample(renderer->maxDepth)); Spectrum L[2]; float I[2]; uint32_t current = 0, proposed = 1; // Compute _L[current]_ for initial sample samples[current] = initialSample; L[current] = renderer->PathL(initialSample, scene, arena, camera, lightDistribution, &cameraPath[0], &lightPath[0], rng); I[current] = ::I(L[current]); arena.FreeAll(); // Compute randomly permuted table of pixel indices for large steps uint32_t pixelNumOffset = 0; vector<int> largeStepPixelNum; largeStepPixelNum.reserve(nPixels); for (uint32_t i = 0; i < nPixels; ++i) largeStepPixelNum.push_back(i); Shuffle(&largeStepPixelNum[0], nPixels, 1, rng); PBRT_MLT_FINISHED_TASK_INIT(); for (uint64_t s = 0; s < nTaskSamples; ++s) { // Compute proposed mutation to current sample PBRT_MLT_STARTED_MUTATION(); samples[proposed] = samples[current]; bool largeStep = ((s % largeStepRate) == 0); if (largeStep) { int x = x0 + largeStepPixelNum[pixelNumOffset] % (x1 - x0); int y = y0 + largeStepPixelNum[pixelNumOffset] / (x1 - x0); LargeStep(rng, &samples[proposed], renderer->maxDepth, x + dx, y + dy, t0, t1, renderer->bidirectional); ++pixelNumOffset; } else SmallStep(rng, &samples[proposed], renderer->maxDepth, x0, x1, y0, y1, t0, t1, renderer->bidirectional); PBRT_MLT_FINISHED_MUTATION(); // Compute contribution of proposed sample L[proposed] = renderer->PathL(samples[proposed], scene, arena, camera, lightDistribution, &cameraPath[0], &lightPath[0], rng); I[proposed] = ::I(L[proposed]); arena.FreeAll(); // Compute acceptance probability for proposed sample float a = min(1.f, I[proposed] / I[current]); // Splat current and proposed samples to _Film_ PBRT_MLT_STARTED_SAMPLE_SPLAT(); if (I[current] > 0.f) { if (!isinf(1.f / I[current])) { Spectrum contrib = (b / nPixelSamples) * L[current] / I[current]; camera->film->Splat(samples[current].cameraSample, (1.f - a) * contrib); } } if (I[proposed] > 0.f) { if (!isinf(1.f / I[proposed])) { Spectrum contrib = (b / nPixelSamples) * L[proposed] / I[proposed]; camera->film->Splat(samples[proposed].cameraSample, a * contrib); } } PBRT_MLT_FINISHED_SAMPLE_SPLAT(); // Randomly accept proposed path mutation (or not) if (consecutiveRejects >= renderer->maxConsecutiveRejects || rng.RandomFloat() < a) { PBRT_MLT_ACCEPTED_MUTATION(a, &samples[current], &samples[proposed]); current ^= 1; proposed ^= 1; consecutiveRejects = 0; } else { PBRT_MLT_REJECTED_MUTATION(a, &samples[current], &samples[proposed]); ++consecutiveRejects; } if (--progressCounter == 0) { progress.Update(); progressCounter = progressUpdateFrequency; } } Assert(pixelNumOffset == nPixels); // Update display for recently computed Metropolis samples PBRT_MLT_STARTED_DISPLAY_UPDATE(); int ntf = AtomicAdd(&renderer->nTasksFinished, 1); int64_t totalSamples = int64_t(nPixels) * int64_t(nPixelSamples); float splatScale = float(double(totalSamples) / double(ntf * nTaskSamples)); camera->film->UpdateDisplay(x0, y0, x1, y1, splatScale); if ((taskNum % 8) == 0) { MutexLock lock(*filmMutex); camera->film->WriteImage(splatScale); } PBRT_MLT_FINISHED_DISPLAY_UPDATE(); PBRT_MLT_FINISHED_MLT_TASK(this); }
void MLTTask::Run() { PBRT_MLT_STARTED_MLT_TASK(this); // Declare basic _MLTTask_ variables and prepare for sampling RNG rng(taskNum); MemoryArena arena; vector<MLTSample> mltSamples(2, MLTSample(maxDepth)); Spectrum sampleLs[2]; uint32_t currentSample = 0, proposedSample = 1; mltSamples[currentSample] = initialSample; sampleLs[currentSample] = L(scene, renderer, camera, arena, rng, maxDepth, ignoreDirect, mltSamples[currentSample]); int consecutiveRejects = 0; for (int sampleNum = 0; sampleNum < nSamples; ++sampleNum) { // Compute proposed mutation to current sample bool largeStep = rng.RandomFloat() < largeStepProbability; mltSamples[proposedSample] = mltSamples[currentSample]; if (largeStep) LargeStep(rng, &mltSamples[proposedSample], maxDepth, x0, x1, y0, y1, t0, t1); else SmallStep(rng, &mltSamples[proposedSample], maxDepth, x0, x1, y0, y1, t0, t1); // Compute contribution of proposed sample and acceptance probability sampleLs[proposedSample] = L(scene, renderer, camera, arena, rng, maxDepth, ignoreDirect, mltSamples[proposedSample]); float currentI = I(sampleLs[currentSample], mltSamples[currentSample]); float proposedI = I(sampleLs[proposedSample], mltSamples[proposedSample]); float a = min(1.f, proposedI / currentI); float currentWeight = (1.f - a) / (currentI / b + largeStepProbability) * float(nPixels) / float(totalSamples); float proposedWeight = (a + (largeStep ? 1.f : 0.f)) / (proposedI / b + largeStepProbability) * float(nPixels) / float(totalSamples); // Splat current and proposed samples to _Film_ if (currentWeight > 0.f && currentI > 0.f) camera->film->Splat(mltSamples[currentSample].cameraSample, sampleLs[currentSample] * currentWeight); if (proposedWeight > 0.f && proposedI > 0.f) camera->film->Splat(mltSamples[proposedSample].cameraSample, sampleLs[proposedSample] * proposedWeight); // Randomly accept proposed path mutation (or not) if (consecutiveRejects >= maxConsecutiveRejects || rng.RandomFloat() < a) { PBRT_MLT_ACCEPTED_MUTATION(a, &mltSamples[currentSample], &mltSamples[proposedSample]); currentSample ^= 1; proposedSample ^= 1; consecutiveRejects = 0; } else { PBRT_MLT_REJECTED_MUTATION(a, &mltSamples[currentSample], &mltSamples[proposedSample]); ++consecutiveRejects; } arena.FreeAll(); } // Update display for recently computed Metropolis samples float nf = AtomicAdd(nSamplesFinished, nSamples); float splatScale = float(totalSamples)/nf; camera->film->UpdateDisplay(x0, y0, x1, y1, splatScale); if ((taskNum % 32) == 0) { MutexLock lock(*filmMutex); camera->film->WriteImage(splatScale); } progress.Update(); PBRT_MLT_FINISHED_MLT_TASK(this); }