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.

猜你喜欢

转载自blog.csdn.net/aa20274270/article/details/83825021