一 前言
1.鋸齒
也叫 走樣(Aliasing),產生原因 ,我們屏幕的分辨率有限,在光柵插值時三角形的邊會從像素裏穿過,被穿過的像素,無論着色 還是不着色,都會產生鋸齒。
圖片來自 learnopengl
2. msaa的原理
原理比較簡單,光柵化時在一個像素裏生成更多的樣本,計算覆蓋率,片元着色器結束後 用覆蓋率 乘以像素的顏色,使之顯得平滑,不管生成多少樣點,shading sample 還是一個樣點 shading。
二 . forward msaa 的核心步驟
1. 設置 setupMultisampleTarget
創建 顏色 和 深度的 image buffer ,設置 下面結構體VkImageCreateInfo 的VkSampleCountFlagBits ,樣本數量取決於具體的硬件,一般是4倍樣本,VkSampleCountFlagBits = 4;
2. 設置 setupFrameBuffer
一個framebuffer 關聯 4 個 附件的視圖,兩個是上面的Multisample的附件,兩個是單樣本的附件。
3. 設置渲染通道
關鍵是 subpass 的 這個
typedef struct VkSubpassDescription {
VkSubpassDescriptionFlags flags;
VkPipelineBindPoint pipelineBindPoint;
uint32_t inputAttachmentCount;
const VkAttachmentReference* pInputAttachments;
uint32_t colorAttachmentCount;
const VkAttachmentReference* pColorAttachments;
const VkAttachmentReference* pResolveAttachments;
const VkAttachmentReference* pDepthStencilAttachment;
uint32_t preserveAttachmentCount;
const uint32_t* pPreserveAttachments;
} VkSubpassDescription;
這個 結構 會在 片元着色器計算後,framebuffer 階段 把 pColorAttachments 的附件 解析到 pResolveAttachments 這個附件上,把多樣本的image 解析給交換鏈一個樣本的image. 這是自動解析多樣本。
三. deferred msaa 的核心步驟
在 deferred 時 光柵化時 只輸出 outPosition outNormal outAlbedo ,並沒有做shading,而是轉移到 下一個 pass 處理 shading, 所以會有 msaa 和 deferred 衝突。
解決辦法 就是 給 輸出 outPosition outNormal outAlbedo depth的 image 都設置成 超樣本,這個和 forward 時一樣。
在fs 做 shading 我們採樣在這些保存着多樣本的 gbuffer ,手動解析多樣本。
sampler2DMS 表示 這是一個多樣本紋理 ,要用 texelFetch 去採樣。
layout (binding = 1) uniform sampler2DMS samplerPosition;
layout (binding = 2) uniform sampler2DMS samplerNormal;
layout (binding = 3) uniform sampler2DMS samplerAlbedo;
vec4 resolve(sampler2DMS tex, ivec2 uv)
{
vec4 result = vec4(0.0);
for (int i = 0; i < NUM_SAMPLES; i++)
{
// i 就是每個樣本
vec4 val = texelFetch(tex, uv, i);
result += val;
}
// Average resolved samples
return result / float(NUM_SAMPLES);
}
// Calualte lighting for every MSAA sample
for (int i = 0; i < NUM_SAMPLES; i++)
{
vec3 pos = texelFetch(samplerPosition, UV, i).rgb;
vec3 normal = texelFetch(samplerNormal, UV, i).rgb;
vec4 albedo = texelFetch(samplerAlbedo, UV, i);
fragColor += calculateLighting(pos, normal, albedo);
}
fragColor = (alb.rgb * ambient) + fragColor / float(NUM_SAMPLES);