PBRT_V2 总结记录 <4> WhittedIntegrator

WhittedIntegrator 类

// WhittedIntegrator Declarations
class WhittedIntegrator : public SurfaceIntegrator {
public:
    // WhittedIntegrator Public Methods
    Spectrum Li(const Scene *scene, const Renderer *renderer,
        const RayDifferential &ray, const Intersection &isect, const Sample *sample,
        RNG &rng, MemoryArena &arena) const;
    WhittedIntegrator(int md) {
        maxDepth = md;
    }
private:
    // WhittedIntegrator Private Data
    int maxDepth;
};

类的作用 : (WhittedIntegrator 主要就是用来 计算 光的反射和传输 针对于表面是光滑的物体 ,像玻璃,镜子,水表面,但是没有间接光,只有直接光)

Here we will present a surface integrator based on Whitted’s ray-tracing algorithm. This integrator
accurately computes reflected and transmitted light from specular surfaces like
glass, mirrors, and water, although it doesn’t account for other types of indirect lighting
effects like light bouncing off a wall and illuminating a room.

Spectrum Li(const Scene *scene, const Renderer *renderer,
        const RayDifferential &ray, const Intersection &isect, const Sample *sample,
        RNG &rng, MemoryArena &arena) const;

作用:(这个方法是所有surface integrators最重要的方法,主要用来计算  radiance )

The key method that all surface integrators must provide is SurfaceIntegrator::Li(),
which returns the radiance along a ray

代码细节:

Spectrum WhittedIntegrator::Li(const Scene *scene,
        const Renderer *renderer, const RayDifferential &ray,
        const Intersection &isect, const Sample *sample, RNG &rng,
        MemoryArena &arena) const {
    Spectrum L(0.);
    // Compute emitted and reflected light at ray intersection point

    // Evaluate BSDF at hit point
    BSDF *bsdf = isect.GetBSDF(ray, arena);

    // Initialize common variables for Whitted integrator
    const Point &p = bsdf->dgShading.p;
    const Normal &n = bsdf->dgShading.nn;
    Vector wo = -ray.d;

    // Compute emitted light if ray hit an area light source
    L += isect.Le(wo);

    // Add contribution of each light source
    for (uint32_t i = 0; i < scene->lights.size(); ++i) {
        Vector wi;
        float pdf;
        VisibilityTester visibility;
        Spectrum Li = scene->lights[i]->Sample_L(p, isect.rayEpsilon,
            LightSample(rng), ray.time, &wi, &pdf, &visibility);

        if (Li.IsBlack() || pdf == 0.f) continue;

        Spectrum f = bsdf->f(wo, wi);
        if (!f.IsBlack() && visibility.Unoccluded(scene))
            L += f * Li * AbsDot(wi, n) *
                 visibility.Transmittance(scene, renderer,
                                          sample, rng, arena) / pdf;
    }
    if (ray.depth + 1 < maxDepth) {
        // 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;
}

a.

BSDF 类:

(bidirectional scattering distribution functions 描述了 一个表面是怎么反射 光线的,它本质上概述了 镜子和油漆等,诸如此类 外观的差别,BSDF类就是 代表 bidirectional scattering distribution functions,BSDF类 可以计算表面上一个点的反射光,一个表面的每一个点的可能有不同的BSDF。)

Recall that bidirectional scattering distribution functions describe how a surface reflects
light arriving at its boundary;
they essentially encapsulate(概述) the difference(差别) between the
appearance of a mirror versus(与) colored paint, and so forth. They are represented in pbrt
by the BSDF class. pbrt provides BSDF implementations for several standard scattering
functions used in computer graphics, such as Lambertian reflection and the Torrance–
Sparrow microfacet model.These and other reflection models are described in Chapter 8.

The BSDF interface makes it possible to compute reflected light at a single surface point,
but BSDFs may vary across a surface. Surfaces with complex material properties, such
as wood or marble, have a different BSDF at each point.
Even if wood is modeled as
being perfectly diffuse, the color at each point will depend on the wood’s grain. These
spatial variations of shading parameters are described with Textures, which in turn may
be described procedurally or stored in image maps (Chapter 10).

b.

BSDF *bsdf = isect.GetBSDF(ray, arena);

作用:(获得表面上一个点的BSDF)

To obtain the BSDF at the hit point。

c.

 Spectrum Li = scene->lights[i]->Sample_L(p, isect.rayEpsilon,
            LightSample(rng), ray.time, &wi, &pdf, &visibility);

作用:(计算 光源到达 表面上的点 的radiance,同时计算 表面上的点 指向 光源的方向 wi。)

For each light, the integrator calls the Light::Sample_L() method to compute the radiance
from that light falling on the surface at the point being shaded.
This method also
returns the direction vector from the point being shaded to the light source, which is
stored in the variable wi
(denoting an incident direction ωi).

The spectrum returned by this method does not account for the possibility that some
other shape may block light from the light and prevent it from reaching the point being
shaded. Instead, it returns a VisibilityTester object that can be used to determine if
any primitives block the surface point from the light source. This test is done by tracing
a shadow ray between the point being shaded and the light to verify that the path is clear.
pbrt’s code is organized in this way so that it can avoid tracing the shadow ray unless
necessary. Specifically, this way it can first make sure that the light falling on the surface
would be scattered in the direction ωo if the light isn’t blocked. For example, if the surface
is not transmissive, then light arriving at the back side of the surface doesn’t contribute
to reflection.

The Sample_L() method also returns the probability density for the light to have sampled
the direction wi in the pdf variable. This value is used for Monte Carlo integration with
complex area light sources where light is arriving at the point from many directions even
though just one direction is sampled here; for simple lights like point lights, the value of
pdf is one. The details of how this probability density is computed and used in rendering
are the topic of Chapters 13 to 15; in the end, the light’s contribution must be divided by
pdf, so this is done by the implementation here.

d.

Spectrum f = bsdf->f(wo, wi);

作用:(可以理解为,利用 wo,wi来获得 bidirectional scattering distribution functions 的一个值,这个值用Spectrum来表示,Spectrum可以理解为RGB,为什么用Spectrum来表示 bidirectional scattering distribution functions 的一个值。

个人理解就是,这里的RGB(Spectrum) 其实代表的就是材质表面对光颜色的R,G,B的吸收程度,例如 返回的 RGB(Spectrum) = (1, 0.5, 0)的话,表示的就是,这个表面材质对 光线颜色的 R 不进行吸收,对G吸收一半, B全部吸收,光线到达这个表面时,因为R不吸收,所以R全部反射,因为G吸收一半,所以G就反射了一半,因为B全部吸收,所以B一点都不反射)

It returns the value of the distribution function for the given pair of directions.

bidirectional scattering distribution functions : how much incident light along wi is scattered from the surface in the direction wo

e.

L += SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
arena);
L += SpecularTransmit(ray, bsdf, rng, isect, renderer, scene, sample,
arena);

