PBRT_V2 总结记录 <97> DirectLightingIntegrator

DirectLightingIntegrator

enum LightStrategy { SAMPLE_ALL_UNIFORM, SAMPLE_ONE_UNIFORM };
class DirectLightingIntegrator : public SurfaceIntegrator {
public:
    // DirectLightingIntegrator Public Methods
    DirectLightingIntegrator(LightStrategy ls = SAMPLE_ALL_UNIFORM, int md = 5);
    ~DirectLightingIntegrator();
    Spectrum Li(const Scene *scene, const Renderer *renderer,
        const RayDifferential &ray, const Intersection &isect,
        const Sample *sample, RNG &rng, MemoryArena &arena) const;
    void RequestSamples(Sampler *sampler, Sample *sample, const Scene *scene);
private:
    // DirectLightingIntegrator Private Data
    LightStrategy strategy;
    int maxDepth;

    // Declare sample parameters for light source sampling
    LightSampleOffsets *lightSampleOffsets;
    BSDFSampleOffsets *bsdfSampleOffsets;
    int lightNumOffset;
};

类的作用:

(直接光照的积分器,没有间接光照,所有的光线都是来自于光源,忽略物体之间的间接光源)

Before we introduce the light transport equation in its full generality, we will implement
an integrator that accounts for only direct lighting—light that has traveled directly from
a light source to the point being shaded—and ignores indirect illumination from objects
that are not themselves emissive.

 

1. 

enum LightStrategy { SAMPLE_ALL_UNIFORM, SAMPLE_ONE_UNIFORM };

作用:

(提供了两种策略,第一种策略 遍历所有的 光源,每一个光源都 采样 Light::nSamples 次, 第二种策略 随机选择一个光源,只采样一次。其实这两种策略依赖于场景,例如,image一个像素发出的 ray比较多的话,那么第二种策略比较合适,因为每一条ray都会进行采样一次光源,足够信息,而image一个像素发出的ray比较少的话,那么第一种策略比较和是,因为ray比较少,所以需要更加多的sample去采样光源 )

The implementation here provides two different strategies for computing direct lighting.
Each method computes an unbiased estimate of exitant radiance at a point in a given
direction. The LightStrategy enumerant records which approach has been selected.
The first strategy loops over all of the lights and takes a number of samples based on
Light::nSamples from each of them, summing the result. The second takes a single
sample from just one of the lights, chosen at random.

Depending on the scene being rendered, either of these approaches may be more appropriate.
For example, if many image samples are being taken for each pixel (e.g., due to
depth of field), a single light sample may be more appropriate, since in the aggregate
they will sample the direct lighting enough to give a high-quality image. Alternatively, if
few image samples are being taken, sampling all lights may be preferable.

 

 

2. 


void DirectLightingIntegrator::RequestSamples(Sampler *sampler,
        Sample *sample, const Scene *scene) {
    if (strategy == SAMPLE_ALL_UNIFORM) {
        // Allocate and request samples for sampling all lights
        uint32_t nLights = scene->lights.size();
        lightSampleOffsets = new LightSampleOffsets[nLights];
        bsdfSampleOffsets = new BSDFSampleOffsets[nLights];
        for (uint32_t i = 0; i < nLights; ++i) {
            const Light *light = scene->lights[i];
            int nSamples = light->nSamples;
            if (sampler) nSamples = sampler->RoundSize(nSamples);
            lightSampleOffsets[i] = LightSampleOffsets(nSamples, sample);
            bsdfSampleOffsets[i] = BSDFSampleOffsets(nSamples, sample);
        }
        lightNumOffset = -1;
    }
    else {
        // Allocate and request samples for sampling one light
        lightSampleOffsets = new LightSampleOffsets[1];
        lightSampleOffsets[0] = LightSampleOffsets(1, sample);
        lightNumOffset = sample->Add1D(1);
        bsdfSampleOffsets = new BSDFSampleOffsets[1];
        bsdfSampleOffsets[0] = BSDFSampleOffsets(1, sample);
    }
}

作用:

