OpenGL 模板緩沖區(qū)的理解

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末遂庄,一起剝皮案震驚了整個(gè)濱河市寥院,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涛目,老刑警劉巖秸谢,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異霹肝,居然都是意外死亡估蹄,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門沫换,熙熙樓的掌柜王于貴愁眉苦臉地迎上來臭蚁,“玉大人,你說我怎么就攤上這事】兀” “怎么了炭晒?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長甥角。 經(jīng)常有香客問我网严,道長,這世上最難降的妖魔是什么嗤无? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任震束,我火速辦了婚禮,結(jié)果婚禮上当犯,老公的妹妹穿的比我還像新娘垢村。我一直安慰自己,他們只是感情好嚎卫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布嘉栓。 她就那樣靜靜地躺著,像睡著了一般拓诸。 火紅的嫁衣襯著肌膚如雪侵佃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天奠支,我揣著相機(jī)與錄音馋辈,去河邊找鬼。 笑死倍谜,一個(gè)胖子當(dāng)著我的面吹牛迈螟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播尔崔,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼答毫,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了季春?” 一聲冷哼從身側(cè)響起洗搂,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鹤盒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侦副,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侦锯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秦驯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尺碰。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亲桥,到底是詐尸還是另有隱情洛心,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布题篷,位于F島的核電站词身,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏番枚。R本人自食惡果不足惜法严,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望葫笼。 院中可真熱鬧深啤,春花似錦、人聲如沸路星。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洋丐。三九已至呈昔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垫挨,已是汗流浹背韩肝。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留九榔,地道東北人哀峻。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像哲泊,于是被迫代替她去往敵國和親剩蟀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容