shader中的z、stencil、alpha测试

本文深入探讨了在像素处理过程中,AlphaTest、StencilTest与ZTest的执行顺序对效率的影响。通过分析这三个测试的作用及相互关系,指出优化方法,如将ZTest提前执行,以减少不必要的计算,提高渲染性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三个测试都用于判断像素是否需要丢弃,但执行顺序却会极大影响效率,按一般顺序,像素经过PixelShader通过光照等计算后,得到颜色值,之后会进入这三个test。首先进行alpha test,不符合条件的(一般是透明度小于参考值)像素值丢弃,然后进入stenci test,不能通过测试的像素丢弃,最后进入z test,同样是丢弃不能通过测试的像素(一般是深度值较大的被遮挡像素)。如果仔细推敲便可发现,如果像素值是被stencil或z test丢弃掉了,那么pixel shader中的光照等计算就是做无用功,所以一个被遮挡的像素直接丢弃就好了,那么一开始就应该做stencil和z test。但这里忽略了个问题,深度值由光栅化得到,但pixel shader可以修改深度值或丢弃像素的,所以,默认深度是被遮挡的,经过pixel shader修改后可能就没有被遮挡了,同样如果一开始做了z test而pixel shader中或alpha test中又把像素丢弃了,那么z test中的深度值就不该写入。基于上面的过程,硬件设备厂商拿出了各自的优化方法,在一些条件下将z test放到pixelshader之前做,比如没有alpha test、关闭z write、pixel shader没有修改深度、pixelshader没有调用clip等函数丢弃像素等,这种做法称为 early z,stecil也类似。
### 如何在Unity的Shader中添加Stencil效果 #### 创建带有模板测试功能的着色器 为了使对象能够参与模板缓冲区测试,在编写自定义着色器时需配置`SubShader`标签内的`Stencil`区块。此部分允许指定一系列参数用于控制如何读取、写入以及处理模板缓冲数据。 ```csharp Shader "Custom/StencilExample" { Properties { _MainTex ("Texture", 2D) = "white" {} _RefVal ("Reference Value", Float) = 1.0 } SubShader { Tags {"Queue"="Geometry"} Stencil { Ref [_RefVal] // 设置参考值,通常与材质属性关联以便动态调整 ReadMask 255 // 定义掩码位,决定哪些bit会被考虑进来做对比 WriteMask 255 // 决定可以修改的bit范围 Comp Always // 指定比较函数,Always表示总是通过 Pass Keep // 当像素通过了所有前面提到的操作后应该做什么;Keep意味着保持原有状态不变 Fail IncrSat // 如果失败,则增加计数值直到饱和为止 ZFail DecrWrap // 只有当深度测试不成功但是模板测试成功的场合才会触发该行为 } CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 col = tex2D(_MainTex, IN.uv_MainTex); o.Albedo = col.rgb; o.Alpha = col.a; } ENDCG } } ``` 上述代码展示了怎样构建一个简单的具有模板测试特性的着色器[^1]。其中设置了几个重要的选项: - `Ref`: 设定了用来同当前帧缓存中的模板值相比较的一个整型常量。 - `ReadMask`, `WriteMask`: 这两个字段限定了参与运算的具体比特位。 - `Comp`: 表达了一种逻辑判断方式,比如是否等于(`Equal`)、小于(`Less`)等。 - `Pass`, `Fail`, `ZFail`: 描述了不同情况下应当采取的动作——替换现有值(`Replace`)、保留原样(`Keep`)或是其他操作。 #### 实现遮罩效果的应用场景 假设存在A和B两个游戏物件,希望只有满足特定条件的情况下才让B显示出来。此时可以通过设置不同的`Ref`值给各自的材料,并利用合适的比较模式达成目的。例如对于负责绘制遮挡物(即A)的对象来说,其对应的着色程序里应包含如下片段[^3]: ```csharp // 对于遮蔽层使用的Shader Stencil { Ref 1 // 告诉引擎我们想要标记这些区域为'1' Comp Always // 不管之前有什么样的值都接受下来 Pass Replace // 把遇到的地方全部替换成新的标志符 } // 而被遮盖的目标(B),则可能采用这样的设定 Stencil { Ref 1 // 寻找那些已经被打上相同记号的位置 Comp Equal // 确认确实匹配上了预期的结果 Pass Zero // 成功的话清除掉这个位置上的任何记录 } ``` 这样做的好处在于即使多个物体重叠在一起也能精确地管理它们之间的可见关系而不必担心相互干扰的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值