模板测试 Stencil testing

渲染管线的流程:应用阶段 -> 几何阶段 -> 光栅阶段

参考:Unity渲染流水线 - 知乎 (zhihu.com)

参考:Unity3D Stencil Test模板测试详解-腾讯游戏学堂 (qq.com)

 

模板测试发生在光栅阶段,顺序是:Alpha测试 -> 模板测试 -> 深度测试

 

 

Unity官方文档,模板测试语法:

https://docs.unity3d.com/cn/2018.4/Manual/SL-Stencil.html

 

1.我们的GPU中有一个模板缓冲区(Stencil Buffer),其大小为整个屏幕大小*8位,即屏幕上的每一个像素点都存储有一个模板值,该模板值是8位的,所以其值范围为0~255

2.如果我们在Shader中开启了模板测试,要渲染某个像素的时候,就会读取读取Shader中设置的参考值Ref(我们按需求设置),同时模板缓冲区中该像素对应的模板值StencilValueInBuffer,如果参考值Ref与模板缓冲区中的值StencilValueInBuffer满足某个条件(此条件是我们在Shader中按我们的需求指定的),则测试通过,该像素可以渲染;如果不满足,则该像素不可以渲染。无论深度测试是否通过,Shader中都有权利向模板缓冲区写入模板值(前提是开启了模板测试)

 

实例:

参考:Unity3D Shader系列之模板测试 - 知乎 (zhihu.com)

比如想实现以下效果,绿色片面在前面,红色面片在后面,只绘制绿色跟红色重叠的部分,并且显示的是红色的像素

   

1.因为想实现绿色面片影响红色,所以绿色必须先渲染,红色再渲染。因此绿色的Z轴,或者渲染队列要比红色的优先。

2.因为我们不想显示绿色的面片,所以可以把绿色的ColorMask关闭,ColorMask 0表示该Shader会正常执行逻辑,只是不渲染出来而已。深度缓冲、模板缓冲会照常写入。

3.因为绿色在前面,Z轴比红色的高,而我们又想画出红绿相交的部分,所以要把绿色的深入写入关闭(ZWrite off),否则被绿色面片挡住的红色部分因为深度检测不通过根本不会渲染

4.绿色面片开启模板测试,并且在每个像素的地方写入模板缓冲值(例如1)

5.等到红色的执行逻辑的时候,会判断每个像素点上对应的模板缓冲值,如果与之前绿色面片写入的一致,证明该区域是绿色覆盖的区域,就让它模板测试通过,画出像素

绿色面片的Shader:

            Stencil
            {
                Ref [1]    // 模板测试参考值为1
                Comp Always  // 与模板缓冲区对比测试,无论任何情况,都通过
                Pass Replace  // 模板测试通过后,往缓冲区里写入参考值1
            }

            ZWrite Off    // 关闭深入检测,防止挡住了红色面片导致红色的逻辑不执行
            ColorMask 0       // 因为不想看到绿色的面片,直接关闭颜色就行了

红色面片的Shader:

        Stencil
            {
                Ref [1]  // 模板测试参考值为1
                Comp Equal  // 只有参考值与该像素对应的模板缓存区里的值一直的时候,才算测试通过,把像素渲染出来
                Pass IncrSat  // 测试通过后,把模板缓冲区里的值+1(用意不明)
            }    
posted @ 2022-11-01 14:45  JeasonBoy  阅读(69)  评论(0编辑  收藏  举报