美文网首页
OpenGL 模板缓冲区的理解

OpenGL 模板缓冲区的理解

作者: 瀚_ | 来源:发表于2019-06-02 16:48 被阅读0次

OpenGL缓冲区

  • 颜色缓冲区
    • 包含颜色索引或者RGBA颜色数据
  • 深度缓冲区
    • 存储每个像素的深度值。
    • 当启动深度测试时,片段像素深度值和深度缓冲区深度值比较,决定片段哪些像素点数据可以替换到颜色缓冲区中。
  • 模板缓冲区
    • 为屏幕上的每个像素点保存一个无符号整数值。
    • 在渲染过程中,可以用缓冲区保存的值与一个预先设定的参考值相比较,根据比较的结果来决定是否更新响应的像素点的颜色值。这个比较的过程称为模板测试。
    • 模板测试发生在透明度测试(alpha test)之后,深度测试(depth test)之前。
模板测试.png

中间小的纸板的T字位置是镂空的,当用喷漆喷在纸板上时,镂空的部分有喷漆通过,没镂空的就被纸板挡住,所以最终显示在大纸板上就是一个T字。模板缓冲区的原理也是如此:通过模板测试的片段像素点颜色会被替换到颜色缓冲区(相当于喷漆通过镂空的部分显示到大纸板上),未通过的则不会保存到颜色缓冲区(相当于没镂空的部分就被小纸板挡住了,显示不到大纸板上)。

  • 累积缓冲区
    • 允许你把渲染到颜色缓冲区的值,拷贝到累积缓冲区。在多次拷贝操作到累积缓冲区时,可以用不同方式的把颜色缓冲区内容和当前累积缓冲区的内容进行重复混合。

模板缓冲区相关函数

  • 开启模板测试
glEnable(GL_STENCIL_TEST);
  • 设置模板缓冲区的写入掩码(默认为0xff)
glStencilMask(GLuint mask)
  • 清除模板缓冲区的值(默认为0)
glClearStencil(GLint s)
  • 设置模板测试是否通过的规则
glStencilFunc(GLenum func, GLint ref, GLuint mask)
枚举值 描述
GL_NEVER 永远不能通过
GL_ALWAYS 永远可以通过
GL_LESS 小于参考值可以通过
GL_LEQUAL 小于或者等于参考值可以通过
GL_EQUAL 等于参考值通过
GL_GEQUAL 大于等于参考值通过
GL_GREATER 大于参考值通过
GL_NOTEQUAL 不等于通过
 ref: 参考值
 mask: 掩码(和模板缓冲区的值进行与操作,结果再和参考值作比较,判断比较结果是否符合设定的规则)  
  • 设置根据测试结果,如何修改模板缓冲区的值
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_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);

/*
    永远无法通过模板测试,drawSpin()绘制的内容的像素点颜色不会替换到颜色缓冲区中。
    
    因为无法通过模板测试,所以glStencilOp()中的第一个参数起作用,把模板缓冲区相对应的值+1。所以drawSpin()后,形成一个背景为0,中间螺旋线是1的模板缓冲区。
*/
    glStencilFunc(GL_NEVER, 0x0, 0x0);
    glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
    drawSpin();
    
/*
    当 stencil buffer 像素值的最后 1 位( mask 参数是 0x1) ,与 0x1 这个 ref 值作比较, 如果 not equal 不相等时,才会绘制下面的内容.

所以 drawRect() 在绘制的时候,有些部分是会绘制的,因为这部分的 stencil buffer 像素的值是 0 ; 而 stencil buffer 像素值是 1 的部分,也就是上一步,绘制螺旋线圈的部分,因为 stencil buffer 里对应的像素的 值是 1 ,所以这部分不会绘制。也就是会出现 drawRect()绘制的图像有镂空的情形(改变背景颜色就更清楚了)。

因为这一步的绘制不想修改模板缓存的值,所以无论通过与否,都希望模板缓存的值保持不变,因此 glStencilOp() 的 3个参数都是 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

相关文章

  • OpenGL模板缓冲区与模板测试(转)

    OpenGL模板缓冲区与模板测试 帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区:用于绘图的缓冲区,它...

  • OpenGL 模板缓冲区的理解

    OpenGL缓冲区 颜色缓冲区包含颜色索引或者RGBA颜色数据 深度缓冲区存储每个像素的深度值。当启动深度测试时,...

  • OpenGL 基础渲染(颜色混合)

    OpenGL 混合 OpenGL渲染时会把颜色值存在颜色缓存区中,每个片段的深度值也是放在深度缓冲区。当深度缓冲区...

  • QT+OPenGL十六之模板缓冲区

    模板缓冲区(Stencil Buffer) 模板缓冲区的作用是可以自定义丢弃片段。作用在深度缓冲区之前,被保留的片...

  • OpenGL 基础教程0

    OpenGL绘图的基本过程是:清除缓冲区,设置当前颜色,绘制几何图元,输出图形。 一、清除缓冲区 缓冲区是用来保存...

  • OpenGL入门详解

    假设你已经对OpenGL有了基本的了解,知道OpenGL的渲染管线等。 1.创建渲染缓冲区 Gluint m_re...

  • QT+OPenGL十七帧缓冲区(离屏渲染)

    帧缓冲区((Framebuffer) OpenGL允许我们自定义一个可渲染的缓冲区,我们之前渲染的场景是默认的缓冲...

  • OpenGL入门(七)-- 图形图像渲染中的深度缓冲区

    今天我们来聊聊一个很重要的概念--深度缓冲区,OpenGL中的深度缓冲区,也叫Z缓冲区,接下来我们来大概了解一下。...

  • OpenGL 视频渲染

    1:所需要的头文件 2:基本设置 3:设置绘制框架的上下文 4:OpenGL 设置 5:设置缓冲区 6:创建缓冲区...

  • OpenGL 帧缓冲区

    文章引用OpenGL 帧缓冲区 - wen_dao_ - 博客园 帧缓冲区 几乎每个图形程序的重要目标之一都是在屏...

网友评论

      本文标题:OpenGL 模板缓冲区的理解

      本文链接:https://www.haomeiwen.com/subject/kywxxctx.html