Example #1
0
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);
}
Example #2
0
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);
}