在2011的SIGGRAPH上,NVIDA提出了FXAA3.1,本文主要介紹FXAA實現思路,提供部分簡單實現的代碼。c++
FXAA全稱「Fast Approximate Anti-Aliasing」,翻譯成中文就是「快速近似抗鋸齒」。app
FXAA3.11在以前FXAA1,2的基礎上作了一些改進。學習
FXAA是一種單程像素着色器,和MLAA同樣運行於目標遊戲渲染管線的後期處理階段,但不像後者那樣使用DirectCompute,而只是單純的後期處理着色器,不依賴於任何GPU計算API。正由於如此,FXAA技術對顯卡沒有特殊要求,徹底兼容NVIDIA、AMD的不一樣顯卡(MLAA僅支持A卡)和DX九、DX十、DX11。this
取4個方向以及中間像素,對5個位置的值作濾波操做,對於範圍以外進行分段線性變換。對於差別較大的像素,進行AA。翻譯
maxLuma = max(nw,ne,sw,se) contrast = max(nw,ne,sw,se,m) - min(nw,ne,sw,se,m) if(contrast >= max(minThreshold, maxLuma * threshold))
dir.x = -((NW+NE)-(SW+SE)) dir.y = ((NW+SW)-(NE+SE)) dir.xy = normalize(dir.xy) * scale
使用2x2的區域,計算像素邊界,作向量運算。獲得dir以後歸一化長度。設計
minDir = min(|dir.x|, |dir.y|) * sharpness
// Use the min and max luma range of the original 4 samples * {NW, NE, SW, SE} // If 4-tap filter luma exceeds this range, * Assume invalid and use just the first 2 taps
我本身再Direct11的環境下,參考FXAA思路,實現了簡單版本的FXAA,相比自帶d3d實現的4xMSAA,效果較爲不明顯,僅供交流學習。3d
//-------------------------------------------------------------------------------------- // File: FXAA.fx //-------------------------------------------------------------------------------------- SamplerState samLinear : register(s0); Texture2D txFxaa : register(t0); struct PS_INPUT { float4 Pos : SV_POSITION; float4 PosProj : POSITION; float3 Norm : NORMAL; float4 Diffuse : COLOR0; float2 Tex : TEXCOORD; float3 Tangent : TANGENT; }; float4 FxaaPS(PS_INPUT input) : SV_Target { float4 texColor = txFxaa.Sample(samLinear, input.Tex); // FXAA 3x3取9個像素 float3 luma = float3(0.299, 0.587, 0.114); //luma = float3(0.33, 0.33, 0.33); float lumaTL = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(-1.0, -1.0)).xyz); float lumaTR = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(1.0, -1.0)).xyz); float lumaBL = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(-1.0, 1.0)).xyz); float lumaBR = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy + float2(1.0, 1.0)).xyz); float lumaM = dot(luma, txFxaa.Sample(samLinear, input.Tex.xy).xyz); float2 dir; dir.x = -((lumaTL + lumaTR) - (lumaBL + lumaBR)); dir.y = (lumaTL + lumaBL) - (lumaTR + lumaBR); float FXAA_SPAN_MAX = 8.0; float direReduce = 1.0 / 128.0; float inverseDir = 1.0 / (min(abs(dir.x), abs(dir.y)) + direReduce); dir = min(float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir*inverseDir)); float3 res1 = (1.0 / 2.0) * ( txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(1.0 / 3.0 - 0.5, 1.0 / 3.0 - 0.5))).xyz + txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(2.0 / 3.0 - 0.5, 2.0 / 3.0 - 0.5))).xyz); float3 res2 = res1 * (1.0 / 2.0) + (1.0 / 4.0) * ( txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(0.0 / 3.0 - 0.5, 0.0 / 3.0 - 0.5))).xyz + txFxaa.Sample(samLinear, input.Tex.xy + (dir * float2(3.0 / 3.0 - 0.5, 3.0 / 3.0 - 0.5))).xyz); float lumaRes = dot(luma, res2); float lumaMin = min(lumaM, min(min(lumaTL, lumaTR), min(lumaBL, lumaBR))); float lumaMax = max(lumaM, max(max(lumaTL, lumaTR), max(lumaBL, lumaBR))); if (lumaRes <lumaMin || lumaRes > lumaMax) texColor = float4(res2, 1.0); else texColor = float4(res1, 1.0); return texColor; }