1. 程式人生 > >PBRT_V2 總結記錄 Light 和 VisibilityTester

PBRT_V2 總結記錄 Light 和 VisibilityTester

Light 類

class Light {
public:
    // Light Interface
    virtual ~Light();
    Light(const Transform &l2w, int ns = 1)
        : nSamples(max(1, ns)), LightToWorld(l2w),
          WorldToLight(Inverse(l2w)) {
        // Warn if light has transformation with scale
        if (WorldToLight.HasScale())
            Warning("Scaling detected in world to light transformation!\n"
                    "The system has numerous assumptions, implicit and explicit,\n"
                    "that this transform will have no scale factors in it.\n"
                    "Proceed at your own risk; your image may have errors or\n"
                    "the system may crash as a result of this.");
    }
    virtual Spectrum Sample_L(const Point &p, float pEpsilon,
        const LightSample &ls, float time, Vector *wi, float *pdf,
        VisibilityTester *vis) const = 0;
    virtual Spectrum Power(const Scene *) const = 0;
    virtual bool IsDeltaLight() const = 0;
    virtual Spectrum Le(const RayDifferential &r) const;
    virtual float Pdf(const Point &p, const Vector &wi) const = 0;
    virtual Spectrum Sample_L(const Scene *scene, const LightSample &ls,
                              float u1, float u2, float time, Ray *ray,
                              Normal *Ns, float *pdf) const = 0;
    virtual void SHProject(const Point &p, float pEpsilon, int lmax,
        const Scene *scene, bool computeLightVisibility, float time,
        RNG &rng, Spectrum *coeffs) const;

    // Light Public Data
    const int nSamples;
protected:
    // Light Protected Data
    const Transform LightToWorld, WorldToLight;
};

類的作用:

(光源的基類,這個設計思路基本和 acceleration structures 一致,都是不需要關心具體的光源細節)

This chapter introduces the abstract Light class, which
defines the interface used for light sources in pbrt, as well as the implementations of a
number of useful light sources. By hiding the implementation of different types of lights
behind a carefully designed interface, the light transport routines can operate without
knowing which particular types of lights are in the scene, similar to how the acceleration
structures can hold collections of primitives without needing to know their actual types.

 

1. 建構函式

 Light(const Transform &l2w, int ns = 1)
        : nSamples(max(1, ns)), LightToWorld(l2w),
          WorldToLight(Inverse(l2w)) {
        // Warn if light has transformation with scale
        if (WorldToLight.HasScale())
            Warning("Scaling detected in world to light transformation!\n"
                    "The system has numerous assumptions, implicit and explicit,\n"
                    "that this transform will have no scale factors in it.\n"
                    "Proceed at your own risk; your image may have errors or\n"
                    "the system may crash as a result of this.");
    }



作用:

(所有的Light都會有兩個引數,1個是 transformation l2w, 從光源座標系變換到世界座標系,nSamples 光源的取樣數目,所以建構函式就直接傳入這兩個引數,這裡需要注意的是,光源也有自己的座標系)

All lights share two common parameters: a transformation that defines the light’s coordinate
system in world space and a parameter that affects Monte Carlo sampling of lights,
nSamples.
As with shapes, it’s often handy to be able to implement a light assuming a particular
coordinate system
(e.g., that a spotlight is always located at the origin of its light
space, shining down the +z axis). The light-to-world transformation makes it possible
to place such lights at arbitrary positions and orientations in the scene. The nSamples parameter
is used for area light sources where it may be desirable to trace multiple shadow
rays to the light to compute soft shadows; it allows the user to have finer-grained(粒度) control
of the number of samples taken on a per-light basis.

The only other job for the constructor is to warn if the light-to-world
transformation has a scale factor; many of the Light methods will return incorrect results
in this case.1

 

2. 

virtual Spectrum Sample_L(const Point &p, float pEpsilon,
        const LightSample &ls, float time, Vector *wi, float *pdf,
        VisibilityTester *vis) const = 0;