(RequestSample 在申请采样点的时候,是根据策略进行申请的,如果是 策略2(随机选择一个光源,只采样一次),那么 就只需要 1个lightSampleOffset 和 1个 bsdfSampleOffset,并且这个多了一个 ligthNumOffset 主要就是用来随机采样哪一个光源, 如果是策略1(每一个光源都 采样 Light::nSamples 次),那么就需要 nLight 个 lightSampleOffset[nSample] 数组,和 nLight 个 bsdfSampleOffset[nSample] 数组)

The number and types of samples needed by this integrator depend on the sampling
strategy used: if a single sample is taken from a single light, then only one of each of the
LightSampleOffsets and BSDFSampleOffsets object needs to be created; otherwise, one is
allocated for each light source in the scene. These structures handle the mechanics of informing
the sampler of how many samples and of what dimensionality are needed.

Sample patterns are needed both
to select points on light sources and to select BSDF directions for the direct lighting computation;
both sampling approaches are combined with multiple importance sampling
in the implementation below.

 

3. 


Spectrum DirectLightingIntegrator::Li(const Scene *scene,
        const Renderer *renderer, const RayDifferential &ray,
        const Intersection &isect, const Sample *sample, RNG &rng, MemoryArena &arena) const {
    Spectrum L(0.f);
    // Evaluate BSDF at hit point
    BSDF *bsdf = isect.GetBSDF(ray, arena);
    Vector wo = -ray.d;
    const Point &p = bsdf->dgShading.p;
    const Normal &n = bsdf->dgShading.nn;
    // Compute emitted light if ray hit an area light source
    L += isect.Le(wo);

    // Compute direct lighting for _DirectLightingIntegrator_ integrator
    if (scene->lights.size() > 0) {
        // Apply direct lighting strategy
        switch (strategy) {
            case SAMPLE_ALL_UNIFORM:
                L += UniformSampleAllLights(scene, renderer, arena, p, n, wo,
                    isect.rayEpsilon, ray.time, bsdf, sample, rng,
                    lightSampleOffsets, bsdfSampleOffsets);
                break;
            case SAMPLE_ONE_UNIFORM:
                L += UniformSampleOneLight(scene, renderer, arena, p, n, wo,
                    isect.rayEpsilon, ray.time, bsdf, sample, rng,
                    lightNumOffset, lightSampleOffsets, bsdfSampleOffsets);
                break;
        }
    }
    if (ray.depth + 1 < maxDepth) {
        Vector wi;
        // Trace rays for specular reflection and refraction
        L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
                             arena);
        L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample,
                              arena);
    }
    return L;
}

作用:

(计算 Radiance,在这个函数里面,最主要的 根据策略来 使用  UniformSampleAllLights 还是 UniformSampleOneLight,所有的核心都在这两个函数当中了)

The general form of the DirectLightingIntegrator::Li() method is similar to that of
WhittedIntegrator::Li(). The BSDF at the intersection point is computed, emitted radiance
is added if the surface is emissive, and so on.

 

4. 

Spectrum UniformSampleAllLights(const Scene *scene,
        const Renderer *renderer, MemoryArena &arena, const Point &p,
        const Normal &n, const Vector &wo, float rayEpsilon,
        float time, BSDF *bsdf, const Sample *sample, RNG &rng,
        const LightSampleOffsets *lightSampleOffsets,
        const BSDFSampleOffsets *bsdfSampleOffsets) {
    Spectrum L(0.);
    for (uint32_t i = 0; i < scene->lights.size(); ++i) {
        Light *light = scene->lights[i];
        int nSamples = lightSampleOffsets ?
                       lightSampleOffsets[i].nSamples : 1;
        // Estimate direct lighting from _light_ samples
        Spectrum Ld(0.);
        for (int j = 0; j < nSamples; ++j) {
            // Find light and BSDF sample values for direct lighting estimate
            LightSample lightSample;
            BSDFSample bsdfSample;
            if (lightSampleOffsets != NULL && bsdfSampleOffsets != NULL) {
                lightSample = LightSample(sample, lightSampleOffsets[i], j);
                bsdfSample = BSDFSample(sample, bsdfSampleOffsets[i], j);
            }
            else {
                lightSample = LightSample(rng);
                bsdfSample = BSDFSample(rng);
            }
            Ld += EstimateDirect(scene, renderer, arena, light, p, n, wo,
                rayEpsilon, time, bsdf, rng, lightSample, bsdfSample,
                BxDFType(BSDF_ALL & ~BSDF_SPECULAR));
        }
        L += Ld / nSamples;
    }
    return L;
}

