PBRT_V2 总结记录 EmissionIntegrator

EmissionIntegrator

class EmissionIntegrator : public VolumeIntegrator {
public:
    // EmissionIntegrator Public Methods
    EmissionIntegrator(float ss) { stepSize = ss; }
    void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene);
    Spectrum Li(const Scene *scene, const Renderer *renderer,
            const RayDifferential &ray, const Sample *sample, RNG &rng,
            Spectrum *transmittance, MemoryArena &arena) const;
    Spectrum Transmittance(const Scene *scene, const Renderer *,
            const RayDifferential &ray, const Sample *sample, RNG &rng,
            MemoryArena &arena) const;
private:
    // EmissionIntegrator Private Data
    float stepSize;
    int tauSampleOffset, scatterSampleOffset;
};

作用:

(EmissionIntegrator 这个积分器 是忽略了 participating media 的 in-scattering 效果,只有 emission 和 attenuation,所以就可以把 16.1的公式进行简化。

因为 忽略了 in-Scattering 效果,S 项 只剩下 Lve,

所以就得到

The simplest possible volume integrator (other than one that ignored participating media
completely) simplifies the source term by ignoring in-scattering and only accounting
for emission and attenuation
. Because in-scattering is ignored, the integral over the
sphere in the source term at each point along the ray disappears, and the resulting simplified equation of transfer is

1. 

void EmissionIntegrator::RequestSamples(Sampler *sampler, Sample *sample,
                                        const Scene *scene) {
    tauSampleOffset = sample->Add1D(1);
    scatterSampleOffset = sample->Add1D(1);
}

作用:

(看上面的公式可以知道,需要求t的积分,所以就用到1D的采样点,所以就请求采样点)

The Transmittance() and Li() methods each only need a single 1D sample value to
evaluate their respective integrals:

2. 

Spectrum EmissionIntegrator::Transmittance(const Scene *scene,
        const Renderer *renderer, const RayDifferential &ray,
        const Sample *sample, RNG &rng, MemoryArena &arena) const {
    if (!scene->volumeRegion) return Spectrum(1.f);
    float step, offset;
    if (sample) {
        step = stepSize;
        offset = sample->oneD[tauSampleOffset][0];
    }
    else {
        step = 4.f * stepSize;
        offset = rng.RandomFloat();
    }
    Spectrum tau = scene->volumeRegion->tau(ray, step, offset);
    return Exp(-tau);
}

作用:

(计算 Tr,可以参考《PBRT_V2 总结记录 <54> Volume Scattering Processes》 计算 Tr的 方法,那么,volumeRegion->tau 主要的作用就是计算 ray 在 volumeRegion 的厚度)

The Transmittance() method is reasonably straightforward. The VolumeRegion’s tau()
method takes care of computing the optical thickness τ from the ray’s starting point to
its ending point.
The only work for the integrator here is to choose a step size (in case
tau() does Monte Carlo integration, as the implementation in Section 14.7 does), pass a single sample value to that method, and return e^(−τ). If the tau() method can compute τ analytically, it will ignore these additional values.

3. 


Spectrum EmissionIntegrator::Li(const Scene *scene,
        const Renderer *renderer, const RayDifferential &ray,
        const Sample *sample, RNG &rng, Spectrum *T,
        MemoryArena &arena) const {
    VolumeRegion *vr = scene->volumeRegion;
    Assert(sample != NULL);
    float t0, t1;
    if (!vr || !vr->IntersectP(ray, &t0, &t1) || (t1-t0) == 0.f) {
        *T = Spectrum(1.f);
        return 0.f;
    }
    // Do emission-only volume integration in _vr_
    Spectrum Lv(0.);

    // Prepare for volume integration stepping
    int nSamples = Ceil2Int((t1-t0) / stepSize);
    float step = (t1 - t0) / nSamples;
    Spectrum Tr(1.f);
    Point p = ray(t0), pPrev;
    Vector w = -ray.d;
    t0 += sample->oneD[scatterSampleOffset][0] * step;
    for (int i = 0; i < nSamples; ++i, t0 += step) {
        // Advance to sample at _t0_ and update _T_
        pPrev = p;
        p = ray(t0);
        Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth);
        Spectrum stepTau = vr->tau(tauRay,
                                   .5f * stepSize, rng.RandomFloat());
        Tr *= Exp(-stepTau);

        // Possibly terminate ray marching if transmittance is small
        if (Tr.y() < 1e-3) {
            const float continueProb = .5f;
            if (rng.RandomFloat() > continueProb) {
                Tr = 0.f;
                break;
            }
            Tr /= continueProb;
        }

        // Compute emission-only source term at _p_
        Lv += Tr * vr->Lve(p, w, ray.time);
    }
    *T = Tr;
    return Lv * step;
}

作用:

(在这里,最主要的计算就是计算

同时也会计算 Tr)

The Li() method is responsible for evaluating the second term of the sum in Equation
 

An estimate of the value of this integral, 

can be found by uniformly selecting random points pi along the ray between t0 and t1
and evaluating the estimator

since for uniformly sampled points p(pi) = 1/(t1− t0). The Lve term in the estimator
can be evaluated directly with the corresponding volumeRegion method, and the optical
thickness τ to evaluate Tr can be evaluated either directly

整体思路:

Figure 16.5:Volume Integration Ray Sampling.

(a) The ray’s extent from t0 to t1 is subdivided(细分) into a
number of segments based on the user-supplied stepSize parameter. A single sample is taken in each
segment, where the first sample is placed randomly in the first segment and all additional samples
are offset by equal-sized steps.

(b) Ray marching tracks the previous point to which transmittance
was computed, pPrev, as well as the current point, p. Initially, pPrev is the point where the ray
enters the volume.

(c) At each subsequent step, beam transmittance is computed as the product of
transmittance to pPrev and the additional transmittance from pPrev to p.

理解:(把 Ray 分成很多段,计算每一段的对应的值,之后再积分起来.)

int nSamples = Ceil2Int((t1-t0) / stepSize);   //ray 从t0 ~ t1 根据步长 stepSize 进行细分ray,ray每一段只采样一个sample的话,就有nSample 个采样点.

float step = (t1 - t0) / nSamples; //这里就是计算新的步长 step,这个step 就是用来 一步一步移动 ray的起点t0

pPrev = p;
p = ray(t0);
Ray tauRay(pPrev, p - pPrev, 0.f, 1.f, ray.time, ray.depth);
Spectrum stepTau = vr->tau(tauRay,
                                   .5f * stepSize, rng.RandomFloat());
Tr *= Exp(-stepTau);

(计算  pPrev 到 P 点之间的 Tr,这个会累积的。)

Lv += Tr * vr->Lve(p, w, ray.time);  // 这里就是直接计算公式中的黎曼合。

return Lv * step; //这里就是 把黎曼合 进行 与 (t1-t0)/N 相乘。

猜你喜欢

转载自blog.csdn.net/aa20274270/article/details/86219040