一、Mipmap 生成總結
一、Mipmap 基礎概念
- 定義:Mipmap 是圖像預先計算的縮小版本,每個層級寬高為前一層的一半,用作細節級別(LOD)。
- 作用:
- 遠離相機的對象使用較小層級采樣,提升渲染速度。
- 避免莫爾條紋等偽影。
- 存儲方式:在 Vulkan 中存儲于
VkImage
的不同 mip 級別,級別 0 為原始圖像,后續層級構成 mip 鏈。
二、圖像創建與 mip 級別計算
-
計算 mip 級別數:
mipLevels = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
- 原理:通過最大維度的對數計算可被 2 整除的次數,加 1 包含原始圖像。
-
修改關鍵函數:
createImage
:添加mipLevels
參數,設置imageInfo.mipLevels
。createImageView
:設置viewInfo.subresourceRange.levelCount
為mipLevels
。transitionImageLayout
:設置barrier.subresourceRange.levelCount
為mipLevels
。
-
函數調用更新示例:
// 紋理圖像創建(含 mipLevels) createImage(texWidth, texHeight, mipLevels, VK_FORMAT_R8G8B8A8_SRGB, ...); // 紋理圖像視圖創建 textureImageView = createImageView(textureImage, ..., mipLevels);
三、Mipmap 生成流程
-
準備工作:
- 為紋理圖像添加
VK_IMAGE_USAGE_TRANSFER_SRC_BIT
使用標志。 - 確保圖像布局為
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
。
- 為紋理圖像添加
-
核心函數
generateMipmaps
:- 循環處理每個 mip 級別(從 1 開始):
- 轉換源層級布局:將
i-1
層級轉為VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
。 - 設置 blit 操作:
VkImageBlit blit{}; blit.srcSubresource.mipLevel = i - 1; // 源層級 blit.dstSubresource.mipLevel = i; // 目標層級 blit.dstOffsets[1] = {mipWidth/2, mipHeight/2, 1}; // 目標尺寸減半
- 執行 blit 命令:使用
vkCmdBlitImage
復制并縮放數據,過濾方式為VK_FILTER_LINEAR
。 - 轉換源層級為渲染可用:轉為
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
。
- 轉換源層級布局:將
- 處理最后一個層級:單獨轉換為渲染布局。
- 循環處理每個 mip 級別(從 1 開始):
-
關鍵代碼邏輯:
for (uint32_t i = 1; i < mipLevels; i++) {// 布局轉換與 blit 操作...if (mipWidth > 1) mipWidth /= 2;if (mipHeight > 1) mipHeight /= 2; }
四、線性濾波支持檢查
-
硬件支持驗證:
VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, imageFormat, &formatProperties); if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {throw std::runtime_error("不支持線性濾波!"); }
-
備選方案:
- 搜索支持線性濾波的格式。
- 使用
stb_image_resize
等庫在軟件中生成 mipmap。
五、采樣器配置
-
關鍵參數:
mipmapMode
:VK_SAMPLER_MIPMAP_MODE_NEAREST
:直接選擇層級采樣。VK_SAMPLER_MIPMAP_MODE_LINEAR
:混合相鄰層級采樣。
minLod/maxLod
:控制采樣的 lod 范圍,VK_LOD_CLAMP_NONE
表示使用所有層級。mipLodBias
:偏移 lod 值,調整采樣層級。
-
典型配置示例:
VkSamplerCreateInfo samplerInfo{}; samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; samplerInfo.minLod = 0.0f; samplerInfo.maxLod = VK_LOD_CLAMP_NONE; samplerInfo.mipLodBias = 0.0f;
六、效果與實踐建議
- 視覺效果:消除莫爾條紋,文字邊緣更平滑。
- 性能優化:預先生成 mipmap 可避免運行時計算,通常存儲于紋理文件中。
- 調試建議:修改
minLod
可強制使用特定層級,觀察不同 LOD 效果。- 設置
samplerInfo.minLod = static_cast<float>(texture.mipLevels / 2);
效果:
- 設置
samplerInfo.minLod = static_cast<float>(texture.mipLevels / 4);
效果:
- 默認
samplerInfo.minLod = 0.0f;
效果:
- 設置
多重采樣抗鋸齒(MSAA)總結
一、MSAA基礎概念
- 作用:解決幾何圖形邊緣鋸齒狀走樣問題,通過每個像素使用多個采樣點計算最終顏色。
- 原理:普通渲染使用單個采樣點,MSAA使用多個采樣點(如2/4/8倍),采樣數越多效果越好但性能開銷越大。
- 核心流程:在屏幕外多重采樣緩沖中渲染,再解析到常規幀緩沖。
二、獲取硬件支持的采樣計數
- 實現函數:
VkSampleCountFlagBits getMaxUsableSampleCount() {VkPhysicalDeviceProperties props;vkGetPhysicalDeviceProperties(physicalDevice, &props);// 取顏色和深度采樣計數的交集VkSampleCountFlags counts = props.limits.framebufferColorSampleCounts & props.limits.framebufferDepthSampleCounts;// 按優先級返回最高支持的采樣數if (counts & VK_SAMPLE_COUNT_64_BIT) return VK_SAMPLE_COUNT_64_BIT;// 依次檢查32/16/8/4/2/1位采樣return VK_SAMPLE_COUNT_1_BIT; }
- 應用場景:在物理設備選擇時調用,設置類成員
msaaSamples
。
三、渲染目標設置
- 創建多重采樣顏色緩沖:
void createColorResources() {VkFormat format = swapChainImageFormat;// 關鍵參數:采樣數msaaSamples,禁用mipmap(1級)createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, colorImage, colorImageMemory);colorImageView = createImageView(colorImage, format, VK_IMAGE_ASPECT_COLOR_BIT, 1); }
- 深度緩沖同步修改:
void createDepthResources() {// 同步更新深度緩沖的采樣數createImage(swapChainExtent.width, swapChainExtent.height, 1, msaaSamples, ...); }
- 資源清理與重建:
- 在
cleanupSwapChain
中釋放colorImage
相關資源。 - 在
recreateSwapChain
中重新創建顏色和深度資源。
- 在
四、渲染通道與附件配置
- 修改顏色/深度附件:
colorAttachment.samples = msaaSamples; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // 不再直接呈現 depthAttachment.samples = msaaSamples;
- 添加解析附件:
VkAttachmentDescription colorAttachmentResolve{}; colorAttachmentResolve.format = swapChainImageFormat; colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT; // 解析到單采樣常規圖像 colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; // 用于呈現
- 子通道與依賴關系:
VkAttachmentReference colorAttachmentResolveRef{2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; subpass.pResolveAttachments = &colorAttachmentResolveRef; // 啟用解析操作 // 更新依賴關系以確保寫入完成 dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- 幀緩沖與管線配置:
// 幀緩沖附件包含多重采樣顏色、深度和解析目標 std::array<VkImageView, 3> attachments = {colorImageView, depthImageView, swapChainImageViews[i]}; // 管線啟用多重采樣 multisampling.rasterizationSamples = msaaSamples;
五、質量優化:采樣著色(Sample Shading)
- 作用:解決紋理內部著色混疊,補充MSAA僅平滑邊緣的不足。
- 實現步驟:
- 設備功能啟用:
deviceFeatures.sampleRateShading = VK_TRUE;
- 管線配置:
multisampling.sampleShadingEnable = VK_TRUE; multisampling.minSampleShading = 0.2f; // 采樣著色閾值,越接近1越平滑
- 設備功能啟用:
六、關鍵注意事項
- 性能權衡:高采樣數(如64x)對性能影響顯著,建議根據設備能力動態調整。
- 解析必要性:多重采樣圖像無法直接呈現,必須通過解析附件轉換為單采樣圖像。
- 兼容性檢查:部分舊設備可能不支持高采樣數,需做好降級處理。
- 視覺效果:MSAA主要改善幾何邊緣平滑度,紋理混疊需結合采樣著色或紋理過濾處理。
效果
-
MSAA = VK_SAMPLE_COUNT_1_BIT
-
MSAA = getMaxUsableSampleCount()
當前代碼分支:13_mipmap_msaa