作用:(计算 wo 这个方向的 radiance)

(这里的个人理解, 

上面  Ld += EstimateDirect 中就是计算公式的黎曼和部分,而最后的 Ld / nSample 其实就是 执行 公式的 1 / N,

而对于 《PBRT_V2 总结记录 <81> Importance Sampling》, ,

在这个公式中,nf 和 ng 是一致的,所有是可以提取出去的,也就是,Ld += EstimateDirect  执行的就是 两个 黎曼和 的和,而 Ld / nSample 其实就是 执行 公式的 1 / nf (或者是 1 / ng))

 

To understand the approaches implemented by the different strategies, first consider the
part of the direct lighting equation that we’re concerned with here:

This can be broken into a sum over the lights in the scene

where Ld(j ) denotes incident radiance from the j th light and

One valid approach is to estimate each term of this sum individually, adding the results
together. This is the most basic direct lighting strategy and is implemented in
UniformSampleAllLights(), which we have implemented as a global function rather than
a DirectLightingIntegrator method so that other integrators can use it as well.

For each light sample the EstimateDirect() function, to be defined shortly, computes the
value of theMonte Carlo estimator for its contribution. All that has to be done here is to
average the values of the estimates.

 

Having chosen a particular light to estimate direct lighting from, we need to estimate the
value of the integral

for that light. To compute this estimate, we need to choose one or more directions ωj
and apply the Monte Carlo estimator:

 

5. 


Spectrum UniformSampleOneLight(const Scene *scene,
        const Renderer *renderer, MemoryArena &arena, const Point &p,
        const Normal &n, const Vector &wo, float rayEpsilon, float time,
        BSDF *bsdf, const Sample *sample, RNG &rng, int lightNumOffset,
        const LightSampleOffsets *lightSampleOffset,
        const BSDFSampleOffsets *bsdfSampleOffset) {
    // Randomly choose a single light to sample, _light_
    int nLights = int(scene->lights.size());
    if (nLights == 0) return Spectrum(0.);
    int lightNum;
    if (lightNumOffset != -1)
        lightNum = Floor2Int(sample->oneD[lightNumOffset][0] * nLights);
    else
        lightNum = Floor2Int(rng.RandomFloat() * nLights);
    lightNum = min(lightNum, nLights-1);
    Light *light = scene->lights[lightNum];

    // Initialize light and bsdf samples for single light sample
    LightSample lightSample;
    BSDFSample bsdfSample;
    if (lightSampleOffset != NULL && bsdfSampleOffset != NULL) {
        lightSample = LightSample(sample, *lightSampleOffset, 0);
        bsdfSample = BSDFSample(sample, *bsdfSampleOffset, 0);
    }
    else {
        lightSample = LightSample(rng);
        bsdfSample = BSDFSample(rng);
    }
    return (float)nLights *
        EstimateDirect(scene, renderer, arena, light, p, n, wo,
                       rayEpsilon, time, bsdf, rng, lightSample,
                       bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR));
}

作用:

(随机采样一个 光源,然后这个光源所形成的 radiance,radiance * nLights 可以表示 均值,其实类似于 UniformSampleAllLights 只不过大家计算 黎曼和的方式不同,在代码中需要注意的是,lightNumOffset 负责 随机采样一个光源)

