1. 程式人生 > >PBRT_V2 總結記錄 MIPMap.Lookup (Triangle Filter)

PBRT_V2 總結記錄 MIPMap.Lookup (Triangle Filter)

 MIPMap.Lookup

template <typename T>
T MIPMap<T>::Lookup(float s, float t, float width) const {
    // Compute MIPMap level for trilinear filtering
    float level = nLevels - 1 + Log2(max(width, 1e-8f));

    // Perform trilinear interpolation at appropriate MIPMap level
    PBRT_MIPMAP_TRILINEAR_FILTER(const_cast<MIPMap<T> *>(this), s, t, width, level, nLevels);
    if (level < 0)
        return triangle(0, s, t);
    else if (level >= nLevels - 1)
        return Texel(nLevels-1, 0, 0);
    else {
        uint32_t iLevel = Floor2Int(level);
        float delta = level - iLevel;
        return (1.f-delta) * triangle(iLevel, s, t) +
               delta * triangle(iLevel+1, s, t);
    }
}


template <typename T>
T MIPMap<T>::triangle(uint32_t level, float s, float t) const {
    level = Clamp(level, 0, nLevels-1);
    s = s * pyramid[level]->uSize() - 0.5f;
    t = t * pyramid[level]->vSize() - 0.5f;
    int s0 = Floor2Int(s), t0 = Floor2Int(t);
    float ds = s - s0, dt = t - t0;
    return (1.f-ds) * (1.f-dt) * Texel(level, s0, t0) +
           (1.f-ds) * dt       * Texel(level, s0, t0+1) +
           ds       * (1.f-dt) * Texel(level, s0+1, t0) +
           ds       * dt       * Texel(level, s0+1, t0+1);
}


作用:

(個人理解,Lookup 採用三線性取樣,思路: 先利用引數width(a texel spacing width),來確定MIPMap的哪一層(level層),再用 雙線性插值 混合 第 level 層 (s,t)座標附近4個texel 的值,得到v0,  同樣的方法混合 第 level + 1 層的 (s,t) 附近4個texel,得到 v1, 之後再混合 v0 和 v1 ,得到最終的值)

The first of the two MIPMap::Lookup() methods uses a triangle filter over the texture
samples to remove high frequencies.

Although this filter function does not give highquality
results, it can be implemented very efficiently. In addition to the (s , t) coordinates
of the evaluation point, the caller passes this method a filter width for the lookup, giving
the extent of the region of the texture to filter across. This method filters over a square
region in texture space, so the width should be conservatively chosen to avoid aliasing
in both the s and t directions. Filtering techniques like this one that do not support a
filter extent that is nonsquare or non-axis-aligned are known as isotropic.
The primary
disadvantage of isotropic filtering algorithms is that textures viewed at an oblique angle
will appear blurry, since the required sampling rate along one axis will be very different
from the sampling rate along the other in this case.

Because filtering over many texels for wide filter widths would be inefficient, this method
chooses a MIP map level from the pyramid such that the filter region at that level would
cover four texels at that level.
Figure 10.13 illustrates this idea.

Figure 10.13: Choosing a MIP Map Level for the Triangle Filter. The MIPMap chooses a level such
that the filter covers four texels.

 

細節

1.

    // Compute MIPMap level for trilinear filtering
    float level = nLevels - 1 + Log2(max(width, 1e-8f));

:(利用 引數 w ,w是texel的寬度,計算出 哪一層的 texel 寬度是 w )

Since the resolutions of the levels of the pyramid are all powers of two, the resolution of
level L is 2^(nLevels−1−L) . Therefore, to find the level with a texel spacing width w requires
solving

for L. In general, this will be a floating-point value between two MIP map levels.

 

