Bilateral Filter

本文详细探讨了双边滤波技术的不同实现方式,包括AMD、NVIDIA及Splinter Cell 5中的应用案例。介绍了如何通过深度差异计算权重进行图像平滑处理,并针对不同场景优化算法以提高效率。

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截图



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值