The Frame Buffer

  光柵器將圖形primitives轉化成像素流,這些像素將與Frame buffer裏的目的像素結合在一起。Frame buffer這個術語起源於早期的光柵圖形,它就是一塊能容納一張圖片的存儲空間。隨着計算機圖形的發展,這個術語不僅包含圖像數據,而且也包含一些圖形渲染所需要的輔助信息。在Direct3D中,Frame Buffer 不僅包括當前所選擇的render target的表面,而且也包含depth/stencil面。如果使用了多采樣,需要更多的內存。

 在光柵化以後,每個源像素都包含一個RGB顏色,一個Alpha channel裏的透明度值,Z 值裏面的depth值。Z值是由光柵器產生的固定精度值。在像素被結合到render target之前,可以進行霧化處理。霧化以後或者stenciling操作以後,基於每個像素的透明度值以及場景裏面的深度,它們有可能被拒絕。Stenciling操作可以讓Frame Buffer的任意區域的像素被masked away. 與alpha和depth不同的是,與源像素相關的stencil值是從一個render state獲得的。像素經過alpha, depth和stencil測試以後,它將被結合到render target裏面去。源像素深度值只用於可視計算,深度test以後,就沒有與深度值相關的進一步處理被執行了。最後,當render target包含一個RGB顏色的reduced dynamic range,源像素執行抖動處理來減少任何banding artifacts.  抖動處理執行完畢後,源像素就可以寫到render target,以及相關的depth/stencil表面。寫操作是通過一組write mask控制的。

 Multisampling 爲Render Target每個像素提供了提供了多個顏色,深度,stencil值。多個顏色值結合在一起,最終產生出一副圖片用於video scan out. 額外的depth和stencil值用來取得合適視覺和steniling效果。Multisampling可以用於antialiasing, depth of field, motion blur 和其他效果。 在渲染的過程中,你可以控制多采樣render target的哪個採樣將用於detination. 有的效果,是在一個pass裏面渲染到與像素有關的所有的samples,然而有的像素在每個pass只渲染到這些採樣裏面的一部分。 

Fog Blending

在Frame buffer處理之前,霧的顏色混合到源像素的RGB顏色裏面。注意:霧只是影響源像素的顏色,並沒有影響其Transparency.

Alpha Test

在霧化以後,像素進行基於transparency值的rejection測試。如果alpha Test enable,源像素的alpha值和由render state提供的固定alpha值將進行比較。如果測試失敗,這個像素就會被刪除掉。

 你能完全reject透明的像素,這些像素在最後的渲染狀態中將不會產生任何效果。在大量的像素是完全透明的情況下,這種方法將會減少Frame Buffer裏面的工作並且還能提高渲染的效率。

  Alpha Test比較可以通過如下等式: As <op> Ar。

  在這裏As是源像素的alpha值, Ar是參考alpha值。<op>是比較函數。 小心不要混淆Alpha Test和Alpha blending,Alpha Test基於源像素的alpha值做reject操作,Alpha blending使用源像素的alpha值將它與Frame buffer結合起來。RS Alpha Blend Enable 控制是否使用alpha test. RS Alpha Func 指定他們的比較函數, RS Alpha Ref指定參考alpha值,它是一個在[0,255]的DWORD值,0對應全透明,255對應全模糊。

typedef enum _D3DCMPFUNC

{

   D3DCMP_NEVER = 1,

   D3DCMP_LESS = 2,

   D3DCMP_EQUAL = 3,

   D3DCMP_LESSEQUAL = 4,

   D3DCMP_GREATER = 5,

   D3DCMP_NOTEQUAL= 6,

  D3DCMP_GREATEREQUAL = 7,

   D3DCMP_ALWAYS = 8

} D3DCMPFUNC;

  D3DCMPFUNC 對應常用的數學比較操作,但是D3DCMP_NEVER和D3DCMP_ALWAYS除外。D3DCMP_NEVER將總是失敗,D3DCMP_ALWAYS將總是成功。D3DCAPS9::AlphaCmpCaps 描述了設備支持的比較函數,它的每個位對應一個比較函數。

