(一)、Stencil的理论知识
Stencil用于在渲染时保留和抛弃像素
Stencil对应的材质组件在Unity中的显示如图:
1. Ref ReferenceValue
对应组件中的Stencil ID由程序自己设定,用于和缓冲(Stencil Buffer)中的值相比较,比较的方式在Stencil Comparison中设定,满足条件则渲染出来(保留)。
2. Stencil Comparison
渲染时判断是否保留的条件。将ref中的value与buf中的value进行比较公式如下:
if((refValue & readMask) comparisonFunction (bufferValue & readMask))
{ 通过测试,渲染时保留 }
else
{ 渲染时抛弃 }
具体的方式包括:
比较方法 | 值 | 含义 |
---|---|---|
Disabled | 0 | 不进行Stencil与深度测试 |
Never | 1 | 无论左边和右边为何值,使测试永远不通过,渲染时总是抛弃 |
Less | 2 | 左边 < 右边时通过测试,渲染时保留,否则抛弃 |
Equal | 3 | 左边 = 右边时通过测试,渲染时保留,否则抛弃 |
LessEqual | 4 | 左边 <= 右边时通过测试,渲染时保留,否则抛弃 |
Greater | 5 | 左边 > 右边时通过测试,渲染时保留,否则抛弃 |
NotEqual | 6 | 左边 != 右边时通过测试,渲染时保留,否则抛弃 |
GreaterEqual | 7 | 左边 >= 右边时通过测试,渲染时保留,否则抛弃 |
Always | 8 | 使测试永远通过,渲染时总是保留(是Stencil Comparison的默认值即8) |
具体对应的值可在Unity的接口UnityEngine.Rendering.CompareFunction
枚举中查看,当所填值不在该范围内时采用默认值8即Always渲染时总是保留。
3. Stencil Operation
渲染测试之后,无论像素最终被保留或被抛弃都会执行Stencil Operation来更新缓冲中的值stencilBufferValue,具体更新的方式包括:
更新方式 | 值 | 含义 |
---|---|---|
Keep | 0 | 保持当前buf的值不变 |
Zero | 1 | 不管ref值为何值都将当前buf的值置0 |
Replace | 2 | 将ref值写入buf,即将原来的buf值替换为现在的ref值 |
IncrementSaturate | 3 | 不管ref值为何值都将当前buf的值+1,超过255不变 |
DecrementSaturate | 4 | 不管ref值为何值都将当前buf的值置-1,超过0不变 |
Invert | 5 | 不管ref值为何值都将当前buf的值按位取反 |
IncrementWrap | 6 | 不管ref值为何值都将当前buf的值+1,若当前值为255增1则变为0 |
DecrementWrap | 7 | 不管ref值为何值都将当前buf的值-1,若当前值为0减1则变为255 |
具体对应的值可在Unity的接口UnityEngine.Rendering.StencilOp
枚举中查看,当所填值不在范围内时采用默认值zero(试验得来·)。
4. Read Mask & Write Mask
读遮罩与写遮罩,分别在读取与写入时对ref的值与buf的值进行掩码操作,最大255,默认255即不对ref值与buf值进行操作,直接读或者写。
(二)、Stencil实例
1. 新建材质
新建材质MatCube、MatSphere,shader选择带Stencil的即可,可见Stencil Comparison的默认值是8即总在渲染时保留,另外将MatCube颜色设成黑色、MatSphere颜色设成白色便于区分。
2. 新建Cube与Sphere
新建Cube与Sphere,并将Cube放大2倍,调整好相对位置,设置好相机便于观察,Scene与Game视图如图,此时Cube与Sphere都被渲染出来了。
3. 设置参数
这里参数的含义是将方块永远渲染出来并且将buf中的值(默认是0)替换成2,这时界面不会有任何变化,因为球体的Stencil Comparison是8默认渲染时全部保留,不管ref与buf中的值是多少。如图所示:
再将球体的Stencil Comparison改为3,即等于0的部分渲染时保留,此时界面就变成了这样,如图,因为方块已经将方块区域buf的值改成了2,而整个小球所有的ref值都是0,所以只有没被方块改变的部分,渲染时保留了下来。
再将球体的ref值改为2,结果如图,只有buf值等于2的部分被渲染出来了。
4. 总结与注意
buf中值的更改总是作用于被Stencil影响的区域,没有影响的区域buf的默认值是0,并且buf中值的更新总是在渲染测试之后,所以在只有方块和球体且渲染顺序是Cube > Sphere的情况下,MatSphere中Stencil Operation无论为何值都不会影响方块与球体的渲染,只会影响后续在此位置的物体的渲染。
(三)、利用代码改变Stencil的相关参数
private Material m_MatSphere;
void Start ()
{
//int op = (int)UnityEngine.Rendering.StencilOp.Replace;
//int com = (int)UnityEngine.Rendering.CompareFunction.Equal;
m_MatSphere = transform.GetComponent<Renderer>().material;
if (m_MatSphere.HasProperty("_StencilComp") && m_MatSphere.HasProperty("_Stencil") && m_MatSphere.HasProperty("_StencilOp"))
{
//float value = m_MatSphere.GetFloat("_StencilComp");
m_MatSphere.SetFloat("_StencilComp", 3);
m_MatSphere.SetFloat("_Stencil", 3);
m_MatSphere.SetFloat("_StencilOp", 3);
}
}
具体这些key可以先选中材质然后Edit Shader看到,如图所示:
将脚本挂在Sphere上,运行游戏,结果如下:
(四)、渲染顺序
关于物体的渲染顺序可以在Frame Debugger中查看Windows -> Analysis -> Frame Debugger。如图:
点击Enable即可得到当前场景的渲染信息,点击小箭头也可查看每一步的渲染信息,如图也能看到当前场景中Cube的渲染是优于Sphere的所以Cube的Stencil Operation是能够影响Sphere的渲染的。