原文地址:http://www.blogjava.net/qileilove/archive/2014/01/23/409269.html
幀緩沖區有許多緩沖區構成,這些緩沖區大致分為:
顏色緩沖區:用於繪圖的緩沖區,它包含了顏色索引或者RGBA顏色數據。
深度緩沖區:存儲每個像素的深度值,當啟動深度
測試時,片段像素深度值和深度緩沖區深度值進行比較,決定片段哪些像素點數據可以替換到顏色緩沖區中。
模板緩沖區:就像使用紙板和噴漆一樣精確的混圖一樣,當啟動
模板測試時,通過模板測試的片段像素點會被替換到顏色緩沖區中,從而顯示出來,未通過的則不會保存到顏色緩沖區中,從而達到了過濾的功能。
累積緩沖區:累積緩沖區允許你把渲染到顏色緩沖區的值,拷貝到累積緩沖區。在多次拷貝操作到累積緩沖區時,可以用不同方式的把顏色緩沖區內容和當前累積緩沖區的內容進行重復混合
模板測試
模板測試只有存在模板緩沖區的情況下進行,模板測試把像素存儲在模板緩沖區的點與一個參考值進行比較(glStencilFunc),根據測試結果,對模板緩沖區的值進行響應的修改glStencilOp
void glStencilFunc (GLenum func, GLint ref, GLuint mask);
func:GL_NEVER 從來不能通過
GL_ALWAYS 永遠可以通過(默認值)
GL_LESS 小於參考值可以通過
GL_LEQUAL 小於或者等於可以通過
GL_EQUAL 等於通過
GL_GEQUAL 大於等於通過
GL_GREATER 大於通過
GL_NOTEQUAL 不等於通過
ref: 參考值
mask:掩碼,書上說模板測試只在哪些對應為1的位上進行。(不是很確定具體作用)
舉例:glStencilFunc (GL_LESS, 1.0, 1.0);模板緩沖區對應的像素點的值如果小於1.0,則通過模板測試
void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
fail模板測試未通過時該如何變化;zfail表示模板測試通過,但深度測試未通過時該如何變化;zpass表示模板測試和深度測試或者未執行深度測試均通過時該如何變化
GL_KEEP(不改變,這也是默認值)
GL_ZERO(回零)
GL_REPLACE(使用測試條件中的設定值來代替當前模板值)
GL_INCR(增加1,但如果已經是最大值,則保持不變),
GL_INCR_WRAP(增加1,但如果已經是最大值,則從零重新開始)
GL_DECR(減少1,但如果已經是零,則保持不變),
GL_DECR_WRAP(減少1,但如果已經是零,則重新設置為最大值)
GL_INVERT(按位取反)
未啟用模板緩沖區
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -20);
glColor3f(1.0f,1.0f,1.0f);
dRadius = 5.0*(sqrt(2.0)/2.0);
glBegin(GL_LINE_STRIP);
for (dAngel=0;dAngel<380.0;dAngel+=0.1)
{
glVertex2d(dRadius*cos(dAngel),dRadius*sin(dAngel));
dRadius*=1.003;
}
glEnd();
glColor3f(1.0f,0.0f,0.0f);
glRectf(-5,-5,5,5);
|
初始清除背景填充顏色為藍色
以上這部分代碼可以用如下3張圖表示繪制的過程
開啟模板緩沖區
void init()
{
glClearColor(0,0,1.0,0);
glClearStencil(0);
glClearDepth(1.0f);
glEnable(GL_STENCIL_TEST);
}
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);//1
glLoadIdentity();
glTranslatef(0, 0, -20);
glStencilFunc(GL_NEVER,0x0,0xFF); //2
glStencilOp(GL_INCR,GL_INCR,GL_INCR);//3
glColor3f(1.0f,1.0f,1.0f);
dRadius = 5.0*(sqrt(2.0)/2.0);
glBegin(GL_LINE_STRIP);
for (dAngel=0;dAngel<380.0;dAngel+=0.1)
{
glVertex2d(dRadius*cos(dAngel),dRadius*sin(dAngel));
dRadius*=1.003;
}
glEnd();
glStencilFunc(GL_NOTEQUAL,0x1,0xFF); //4
glStencilOp(GL_KEEP,GL_KEEP,KEEP); //5
glColor3f(1.0f,0.0f,0.0f);
glRectf(-5,-5,5,5);
|
當執行到1處,3個緩沖區都被清空
顏色緩沖區:每個像素點顏色都是藍色
深度緩沖區:每個像素點深度都是1.0
模板緩沖區:每個像素點模板值都是0
執行到2,3處,模板測試條件是從不通過測試,如果不通過測試結果是模板值+1
接着應用模板測試進行繪制一組點,由於模板測試條件是從不通過測試,所以顏色緩沖器值不會變化,但是繪制的點對應的像素點的模板值變為1,此時
顏色緩沖區:每個像素點顏色都是藍色
深度緩沖區:每個像素點深度都是1.0
模板緩沖區:點數組對應的模板值是1,其他區域像素點的模板值還是0
執行到4,5處,模板測試條件是模板值不一定1則通過測試,如果不通過測試結果是模板值+1
接着應用剛才的模板測試進行繪制一個(-5,-5,5,5)的矩形,在這個矩形區域內,像素點的模板值分為2中,值為1的是上1步的點數組。值為0的是 上一步非的點數組像素點。那個根據模板測試條件,模板值為0的像素點通過測試,可以進行替換顏色緩沖區的值(替換成紅色),模板值為0的像素點不能通過測 試,因此不能改變顏色緩沖區的值
顏色緩沖區:(-5,-5,5,5)區域內 模板值為0的像素點為紅色,其他區域都為藍色
深度緩沖區:每個像素點深度都是1.0
模板緩沖區:點數組對應的模板值是1,其他區域像素點的模板值還是0
模板查詢
可以用glGetInteger函數獲取與模板相關的參數值
#include "header.h"
float dRadius =0;
float dAngel;
float aspect=0;
void init()
{
glClearColor(0,0,1.0,0);
glClearStencil(0);
glClearDepth(1.0f);
glEnable(GL_STENCIL_TEST);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -20);
////glStencilFunc(GL_ALWAYS, 0,0x00);
glStencilFunc(GL_NEVER,0x0,0xFF);
glStencilOp(GL_INCR,GL_INCR,GL_INCR);
glColor3f(1.0f,1.0f,1.0f);
dRadius = 5.0*(sqrt(2.0)/2.0);
glBegin(GL_LINE_STRIP);
for (dAngel=0;dAngel<380.0;dAngel+=0.1)
{
glVertex2d(dRadius*cos(dAngel),dRadius*sin(dAngel));
dRadius*=1.003;
}
glEnd();
glStencilFunc(GL_NOTEQUAL,0x1,0xFF);
glStencilOp(GL_INCR,GL_INCR,GL_INCR);//
glColor3f(1.0f,0.0f,0.0f);
glRectf(-5,-5,5,5);
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0,0,w,h);
aspect = (w*1.0)/h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, aspect, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
//glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_STENCIL);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_STENCIL|GLUT_DEPTH);
glutInitWindowPosition(200,200);
glutInitWindowSize(600,600);
glutCreateWindow("模板緩沖區與模板測試");
glewInit();
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}