Bilateral Filter

Bilateral Filter是一個非常神奇的Filter,在實時渲染從低分辨向高分辨率轉換的時候可以起到很好的抑制鋸齒的作用。 

1. AMD Way

Jeremy在Mixed Resolution中有詳細的講到:一般的Filter是根據像素和周圍像素的距離作爲權重來插值的,而Jemery採用的是高精度和低精度depth或者normal的差異來計算權重,在遊戲裏depth很容易拿到,所以一般就採用depth差異來決定權重,這樣需要得到高精度深度和4個低精度深度和顏色值,一共是9個sample,而且這是一個全屏pass,因此最原始的Bilateral Filter是一個很費的操作,對於實時圖形渲染尤其是尤其還是很奢侈的操作。


Linear Filter



Bilateral Filter

2.NV Way

NV SDK 11有一個OpacityMapping的demo講的是Volume Particle及其Shadow,裏面正好展示了Bilateral Filter,這裏的Filter是經過優化的,從最終結果來看,效果還是很不錯的。在這個demo把這個技術稱之爲Nearest-Depth Filter,它的原理和Cross Bilateral Filter類似,區別在於只需要採一次顏色值,這個顏色值不是周圍像素加權平均的結果而是和高精度深度差異最小的低精度像素的顏色值,這就減少了3次Sample.



採用Nearest-Depth Filter會帶來一個問題:因爲只採用了低精度的顏色值可能會在非邊緣區域噪聲像素塊比較明顯的瑕疵。因此對於edge的像素採用Nearest-Depth Filter,而對於非edge的像素採用雙向性插值。Edge可以通過低精度和高精度深度差異來檢測,我們可以認爲如果一個像素附近的所有低精度深度和對應的高精度深度的差異小於一定閾值時這個像素一定是非edge像素。可以理解爲自適應的Bilateral Filter.


Nearest-Depth Filter Shader代碼

float4 LowResUpsample_PS(VS_SAQ_OUTPUT In) : SV_Target
{
	uint w, h;

	g_ReducedResDepth.GetDimensions(w,h);
	float2 LowResTexelSize = 1.f/float2(w,h);


	g_FullResDepth.GetDimensions(w, h);

	// This corrects for cases where the hi-res texture doesn't correspond to 100% of the low-res
	// texture (e.g. 1023x1023 vs 512x512)
	float2 LoResUV = g_ReductionFactor * LowResTexelSize * float2(w,h) * In.TexCoord;


	float ZFull = FetchFullResDepth(In.Position.xy);

	float MinDist = 1.e8f;

	float4 ZLo = FetchLowResDepths(LoResUV);
	
	float2 UV00 = LoResUV - 0.5 * LowResTexelSize;
	float2 NearestUV = UV00;
	float Z00 = ZLo.w;
	UpdateNearestSample(MinDist, NearestUV, Z00, UV00, ZFull);
	
	float2 UV10 = float2(UV00.x+LowResTexelSize.x, UV00.y);
	float Z10 = ZLo.z;
	UpdateNearestSample(MinDist, NearestUV, Z10, UV10, ZFull);

	float2 UV01 = float2(UV00.x, UV00.y+LowResTexelSize.y);
	float Z01 = ZLo.x;
	UpdateNearestSample(MinDist, NearestUV, Z01, UV01, ZFull);
	
	float2 UV11 = UV00 + LowResTexelSize;
	float Z11 = ZLo.y;
	UpdateNearestSample(MinDist, NearestUV, Z11, UV11, ZFull);
	
	[branch]
	if (abs(Z00 - ZFull) < g_DepthThreshold &&
	    abs(Z10 - ZFull) < g_DepthThreshold &&
	    abs(Z01 - ZFull) < g_DepthThreshold &&
	    abs(Z11 - ZFull) < g_DepthThreshold)
	{
		return g_ScreenAlignedQuadSrc.SampleLevel(g_SamplerLoResBilinear, LoResUV, g_ScreenAlignedQuadMip);
	}
	else
	{
		return g_ScreenAlignedQuadSrc.SampleLevel(g_SamplerLoResNearest, NearestUV, g_ScreenAlignedQuadMip);
	}
}

3. Splint Cell 5 Way

RealTime Rendering有一篇關於SC5 Rendering的討論,裏面重點討論了SC5的GPU Occlusion Culling和Volume Ambient Occlusion的技術,個人非常喜歡這個技術,比SSAO質量好很多,而且還有Normal的感覺,這裏的AO採用Box作爲Proxy Mesh,然後結合深度將worldSpace轉化到AO Space然後採一個Volume Texture就可以算出高質量的AO了,這個過程是一個很明顯的Pixel Bound,因此Quarter Buffer可以大放異彩了,Stephen Hill採用的就是類似於NV的方法(不知道哪個更先使用這個方法,待考證:)),從Blog裏來看,似乎還用到了Object ID作爲額外信息,和NV不同的地方是他最後採的是和高精度深度差異最小的像素,而不像NV還自適應了一把,最後效果驚人的好。原因我想應該是因爲AO只有明暗變化,信息比較少,不像Particle那樣的東西各種顏色的像素都有,顆粒感稍微強一點就很明顯。對於AO這樣做就可以減少一個動態分支,而動態分支裏的tex2Dlod(DX9下)會被展成2個sample,這樣也相當於省了一個sample
RealTime Rendering的鏈接
最後附上精美的SC5的AO截圖



發佈了27 篇原創文章 · 獲贊 5 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章