OpenGL学习日志之模板测试

模板测试(Stencil Test)出现原因

深度测试更多是为了解决如何区分物体前后遮挡关系,从而选择丢弃片段的测试。而模板测试,是通过设置片元模板缓冲区模板值和引用模板值,再按照我们设定的运算函数来丢弃某些片段,从而来达到我们想要的一些效果。是一种在深度测试之前丢弃片元的一个辅助方法,是为了达到我们预定的一些效果而添加的一个测试手段。

模板测试(Stencil Test)的位置

模板测试是在透明度测试之后,深度测试之前进行的,模板测试也有一个自己的缓冲区,叫做模板缓冲区。它和颜色缓冲区,深度缓冲区类似,模板缓冲区的模板值通常是8bit(一个字节),因此每个片段的模板值的范围是0-255。模板测试根据模板缓冲区中片段的模板值与设置的引用值,进行我们设置的运算式进行比较,如果没有通过测试,则丢弃该片段。
在这里插入图片描述

模板测试(Stencil Test)

openGL中开启模板测试

glEnable(GL_STENCIL_TEST);

清除缓冲区
一旦启用模板测试,在每一次渲染以前,我们需要像清空颜色缓冲区和深度缓冲区一样,清空模板缓冲区。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

通过模板函数,设置运算符和模板引用值

void glStencilFunc(GLenum func, GLint ref, GLuint mask)

//简单例子:它会告诉OpenGL,无论何时,一个片段模板值等于引用值1,片段就能通过测试被绘制了,否则就会被丢弃
glStencilFunc(GL_EQUAL, 1, 0xFF)

func:设置模板测试运算符,可用的选项是:GL_NEVER、GL_LEQUAL、GL_GREATER、GL_GEQUAL、GL_EQUAL、
GL_NOTEQUAL、GL_ALWAYS。它们的语义和深度缓冲的相似。

操作描述
GL_NEVER永远不通过测试
GL_ALWAYS永远通过测试
GL_LEQUAL模板值小于等于引用值时通过测试
GL_GEQUAL模板值大于等于引用值时用过测试
GL_EQUAL模板值等于引用值的时通过测试
GL_GREATER模板值大于引用值时通过测试
GL_NOTEQUAL模板值不等于引用值时通过测试

ref:引用值,用于和模板缓冲的模板值做运算比较的
mask:模板值在比较以前位遮罩,即模板值在和引用值ref做运算比较以前,需要先与mask遮罩值进行按位与,然后与后的结果再进行和引用值比较,一般设置0xFF

设置模板缓冲是否可写
OpenGL是通过设置位遮罩来控制写操作的,当我们在准备写入模板值之前,我们会将模板值与这个位遮罩进行与运算,一般我们使用0xFF和0x00就行,如果你有特殊的需求需要控制某一位的写入和其他不一样,你也可以自己设置。

//此时,模板值与它进行按位与运算结果是模板值,模板缓冲可写
glStencilMask(0xFF); 

//此时,模板值与它进行按位与运算结果是0,模板缓冲不可写
glStencilMask(0x00); 

如何更新缓冲区
与更新深度缓冲区不同,当通过了测试,并且缓冲区设置为可写模式,我们仍然可以设置如何更新模板缓冲区,以及什么时候更新缓冲区,具有更大的自由度。通过glStencilOp函数。

void glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)

sfail:如果模板测试失败将采取的动作
dpfail:如果模板测试通过,但是深度测试失败时采取的动作
dppass:如果深度测试和模板测试都通过,将采取的动作

每个选项可以有以下几种动作

操作描述
GL_KEEP保持现有的模板值
GL_ZERO将模板值设置为0
GL_REPLACE将模板值设置为ref引用值
GL_INCR如果模板值不是最大值,则模板值+1
GL_INCR_WRAP与GL_INCR一样将模板值+1,如果模板值已经是最大值则设为0
GL_DECR如果模板值不是最小值就将模板值-1
GL_DECR_WRAP与GL_DECR一样将模板值-1,如果模板值已经是最小值则设为最大值
GL_INVERT按位反转当前模板缓冲区值

示列代码:代表任何测试的任何结果,模板缓冲都会保留它的值。默认行为不会更新模板缓冲。

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP)

模板测试应用1–物体轮廓

在这里插入图片描述
大概步骤是

第一步

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glEnable(GL_STENCIL_TEST);
    glStencilFunc(GL_ALWAYS, 1, 0xFF); //所有片段都要写入模板缓冲
    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

开启深度测试 ,开启深度写入,设置深度运算为GL_LESS,即片元深度值<深度缓冲值通过测试
开启模板测试,设置模板运算函数为,所有片段都通过
写入模板缓冲为当通过深度测试且通过模板测试,用ref引用值1替换模板缓冲区

第二步
普通绘制正方形1
普通绘制正方形2
绘制完以后
此时能通过深度测试,绘制出来的片元,模板值都为1。

        glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
        glStencilMask(0x00);
        glDisable(GL_DEPTH_TEST);

深度测试依旧开启,但关闭深度写入
模板测试依旧开启,但关闭模板写入
设置模板值为不等于1则通过
绘制放大一点的正方形1
绘制放大一点的正方形2

由于原本绘制的正方形区域片元模板值都为1,而我们设置的模板值不等于1通过,因此放大的正方形绘制时,只有大于原本大小的正方形的片元片段才能通过模板测试,也就是我们拿来作为描边的部分。

第三步
绘制完成以后,重新开启深度写入和模板写入

        glStencilMask(0xFF);
        glEnable(GL_DEPTH_TEST);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值