在 Unity 的 ShaderLab 中,Blend 命令是控制 GPU 混合片元着色器输出与渲染目标(帧缓冲)的核心机制。通过配置混合因子(Source Factor)和目标因子(Destination Factor),可以实现透明、发光、溶解等复杂视觉效果。本文将深入解析 Blend 的工作原理、常用模式及性能影响,并结合代码示例说明其应用场景。
一、Blend 的核心原理:从数学公式到 GPU 行为
Blend 的本质是通过数学公式将 ** 片元着色器输出的颜色(源颜色,Source Value)与渲染目标已存在的颜色(目标颜色,Destination Value)** 进行混合。其核心公式为:FinalColor=(SourceFactor×SourceColor)Operation(DestinationFactor×DestinationColor)
-
关键参数:
- SourceFactor:源颜色的混合因子(如透明度、颜色值)。
- DestinationFactor:目标颜色的混合因子(如保留比例、反相值)。
- Operation:混合操作(默认加法,可通过
BlendOp
修改为减法、取最小值等)。
-
执行流程:
- 片元着色器输出源颜色(含 RGB 和 Alpha 通道)。
- 根据 Blend 命令计算源因子与目标因子。
- 按指定操作(如相加、相乘)合并两者,更新渲染目标。
二、Blend 因子与操作的有效值
Blend 支持多种预定义因子和操作,以下是核心取值及典型用途:
1. 混合因子(Factor)
因子名称 | 数学表达式 | 典型场景 |
---|---|---|
One | 1 | 完全保留源或目标颜色(如相加混合) |
Zero | 0 | 忽略源或目标颜色 |
SrcAlpha | 源颜色的 Alpha 值 | 标准透明混合(如玻璃、植被) |
OneMinusSrcAlpha | 1 - 源 Alpha 值 | 与 SrcAlpha 配合实现透明效果 |
DstColor | 目标颜色值 | 乘法混合(如阴影叠加) |
OneMinusDstColor | 1 - 目标颜色值 | 反相混合(如发光边缘) |
2. 混合操作(Operation,需配合 BlendOp 命令)
操作名称 | 数学表达式 | 效果说明 |
---|---|---|
Add (默认) | 源结果 + 目标结果 | 常规加法混合(如粒子发光) |
Sub | 源结果 - 目标结果 | 颜色相减(如蚀刻效果) |
RevSub | 目标结果 - 源结果 | 反向相减 |
Min | 取两者最小值 | 保留较暗区域(如雾气效果) |
Max | 取两者最大值 | 保留较亮区域(如高光叠加) |
三、常用 Blend 模式与代码示例
1. 标准透明混合(Alpha Blending)
公式:Final = SrcAlpha * SrcColor + (1 - SrcAlpha) * DstColor
用途:实现半透明物体(如水面、UI 元素)。
hlsl
Blend SrcAlpha OneMinusSrcAlpha // 开启混合,源因子为Alpha,目标因子为1-Alpha
ZWrite Off // 关闭深度写入,避免透明物体遮挡问题
2. 相加混合(Additive Blending)
公式:Final = SrcColor + DstColor
用途:模拟发光效果(如火焰、魔法特效)。
hlsl
Blend One One // 源和目标因子均为1,颜色直接相加
ColorMask RGB // 仅混合RGB通道,保留Alpha通道
3. 乘法混合(Multiplicative Blending)
公式:Final = SrcColor * DstColor
用途:制作暗化效果(如阴影投射、夜视滤镜)。
hlsl
Blend DstColor Zero // 源因子为目标颜色,目标因子为0,仅保留目标颜色与源颜色的乘积
4.预乘透明(Premultiplied Alpha)
公式:Final = SrcColor + (1 - SrcAlpha) * DstColor
用途:处理已预乘 Alpha 的纹理(如美术工具导出的带透明通道资源)。
hlsl
Blend One OneMinusSrcAlpha // 源因子为1,目标因子为1-Alpha
5. 溶解效果(Discard with Blend)
技巧:结合clip()
函数剔除部分片元,再通过混合实现边缘过渡。
hlsl
float dissolve = tex2D(_MainTex, uv).r;
clip(dissolve - _Threshold); // 低于阈值的片元被剔除
Blend SrcAlpha OneMinusSrcAlpha // 保留的片元进行透明混合
四、多渲染目标(MRT)与通道分离混合
在支持多渲染目标的管线(如 URP/HDRP)中,可针对不同 RT 设置独立混合模式:
hlsl
Blend 0 SrcAlpha OneMinusSrcAlpha // 对RT0使用标准透明混合
Blend 1 One One // 对RT1使用相加混合
- 注意:需确保 GPU 支持
GL_ARB_draw_buffers_blend
等扩展(现代桌面 GPU 通常支持,移动端需谨慎)。
五、性能影响与优化策略
-
禁用 Early-Z 优化:
混合会关闭 GPU 的 Early-Z(早终止深度测试),导致所有片元均需执行至混合阶段,增加 GPU 压力。- 优化:尽量减少混合区域(如使用遮挡剔除减少透明物体数量)。
-
过度绘制(Overdraw):
多层半透明物体叠加时,底层片元会被多次混合,加剧性能消耗。- 优化:
- 减少透明物体层级(如合并 UI 层级)。
- 使用
ZTest
和ZWrite
控制深度缓冲(如透明物体不写入深度但读取深度)。
- 优化:
-
因子与操作的选择:
- 避免使用复杂因子(如
SrcAlphaSaturate
)和非加法操作(如Sub
),部分 GPU 对这些模式支持低效。 - 优先使用硬件优化的模式(如
SrcAlpha OneMinusSrcAlpha
和One One
)。
- 避免使用复杂因子(如
六、渲染管线兼容性与注意事项
渲染管线 | 支持情况 | 特殊配置 |
---|---|---|
内置管线 | 完全支持 | 直接使用 Blend 命令即可 |
URP | 完全支持 | 可在管线设置中启用 “Alpha Clipping” |
HDRP | 完全支持 | 需注意与体积雾、全局光照的混合顺序 |
自定义 SRP | 需手动实现 | 通过RenderStateBlock 设置混合状态 |
- 移动端限制:
部分低端安卓设备对多 RT 混合支持有限,建议优先使用单 RT 混合模式。
七、常见错误与调试方法
-
混合结果异常:
- 原因:因子或操作选择错误(如误将
OneMinusSrcAlpha
写成OneMinusDstAlpha
)。 - 调试:通过
Blend Off
关闭混合,确认源颜色是否正确;逐步调整因子观察结果变化。
- 原因:因子或操作选择错误(如误将
-
性能骤降:
- 原因:大量透明物体混合导致 Early-Z 失效。
- 调试:使用 Unity Profiler 的 “Render” 模块查看
Gfx.WaitForPresent
耗时,定位混合密集区域。
-
与后期处理冲突:
- 原因:混合顺序错误(如后处理效果先于物体混合执行)。
- 调试:调整渲染队列(
Queue
标签)或使用RenderTexture
隔离混合阶段。
八、总结:Blend 的使用原则
- 最小化混合范围:仅对必要物体启用混合,避免全局混合。
- 优先简单模式:能用
SrcAlpha OneMinusSrcAlpha
实现的效果,避免使用复杂因子组合。 - 结合深度控制:通过
ZWrite Off
和合理的深度测试(ZTest
)减少无效混合。 - 测试多平台兼容性:在目标设备上验证混合效果与性能,避免依赖边缘特性。
通过深入理解 Blend 的数学原理与 GPU 行为,开发者可精准控制颜色混合效果,在视觉表现与性能优化之间找到平衡点。无论是透明材质、粒子特效还是艺术化渲染,Blend 都是 Shader 开发中不可或缺的核心工具。