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);主要的采样参数包括:
- 过滤模式:
- VK_FILTER_NEAREST:最近邻过滤
- VK_FILTER_LINEAR:线性过滤
- 寻址模式:
- 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:钳制到边界颜色
- 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);
}实际应用场景:
- 基础纹理采样:
// 创建基础的线性过滤采样器
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;- 高质量纹理采样:
// 创建高质量采样器(带各向异性过滤)
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);采样器的使用注意事项:
- 性能考虑:
- 各向异性过滤会影响性能
- 合理设置 mipmap 级别可以提高性能
- 不同的过滤模式对性能有不同影响
- 资源管理:
- 采样器是独立的对象,可以被多个纹理共享
- 需要在不再使用时正确销毁
- 考虑采样器池化以重用常用配置
- 驱动限制:
- 检查设备支持的最大各向异性级别
- 注意设备对采样器数量的限制
为什么需要采样器
采样器的存在主要是为了解决纹理采样过程中的一系列关键问题。让我详细解释为什么需要采样器:
- 纹理坐标与像素的映射问题:
纹理坐标 (0.0 ~ 1.0) ←→ 纹理像素坐标 (0 ~ width/height)
当这种映射不是一对一时,就会产生以下问题:
-
放大问题:当纹理比显示区域小时
- 一个纹理像素要映射到多个屏幕像素
- 如果不处理会出现严重的锯齿
- 采样器的 magFilter 用于处理这种情况
-
缩小问题:当纹理比显示区域大时
- 多个纹理像素要映射到一个屏幕像素
- 如果不处理会出现闪烁和锯齿
- 采样器的 minFilter 用于处理这种情况
- 边界处理问题: 当纹理坐标超出 0.0~1.0 范围时需要有处理策略:
- 重复 (REPEAT)
- 镜像重复 (MIRRORED_REPEAT)
- 边缘拉伸 (CLAMP_TO_EDGE)
- 边界颜色 (CLAMP_TO_BORDER)
- 质量与性能平衡:
// 高质量设置(但性能开销较大)
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;- MipMap 级别管理:
- 远处的纹理需要使用较低分辨率的版本
- 近处的纹理需要使用较高分辨率的版本
- 采样器负责在不同级别之间平滑过渡
举个实际的例子来说明为什么需要采样器:
想象一面贴了瓷砖纹理的墙:
1. 近处观察:
- 一个瓷砖纹理像素可能要覆盖多个屏幕像素
- 需要magFilter进行插值,避免出现明显的像素块
2. 远处观察:
- 多个瓷砖纹理像素要压缩到一个屏幕像素
- 需要minFilter和mipmap来避免闪烁
3. 墙面延伸到无限远:
- 需要addressMode来处理纹理重复
4. 斜着看墙面:
- 需要anisotropic filtering来保持细节清晰
不同的观察情况对应采样器的不同功能:
- 正面近距离观察:
samplerInfo.magFilter = VK_FILTER_LINEAR; // 平滑放大- 远距离观察:
samplerInfo.minFilter = VK_FILTER_LINEAR; // 平滑缩小
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; // mipmap平滑过渡- 斜视角观察:
samplerInfo.anisotropyEnable = VK_TRUE; // 启用各向异性过滤
samplerInfo.maxAnisotropy = 16.0f; // 最大各向异性级别如果没有采样器:
- 纹理会出现严重的视觉伪影
- 远处纹理会闪烁
- 斜视角下纹理会模糊
- 纹理边界会有明显的不连续
- 渲染性能会受到影响
因此,采样器是图形渲染中不可或缺的组件,它解决了纹理采样中的核心问题,确保了渲染质量,并提供了性能优化的可能性。