Vulkan 中的采样器 (Sampler) 是用来定义如何从纹理中读取颜色数据的对象。它定义了纹理采样的各种参数,如过滤方式、寻址模式等。

以下是创建采样器的基本示例:

VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
// 缩小和放大时的过滤方式
samplerInfo.magFilter = VK_FILTER_LINEAR;    // 放大过滤
samplerInfo.minFilter = VK_FILTER_LINEAR;    // 缩小过滤
 
// 纹理寻址模式(超出纹理坐标范围时的处理方式)
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
 
// Mipmap 相关设置
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;  // mipmap 插值模式
samplerInfo.minLod = 0.0f;                   // 最小 LOD 级别
samplerInfo.maxLod = static_cast<float>(mipLevels);  // 最大 LOD 级别
samplerInfo.mipLodBias = 0.0f;              // LOD 偏移值
 
// 各向异性过滤
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 16.0f;
 
// 边界颜色(在 CLAMP_TO_BORDER 模式下使用)
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
 
// 是否使用非标准化坐标
samplerInfo.unnormalizedCoordinates = VK_FALSE;
 
VkSampler sampler;
vkCreateSampler(device, &samplerInfo, nullptr, &sampler);

主要的采样参数包括:

  1. 过滤模式:
  • VK_FILTER_NEAREST:最近邻过滤
  • VK_FILTER_LINEAR:线性过滤
  1. 寻址模式:
  • VK_SAMPLER_ADDRESS_MODE_REPEAT:重复纹理
  • VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:镜像重复
  • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:钳制到边缘
  • VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:钳制到边界颜色
  1. Mipmap 相关:
// 创建带有完整 mipmap 设置的采样器
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = static_cast<float>(mipLevels);
samplerInfo.mipLodBias = 0.0f;

在着色器中使用采样器:

layout(binding = 1) uniform sampler2D texSampler;
 
void main() {
    vec4 color = texture(texSampler, fragTexCoord);
}

实际应用场景:

  1. 基础纹理采样:
// 创建基础的线性过滤采样器
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
  1. 高质量纹理采样:
// 创建高质量采样器(带各向异性过滤)
VkSamplerCreateInfo samplerInfo = {};
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 16.0f;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = static_cast<float>(mipLevels);

采样器的使用注意事项:

  1. 性能考虑:
  • 各向异性过滤会影响性能
  • 合理设置 mipmap 级别可以提高性能
  • 不同的过滤模式对性能有不同影响
  1. 资源管理:
  • 采样器是独立的对象,可以被多个纹理共享
  • 需要在不再使用时正确销毁
  • 考虑采样器池化以重用常用配置
  1. 驱动限制:
  • 检查设备支持的最大各向异性级别
  • 注意设备对采样器数量的限制

为什么需要采样器

采样器的存在主要是为了解决纹理采样过程中的一系列关键问题。让我详细解释为什么需要采样器:

  1. 纹理坐标与像素的映射问题:
纹理坐标 (0.0 ~ 1.0) ←→ 纹理像素坐标 (0 ~ width/height)

当这种映射不是一对一时,就会产生以下问题:

  • 放大问题:当纹理比显示区域小时

    • 一个纹理像素要映射到多个屏幕像素
    • 如果不处理会出现严重的锯齿
    • 采样器的 magFilter 用于处理这种情况
  • 缩小问题:当纹理比显示区域大时

    • 多个纹理像素要映射到一个屏幕像素
    • 如果不处理会出现闪烁和锯齿
    • 采样器的 minFilter 用于处理这种情况
  1. 边界处理问题: 当纹理坐标超出 0.0~1.0 范围时需要有处理策略:
  • 重复 (REPEAT)
  • 镜像重复 (MIRRORED_REPEAT)
  • 边缘拉伸 (CLAMP_TO_EDGE)
  • 边界颜色 (CLAMP_TO_BORDER)
  1. 质量与性能平衡:
// 高质量设置(但性能开销较大)
samplerInfo.anisotropyEnable = VK_TRUE;
samplerInfo.maxAnisotropy = 16.0f;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
 
// 性能优先设置
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
  1. MipMap 级别管理:
  • 远处的纹理需要使用较低分辨率的版本
  • 近处的纹理需要使用较高分辨率的版本
  • 采样器负责在不同级别之间平滑过渡

举个实际的例子来说明为什么需要采样器:

想象一面贴了瓷砖纹理的墙:

1. 近处观察:
- 一个瓷砖纹理像素可能要覆盖多个屏幕像素
- 需要magFilter进行插值,避免出现明显的像素块

2. 远处观察:
- 多个瓷砖纹理像素要压缩到一个屏幕像素
- 需要minFilter和mipmap来避免闪烁

3. 墙面延伸到无限远:
- 需要addressMode来处理纹理重复

4. 斜着看墙面:
- 需要anisotropic filtering来保持细节清晰

不同的观察情况对应采样器的不同功能:

  1. 正面近距离观察:
samplerInfo.magFilter = VK_FILTER_LINEAR;  // 平滑放大
  1. 远距离观察:
samplerInfo.minFilter = VK_FILTER_LINEAR;  // 平滑缩小
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;  // mipmap平滑过渡
  1. 斜视角观察:
samplerInfo.anisotropyEnable = VK_TRUE;  // 启用各向异性过滤
samplerInfo.maxAnisotropy = 16.0f;  // 最大各向异性级别

如果没有采样器:

  1. 纹理会出现严重的视觉伪影
  2. 远处纹理会闪烁
  3. 斜视角下纹理会模糊
  4. 纹理边界会有明显的不连续
  5. 渲染性能会受到影响

因此,采样器是图形渲染中不可或缺的组件,它解决了纹理采样中的核心问题,确保了渲染质量,并提供了性能优化的可能性。