采样器

我们需要使用VkSampler对象来控制读取细化级别的纹理图像数据。Vulkan允许我们指定minLod、maxLod、mipLodBias和mipmapMode参数用于对纹理进行细化级别采样。它的采样方式可以用下面的代码表示:

lod = getLodLevelFromScreenSize(); //smaller when the object is close, may be negative
lod = clamp(lod + mipLodBias, minLod, maxLod);

//clamped to the number of mip levels in the texture
level = clamp(floor(lod), 0, texture.mipLevels - 1);

if (mipmapMode == VK_SAMPLER_MIPMAP_MODE_NEAREST) {
    color = sample(level);
} else {
    color = blend(sample(level), sample(level + 1));
}

如果samplerInfo.mipmapMode变量的值为VK_SAMPLER_MIPMAP_MODE_NEAREST,就会根据计算出的细化级别选择对应的纹理图像进行采样。如果它的值为VK_SAMPLER_MIPMAP_MODE_LINEAR,则会使用计算出的相邻两个级别的纹理图像进行线性混合采样。

采样操作同样受上面代码中的lod变量影响:

if (lod <= 0) {
    color = readTexture(uv, magFilter);
} else {
    color = readTexture(uv, minFilter);
}

如果对象离相机较近,就会使用magFilter的过滤设置。如果对象离相机较远,就会使用minFilter的过滤设置。通常,lod的值为非负数,当lod的值为0时我们认为对象离相机较近。通过设置mipLodBias,我们可以对Vulkan采样使用的lod和level值进行一定程度的偏移。

在这里,我们将minFilter和magFilter都指定为VK_FILTER_LINEAR。然后使用下面代码指定其它的细化采样使用的参数:

void createTextureSampler() {
        ...
    samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
    samplerInfo.minLod = 0; // Optional
    samplerInfo.maxLod = static_cast<float>(mipLevels);
    samplerInfo.mipLodBias = 0; // Optional
        ...
}

这里,我们将minLod设置为0,maxLod设置为纹理图像的最大细化级别。我们不需要对lod的值进行偏移,所以将mipLodBias设置为0。

现在编译运行程序,可以看到下面的画面:

image

为了方便读者观察使用与不使用细化级别的差异,我们将它们放在下面进行对比:

image

可以看出,使用包含细化级别的纹理可以得到更加光滑的渲染结果。

读者可以对采样器的设置进行修改来观察它们的渲染结果的影响。比如修改minLod的值,读者可以强制采样器不使用较小细化级别的纹理图像:

samplerInfo.minLod = static_cast<float>(mipLevels / 2);

下面是这一设置产生的渲染效果:

image