In a scene with a large number of lights, it may not be desirable to always compute direct
lighting from all of the lights at every point that is shaded.Monte Carlo gives a way to do
this that still computes the correct result on average. Consider as an example computing
the expected value of the sum of two functions E[f (x) + g(x)]. If we randomly evaluate
just one of f (x) or g(x) and multiply the result by two, then the expected value of
the result will still be f (x) + g(x). In fact, this generalizes to sums of N terms. This
is a straightforward application of conditional probability; see Ross (2002, p. 102) for a
proof. Here we estimate direct lighting for only one randomly chosen light and multiply
the result by the number of lights to compensate(抵消).

 

6. 


Spectrum EstimateDirect(const Scene *scene, const Renderer *renderer,
        MemoryArena &arena, const Light *light, const Point &p,
        const Normal &n, const Vector &wo, float rayEpsilon, float time,
        const BSDF *bsdf, RNG &rng, const LightSample &lightSample,
        const BSDFSample &bsdfSample, BxDFType flags) {
    Spectrum Ld(0.);
    // Sample light source with multiple importance sampling
    Vector wi;
    float lightPdf, bsdfPdf;
    VisibilityTester visibility;
    Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time,
                                  &wi, &lightPdf, &visibility);
    if (lightPdf > 0. && !Li.IsBlack()) {
        Spectrum f = bsdf->f(wo, wi, flags);
        if (!f.IsBlack() && visibility.Unoccluded(scene)) {
            // Add light's contribution to reflected radiance
            Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena);
            if (light->IsDeltaLight())
                Ld += f * Li * (AbsDot(wi, n) / lightPdf);
            else {
                bsdfPdf = bsdf->Pdf(wo, wi, flags);
                float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf);
                Ld += f * Li * (AbsDot(wi, n) * weight / lightPdf);
            }
        }
    }

    // Sample BSDF with multiple importance sampling
    if (!light->IsDeltaLight()) {
        BxDFType sampledType;
        Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &bsdfPdf, flags,
                                    &sampledType);
        if (!f.IsBlack() && bsdfPdf > 0.) {
            float weight = 1.f;
            if (!(sampledType & BSDF_SPECULAR)) {
                lightPdf = light->Pdf(p, wi);
                if (lightPdf == 0.)
                    return Ld;
                weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf);
            }
            // Add light contribution from BSDF sampling
            Intersection lightIsect;
            Spectrum Li(0.f);
            RayDifferential ray(p, wi, rayEpsilon, INFINITY, time);
            if (scene->Intersect(ray, &lightIsect)) {
                if (lightIsect.primitive->GetAreaLight() == light)
                    Li = lightIsect.Le(-wi);
            }
            else
                Li = light->Le(ray);
            if (!Li.IsBlack()) {
                Li *= renderer->Transmittance(scene, ray, NULL, rng, arena);
                Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf;
            }
        }
    }
    return Ld;
}

作用:

(在 EstimateDirect 函数中,选择采用 multiple importance sampling 和 the standard estimator 来进行计算。)

To reduce variance, we will use importance sampling to choose the directions ωj . Because
both the BSDF and the direct radiance terms are individually complex, it can be difficult
to find sampling distributions that match their product well.

By applyingmultiple importance sampling, not only can we use both of the two sampling
methods, but we can also do so in a way that eliminates the extreme variance from these
two situations, since the weighting terms from MIS reduce this variance substantially.

细节

a.

    Vector wi;
    float lightPdf, bsdfPdf;
    VisibilityTester visibility;
    Spectrum Li = light->Sample_L(p, rayEpsilon, lightSample, time,
                                  &wi, &lightPdf, &visibility);
    if (lightPdf > 0. && !Li.IsBlack()) {
        Spectrum f = bsdf->f(wo, wi, flags);
        if (!f.IsBlack() && visibility.Unoccluded(scene)) {
            // Add light's contribution to reflected radiance
            Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena);
            if (light->IsDeltaLight())
                Ld += f * Li * (AbsDot(wi, n) / lightPdf);
            else {
                bsdfPdf = bsdf->Pdf(wo, wi, flags);
                float weight = PowerHeuristic(1, lightPdf, 1, bsdfPdf);
                Ld += f * Li * (AbsDot(wi, n) * weight / lightPdf);
            }
        }
    }

