深度测试和模板测试
文章目录
一、模板测试
模板测试是在深度测试前的,片段着色器处理之后进行。
模板缓冲
模板缓冲区可以为屏幕上的每一个像素点保存一个无符号整数值(通常为8位int 0-255)。
模板测试函数
渲染过程中,可以用这个值与预先设定好的参考值作(ReferenceValue)比较,根据结果来决定是否更新相应的像素点的颜色值
glStencilFunc
glStencilFunc(GLenum func, GLint ref, GLuint mask)
- func:比较函数的选择参数
- ref:模板测试的参考值
- 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函数
- 简述一下按位与&:全1为1,负责为0
glStencilOp
描述缓冲区如何更新
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
- sfail:模板测试失败时采取的行为。
- dpfail:模板测试通过,但深度测试失败时采取的行为。
- 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);
可能代码比较难懂:来简述
- 使用【禁止模板缓冲写入】绘制地板,但不写入模板缓冲,此时地板已经绘制,缓冲区全为0,
- 使用【开启模板缓冲写入】和【设置通过测试设为1】,此时cube渲染,缓冲区cube区域为1
- 再次使用【禁止模板缓冲写入】和【在模板缓冲值不为1的地方绘制】,此时再次绘制cube,源码里可以看到此处渲染时 float scale = 1.1f,所以大一点点。
- 诶嘿,此时对缓冲去内为1的地方的大一点点的为0的地方设置为1开始绘制,即为边界。
二、深度测试
太多概念LearnOpenGL有,不赘述。
简而言之:判断场景中物体之间前后遮挡关系
Z-Buffer (深度缓冲)和深度值
可以理解为和颜色缓冲区一样的东西,有每个需要渲染的片段,只不过它存储的是深度值。
摘录:
- 模型一开始所在的模型空间:无深度
- 通过M矩阵变换到世界空间,此时模型坐标已经变换到了齐次坐标(x,y,z,w):深度存在z分量
- 通过V矩阵变换到视察空间(摄像机空间):深度存在z分量(线性)通过P矩阵变换到裁剪空间:深度缓冲中此空间的z/w中(已经变成了非线性的深度)
- 最后通过一些投影映射变换到屏幕空间
使用非线性主要是远近显示的精度需求不一样,不需要为低精度的花费更多的资源。
深度测试函数 glDepthFunc
glDepthFunc(GL_LESS);
这里其实没什么,就是系统的值去如何通过或丢弃一个片段。