OpenGL之模板测试

模板测试

当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做模板缓冲(Stencil Buffer)

模板测试需要模板缓存,GLFW默认创建。
如果自己创建的帧缓存没有模板缓存,则模板测试总是通过。

三个相关函数 参考1 参考2
(1)glStencilMask(GLunit mask)设置一个模板缓冲区的位遮罩

glStencilMask允许我们设置一个位掩码(Bitmask),它会与将要写入缓冲的模板值进行与(AND)运算

glStencilMask(0xFF); // 每一位写入模板缓冲时都保持原样

//禁止模板缓冲的写入
glStencilMask(0x00); // 每一位在写入模板缓冲时都会变成0(禁用写入)

glStencilMask(GLunit mask)
设置一个模板缓冲区的位遮罩,默认位遮罩为1。

模板测试最后,当测试通过要写入新的模板值时,新的模板值会与位遮罩进行按位与(AND)运算,不为0的位才会写入(注意不是写入整个模板值)。比如:现在要写入的模板值是2(10),但是位遮罩是5(101),与后每位都为0,所以最后什么都没有写入

(2)设置比较函数、引用值和掩码glStencilFunc
glStencilFunc(GLenum func, GLint ref,Gluint mask);

func:设置模板测试函数。用于比较已储存的模板值上和glStencilFunc函数的ref值上。可用的选项
有:GL_NEVER,GL_LESS,GL_LEQUAL,GL_GREATER,GL_GEQUAL,GL_EQUAL,GL_NOTEQUAL和GL_ALWAYS

ref:设置了模板测试的参考值。模板缓冲的内容将会与这个值进行比较。

mask:设置一个掩码,它将会与参考值和储存的模板值在测试比较它们之前进行与(AND)运算。初始情况下所有位都为1.
行为含义
GL_NEVERAlways fails
GL_LESSPasses if ( ref & mask ) < ( stencil & mask )
GL_LEQUALPasses if ( ref & mask ) <= ( stencil & mask )
GL_GREATERPasses if ( ref & mask ) > ( stencil & mask )
GL_GEQUALPasses if ( ref & mask ) >= ( stencil & mask )
GL_EQUALPasses if ( ref & mask ) = ( stencil & mask )
GL_NOTEQUALPasses if ( ref & mask ) != ( stencil & mask )
GL_ALWAYSAlways passes
(3)指示如何更新缓冲,需要glStencilOp函数:
glStencilOp(GLenum sfail,GLenum dpfail,GLenum dppass);

sfail:模板测试失败时采取的行为

dpfail:模板测试通过,但深度测试失败时采取的行为。

dppass:模板测试和深度测试都通过时采取的行为。

在这里插入图片描述

模板缓冲简单例子

在这里插入图片描述
模板缓冲首先会被清除为0,之后在模板缓冲中使用1填充了一个空心矩形。场景中的片段将会只在片段的模板值为1的时候会被渲染(其它的都被丢弃了)

大体步骤
(1)启用模板缓冲的写入。

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE)

(2)渲染物体,更新模板缓冲的内容。

glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // don't forget to clear the stencil buffer!

(3)禁用模板缓冲的写入。

// draw floor as normal, but don't write the floor to the stencil buffer, we only care about the containers. We set its mask to 0x00 to not write to the stencil buffer.
//正常绘制地板,但不要将地板写入模具缓冲区,我们只关心容器。我们将它的掩码设置为0x00,以避免写入模板缓冲区。
 glStencilMask(0x00);

(4)渲染(其它)物体,这次根据模板缓冲的内容丢弃特定的片段。

glEnable(GL_DEPTH_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

glStencilMask(0x00); // 记得保证我们在绘制地板的时候不会更新模板缓冲
normalShader.use();
DrawFloor()  

glStencilFunc(GL_ALWAYS, 1, 0xFF); 
glStencilMask(0xFF); 
DrawTwoContainers();

glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00); 
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use(); 
DrawTwoScaledUpContainers();
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);  
ubuntu下代码中注意事项

完整代码
在这里插入图片描述

(1)#include <boost/filesystem.hpp>的使用
unsigned int cubeTexture = loadTexture(FileSystem::getPath("resources/textures/marble.jpg").c_str());
unsigned int floorTexture = loadTexture(FileSystem::getPath("resources/textures/metal.png").c_str());

修改为

unsigned int cubeTexture = loadTexture(boost::filesystem::path("textures/marble.jpg").c_str());
unsigned int floorTexture = loadTexture(boost::filesystem::path("textures/metal.png").c_str());
(2)有关图片源(网上随意选择下载)

resources/textures/marble.jpg
resources/textures/metal.png

(3)有关着色器

将相应文件放入工程目录下即可(VSCode可在应用商店安装Shader languages support for VS Code)

Shader shader("2.stencil_testing.vs", "2.stencil_testing.fs");
Shader shaderSingleColor("2.stencil_testing.vs", "2.stencil_single_color.fs");
(4)有关CMakeLists.txt和编译所出现的错误
main.cpp:(.text+0x7b4):对‘stbi_load’未定义的引用
...

对‘boost::system::generic_category()’未定义的引用
对‘boost::system::generic_category()’未定义的引用
...

第一个错误std_image.h
解决
include:std_image.h
①、新建src目录:std_image.cpp

#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

②、修改CMakeLists.txt
在这里插入图片描述

第二个错误:boost相关
解决
在CMakeLists.txt里面添加相应配置
在这里插入图片描述

(5)result

运行时图像随鼠标移动太频繁,导致不好控制,且失去鼠标对终端的控制
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值