模板测试是在深度测试前的,片段着色器处理之后进行。
模板缓冲区可以为屏幕上的每一个像素点保存一个无符号整数值(通常为8位int 0-255)。
渲染过程中,可以用这个值与预先设定好的参考值作(ReferenceValue)比较,根据结果来决定是否更新相应的像素点的颜色值
glStencilFunc(GLenum func, GLint ref, GLuint mask)
LearnOpenGL里写的不太详细。通过查询docs.gl可以知道:
GL_LESS:
if ( ref & mask ) < ( stencil & mask )
GL_GREATER
Passes if ( ref & mask ) > ( stencil & mask ).
将ref值和mask值做&运算,结果为R,然后将模板缓冲中的中的值和mask做&运算结果为S,之后在比较测试S和R,比较的方法是用前面设置的func函数
描述缓冲区如何更新
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
描边如何使用:
//启用模板测试
glEnable(GL_DEPTH_TEST);
//如果通过测试,就将模板缓冲中的值设置为指定的ref值。 可以不要
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
//清除颜色缓冲和深度缓冲,模板缓冲清除为0
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//禁止模板缓冲写入
glStencilMask(0x00); // 记得保证我们在绘制地板的时候不会更新模板缓冲
normalShader.use();
//画地板
DrawFloor()
//全通过:在绘制箱子的地方,将模板缓冲的值设置为1,通过模板测试后就会更新模板值为1。
glStencilFunc(GL_ALWAYS, 1, 0xFF);
//开启模板写入
glStencilMask(0xFF);
//画两个方框
DrawTwoContainers();
//GL_NOTEQUAL:( ref & mask ) != ( stencil & mask ).
//开始绘制边框:在模板缓冲值不为1的地方绘制
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
//禁止模板缓冲写入
glStencilMask(0x00);
//将深度测试禁用,是为了让边框不被地面所遮挡
glDisable(GL_DEPTH_TEST);
shaderSingleColor.use();
DrawTwoScaledUpContainers();
//这里是为了将模板缓冲清零,为下一次渲染做准备。
glStencilMask(0xFF);
glEnable(GL_DEPTH_TEST);
可能代码比较难懂:来简述
太多概念LearnOpenGL有,不赘述。
简而言之:判断场景中物体之间前后遮挡关系
可以理解为和颜色缓冲区一样的东西,有每个需要渲染的片段,只不过它存储的是深度值。
摘录:
- 模型一开始所在的模型空间:无深度
- 通过M矩阵变换到世界空间,此时模型坐标已经变换到了齐次坐标(x,y,z,w):深度存在z分量
- 通过V矩阵变换到视察空间(摄像机空间):深度存在z分量(线性)通过P矩阵变换到裁剪空间:深度缓冲中此空间的z/w中(已经变成了非线性的深度)
- 最后通过一些投影映射变换到屏幕空间
使用非线性主要是远近显示的精度需求不一样,不需要为低精度的花费更多的资源。
glDepthFunc(GL_LESS);
这里其实没什么,就是系统的值去如何通过或丢弃一个片段。