1. 程式人生 > >PBRT_V2 總結記錄 Procedural Texturing

PBRT_V2 總結記錄 Procedural Texturing

Solid Texture And Procedural Texturing :

it is natural to generalize texture functions to be defined
over three-dimensional domains (often called solid textures) rather than just 2D (s , t).

Solid textures introduce a new problem, however: texture representation. A threedimensional
image map takes up a fair amount of storage space and is much harder to
acquire than a two-dimensional texture map, which can be extracted from photographs or painted by an artist.

Therefore, procedural texturing—the idea that programs could
be executed to generate texture values at arbitrary positions on surfaces in the scene—
came into use at the same time that solid texturing was developed.

(Solid Texture 的 texture functions 定義在 三維空間,但是由於 這樣的三維空間image 佔用 儲存空間較大,所以 就引入了 procedural texturing,procedural texturing 其實就是 計算texture的值出來,而不是從圖片中取值)

 

UVTexture 類


// UVTexture Declarations
class UVTexture : public Texture<Spectrum> {
public:
    // UVTexture Public Methods
    UVTexture(TextureMapping2D *m) {
        mapping = m;
    }
    ~UVTexture() {
        delete mapping;
    }
    Spectrum Evaluate(const DifferentialGeometry &dg) const {
        float s, t, dsdx, dtdx, dsdy, dtdy;
        mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy);
        float rgb[3] = { s - Floor2Int(s), t - Floor2Int(t), 0.f };
        return Spectrum::FromRGB(rgb);
    }
private:
    TextureMapping2D *mapping;
};

作用:

(UVTexture 是一個 procedural texture,u 表示 紅色,v 表示 綠色)

Our first procedural texture converts the surface’s (u, v) coordinates into the red and
green components of a Spectrum It is especially useful when debugging
the parameterization of a new Shape。
(The u parameter is
mapped to the red channel, and the v parameter is mapped to green.)

 

Checkerboard2DTexture 類

template <typename T> class Checkerboard2DTexture : public Texture<T> {
public:
    // Checkerboard2DTexture Public Methods
    Checkerboard2DTexture(TextureMapping2D *m, Reference<Texture<T> > c1,
                          Reference<Texture<T> > c2, const string &aa)
        : mapping(m), tex1(c1), tex2(c2) {
        // Select antialiasing method for _Checkerboard2DTexture_
        if (aa == "none")             aaMethod = NONE;
        else if (aa == "closedform")  aaMethod = CLOSEDFORM;
        else {
            Warning("Antialiasing mode \"%s\" not understood by "
                    "Checkerboard2DTexture; using \"closedform\"", aa.c_str());
            aaMethod = CLOSEDFORM;
        }
    }
    ~Checkerboard2DTexture() {
        delete mapping;
    }
    T Evaluate(const DifferentialGeometry &dg) const {
        float s, t, dsdx, dtdx, dsdy, dtdy;
        mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy);
        if (aaMethod == NONE) {
            // Point sample _Checkerboard2DTexture_
            if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                return tex1->Evaluate(dg);
            return tex2->Evaluate(dg);
        }
        else {
            // Compute closed-form box-filtered _Checkerboard2DTexture_ value

            // Evaluate single check if filter is entirely inside one of them
            float ds = max(fabsf(dsdx), fabsf(dsdy));
            float dt = max(fabsf(dtdx), fabsf(dtdy));
            float s0 = s - ds, s1 = s + ds;
            float t0 = t - dt, t1 = t + dt;
            if (Floor2Int(s0) == Floor2Int(s1) && Floor2Int(t0) == Floor2Int(t1)) {
                // Point sample _Checkerboard2DTexture_
                if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                    return tex1->Evaluate(dg);
                return tex2->Evaluate(dg);
            }

            // Apply box filter to checkerboard region
#define BUMPINT(x) \
                (Floor2Int((x)/2) + \
                 2.f * max((x/2)-Floor2Int(x/2) - .5f, 0.f))
            float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds);
            float tint = (BUMPINT(t1) - BUMPINT(t0)) / (2.f * dt);
            float area2 = sint + tint - 2.f * sint * tint;
            if (ds > 1.f || dt > 1.f)
                area2 = .5f;
            return (1.f - area2) * tex1->Evaluate(dg) +
                   area2         * tex2->Evaluate(dg);
        }
    }
private:
    // Checkerboard2DTexture Private Data
    TextureMapping2D *mapping;
    Reference<Texture<T> > tex1, tex2;
    enum { NONE, CLOSEDFORM } aaMethod;
};

類的作用:

(棋盤紋理)

The checkerboard is the canonical(標準) procedural texture . The (s , t) texture
coordinates are used to break up(打碎) parameter space into square regions that are shaded with
alternating patterns. Rather than just supporting checkerboards that switch between two
fixed colors, the implementation here allows the user to pass in two textures to color the
alternating regions. The traditional black-and-white checkerboard is obtained by passing
two ConstantTextures.

 

