模版测试 Stencil 简介,及在 Unity 中的应用
1 什么是模版测
首先了解图形渲染管线,如下图:
模版测试是GPU渲染流水线中的一个环节,在片元着色器之后的逐片元操作过程中执行。在透明度之后,深度测试之前。
模版测试通过模版值进行相应操作,默认的模版值是0,是范围0-255的8位数。
模版测试通过比较操作来决定片元是否渲染,以及如何更新模版值。参考值 Ref 和当前模版值 Mask 进行比较。
--通过则进行渲染,并把模版值根据更新操作设置为参考值,
--否则丢弃片元,且不更新模版值。
比较操作:
/* StencilFunction */
#define GL_NEVER 0x0200
#define GL_LESS 0x0201
#define GL_EQUAL 0x0202
#define GL_LEQUAL 0x0203
#define GL_GREATER 0x0204
#define GL_NOTEQUAL 0x0205
#define GL_GEQUAL 0x0206
#define GL_ALWAYS 0x0207
更新操作:
/* StencilOp */
/* GL_ZERO */ 0
#define GL_KEEP 0x1E00
#define GL_REPLACE 0x1E01
#define GL_INCR 0x1E02
#define GL_DECR 0x1E03
/* GL_INVERT */ 0x150A
#define GL_INCR_WRAP 0x8507
#define GL_DECR_WRAP 0x8508
模版值的读取和写入,可以通过掩码控制。掩码分为 ReadMask 和 WiriteMask。
掩码也是范围0-255的8位数,通过按位与进行掩码运算。这样模版值可以进行精准位操作,同时进行多层模版测试。
--读入时值为 Mask & ReadMask
--写入时值为 Ref & ReadMask
2 模版测试在OpenGL中怎么使用?
第一步,开启模版测试。
glEnable(GL_STENCIL_TEST);
第二步,清除模版缓冲。下面同时包含清除颜色缓冲和深度缓冲。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
第三步,设置掩码值,此掩码为 WriteMask。一般总是0或255。
glStencilMask(0xFF);
第四步,设置模版函数。func 为上面提到的比较操作;ref 为参考模版值;mask 为 ReadMask。
glStencilFunc(GLenum func, GLint ref, GLuint mask)
第五步,Ref 设置操作函数。 所有参数为上面提到的更新操作。sfail为模版测试失败的操作;
dpfail为模版测试成功,深度测试失败的操作;dppass 为模版测试和深度测试都通过的操作。
glStencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
3 模版测试在GLSL中怎么使用?
模版测试在 Shader 中通过下面函数进行控制,其中后面五个为可选,不填写使用默认值。
stencil{
Ref 128
Comp GEqual
ReadMask 255
WriteMask 255
Pass Replace
Fail Keep
ZFail Keep
}
4 模版测试在Unity中怎么使用?
在 unity 中在 UI 的默认着色器中支持了此功能,为了在同一个着色器中支持多个操作,参数通过数值进行操作。
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
_StencilComp ("Stencil Comparison", Float) = 8 --比较操作
_Stencil ("Stencil ID", Float) = 0 --参考值
_StencilOp ("Stencil Operation", Float) = 0 --通过时 Ref 更新操作
_StencilWriteMask ("Stencil Write Mask", Float) = 255 --写入掩码
_StencilReadMask ("Stencil Read Mask", Float) = 255 --读取掩码
下面为参数树枝和操作的对照关系表,因为在 OpenGL 中更新操作不是连续的枚举值,所以和下面的顺序无法对应,
而且 unity 官方文档没有说明导致试使用起来比较迷惑~_~。将下面的值在 material 中填写即可完成模版测试。
1 - Never
2 - Less
3 - Equal
4 - LEqual
5 - Greater
6 - NotEqual
7 - GEqual
8 - Always
0 - Keep
1 - Zero
2 - Replace
3 - IncrSat
4 - DecrSat
5 - Invert
6 - IncrWrap
7 - DecrWrap
5 模版测试的应用
主要应用就是控制片元是否绘制来完成我们的图形绘制需求。且模版测试本身的性能不是问题,可以放心使用。
例如:
1 UGUI 的 SrollView 组件中,默认会有一个 Mask 组件,就是通过模版测试来控制是否可见进行渲染。
实现方式
--通过在运行时将子组件的 material 进行切换为含有默认模版测试的 material 进行渲染。
导致问题
--在子组件中不能使用我们自定义的 material,否则会被替换。
--在替换的过程中还有一个遍历操作,当含有大量子组件时,性能会受到影响。
2 引导过程中高亮显示。尤其是我就有高要求的轮廓显示和不规则图形的显示。
3 规定类型和区域的渲染显示。
参考文章:
https://learnopengl-cn.github.io/04%20Advanced%20OpenGL/02%20Stencil%20testing/
https://docs.unity3d.com/Manual/SL-Stencil.html
https://blog.****.net/wangdingqiaoit/article/details/52143197
注:图片资源来源于网络