在Unity中,Stencil Buffer(模板缓冲区)是一种图形渲染技术,用于控制在渲染过程中绘制像素的方式。Stencil Buffer通常用于实现一些高级的渲染效果,如轮廓描边、遮罩、投影阴影、镜面反射等。它允许您在绘制像素时根据特定条件进行控制,而不仅仅是基于颜色或深度。
Stencil Buffer实际上是一个与屏幕像素数量相同的附加缓冲区,每个像素都有一个对应的Stencil值。Stencil值可以被用来在渲染中的不同阶段进行检查和修改。通常情况下,Stencil值在绘制对象时被设置,然后在随后的绘制步骤中用来决定哪些像素应该被绘制,哪些像素应该被忽略,或者以不同的方式处理。
本文将实现一个有趣的立方体,如图:
可以理解为,立方体的每个面都有自己的世界,每面只显示自己世界里的东西。
比如第一张图右边的正方体和球体,只在左侧的面对应的“世界”中存在,在另一个面中就不会显示。
实现原理
我们先来看Unity中对一个材质的Stencil属性的示例:
Stencil
{
Ref 1
Comp Always
Pass Replace
}
在我们的屏幕上,每一个像素都有自己的stencil值,默认是0。在实际应用中,我们可以通过stencil test来改变像素的stencil值,也可以通过stencil test来剔除一些像素的渲染。
图中就是一个改变像素stencil值的方法。
Ref:代表进行stencil测试时,与当前像素的stencil值进行比较的值。如这个实例代码中,我们的像素的stencil值会在深度测试时与1进行比较。
comp:代表比较过后什么情况可以通过。这里设为Always,代表所有情况都可以通过。如果不通过,则该像素不会被渲染
Pass: 通过之后做什么。这里填的是Replace,代表通过之后,用Ref的值替换当前缓冲的值。
所以我们可以得出这代码的意义:进行stencil test,结果总是通过。通过之后,就将该像素的stencil替换成ref里给出的值1。总结来说,就是对于当前模型覆盖的所有像素,都把像素中存的stencil值替换为1。
注意,stencil test是在深度测试之前进行的。如果stencil没通过,那么后面的渲染流程不会执行。
那么,利用这些原理,我们就可以实现这个效果了。
实现过程
在场景里创建两个plane,写一个shader如下
Shader "Examples/StencilAvatar"
{
Properties
{
[IntRange] _StencilID("Stencil ID", Range(0, 255)) = 0
}
SubShader
{
Tags
{
"RenderType"="Geometry"
"RenderPipeline" = "UniversalPipeline"
"Queue" = "Geometry"
}
Pass
{
//Blend Zero One
ZWrite Off
Stencil
{
Ref [_StencilID]
Comp Always
Pass Replace
Fail Keep
}
}
}
}
我们运用之前说的方法将所有这个模型覆盖的像素对应的stencil都替换成给出的_stencilID属性。stencil的值只有八位存储大小,所以范围是0到255。
然后创建2个材质,shader替换成我们写的这个shader。然后把两个shader的stencilID分别设为1,2。
把这两个材质赋给两个plane上。
创建两个layer,叫stencil1, stencil2 。
在两个plane后边分别放一堆物体。把他们的layer设为我们新建的这两个。
然后打开你的renderer设置,通常在你project里的settings文件夹下。
在Filtering的两个选项中,把新建的两个层级都取消勾选。最后看到它们变成Mixed。此时你应该在场景里就看不到那些物体了。
点最下面的 Add Render Feature,选render object。
按图片这样设置。 在创建一个一样的,命名为Stencil2,Stencil的Value设为2,其他一样。