The Z Buffer and Visiblity

 Direct3D的可視性通常是由Z buffer決定的。也有其他可視性算法。但是Z Buffer在硬件上容易實現,並且是最通用的可視性算法。當設備創建的時候設置了AutoDepthStencil和AutoDepthStencilFormat,你能創建一個depth/stencil buffer。 如果你使用CreateRenderTarget創建額外的Render Target或者其他swap chains,那麼你也可以爲這些Render target創建它們的depth/stencil buffer。使用CreateDepthStencilSurface和SetRenderTarget可以到達這個目的。GetDepthStencilSurface返回當前render target的depth/stencil surface.

  Z buffer算法爲每個像素保存一個深度值。 當場景被渲染的時候,Z buffer初始化爲一個最遠的Z 值。 隨着源像素經過光柵化產生後,每個像素就有一個Z value。 源像素的Z值與Z buffer的相同位置像素的Z value進行比較。如果源像素的Z值比Z buffer裏面的值更加靠近觀察者,這個源像素將會被存儲在Z buffer裏面。 通過這樣一種對每個像素的深度值的排序方法實現了可視性檢測。

  RS Z Enbale控制是否Enable Z buffer test. 

typedef enum _D3DZBUFFERTYPE

{

   D3DZB_FALSE = 0,

   D3DZB_TRUE = 1, //選擇 z buffer

   D3DZB_USEW = 2 // 選擇w buffering
}D3DZBUFFERTYPE;

Z buffer test的執行方程是:

   Zs <op>  Zd

Zs 是源像素的Z值, Zd是存儲在Render Target裏面的深度buffer裏面的Z值。op是比較函數。

  • W Buffering

  當使用透視投影的時候,Z buffer對於深度的低位可能是個問題。透視投影使大部分Z buffer的值用於場景中靠近相機的部分。這對於距離相機遠的primitive產生了視覺上的artifacts。 你也許可以通過將視截體的近平面和遠平面拉近來降低這種影響,但是也不能消除這種問題。另外一種方法就是使用W buffer,W buffer存儲的值是齊次深度w的倒數。在這種情況下,w buffer的值甚至會超出視截體的範圍。對於一個16位的深度buffer,W buffer 能提高場景裏面的可視性的分辨率。

插一段人家寫的z buffer 和w buffer的比較:

z-buffering 和 w-buffering都表示深度值。幾乎所有的3-D加速卡都支持z-buffering,這樣就使得z-buffers成爲現在最常用的深度緩衝類型。但是,z-buffers也有它本身的缺陷。由於它所使用的數學方法,使得一個z-buffer中產生的z值在它允許的範圍內[0.0,1.0]並不是均勻分佈的。特別是靠近剪切面與遠離剪切面處的比例,更是影響了z值的均勻分佈。如果遠平面的距離與近平面的距離的比爲100,那麼導致深度緩衝區的90%被花費在前10%的場景深度。一般的娛樂程序或視覺仿真程序要求遠近平面的距離比在1000到10000之間。比值爲1000時,範圍的98%花費在深度的前2%上,並且隨着比值的增大,分佈將變得更糟。這樣可能會使較遠距離的物體上的隱藏表面產生失真,特別是當使用16-bit深度緩衝時。

  w深度緩衝比z-buffer能更均勻地在遠近剪切面之間進行分配。使用它的最大好處就是遠近剪切面的距離比不再是關鍵因素。這樣就允許程序使用更大的距離範圍,同時仍能保持深度緩衝與觀察位置間的精確聯繫。w-buffer也不是完美的,有時也會使近處物體的隱藏表面產生失真。w-buffer的另一個缺點是不能得到硬件的廣泛支持。

 

  • Visibility of Transparent Primitives

  Z Buffer的可視性算法實際上就找到離相機最近的一種排序算法,你可能會忽略它的順序。當primitive完全模糊,最近的pimitive將會出現在最後的渲染圖像裏面。然而,當primitive半透明,就會顯示它後面的像素。爲了能夠正確的渲染,我們必須維護一個back-to-front的list。 但是這種渲染方式,不能只是通過簡單的Z buffer的方式能實現的。

   首先對於完全模糊的物體使用標準的Z buffer可視性算法。接下來,對於場景裏面的透明物體,基於他們的bouding box back-to-front排序。然後,對Z buffer的寫入被disable,透明物體按照back-to-front的順序一一被繪製出來。雖然Z buffer寫入被禁止,但是Z test還是需要enable,透明的物體依然可以被模糊的物體所遮擋,但是它們還是可以滲透(interpenetrate)到其他透明物體。按照back-to-front的順序繪製透明的物體,只要物體不相互滲透,它們還是可以遮擋透明物體。對於相互滲透物體的完美的渲染,你應該排序他們的每個三角形,保證每個三角形back-to-front的順序。然而,取得這個額外的視覺效果往往需要很高的計算成本。

  • Biasing Primitive

  有時候你可能需要繪製兩個在數學上是同一個位置的primitive。 比如,你可能想要繪製一個在立方體某一邊上的primitive。 解決這種問題你可能通過建模的方法,連接重合的三角形。 另外一個更加簡單的辦法是使用Z buffer增加一個固定的Z值使它顯示在在立方體的前面(front)。

  RSZBias代表增加的Z值,他一般在【0,16】範圍以內。

  如果D3DCAPS9::RASTERCAPS的DDPRasterCapsZBias被設置,設置將支持這種處理。

  • Filling and Reading the Z Buffer

  可能有很多次你會往Z buffer裏面寫值和讀取Z buffer的數據。然而,如果你不使用能夠鎖住的Z buffer格式,這可能不會直接操作。