1. 建構函式

    Checkerboard2DTexture(TextureMapping2D *m, Reference<Texture<T> > c1,
                          Reference<Texture<T> > c2, const string &aa)
        : mapping(m), tex1(c1), tex2(c2) {
        // Select antialiasing method for _Checkerboard2DTexture_
        if (aa == "none")             aaMethod = NONE;
        else if (aa == "closedform")  aaMethod = CLOSEDFORM;
        else {
            Warning("Antialiasing mode \"%s\" not understood by "
                    "Checkerboard2DTexture; using \"closedform\"", aa.c_str());
            aaMethod = CLOSEDFORM;
        }
    }

作用:

(建構函式也是傳入 aa 引數,來用棋盤紋理來測試各種抗鋸齒方法)

For simplicity, the frequency of the check function is 1 in (s , t) space: checks are one
unit wide in each direction. The effective frequency can always be changed by the
TextureMapping2D class with an appropriate scale of the (s , t) coordinates.

The checkerboard is good for demonstrating trade-offs(權衡) between various antialiasing(抗鋸齒) approaches
for procedural textures. The implementation here supports both simple point
sampling (no antialiasing) and a closed-form box filter evaluated over the filter region

 

 

2. T Evaluate(const DifferentialGeometry &dg) const

    T Evaluate(const DifferentialGeometry &dg) const {
        float s, t, dsdx, dtdx, dsdy, dtdy;
        mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy);
        if (aaMethod == NONE) {
            // Point sample _Checkerboard2DTexture_
            if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                return tex1->Evaluate(dg);
            return tex2->Evaluate(dg);
        }
        else {
            // Compute closed-form box-filtered _Checkerboard2DTexture_ value

            // Evaluate single check if filter is entirely inside one of them
            float ds = max(fabsf(dsdx), fabsf(dsdy));
            float dt = max(fabsf(dtdx), fabsf(dtdy));
            float s0 = s - ds, s1 = s + ds;
            float t0 = t - dt, t1 = t + dt;
            if (Floor2Int(s0) == Floor2Int(s1) && Floor2Int(t0) == Floor2Int(t1)) {
                // Point sample _Checkerboard2DTexture_
                if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                    return tex1->Evaluate(dg);
                return tex2->Evaluate(dg);
            }

            // Apply box filter to checkerboard region
#define BUMPINT(x) \
                (Floor2Int((x)/2) + \
                 2.f * max((x/2)-Floor2Int(x/2) - .5f, 0.f))
            float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds);
            float tint = (BUMPINT(t1) - BUMPINT(t0)) / (2.f * dt);
            float area2 = sint + tint - 2.f * sint * tint;
            if (ds > 1.f || dt > 1.f)
                area2 = .5f;
            return (1.f - area2) * tex1->Evaluate(dg) +
                   area2         * tex2->Evaluate(dg);
        }
    }

作用:

The evaluation routine does the usual texture coordinate and differential(微分) computation
and then uses the appropriate fragment to compute an antialiased checkerboard value
(or not antialiased, if point sampling has been selected).

 

細節

a.

        if (aaMethod == NONE) {
            // Point sample _Checkerboard2DTexture_
            if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                return tex1->Evaluate(dg);
            return tex2->Evaluate(dg);
        }

作用:

(沒有抗鋸齒的情況下,直接利用 s,t 從 tex1 和 tex2 取值)

The simplest case is to ignore antialiasing and just point-sample the checkerboard texture
at the point.
For this case, after getting the (s , t) texture coordinates from the
TextureMapping2D, the integer checkerboard coordinates for that (s , t) position are computed,
added together, and checked for odd or even parity to determine which of the two
textures to evaluate.

 

b.

            // Evaluate single check if filter is entirely inside one of them
            float ds = max(fabsf(dsdx), fabsf(dsdy));
            float dt = max(fabsf(dtdx), fabsf(dtdy));
            float s0 = s - ds, s1 = s + ds;
            float t0 = t - dt, t1 = t + dt;
            if (Floor2Int(s0) == Floor2Int(s1) && Floor2Int(t0) == Floor2Int(t1)) {
                // Point sample _Checkerboard2DTexture_
                if ((Floor2Int(s) + Floor2Int(t)) % 2 == 0)
                    return tex1->Evaluate(dg);
                return tex2->Evaluate(dg);
            }

作用:

(當 整個 filter 區域都在一個 棋盤格子的時候,就直接不進行抗鋸齒,那麼,怎麼判斷 整個 filter 區域都在一個 棋盤格子呢?主要的思路就是 計算 filter 的 包圍盒,判斷這個包圍盒的四個角 是否在 同一個格子裡面,怎麼計算這個包圍盒,主要就是利用 偏導數來計算)

The easiest case happens when the entire filter region
lies inside a single check (Figure 10.19). In this case, we simply need to determine which
of the check types we are inside and evaluate that one. As long as the Texture inside that
check does appropriate antialiasing itself, the result for this case will be antialiased.

