概述

MipMap(纹理金字塔)是一种纹理处理技术,它预先生成一系列分辨率逐渐降低的纹理图像。

MipMap 的基本概念

原始纹理(级别 0):     256 x 256
第一级 Mip(级别 1):   128 x 128
第二级 Mip(级别 2):   64 x 64
第三级 Mip(级别 3):   32 x 32
第四级 Mip(级别 4):   16 x 16
...直到 1x1

在 Vulkan 中创建带 MipMap 的纹理:

// 计算 MipMap 级别
uint32_t mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1;
 
// 创建图像时指定 MipMap 级别
VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = mipLevels;  // 指定 MipMap 级别数量
imageInfo.arrayLayers = 1;

MipMap 的生成过程

void generateMipmaps(VkImage image, int32_t texWidth, int32_t texHeight, uint32_t mipLevels) {
    VkCommandBuffer commandBuffer = beginSingleTimeCommands();
 
    for (uint32_t i = 1; i < mipLevels; i++) {
        // 设置图像布局转换障碍
        VkImageMemoryBarrier barrier = {};
        // ... 设置 barrier 参数
 
        // 执行 blit 操作来生成下一级 MipMap
        VkImageBlit blit = {};
        blit.srcOffsets[0] = {0, 0, 0};
        blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
        blit.dstOffsets[0] = {0, 0, 0};
        blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1,
                             mipHeight > 1 ? mipHeight / 2 : 1,
                             1};
 
        vkCmdBlitImage(commandBuffer,
            image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
            image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
            1, &blit,
            VK_FILTER_LINEAR);
 
        mipWidth = mipWidth > 1 ? mipWidth / 2 : 1;
        mipHeight = mipHeight > 1 ? mipHeight / 2 : 1;
    }
 
    endSingleTimeCommands(commandBuffer);
}

MipMap 的主要用途

性能优化

  • 减少内存带宽使用
  • 减少采样计算量
  • 避免远处纹理的采样混叠

视觉质量

  • 减少远处纹理的闪烁
  • 提供更平滑的层级过渡
  • 改善整体视觉效果

MipMap 级别的选择

// 在采样器创建时设置 MipMap 参数
VkSamplerCreateInfo samplerInfo = {};
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 偏移值

实际应用场景

远景渲染

// 根据距离选择合适的 MipMap 级别
float distance = length(cameraPos - objectPos);
float lodLevel = log2(distance / baseDistance);

LOD 过渡

// 在着色器中手动控制 LOD 级别
vec4 color = textureLod(sampler2D tex, vec2 coord, float lod);

内存占用分析

总内存 = 原始大小 * (4/3)
例如:
256x256 原始纹理 = 65,536 像素
128x128 = 16,384 像素
64x64 = 4,096 像素
...
总像素 = 65,536 + 16,384 + 4,096 + ... ≈ 87,381 像素

使用注意事项

性能考虑

  • 根据实际需求选择是否生成 MipMap
  • 权衡内存使用和渲染质量
  • 考虑生成 MipMap 的计算开销

质量控制

  • 选择合适的过滤模式
  • 调整 LOD 偏移以控制细节级别
  • 注意边界情况的处理

MipMap 是图形渲染中非常重要的优化技术,它通过预先生成不同分辨率的纹理版本,在保证渲染质量的同时提高了性能。理解和正确使用 MipMap 对于开发高质量的图形应用至关重要。