作用: (递归地计算镜面反射和折射)

This integrator also handles light scattered by perfectly specular surfaces like mirrors
or glass. It is fairly simple to use properties of mirrors to find the reflected directions
(Figure 1.21), and to use Snell’s law to find the transmitted directions (Section 8.2).
The
integrator can then recursively follow the appropriate ray in the new direction and add its
contribution to the reflected radiance at the point originally seen from the camera. The
computation of the effect of specular reflection and transmission is handled in separate
utility functions so these functions can easily be reused by other Integrators.

d.

SpecularReflect(ray, bsdf, rng, isect, renderer, scene, sample,
arena);

Spectrum SpecularReflect(const RayDifferential &ray, BSDF *bsdf,
	RNG &rng, const Intersection &isect, const Renderer *renderer,
	const Scene *scene, const Sample *sample, MemoryArena &arena) {
	Vector wo = -ray.d, wi;
	float pdf;
	const Point &p = bsdf->dgShading.p;
	const Normal &n = bsdf->dgShading.nn;

	Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf,
		BxDFType(BSDF_REFLECTION | BSDF_SPECULAR));

	Spectrum L = 0.f;
	if (pdf > 0.f && !f.IsBlack() && AbsDot(wi, n) != 0.f) {
		// Compute ray differential _rd_ for specular reflection
		RayDifferential rd(p, wi, ray, isect.rayEpsilon);
		if (ray.hasDifferentials) {
			rd.hasDifferentials = true;
			rd.rxOrigin = p + isect.dg.dpdx;
			rd.ryOrigin = p + isect.dg.dpdy;
			// Compute differential reflected directions
			Normal dndx = bsdf->dgShading.dndu * bsdf->dgShading.dudx +
				bsdf->dgShading.dndv * bsdf->dgShading.dvdx;
			Normal dndy = bsdf->dgShading.dndu * bsdf->dgShading.dudy +
				bsdf->dgShading.dndv * bsdf->dgShading.dvdy;
			Vector dwodx = -ray.rxDirection - wo, dwody = -ray.ryDirection - wo;
			float dDNdx = Dot(dwodx, n) + Dot(wo, dndx);
			float dDNdy = Dot(dwody, n) + Dot(wo, dndy);
			rd.rxDirection = wi - dwodx + 2 * Vector(Dot(wo, n) * dndx +
				dDNdx * n);
			rd.ryDirection = wi - dwody + 2 * Vector(Dot(wo, n) * dndy +
				dDNdy * n);
		}
		Spectrum Li = renderer->Li(scene, rd, sample, rng, arena);
		L = f * Li * AbsDot(wi, n) / pdf;
	}
	return L;
}

Spectrum f = bsdf->Sample_f(wo, &wi, BSDFSample(rng), &pdf,
        BxDFType(BSDF_REFLECTION | BSDF_SPECULAR));

作用:(有 bsdf->f(), 为什么会有 bsdf->Sample_f(), 因为不是所有的 bsdf 都可以利用 wi, wo来获得一个反射值,像一些镜面反射只会反射某一个方向的,类似这样的镜面反射的BSDF用 delta distributions 来描述是最好的,所以,PBRT就专门用 Sample_f 来特殊处理这些 delta distributions 的 BSDF,Sample_f() 与f() 不同的还有的就是,Sample_f() 会计算wi)

Not all BxDFs can be evaluated with the f() method. For example, perfectly specular
objects like a mirror, glass, or water only scatter light from a single incident direction
into a single outgoing direction. Such BxDFs are best described with delta distributions
that are zero except for the single direction where light is scattered.

These BxDFs need special handling in pbrt, so we will also provide the meuothod BxDF::
Sample_f(). This method is used both for handling scattering that is described by delta
distributions as well as for randomly sampling directions from BxDFs that scatter light
along multiple directions;

BxDF::Sample_f() computes the direction of
incident light ωi given an outgoing direction ωo and returns the value of the BxDF for the
given pair of directions. For delta distributions, it is necessary for the BxDF to choose
the incident light direction in this way, since the caller has no chance of generating
the appropriate ωi direction.

This method returns the sampled direction in *wi and returns the value of p(ωi) in
*pdf. The value of the BSDF for the chosen direction is returned with a Spectrum return
value. The PDF value returned should be measured with respect to solid angle on the
hemisphere, and both the outgoing direction ωo and the sampled incident direction
ωi should be in the standard reflection coordinate system.

The default implementation of this method samples the unit hemisphere with a cosineweighted
distribution.

猜你喜欢

转载自blog.csdn.net/aa20274270/article/details/82930943
今日推荐