It’s straightforward to check if the entire filter region is inside a single check by computing
its bounding box and seeing if its extent lies inside the same check.
For the remainder of
this section, we will use the axis-aligned bounding box of the filter region given by the
partial derivatives ∂s/∂x, ∂s/∂y, and so on, as the area to filter over,
rather than trying to
filter over the ellipse defined by the partial derivatives as the EWA filter did (Figure 10.20).
This simplifies the implementation here, although somewhat increases the blurriness of
the filtered values. The variables ds and dt in the following hold half the filter width in
each direction, so the total area filtered over ranges from (s-ds, t-dt) to (s+ds, t+dt).

 

Figure 10.19: The Easy Case for Filtering the Checkerboard. If the filter region around the lookup
point is entirely in one check, the checkerboard texture doesn’t need to worry about antialiasing and
can just evaluate the texture for that check.

 

c.

            #define BUMPINT(x) \
                (Floor2Int((x)/2) + \
                 2.f * max((x/2)-Floor2Int(x/2) - .5f, 0.f))
            float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds);
            float tint = (BUMPINT(t1) - BUMPINT(t0)) / (2.f * dt);
            float area2 = sint + tint - 2.f * sint * tint;
            if (ds > 1.f || dt > 1.f)
                area2 = .5f;
            return (1.f - area2) * tex1->Evaluate(dg) +
                   area2         * tex2->Evaluate(dg);

作用:

(這種情況就是,filter 是跨越 多個 棋盤網格,目的就是要計算 哪一種棋盤格子 佔用 filter 多少區域, 知道了 佔用的  百分比就可以進行 混合了。

因為 棋盤 是一個 2D step function, 就是下面的 c(x),  計算哪一種棋盤格子佔用 filter 多少區域,其實就是計算  2D step function 的平均值,因為計算出來的平均值肯定是 [0,1],因為格子不是0, 就是1 ,全部格子相加 再除以 格子的數量,肯定是 [0,1], 那麼,平均值就可以表明 1 的格子佔用了百分之多少.

BUMPINT 就是 c(x) 的積分, BUMPINT(s0) 表示  從0開始,到 s0 之間 有多少個 "1"格子

float sint = (BUMPINT(s1) - BUMPINT(s0)) / (2.f * ds);  sint 表示 s0-s1 之間平均有多少  "1"格子

float area2 = sint + tint - 2.f * sint * tint;

因為 sint 表示 s0-s1 之間平均有多少  "1"格子, tint 表示 t0-t1 之間平均有多少  "1"格子,

那麼  area2 表示的意思就是,sint + tint - 2 * sint * tint = (sint) *(1 - tint) + (1-sint) * tint,  =  "1" 格子 總面積 

the lookup method approximates the filtered value by first computing a
floating-point value that indicates what fraction of the filter region covers each of the
two check types.
This is equivalent to computing the average of the 2D step function that
takes on the value 0 when we are in tex1 and 1 whenwe are in tex2, over the filter region.

Figure 10.21(a) shows a graph of the checkerboard function c(x), defined as

 

 

Given the average value, we can blend between the two subtextures, according to what
fraction of the filter region each one is visible for.

The integral of the 1D checkerboard function c(x) can be used to compute the average
value of the function over some extent.
Inspection of the graph reveals that

To compute the average value of the step function in two dimensions, we separately
compute the integral of the checkerboard in each 1D direction in order to compute its
average value over the filter region.

 

Checkerboard3DTexture 類


template <typename T> class Checkerboard3DTexture : public Texture<T> {
public:
    // Checkerboard3DTexture Public Methods
    Checkerboard3DTexture(TextureMapping3D *m, Reference<Texture<T> > c1,
                          Reference<Texture<T> > c2)
        : mapping(m), tex1(c1), tex2(c2) {
    }
    ~Checkerboard3DTexture() {
        delete mapping;
    }
    T Evaluate(const DifferentialGeometry &dg) const {
        Vector dpdx, dpdy;
        Point p = mapping->Map(dg, &dpdx, &dpdy);
        if ((Floor2Int(p.x) + Floor2Int(p.y) + Floor2Int(p.z)) % 2 == 0)
            return tex1->Evaluate(dg);
        else
            return tex2->Evaluate(dg);
    }
private:
    // Checkerboard3DTexture Private Data
    TextureMapping3D *mapping;
    Reference<Texture<T> > tex1, tex2;
};

類的作用:

(利用 Point 進行 取樣 tex1 和tex2)

We can also define a solid checkerboard pattern
based on three-dimensional texture coordinates so that the object appears carved(雕刻) out
of 3D checker cubes 。Like the 2D variant, this implementation chooses
between texture functions based on the lookup position. Note that these two textures
need not be solid textures themselves; the Checkerboard3DTexture merely(只不過) chooses between
them based on the 3D position of the point.

Ignoring antialiasing, the basic computation to see if a point is inside a 3D checker
region is
((Floor2Int(P.x) + Floor2Int(P.y) + Floor2Int(P.z)) % 2 == 0).
The Checkerboard3DTexture doesn’t have any built-in support for antialiasing.