Stencil Test

  stencil test需要與z buffer聯合起來使用。stencil buffer基於depth test的結果和stencil test的結果可以對源像素進行任意的rejection. stencil test把當前的stecil 值與其參考值進行比較。 兩個stencil值使用當前的stencil掩碼進行And計算,這樣就可以指定那些位進行比較計算。

  Stencil buffer是Z Buffer的一部分。 當Z Buffer格式是D3DFMT_Z24S8, D3DFMT_Z15S1, D3DFMT_Z24X4S4,S代表的就是stencil buffer。 RS Stencil Test 控制是否使用stencil test。 RS Stencil Mask控制stencil 參考值和stencil buffer值的那些位用於比較計算。 RS Stencil Func 定義了比較函數。如果比較函數的結果是FALSE,則源像素被discarded,沒有後續的處理。

 Stecil test可能產生的結果:stecil test 失敗;stencil test成功而depth test失敗;stencil test成功depth test也成功。這三個結果對應的渲染狀態分別是RS Stencil Fail, RS Stencil Z Fail和RS Stencil Pass,他們都是從D3DSTENCILOP取值。

typedef enum _D3DSTENCILOP

{

   D3DSTENCILOP_KEEP= 1,

  D3DSTENCILOP_ZERO = 2,

   D3DSTENCILOP_REPLACE= 3,

   D3DSTENCILOP_INVERT = 6,

   D3DSTENCILOP_INCR = 7,

   D3DSTENCILOP_INCRSAT = 4,

   D3DSTENCILOP_DECRSAT = 5

} D3DSTENCILOP;

 D3DCAPS9::StencilCaps 的每個位都對應設備支持一個stencil操作。