作用:

(傳入一個world space的 Point,和light sample需要的time引數,那麼這個函式就會返回 一個 radiance,表示光源到達這個點的 radiance(在沒有被其他物體遮擋的情況下),同時也會返回 wi, 表示 光源的radiance 是從哪一個方向到達的,  同時也會 初始化一個 VisibilityTester  來記錄 point 和 光源的 遮擋關係)

(這裡需要注意的是,對於某一些光源,這個光源發射出來的光線可能從很多個方向來到達這個Point,而不只是一個方向,這種情況的話,需要對光源進行取樣,看看這個光源 發出的所有的光線中, 有哪一些是到達Point的。(其實就是對光源進行積分,而不是對Point進行積分))

The key method for lights to implement is Sample_L(). The caller passes the world space
position of a point in the scene and the time at which the light sample is to be taken, and
the light returns the radiance arriving at that point due to that light, assuming there are
no occluding objects between them (Figure 12.1).Although this method also takes a time
value, the Light implementations do not currently support being animated themselves—
the lights themselves are at fixed positions in the scene.
(Addressing this limitation is
left as an exercise.) However, the time value is needed to set the corresponding value
appropriately in the traced visibility ray.

Figure 12.1: The Light::Sample_L() method returns incident radiance from the light at a point p
and also returns the direction vector ω that gives the direction from which radiance is arriving.

 

The light is also responsible for initializing the incident direction to the light source
ωi and for initializing the VisibilityTester object, which holds information about the
shadow ray that must be traced to verify that there are no occluding objects between the
light and p.
The VisibilityTester, which will be described in Section 12.1.1, need not
be initialized if the returned radiance value is black—for example, due to the point p
being outside of the cone of illumination of a spotlight. In addition to the point p being
illuminated, this method takes an epsilon value for shadow rays leaving p, pEpsilon.

 

For some types of lights, light may arrive at p from many directions, not just from
a single direction as with a point light source, for example. For these types of light
sources, the Sample_L() method must randomly sample a point on the light source’s
surface, so thatMonte Carlo integration can be used to find the reflected light at p due to
illumination from the light.
Implementations of the Sample_L() interface for such lights
will be introduced later, in Section 14.6. The LightSample is used by these methods, and
the pdf output parameter stores the probability density for the light sample taken. For
all of the implementations in this chapter, the LightSample is ignored and the pdf is
set to one. The pdf value’s role in the context of Monte Carlo sampling is discussed in
Section 14.6.1.

 

3. virtual Spectrum Power(const Scene *) const = 0;

作用:

All lights must also be able to return their total emitted power; this quantity is useful for
light transport algorithms that may want to devote(貢獻) additional computational resources
to lights in the scene that make the largest contribution.
Because a precise value for
emitted power isn’t needed elsewhere in the system, a number of the implementations of
this method later in this chapter will compute approximations to this value rather than
expending computational effort to find a precise value.

 

4. virtual bool IsDeltaLight() const = 0;

作用:

(這個方法就是用來表明這個光源 是否被描述為 delta distribution,像 point light 和 directional light 都是 delta light,  因為沒有辦法對 這些光源進行取樣,這個方法主要是用來之後的  Monte Carlo algorithms 計算 radiance 的時候,Monte Carlo 要知道這個光源是否是 delta light,如果是 delta light 的話,採用不一樣的計算方式)

Finally, the IsDeltaLight() method indicates(表明) whether the light is described by a delta
distribution. Examples of such lights include point lights, which emit illumination from
a single point, and directional lights, where all light arrives from the same direction.
The
only way to detect illumination from light sources like these is to call their Sample_L()
methods. It’s impossible to randomly choose a direction from a point p that happens to
find such a light source.
(This is analogous to delta components in BSDFs from specular
reflection or transmission.) The Monte Carlo algorithms that sample illumination from
light sources need to be aware of which lights are described by delta distributions, since
this affects some of their computations.

 

 

VisibilityTester 類


