使用后期处理效果实现运动模糊
1.介紹
在電子游戲中模擬速度的一種最好的方法就是使用運動模糊。運動模糊是游戲中最重要的效果之一,尤其是在賽車游戲中,因為它可以增加真實感和速度感。運動模糊還可以幫助游戲畫面的平滑,尤其是對于幀速小于等于30的游戲來說。但是,在已有的游戲引擎加入運動模糊是具有挑戰性的,因為大多數運動模糊技術需要重新渲染場景,以產生基于每個像素的速度緩沖。這種多輪渲染的方法是具有限制性的:許多應用程序在將場景多次送往圖形管線時,并不能保持原有的幀速。
其他生成基于每個像素的速度映射圖的方法包括使用多個渲染目標,然后將速度信息輸出到其中一個渲染目標。這種方法的主要不足在于需要改變場景的著色器,增加相應的代碼,以計算速度并將其輸出到第二個渲染目標。這種方法的另一個不足在于渲染到多個目標在一些平臺上可能降低性能。另外,一些平臺只有有限的渲染內存,要求一種機制來在1280*720或者更大的幀緩存上使用多個渲染目標。
在這章中,我們將介紹一項使用深度緩沖作為紋理輸入到片段著色器程序來生成場景速度映射圖的技術。片段著色器程序使用深度值和視圖投影矩陣,為每一個像素計算世界坐標中的位置,而深度值保存在深度緩存中。一旦我們計算出該像素在世界坐標中的位置,我們就可以使用前一幀的視圖投影矩陣對它進行變換。然后我們可以計算當前幀和前一幀中視口坐標中該位置的差別,以生成每一個像素的速度值。運動模糊的效果可以通過使用速度向量作為方向來組合幀緩存上的多重采樣,然后進行歸一化最后產生模糊的效果。
這項技術的好處在于可以放在后期處理階段。這將使得這項技術可以很容易地集成到已有的圖形引擎中,這些引擎所運行的硬件可能允許在深度緩存上采樣作為紋理。
圖1和圖2展示了使用運動模糊前后的區別。
?
圖1?使用了運動模糊的場景
?
圖2?沒有使用運動模糊的場景
2.從深度緩存提取物體的位置
當一個物體被渲染并且它的深度值被寫入深度緩存時,保存在深度緩存的值是三角面片的z值的插值,該z值是這樣計算出來的:首先三角形的三個頂點被世界視圖投影矩陣轉換,然后xyz坐標被齊次坐標中的w值所除。通過使用深度緩存作為紋理,我們可以提取出渲染到深度緩存的物體的世界坐標中的位置。我們先將視口中的位置使用視圖投影矩陣的逆矩陣進行轉化,然后用w值乘以結果,得出對應的世界坐標中的位置。令視口位置為像素在視口空間的位置,也就是說,x、y坐標的值在-1到1的范圍內,而原點在屏幕的中心。那個像素在深度緩存中的深度值作為z值,而w值設為1。
我們可以將某一像素的視口位置定義為H:
?
令M為世界視圖投影矩陣,而W為該像素的世界坐標:
?
下面是HLSL/Cg代碼:
//?Get?the?depth?buffer?value?at?this?pixel.
float?zOverW?=?tex2D(depthTexture,?texCoord);
//?H?is?the?viewport?position?at?this?pixel?in?the?range?-1?to?1.
float4?H?=?float4(texCoord.x?*?2?-?1,?(1?-?texCoord.y)?*?2?-?1,
zOverW,?1);
//?Transform?by?the?view-projection?inverse.
float4?D?=?mul(H,?g_ViewProjectionInverseMatrix);
//?Divide?by?w?to?get?the?world?position.
float4?worldPos?=?D?/?D.w;
一旦我們計算出世界坐標,我們可以使用前一幀的視圖投影坐標對其進行變換,然后得到屏幕位置上的差別,以計算像素的速度,代碼如下:
//?Current?viewport?position
float4?currentPos?=?H;
//?Use?the?world?position,?and?transform?by?the?previous?view-
//?projection?matrix.
float4?previousPos?=?mul(worldPos,?g_previousViewProjectionMatrix);
//?Convert?to?nonhomogeneous?points?[-1,1]?by?dividing?by?w.
previousPos?/=?previousPos.w;
//?Use?this?frame's?position?and?last?frame's?to?compute?the?pixel
//?velocity.
float2?velocity?=?(currentPos?-?previousPos)/2.f;
請求深度緩存作為紋理使用的方法取決于使用的平臺,依賴于圖形API。訪問深度緩存作為紋理的細節在Gilham?2006中有詳細討論。如果硬件不支持從深度緩存中采樣作為紋理的話,就要使用多個渲染目標然后將深度輸出到一個單獨的渲染目標,或者將深度值輸出到顏色緩存的alpha通道。
3.運行運動模糊
一旦我們有了像素的速度,我們可以在顏色緩存中沿著那個方向采樣,累計顏色值來得到運動模糊的值,如下代碼:
//?Get?the?initial?color?at?this?pixel.
float4?color?=?tex2D(sceneSampler,?texCoord);
texCoord?+=?velocity;
for(int?i?=?1;?i?<?g_numSamples;?++i,?texCoord?+=?velocity)
{
??//?Sample?the?color?buffer?along?the?velocity?vector.
??float4?currentColor?=?tex2D(sceneSampler,?texCoord);
??//?Add?the?current?color?to?our?color?sum.
??color?+=?currentColor;
}
//?Average?all?of?the?samples?to?get?the?final?blur?color.
float4?finalColor?=?color?/?numSamples;
我們可以在圖3中看到運行結果,注意到接近觀察者的地形比遠處的地形更模糊。
?
圖3?運動模糊的運行結果
?
4.處理動態的物體
這項技術使用在靜止的物體上效果非常好,因為它只考慮到攝像機的運動。但是,如果需要更加精確地記錄動態物體的速度,那么我們可以生成獨立的速度紋理。
為了生成缸體動態物體的速度紋理,首先要使用當前幀的視圖投影矩陣以及前一幀的視圖投影矩陣對物體進行變換,然后計算視口位置的差異。接著將兩個變換后的位置傳入片段著色器,并計算速度。這項技術在DirectX?9?SDK's?的運動模糊示例中被描述。
5.屏蔽的物體
取決于應用程序,你可能需要屏蔽場景的某個部分,不對此部分使用運動模糊。比如,在賽車游戲中,你需要保持所有車輛的清晰度和細節,而不對其進行模糊。一種簡單的方法是渲染一個掩模到一個單獨的紋理或者到顏色緩存的alpha通道,然后使用這個掩模來決定什么像素應該被模糊。
6.額外的工作
使用深度緩存計算物體的世界坐標的技術是非常有用的。我們可以使用這項技術實現深度域的效果,正如Gilham?2006中所描述,還有場景霧也可以使用深度緩存作為后期處理來實現。
7.總結
在這章中,我們討論了一種使用深度緩存中的深度值來計算物體的世界坐標的方法,并且介紹了那些信息如何用于在一個游戲引擎中實現運動模糊的效果。將運動模糊作為后期處理實現的技術可以很簡單地集成到一個已有的渲染引擎中,并能夠提供比傳統的多輪解決方法更好的性能。
8.參考文檔
[1]Gilham,?David.?2006.?"Real-Time?Depth-of-Field?Implemented?with?a?Post-Processing?Only?Technique."?In?Shader?X5,?edited?by?Wolfgang?Engel,?pp.?163–175.?Charles?River?Media.
[2]Microsoft?Corporation.?2006.?"DirectX?9.0?Programmer's?Reference."
轉載于:https://www.cnblogs.com/wangshaohao/archive/2012/11/14/2769663.html
總結
以上是生活随笔為你收集整理的使用后期处理效果实现运动模糊的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20个 css3 html5 设计工具
- 下一篇: allegro约束设置