作者:Nin+.Lee
(紅色部分爲自己修改)
與顏色緩衝區和深度緩衝區類似,模板緩衝區可以爲屏幕上的每個像素點保存一個無符號整數值。這個值的具體意義視程序的具體應用而定。在渲染的過程中,可以用這個值與一個預先設定的參考值相比較,根據比較的結果來決定是否更新相應的像素點的顏色值。這個比較的過程被稱爲模板測試。模板測試發生在透明度測試(alpha test)之後,深度測試(depth test)之前。如果模板測試通過,則相應的像素點更新,否則不更新。圖形渲染管線中,基於單個像素的測試操作的順序如下圖。
在模板測試的過程中,可以先使用一個比較用掩碼(comparison mask)與模板緩衝區中的值進行位與運算,再與參考值進行比較,從而實現對模板緩衝區中的值的某一位上的置位狀態的判斷。這樣,模板緩衝區中的值不僅可以作爲一個獨立的整體使用,還可以作爲一個比特集合使用。
在OpenGL中,可以通過調用glStencilFunc()函數來設定,比較條件(comparison function)、參考值(reference value)以及比較用掩碼(comparison mask)。例如,
glStencilFunc(GL_EQUAL, // 比較條件
0x1, // 參考值
0xff); // 比較用掩碼
比較條件的種類如下:
方法 | 參考值與模板值之間的比較結果 |
GL_NEVER | 總是失敗 |
GL_ALWAYS | 總是通過測試 |
GL_LESS | 當參考值小於模板值時,通過測試 |
GL_LEQUAL | 當參考值小於等於模板值時,通過測試 |
GL_EQUAL | 當參考值等於模板值時,通過測試 |
GL_GEQUAL | 當參考值大於等於模板值時,通過測試 |
GL_GREATER | 當參考值大於模板值時,通過測試 |
GL_NOTEQUAL | 當參考值不等於模板值時,通過測試 |
具體情況是:
GL_NEVER Always fails.
GL_LESS Passes if ( ref & mask ) < ( stencil & mask).
GL_LEQUAL Passes if ( ref & mask ) <= ( stencil & mask).
GL_GREATER Passes if ( ref & mask ) > ( stencil & mask).
GL_GEQUAL Passes if ( ref & mask ) >= ( stencil & mask).
GL_EQUAL Passes if ( ref & mask ) = ( stencil & mask).
GL_NOTEQUAL Passes if ( ref & mask ) != ( stencil & mask).
GL_ALWAYS Always passes.
除了比較參考值與模板值之外,我們還需要使用一些操作來更新模板緩衝區中的值,這些操作被稱爲模板操作(stencil operation)。模板緩衝區的更新與模板測試的結果以及深度測試的結果有着密切的聯繫。模板操作可以爲下述三種情況,分別指定相應的更新方法。
1. 模板測試失敗。
2. 模板測試通過,但深度測試失敗。
3. 模板測試通過,且深度測試通過。
當上述情況中的一個發生時,就會執行預先設定的更新操作。在OpenGL中,可以使用glStencilOp()函數來爲上述三種情況分別設置更新方法。例如,
glStencilOp(GL_KEEP, // 第一種情況更新方法
GL_DECR, // 第二種情況的更新方法
GL_INCR); // 第三種情況的更新方法
可是設置的更新方法如下:
更新方法 | 描述 |
GL_KEEP | 保持當前的模板值不變 |
GL_ZERO | 將當前的模板值設爲0 |
GL_REPLAC | 用glStencilFunc函數所指定的參考值替換蒙板參數值 |
GL_INCR | 在當前的模板值上加1 |
GL_DECR | 在當前的模板值上減1 |
GL_INVERT | 對當前的模板值進行按位取反操作 |
我們可以通過寫入掩碼(write mask)來更新模板值指定比特位上的置位狀態。OpenGL中,提供了glStencilMask()函數來設置寫入掩碼。例如,
glStencilMask(0xff);
默認情況下,模板測試功能是禁用的。在OpenGL中可以通過
glEnable(GL_STENCIL_TEST);
glDisable(GL_STENCIL_TEST);
來啓用和禁用模板測試。
通常,在渲染開始之前,需要對模板緩衝區執行清理操作,將模板緩衝區的值初始化爲某個指定的值。在OpenGL中,可以通過
glClearStencil()函數來設置這個指定的初始值。例如,
glClearStencil(0); // 初始爲0
然後,用
glClear(GL_STENCIL_BUFFER_BIT);
執行實際的清理操作。注意,在使用OpenGL清理模板緩衝區的時候,OpenGL會清理的過程中應用寫入掩碼。如果你想保留模板值某些位上的置位狀態,這個功能顯然是非常有用的。但是,如果你希望將所有的模板值都初始化爲某個指定的初始值時,這同樣也可能會造成一些迷惑。
爲了功能的完整性,OpenGL還提供了讀寫、複製模板值的操作。把glReadPixels()、glDrawPixels()、glCopyPixels()的格式參數設置爲GL_STENCIL之後,就可以對模板緩衝區進行讀寫、複製操作了。
參考文獻
1. David Blythe, The Stencil Buffer,
http://www.opengl.org/resources/code/samples/sig99/advanced99/notes/node117.html
2. Mark J. Kilgard, Improving Shadows and Reflections via the Stencil Buffer