OpenGL緩沖區(qū)
- 顏色緩沖區(qū)
- 包含顏色索引或者RGBA顏色數(shù)據(jù)
- 深度緩沖區(qū)
- 存儲(chǔ)每個(gè)像素的深度值。
- 當(dāng)啟動(dòng)深度測(cè)試時(shí)辆影,片段像素深度值和深度緩沖區(qū)深度值比較,決定片段哪些像素點(diǎn)數(shù)據(jù)可以替換到顏色緩沖區(qū)中黍特。
- 模板緩沖區(qū)
- 為屏幕上的每個(gè)像素點(diǎn)保存一個(gè)無符號(hào)整數(shù)值蛙讥。
- 在渲染過程中,可以用緩沖區(qū)保存的值與一個(gè)預(yù)先設(shè)定的參考值相比較灭衷,根據(jù)比較的結(jié)果來決定是否更新響應(yīng)的像素點(diǎn)的顏色值次慢。這個(gè)比較的過程稱為模板測(cè)試。
- 模板測(cè)試發(fā)生在透明度測(cè)試(alpha test)之后翔曲,深度測(cè)試(depth test)之前迫像。
模板測(cè)試.png
中間小的紙板的T字位置是鏤空的,當(dāng)用噴漆噴在紙板上時(shí)瞳遍,鏤空的部分有噴漆通過闻妓,沒鏤空的就被紙板擋住,所以最終顯示在大紙板上就是一個(gè)T字掠械。模板緩沖區(qū)的原理也是如此:通過模板測(cè)試的片段像素點(diǎn)顏色會(huì)被替換到顏色緩沖區(qū)(相當(dāng)于噴漆通過鏤空的部分顯示到大紙板上)纷闺,未通過的則不會(huì)保存到顏色緩沖區(qū)(相當(dāng)于沒鏤空的部分就被小紙板擋住了,顯示不到大紙板上)份蝴。
- 累積緩沖區(qū)
- 允許你把渲染到顏色緩沖區(qū)的值,拷貝到累積緩沖區(qū)氓轰。在多次拷貝操作到累積緩沖區(qū)時(shí)婚夫,可以用不同方式的把顏色緩沖區(qū)內(nèi)容和當(dāng)前累積緩沖區(qū)的內(nèi)容進(jìn)行重復(fù)混合。
模板緩沖區(qū)相關(guān)函數(shù)
- 開啟模板測(cè)試
glEnable(GL_STENCIL_TEST);
- 設(shè)置模板緩沖區(qū)的寫入掩碼(默認(rèn)為0xff)
glStencilMask(GLuint mask)
- 清除模板緩沖區(qū)的值(默認(rèn)為0)
glClearStencil(GLint s)
- 設(shè)置模板測(cè)試是否通過的規(guī)則
glStencilFunc(GLenum func, GLint ref, GLuint mask)
枚舉值 | 描述 |
---|---|
GL_NEVER | 永遠(yuǎn)不能通過 |
GL_ALWAYS | 永遠(yuǎn)可以通過 |
GL_LESS | 小于參考值可以通過 |
GL_LEQUAL | 小于或者等于參考值可以通過 |
GL_EQUAL | 等于參考值通過 |
GL_GEQUAL | 大于等于參考值通過 |
GL_GREATER | 大于參考值通過 |
GL_NOTEQUAL | 不等于通過 |
ref: 參考值
mask: 掩碼(和模板緩沖區(qū)的值進(jìn)行與操作署鸡,結(jié)果再和參考值作比較案糙,判斷比較結(jié)果是否符合設(shè)定的規(guī)則)
- 設(shè)置根據(jù)測(cè)試結(jié)果,如何修改模板緩沖區(qū)的值
glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
fail: 模板測(cè)試未通過時(shí)該如何變化靴庆。
zfail: 模板測(cè)試通過时捌,但深度測(cè)試未通過該如何變化。
zpass: 模板測(cè)試和深度測(cè)試均通過該如何變化炉抒。
枚舉值 | 描述 |
---|---|
GL_KEEP | 不改變奢讨,默認(rèn)值 |
GL_ZERO | 變回零 |
GL_REPLACE | 使用測(cè)試條件中的設(shè)定值來代替當(dāng)前模板值 |
GL_INCR | 增加1,如果已經(jīng)是最大值焰薄,則保持不變 |
GL_INCR_WRAP | 增加1拿诸,但如果已經(jīng)是最大值扒袖,則從零重新開始 |
GL_DECR | 減少1,但如果已經(jīng)是零亩码,則保持不變 |
GL_DECR_WRAP | 減少1季率,但如果已經(jīng)是零,則重新設(shè)置為最大值 |
GL_INVERT | 按位取反 |
- 清空模板緩沖區(qū)
glClear(GL_STENCIL_BUFFER_BIT)
例子
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
void init()
{
glClearColor(0.f, 0.f, 0.f, 0.f);
glClearStencil(0);
glClearDepth(0);
glEnable(GL_STENCIL_TEST);
}
void reshape(int w, int h)
{
if (h == 0) {
h = 1;
}
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35.f, (w * 1.f) / h, 1.f, 100.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void drawRect()
{
glColor3f(1.f, 0.f, 0.f);
glRectf(-5.f, -5.f, 5.f, 5.f);
}
void drawSpin()
{
glColor3f(0.f, 0.f, 0.f);
float dRadius = 5.f * (sqrt(2.0)/2.0);
glBegin(GL_LINE_STRIP);
for (float dAngel = 0; dAngel < 10.f; dAngel += 0.1) {
glVertex2d(dRadius * cos(dAngel), dRadius * sin(dAngel));
dRadius *= 1.003;
}
glEnd();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -20.f);
/*
永遠(yuǎn)無法通過模板測(cè)試描沟,drawSpin()繪制的內(nèi)容的像素點(diǎn)顏色不會(huì)替換到顏色緩沖區(qū)中飒泻。
因?yàn)闊o法通過模板測(cè)試,所以glStencilOp()中的第一個(gè)參數(shù)起作用吏廉,把模板緩沖區(qū)相對(duì)應(yīng)的值+1泞遗。所以drawSpin()后,形成一個(gè)背景為0迟蜜,中間螺旋線是1的模板緩沖區(qū)刹孔。
*/
glStencilFunc(GL_NEVER, 0x0, 0x0);
glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
drawSpin();
/*
當(dāng) stencil buffer 像素值的最后 1 位( mask 參數(shù)是 0x1) ,與 0x1 這個(gè) ref 值作比較娜睛, 如果 not equal 不相等時(shí)髓霞,才會(huì)繪制下面的內(nèi)容.
所以 drawRect() 在繪制的時(shí)候,有些部分是會(huì)繪制的畦戒,因?yàn)檫@部分的 stencil buffer 像素的值是 0 ; 而 stencil buffer 像素值是 1 的部分,也就是上一步方库,繪制螺旋線圈的部分,因?yàn)?stencil buffer 里對(duì)應(yīng)的像素的 值是 1 障斋,所以這部分不會(huì)繪制纵潦。也就是會(huì)出現(xiàn) drawRect()繪制的圖像有鏤空的情形(改變背景顏色就更清楚了)。
因?yàn)檫@一步的繪制不想修改模板緩存的值垃环,所以無論通過與否邀层,都希望模板緩存的值保持不變,因此 glStencilOp() 的 3個(gè)參數(shù)都是 GL_KEEP
*/
glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
drawRect();
glutSwapBuffers();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_STENCIL | GLUT_DEPTH);
glutInitWindowPosition(200, 200);
glutInitWindowSize(600, 600);
glutCreateWindow("stencil buffer test");
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
效果圖.png
參考博客
https://blog.csdn.net/csxiaoshui/article/details/23457273
https://blog.csdn.net/korekara88730/article/details/42213217