Stencil Buffer(模板緩衝區)
作者: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
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