struct VisibilityTester {
    // VisibilityTester Public Methods
    void SetSegment(const Point &p1, float eps1,
                    const Point &p2, float eps2, float time) {
        float dist = Distance(p1, p2);
        r = Ray(p1, (p2-p1) / dist, eps1, dist * (1.f - eps2), time);
        Assert(!r.HasNaNs());
    }
    void SetRay(const Point &p, float eps, const Vector &w, float time) {
        r = Ray(p, w, eps, INFINITY, time);
        Assert(!r.HasNaNs());
    }
    bool Unoccluded(const Scene *scene) const;
    Spectrum Transmittance(const Scene *scene, const Renderer *renderer,
        const Sample *sample, RNG &rng, MemoryArena &arena) const;
    Ray r;
};

類的作用:

(這個類主要就是 用來判斷 兩點之間 是否 互相可視,判斷是否有其他物體在他們中間)

The VisibilityTester is a closure(閉包)—an object that encapsulates a small amount of data
and some computation that is yet to be done. It allows lights to return a radiance value
under the assumption that the receiving point p and the light source are mutually(互相) visible.

The integrator can then decide if illumination from the direction ω is relevant before
incurring the cost of tracing the shadow ray—for example, light incident on the back
side of a surface that isn’t translucent(不是透明表面) contributes nothing to reflection from the other
side. If the actual amount of arriving illumination is in fact needed, a call to one of the
visibility tester’s methods causes the necessary shadow ray to be traced.

 

1. 

    void SetSegment(const Point &p1, float eps1,
                    const Point &p2, float eps2, float time) {
        float dist = Distance(p1, p2);
        r = Ray(p1, (p2-p1) / dist, eps1, dist * (1.f - eps2), time);
        Assert(!r.HasNaNs());
    }

    void SetRay(const Point &p, float eps, const Vector &w, float time) {
        r = Ray(p, w, eps, INFINITY, time);
        Assert(!r.HasNaNs());
    }

作用:

(初始化 VisibilityTesters 的函式,

SetSegment, 表明 一個兩點之間的視覺化測試,

SetRay 表明 是否有其他物體 與 Ray 進行相交)

There are two methods that initialize VisibilityTesters. The first of them, Visibility
Tester::SetSegment(), indicates that the visibility test is to be done between two points
in the scene.
In addition to the two points, it takes “epsilon” values to offset the ray’s
starting point and ending point, respectively.

The other initialization method, VisibilityTester::SetRay(), indicates that the test
should indicate whether there is any object along a given direction.
This variant is useful
for computing shadows from directional lights.

 

2. 

bool VisibilityTester::Unoccluded(const Scene *scene) const {
    return !scene->IntersectP(r);
}

作用:

(其實這個就是判斷 兩點之間是否可視,或者ray方向是否與一個物體方法碰撞)

The next pair of methods trace the appropriate ray. The first one, VisibilityTester::
Unoccluded() traces the shadow ray and returns a Boolean result. Some ray tracers
include a facility for casting colored shadows from partially transparent objects and
would return a spectrum from a method like this. pbrt does not include this facility
explicitly, since those systems typically implement it with a nonphysical hack. Thus, the
VisibilityTester::Unoccluded() method here returns a Boolean.
Scenes where illumination
passes through a transparent object should be rendered with an integrator that
supports this kind of effect, like the PhotonIntegrator described in Section 15.6.

 

 

3. 

Spectrum VisibilityTester::Transmittance(const Scene *scene,
        const Renderer *renderer, const Sample *sample,
        RNG &rng, MemoryArena &arena) const {
    return renderer->Transmittance(scene, RayDifferential(r), sample,
                                   rng, arena);
}

作用:

(返回經過  participating media ,還剩下百分之多少的 illumination)

VisibilityTester::Transmittance() determines the fraction of illumination from the
light to the point that is not extinguished(滅絕) by participating media in the scene. If the scene
has no participating media, this method returns a constant spectral value of one.