【OpenGL】六、深度测试和模板测试

深度测试和模板测试

文章目录

  • 深度测试和模板测试
  • 一、模板测试
    • 模板缓冲
    • 模板测试函数
      • glStencilFunc
      • glStencilOp
  • 深度测试到底能干什么?
  • 二、深度测试
    • Z-Buffer (深度缓冲)和深度值
    • 深度测试函数 glDepthFunc


一、模板测试

模板测试是在深度测试前的,片段着色器处理之后进行。

模板缓冲

模板缓冲区可以为屏幕上的每一个像素点保存一个无符号整数值(通常为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);  

可能代码比较难懂:来简述

  1. 使用【禁止模板缓冲写入】绘制地板,但不写入模板缓冲,此时地板已经绘制,缓冲区全为0,
  2. 使用【开启模板缓冲写入】和【设置通过测试设为1】,此时cube渲染,缓冲区cube区域为1
  3. 再次使用【禁止模板缓冲写入】和【在模板缓冲值不为1的地方绘制】,此时再次绘制cube,源码里可以看到此处渲染时 float scale = 1.1f,所以大一点点。
  4. 诶嘿,此时对缓冲去内为1的地方的大一点点的为0的地方设置为1开始绘制,即为边界。

二、深度测试

太多概念LearnOpenGL有,不赘述。
简而言之:判断场景中物体之间前后遮挡关系

Z-Buffer (深度缓冲)和深度值

可以理解为和颜色缓冲区一样的东西,有每个需要渲染的片段,只不过它存储的是深度值。
摘录:

  • 模型一开始所在的模型空间:无深度
  • 通过M矩阵变换到世界空间,此时模型坐标已经变换到了齐次坐标(x,y,z,w):深度存在z分量
  • 通过V矩阵变换到视察空间(摄像机空间):深度存在z分量(线性)通过P矩阵变换到裁剪空间:深度缓冲中此空间的z/w中(已经变成了非线性的深度)
  • 最后通过一些投影映射变换到屏幕空间

使用非线性主要是远近显示的精度需求不一样,不需要为低精度的花费更多的资源。


深度测试函数 glDepthFunc

glDepthFunc(GL_LESS);

这里其实没什么,就是系统的值去如何通过或丢弃一个片段。


附录:
LearnOpengl
模板和深度测试
glStencilFunc函数

你可能感兴趣的:(计算机图形学之旅,图形渲染,c++,游戏引擎)