stencil buffer可以用來渲染很多特別效果。

  •  Masking Irregular Regions

  Stencil test常用的例子就是掩蓋render target裏面的不規則的區域。首先,我們創建一個stencil buffer的mask image,然後我們繪製被stencil test masked的幾何數據。

  爲了創建mask, 首先將stencil buffer清0,接下來,設置渲染狀態,一般在stencil buffer渲染產生的源像素位置存儲1。 這就在幾何體被繪製的地方,創建了掩碼。在stencil test執行之前,alpha test reject像素,複雜的幾何體使用簡單的紋理化而且有透明區域的四邊形進行繪製。

   RS Stencil Enable = FALSE

   RS  Stencil Func = D3DCMP_ALWAYS

   RS  Stencil Ref = 1

   RS  Stencil Fail = D3DSTENCILOP_REPLACE

   RS  Stencil Z Fail = D3DSTENCILOP_REPLACE

   RS Stencil Pass =  D3DSTENCILOP_REPLACE

   接下來設置rending state以便讓幾何體被掩碼clipped掉。使用stencil test將那些目的stencil值爲1的地方被reject掉,並且保持stencil buffer值不變。當你改變mask的時候,如果你清除stencil buffer, 你可能在每一幀重用那個mask。

   RS Stencil Enable = TRUE

   RS Stencil Func = D3DCMP_NOTEQUAL

   RS  Stencil Ref = 0

   RS Stencil Fail = D3DSTENCILOP_KEEP

   RS Stencil Z FAIL=D3DSTENCILOP_KEEP

   RS Stencil PASS = D3DSTENCILOP_KEEP

  

  •  Screen Door Transparency and Stippling

 設置stencil buffer的值爲0和1,並且使用stencil buffer爲掩碼,我們能繪製出一個透過一個門看到場景裏面的外觀。在stencil buffer 爲0的地方,screen 被繪製,在stencil buffer值爲1的地方,透過屏幕的場景被繪製。 如果我們使用透明度的alpha 混合,就能取得更好的渲染質量。這種方法能提供一種屏幕空間的stipple的模式。一個值用於打開stipple模式,另外一個用於關閉stipple模式。

  •  Filling and Reading the Stencil Buffer

 因爲stencil buffer是z buffer的一部分,所以,可以跟z buffer一樣的方法來訪問他們的buffer。

Alpha Blending

Alpha blending將源像素和目的像素使用一個函數結合起來,計算出新的像素值。當需要顯示多層效果時,經常會用到它。RS Alpha Blend Enable 控制Alpha blending的應用。

  C = <r, g, b, a>

  f = <fr, fg,fb,fa>

  Cf = <rfr,gfg,bfb,afa>

  Cs'= <func><Csfs,Cdfd>

在這裏Cs是源像素的RGBA顏色值,fs 是源blending係數,Cd是目的像素的RGBA顏色值。<func>是blending函數,Cs'是alpha blending操作的最後結果。在這個方程裏面顏色和blending係數都是4維向量。如果render target的目的像素沒有alpha channel,它的默認值是255。

RS Src Blend 和 RS Dest Blend 用於選擇blend係數對fs和fd。 他們的值都是從D3DBEND枚舉值裏面取。 RS Blend Op指定blend函數,默認值是D3DBLENDOP_ADD。

typedef enum _D3DBLEND

{

   D3DBLEND_ZERO = 1,

   D3DBlEND_ONE = 2,

   D3DBLEND_SRCCOLOR =3,

   D3DBLEND_INVSRCCOLOR = 4,

   D3DBLEND_SRCALPHA = 5,

   D3DBLEND_INVSRCALPHA =6,

   D3DBLEND_DESTALPHA = 7,

   D3DBLEND_INVDESTALPHA = 8,

   D3DBLEND_DESTCOLOR = 9,

   D3DBLEND_INVDESTCOLOR = 10,

   D3DBLEND_SRCALPHASAT = 11,

   D3DBLEND_BOTHINVSRCALPHA = 13
}D3DBLEND

typedef enum _D3DBLENDOP

{

    D3DBLENDOP_ADD = 1,

    D3DBLENDOP_SUBTRACT = 2,

    D3DBLENDOP_REVSUBTRACT = 3,

    D3DBLENDOP_MIN = 4,

    D3DBELNDOP_MAX = 5
} D3DBLENDOP

Alpha blending 也可以執行組合計算,如下圖所示。最常用的操作是over,用來組合back-to-front的每一層。列在下面表裏面的操作數是已經被alpha處理過的,就是alpha通道的已經被乘到顏色通道。

 

 當在exclusivem模式上使用D3DSWAPEFFECT_FLIP或者D3DSWAP_EFFECT_DISCARD,並且設備的D3DCAPS9::Caps3的D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD被設置,設備支持目的地的Alpha。否則,應用程序應該使用D3DSWAPEFFECT_COPY或者D3DSwapEffectCopyVSync。  當D3DCAPS9::PrimitiveMiscCaps的D3DPMISCCAPS_BLENDOP被設置,設備支持擴展的blend操作。D3DCAPS9的成員SrcBlendCaps和DestBlendCaps分別定義可支持的源和目的blend係數。每個位代表一個係數。

