1、模板緩衝app
與模板緩衝相關的操做有兩種——比較操做和更新操做。spa
1. 比較操做對象
Stencil Test 比較的是Reference和Stencil Buffer中的值,公式以下:blog
(Stencil Ref \ &mask ) op (Stencil Buffer \ &mask ) // 左右順序不可顛倒ip
相應的DX和OpenGL中的命令爲:ci
glStencil(cmp_fun, ref, mask) 和 device->SetRenderState(D3DRS_STENCILFUNC, cmp_fun)element
其中的cmp_fun就是上式中的「op」,實際爲 「〉」、「〈」、「〉=」、「〈=」等比較運算。所謂的Stencil Test就是進行op運算。op運算的結果是與Stencil Test的狀態相對應的(Stencil Test只有pass、fail兩種狀態),其對應關係以下:get
op的運算結果 Stencil Testit
true passio
false fail
當op被設爲always(DX:D3DCMP_ALWAYS | OPENGL:GL_ALWAYS)運算時,不管Stencil Ref和Stencil Buffer的當前值如何,Stencil Test永遠爲pass。
2. 更新操做
Stencil Test有pass/fail兩種結果,Z-Buffer Test也有pass/fail兩種結果。Stencil Buffer中的值的更新,須要同時指明是在何種狀態(其實是由Stencil Test和Z-Buffer Test運算結果兩兩組合而成的一共四種狀態)下進行的何種更新。更新操做命令格式以下:
DX: device->SetRenderState(state, op)
OpenGL: glstencilOp(op1, op2, op3)
OpenGL DX(state值)
Stencil Test pass 參數op3 D3DRS_STENCILPASS
Stencil Test fail 參數op1 D3DRS_STENCILFAIL
Z Buffer Test fail 參數op2 D3DRS_STENCILZFAIL
OpenGL(op1/op2/op3的值) DX(op的值)
GL_KEEP D3DSTENCILOP_KEEP
GL_ZERO D3DSTENCILOP_ZERO
GL_REPLACE D3DSTENCILOP_REPLACE //用reference值替換模板緩衝中相應位置的值
GL_INCR D3DSTENCILOP_INCRSAT
GL_DECR D3DSTENCILOP_DECRSAT
GL_INCR_WRAP D3DSTENCILOP_INCR
GL_DECR_WRAP D3DSTENCILOP_DECR
要注意加以區分的兩個概念——「stencil test經過後對顏色緩衝值的更新」和「stencil test經過後對模板緩衝值的更新」。
3. Stencil Reference
Stencil Reference主要有兩個做用:
一是,在比較操做中用做進行比較的一個值;二是,在更新操做中用來替換模板緩衝中的相應數據(GL_REPLACE/D3DSTENCILOP_REPLACE)。
4. Z-Buffer Test 與 Stencil Test 的前後順序
在OpenGL中Depth Test(Z-Buffer Test)是在Stencil Test以後,參見。
而在DirectX中Z-Buffer Test 是在Stencil Test以前,參見。 // 這裏是DX9的資料,DX11後渲染管線有較大變化,不知道這一順序是否有變。
2、陰影體(Shadow Volume)
經過陰影體來描繪物體投影的技術,在不少地方都有相關的介紹,但多不夠直觀。將陰影體(Shadow Volume)與Stencil Test結合來造成物體陰影的技術是其中最多見的一種方式,現結合下圖做簡單介紹。
假設,有一個對象OB在光源L做用下,在平面P上造成自身的陰影W,陰影在屏幕窗口S上對應的區域爲W'(如上圖)。此時光源L與OB相交的邊沿光照方 向的延長線,和OB的背光面一塊兒將造成一個棱臺VL。Shadow Volume的基本思想是這樣的:先生成一個VL的實體並將其投影到S上,但並不真的把它畫出來(也就是說,在將VL投影到S上時,並不真正地更新相應的 顏色緩衝),而只是藉此操做來設置S上的W'區域所對應的模板緩衝的值,同時使W'所對應的模板緩衝中的值與其它區域所對應的模板緩衝中的值區別開來。這 樣就能夠在接下來的過程當中,藉助模板緩衝將S上的W'區域塗黑,造成最終的陰影。
經過VL的投影過程來造成W'區域與其它區域的Stenclil Buffer值的差異,是基於這樣一種思想:假設有一條視線V1與VL正面(面對觀察者或攝像機)相交於點b,而後又與VL背面(背對觀察者或攝像機)相交於點c,那麼說明V1所通過的區域沒有其它的物體,因此VL就不會在此處有陰影投射,也就是說V1與S的交點a上的顏色,將由場景中的其它對象來決定;假設有另外一條視線V2與VL正面相交於點e,在與VL背面相交以前先與平面P相交於點f,這就說明點f必處於OB的陰影中,那麼V2與S的交點d上的顏色必然要帶上陰影色。如下的技術手段是對這一原理的實現。
先將VL的正面(面向觀察者或攝像機)在S上做一次投影(不更新顏色緩衝值),同時使S上與其相應的區域(在上圖中沒有畫出)所對應的模板緩衝值加一;而後,再將VL的背面(背向觀察者或攝像機)在S上再做一次投影(不更新顏色緩衝值),同時使S上與其相應的區域(在上圖中沒有畫出)所對應的模板緩衝值減一。固然,在此過程當中場景裏全部其它對象也要渲染到S上。
在 渲染平面P時,Z-Buffer的Test和Write功能正常開啓,在對VL的正、背面進行投影時,Z-Buffer的Test功能開啓,而Write 功能關閉。這樣就使得在VL正面投影到S上時,不會更新Z-Buffer中的值,而平面P在渲染時會更新Z-Buffer的值。在V2所 通過的路徑上,因爲平面P處於構成VL背面的諸三角形以前,所以,在Z-Buffer Test階段,構成VL背面的諸三角形在光柵化階段將被丟棄,因此,VL背面投影操做所附帶的對相應區域的模板緩衝值的減一操做也就自動取消了,最終使得 f點所對應的模板緩衝值,在加一操做(進行VL正面投影時進行)後就一直不變了;而在V1所通過的路徑上,因爲沒有其它的物體的阻隔,對模板緩衝區的加1、減一操做都會按預期進行。這樣一來,W'區域與其它區域相應的模板緩衝值就被區別開來了。
(注意,DX與OpenGL雖然在Stencil Test和Z-Buffer Test的前後順序上有所不一樣,但二者對Stencil Buffer值的設置都是在Z-Buffer Test和Stencil Test都完成以後才進行的。)