(推導:

log2 (1/w) = nlevels - 1 - l

- log2(w) = nlevels - 1 - l   (由於 loga (M^n) = n * loga M)

l = nlevel - 1 + log2(w)

 

2. 

    if (level < 0)
        return triangle(0, s, t);
    else if (level >= nLevels - 1)
        return Texel(nLevels-1, 0, 0);
    else {
        uint32_t iLevel = Floor2Int(level);
        float delta = level - iLevel;
        return (1.f-delta) * triangle(iLevel, s, t) +
               delta * triangle(iLevel+1, s, t);
    }

:

(像上面所說的,這裡就是混合 v0 和 v1,得到最後的值,然而,怎麼得到 v0 和 v1的就在 triangle 函式中)

As shown by Figure 10.13, applying a triangle filter to the four texels around the sample
point will either filter over too small a region or too large a region (except for very carefully
selected filter widths). The implementation here applies the triangle filter at both of
these levels and blends between them according to how close level is to each of them.

This helps hide the transitions from one MIP map level to the next at nearby pixels in
the final image.While applying a triangle filter to four texels at two levels in this manner
doesn’t give exactly the same result as applying it to the original highest-resolution texels,
the difference isn’t too bad in practice and the efficiency of this approach is worth this
penalty.
In any case, the elliptically weighted average filtering in the next section should
be used when texture quality is important.

 

3. 

template <typename T>
T MIPMap<T>::triangle(uint32_t level, float s, float t) const {
    level = Clamp(level, 0, nLevels-1);
    s = s * pyramid[level]->uSize() - 0.5f;
    t = t * pyramid[level]->vSize() - 0.5f;
    int s0 = Floor2Int(s), t0 = Floor2Int(t);
    float ds = s - s0, dt = t - t0;
    return (1.f-ds) * (1.f-dt) * Texel(level, s0, t0) +
           (1.f-ds) * dt       * Texel(level, s0, t0+1) +
           ds       * (1.f-dt) * Texel(level, s0+1, t0) +
           ds       * dt       * Texel(level, s0+1, t0+1);
}

template <typename T>
const T &MIPMap<T>::Texel(uint32_t level, int s, int t) const {
    Assert(level < nLevels);
    const BlockedArray<T> &l = *pyramid[level];
    // Compute texel $(s,t)$ accounting for boundary conditions
    switch (wrapMode) {
        case TEXTURE_REPEAT:
            s = Mod(s, l.uSize());
            t = Mod(t, l.vSize());
            break;
        case TEXTURE_CLAMP:
            s = Clamp(s, 0, l.uSize() - 1);
            t = Clamp(t, 0, l.vSize() - 1);
            break;
        case TEXTURE_BLACK: {
            static const T black = 0.f;
            if (s < 0 || s >= (int)l.uSize() ||
                t < 0 || t >= (int)l.vSize())
                return black;
            break;
        }
    }
    PBRT_ACCESSED_TEXEL(const_cast<MIPMap<T> *>(this), level, s, t);
    return l(s, t);
}

作用:

(這裡就是上面所說的,用 雙線性插值 混合 第 level 層 (s,t)座標附近4個texel 的值,得到v0, 這裡值得注意的是,傳進來的引數 s,t 是紋理座標,範圍是【0,1】,這裡 s * pyramid[level]->uSize() 就是把 【0,1】 -> 【0, imageResolution】)

Given floating-point texture coordinates in [0, 1]2, the MIPMap::triangle() routine uses
a triangle filter to interpolate between the four texels that surround the sample point,
as shown in Figure 10.14.

Figure 10.14: To compute the value of the image texture function at an arbitrary (s , t) position,
MIPMap::triangle() finds the four texels around (s , t) and weights them according to a triangle filter
based on their distance to (s , t). One way to implement this is as a series of linear interpolations, as
shown here: First, the two texels below (s , t) are linearly interpolated to find a value at (s, 0), and the
two texels above it are interpolated to find (s, 1). Then, (s, 0) and (s, 1) are linearly interpolated again
to find the value at (s , t).

This method first scales the coordinates by the texture resolution
at the given MIP map level in each direction, turning them into continuous texel
coordinates.
Because these are continuous coordinates, but the texels in the image map
are defined at discrete texture coordinates, it’s important to carefully convert into a common
representation. Here, we will do all of our work in discrete coordinates, mapping
the continuous texture coordinates to discrete space.