Dithering

 在概念上,所有的像素處理都是發生在RGBA顏色的四個通道,並且每個通道一般至少8位。但是Render Target可能有少於8位的通道,如D3DFMT_R3G2B2。在一個顏色被寫到render target之前,direct3d將會減少顏色通道的深度,來匹配render target的通道。當render target有一個被縮減的顏色通道時,這將導致banding artifacts。 Dithering算法則可以減少這種artifacts。

  Dithering 通過計算原始顏色和寫入到render target的顏色的誤差來進行操作。隨着像素寫入到render target,dithering算法儘量均衡的分佈誤差。

   RS Dither Enable enable dithering。 如果D3DCaps9::RasterCaps的D3DPRASTERCAPS_DITHER被設置, 設備將支持dithering。

MultiSampling

  使用multisampling, 將爲render target的每個像素的創建多個顏色和depth/stencil buffer。 多個採樣加權計算,就可以提供全屏抗鋸齒和其他效果,如depth-of-field, soft shadow 和motion blur。 使用multisampling的時候,設備必須使用 discard swap effect。 Direct3D的每個render target支持2到16個採樣,你可以通過IDirect3D9的接口CheckDeviceMultiSampleType來查看支持的multisampling。

   全屏抗鋸齒是常用的multisampling的例子。當把RS Sample Antialias設置爲true的時候,設備就enable 全屏Multisampling。 多個採樣通過加權結合在一起產生平滑的多邊形的邊和輪廓。注意只有一個顏色值應用到所有的採樣,它包括了所有的子採樣。這樣,pixel shader和固定功能的多紋理處理爲每個像素都只執行一次,並不是像素的每個採樣。但是depth和stencil需要基於每個採樣來處理。

   當RS Multi Sample Antialias爲False的時候,每個採樣可以通過掩碼 RS Multi Sample Mask控制。特別效果可以通過多個rendering pass和爲每個pass使用不同的採樣來實現。

    如果在render target上n個samples,渲染的時候enable第i個sample。則產生的圖片有i/n強度。如果所有的sample被enable,則圖片的強度跟未採樣一樣。

   如果D3DCAPS9::RasterCaps的DDDPRASTERCapsStretchBltMultiSample位被設置,就執行像stretchblt 操作一樣的採樣。全屏抗鋸齒只能基於每一個frame,並不是每個primitive的。

  •    Depth of Field

  現實中的相機對場景裏面的物體是有一段深度範圍的。這段範圍稱作Depth of Field。 但是direct3d的相機模型卻好像有無限的深度。 你可以通過multi sampling來模擬有限的深度。具體做法是在幾個Pass裏面繪製場景,在每個pass輕微的jitter 視截體。

   假定我們有16個sample,使用16個pass來渲染,每個pass都通過RS Multi Sample Mask enable一個不同的採樣。 每個pass都是用稍微不一樣的視截體。每個視截體都會貫穿同一個相同深度的矩形區域。這個共同的矩形局域就是焦點面,遠離這個焦點面的物體將會被塗抹掉。

  •    Motion Blur

  當場景裏面的物體以快於presentation的速度運動的時候,他們運動就會出現短暫的鋸齒。 常用的例子是出現在19世紀電影裏面的馬車的輪子。在計算機圖形裏面,隨時間採樣場景的行爲是發生在渲染過程中,動態渲染的每一幀只是捕捉每一個瞬間,並沒有考慮物體的運動。

  使用multisampling,每幀渲染快速運動的物體多次,把每次渲染保存到採樣的子集裏面。

Writing to the Render Target

  在所有的frame buffer處理完畢後,它的depth, stencil , color值都會寫到render target。 數據的寫入是通過write mask 集合來控制的。

  RS Z write enable 控制是否把depth和stencil寫入到render target的 depth/stencil buffer。 depth test 與這個write mask無關。 RS stencil Write mask 控制stencil buffer的那些位可以寫。

  可以使用RS Color Write Enable選擇render target的每個顏色通道。如果D3DCAPS9::PrimitiveMiscCaps的D3DPMISCCAPS_COLORWRITEENABLE被設置,設備支持顏色值的寫入。

  RS Multi Sample Mask控制多采樣的那幾個sample被寫。

 

參考文章: 淺談抗鋸齒技術

 

 

 

 

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章