模板测试(Stencil Test)的基础知识

  • Post author:
  • Post category:其他




本文分享模板测试(Stencil Test)的基础知识

在渲染管线中, 模板测试发生在片元着色器处理和透明度测试之后, 深度测试之前.

模板测试最常见的应用就是各种遮罩, 特别是有形状的遮罩, 如Unity中的

Mask

组件, 这些遮罩的特点就是可以按照某种形状(可以是非矩形的)来渲染片元.

比如我们在游戏中经常看到的各种形状的头像 ,而

Rect Mask 2D

组件使用的是裁剪测试(Scissor Test), 可以指定绘制一块矩形区域内的片元. 模板测试的圆形遮罩如图所示.

在这里插入图片描述



模板测试基础

和深度测试类似, 模板测试也有一个对应的缓存, 即模板缓存(Stencil Buffer), 用于记录所有

像素

的模板值, 默认值为0.

在渲染某个物体时, 我们可以指定一个参考值(Referencce value, unity中叫Stencil ID), 当渲染这个物体的某个

片元

时, 将片元携带的参考值与模板缓存中的值作比较, 根据不同的比较方式, 满足要求则通过测试, 然后根据设定好的操作对模板缓存中的值进行更新, 当然, 也可以指定没有通过测试时的操作.

由上面的过程, 我们要注意几个关键的点:


  • 模板值

    : 模板缓存中已经存在的值

  • 参考值

    : 在渲染该物体前, 由程序设置的指定值

  • 比较函数

    : 决定如何将两个值作比较的函数

  • 操作函数

    : 定义通过或者不通过测试后对模板值的更新操作

模板测试是一个不可编程, 但是可以配置的管线阶段. 我们通过指令对模板测试进行配置, 在Unity中, 其基本语法为:

Stencil
{
    Ref refValue
    Comp always
    Pass keep
    Fail keep
    ZFail keep
    WriteMask 255
    ReadMask 255
}



Unity中模板测试语法的说明

我们通过

Ref refValue

来指定参考值, 参考值是一个整型值, 正负都可以.

然后通过

Comp xxx

来指定比较函数, 接收的参数是

比较函数的枚举值

, 对应C#中的枚举

UnityEngine.Rendering.CompareFunction

, 从0到8, 分别代表(括号中的是其对应的枚举):


  • 0(Disabled)

    : 关闭模板测试, 等同于全部通过测试, 经过测试发现不是真的关闭.

  • 1(Never):

    全部不能通过测试

  • 2(Less)

    : 待比较的值小于缓存中的值时通过测试

  • 3(Equal)

    : 待比较的值等于缓存中的值时通过测试

  • 4(LessEqual)

    : 待比较的值小于等于缓存中的值时通过测试

  • 5(Greater)

    : 待比较的值大于缓存中的值时通过测试

  • 6(NotEqual)

    : 待比较的值不等于缓存中的值时通过测试

  • 7(GreaterEqual)

    : 待比较的值大于等于缓存中的值时通过测试

  • 8(Always)

    : 全部通过测试, 默认值

再然后通过通过或者不通过测试的各种情况, 指定对模板值的更新操作, 分别是:


  • Pass operation

    : 模板测试和深度测试都通过后的操作

  • Fail operation

    : 模板测试和深度测试都未通过后的操作

  • ZFail operation

    : 模板测试通过而深度测试未通过后的操作

它们的参数都是同一个类型, 即

操作函数的枚举值

, 对应C#中的枚举

UnityEngine.Rendering.StencilOp

, 从0到7, 分别代表:


  • 0(Keep)

    : 保持模板缓存中的值不变

  • 1(Zero)

    : 将模板缓存中的值置为0

  • 2(Replace)

    : 使用参考值替换模板缓存中的值

  • 3(IncrementSaturate)

    : 使模板缓冲区值增大, 最大限制为可表示的最大无符号值

  • 4(DecrementSaturate)

    : 使模板缓冲区值减小, 最小限制为0

  • 5(Invert)

    : 对模板缓冲区值按位求反

  • 6(IncrementWrap)

    : 与IncrementSaturate类似, 只是达到最大后继续增大将重新设置为 0

  • 7(DecrementWrap)

    : 与DecrementSaturate类似, 只是达到最小后继续减小将重新设置为可表示的最大无符号值

最后的

ReadMask



WriteMask

两个

掩码

是对模板值和参考值的额外处理, 值为0-255之间的整数值,

ReadMask

代表在读取模板值后, 将其与掩码按位与之后再与参考值作比较, 而

WriteMask

代表在使用参考值更新模板值之前, 在模板值与掩码按位与之后再更新, 一般两个掩码都设置为255, 代表不做任何额外处理.

在Unity中可以通过属性面板的方式来设置, 但是经过测试, 使用变量的方式来设置模板参数无法关闭模板测试:

_Stencil ("Stencil ID", Float) = 0
[Enum(UnityEngine.Rendering.CompareFunction)] _StencilComp ("Stencil Comparison", Int) = 8
[Enum(UnityEngine.Rendering.StencilOp)] _StencilOp ("Stencil Operation", Int) = 0
_StencilWriteMask ("Stencil Write Mask", Range(0, 255)) = 255
_StencilReadMask ("Stencil Read Mask", Range(0, 255)) = 255

Stencil
{
    Ref [_Stencil]
    Comp [_StencilComp]
    Pass [_StencilOp]
    ReadMask [_StencilReadMask]
    WriteMask [_StencilWriteMask]
}

效果如图:

在这里插入图片描述

以上就是模板测试的基础内容. 下一篇文章我们会使用模板测试来模拟Unity中

Mask

组件, 并且使用另一种方式来解决锯齿问题, 希望对大家有所帮助.



版权声明:本文为woodengm原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。