作用:

(在这里需要注意的是, 如果light 是 deltaLight 的话,那么 就直接使用 the standard estimator, 因为 如果light 是deltaLight的话,那么 light的Sample_L (Li)是会 带有 delta distribution,并且 pdf  也带有 delta distribution ,那么在 he standard estimator 是可以 抵消 这两个 delta distribution,

而在 MIS 中,是不能抵消的。

There is a potential pitfall with this convention: when multiple importance sampling is

used to compute weights, PDF values that include these implicit delta distributions can’t

be freely mixed with regular PDF values. This isn’t a problem in practice, since there’s no

reason to apply MIS when there’s a delta distribution in the integrand. The light transport

routines in the next chapter have appropriate logic to be sure to avoid this error.

First, one sample is taken with the light’s sampling distribution using Sample_L(), which
also returns the light’s emitted radiance and the value of the PDF for the sampled direction.
Only if the light successfully samples a direction and returns nonzero emitted
radiance does the function here go ahead and evaluate the BSDF for the two directions;
otherwise, there’s no reason to go through the computational expense. For example, a
spotlight returns zero radiance for points outside its illumination cone. Then only if the
BSDF’s value is nonzero is a shadow ray traced to check for occlusion.

Once it is known that the light is visible and radiance is arriving at the point, the value
of the Monte Carlo estimator can be computed. First, radiance from the light to the
illuminated point is scaled by the beam transmittance between the two points to account
for attenuation due to participating media.

Next, recall from Section 14.6.2 that if the
light is described by a delta distribution then there is an implied delta distribution in both
the emitted radiance value returned from Sample_L() as well as the PDF and that they are
expected to cancel out when the estimator is evaluated.
In this case, we must not try to
applymultiple importance sampling and should compute the standard estimator instead.

If this isn’t a delta distribution light source, then the BSDF::Pdf() method is called to
return the BSDF’s PDF value for sampling the direction ωi, and the MIS estimator is
used, where the weight is computed here with the power heuristic.

 

b.

    // Sample BSDF with multiple importance sampling
    if (!light->IsDeltaLight()) {
        BxDFType sampledType;
        Spectrum f = bsdf->Sample_f(wo, &wi, bsdfSample, &bsdfPdf, flags,
                                    &sampledType);
        if (!f.IsBlack() && bsdfPdf > 0.) {
            float weight = 1.f;
            if (!(sampledType & BSDF_SPECULAR)) {
                lightPdf = light->Pdf(p, wi);
                if (lightPdf == 0.)
                    return Ld;
                weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf);
            }
            // Add light contribution from BSDF sampling
            Intersection lightIsect;
            Spectrum Li(0.f);
            RayDifferential ray(p, wi, rayEpsilon, INFINITY, time);
            if (scene->Intersect(ray, &lightIsect)) {
                if (lightIsect.primitive->GetAreaLight() == light)
                    Li = lightIsect.Le(-wi);
            }
            else
                Li = light->Le(ray);
            if (!Li.IsBlack()) {
                Li *= renderer->Transmittance(scene, ray, NULL, rng, arena);
                Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf;
            }
        }
    }

作用:

(综合上面的代码来看,其实这里就是执行MIS公式

In a similar manner, a sample is now generated using the BSDF’s sampling distribution.
This step can be skipped if the light source is a delta distribution because, in that case,
there’s no chance that sampling the BSDF will give a direction that receives light from the
source. If this is not the case, the BSDF can be sampled. One important detail is that the
light’s PDF and the multiple importance sampling weight are only computed if the BSDF
component used for sampling ωi is non specular; in the specular case, MIS shouldn’t be
applied since there is no chance of the light sampling the specular direction.

Given a direction sampled by the BSDF, we need to find out if the ray along that direction
intersects this particular light source, and if so, howmuch radiance fromthe light reaches
the surface. The codemust account for both regular area lights, with geometry associated
with them, as well as lights like the InfiniteAreaLight that don’t have geometry but need
to return their radiance for the sample ray via the Light::Le() method.

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值