问题:传统 Alpha Blend 的黑边
你遇到过这种情况吗?
在使用 PNG 图标、UI 图集或半透明特效时,边缘总是出现难看的黑色轮廓(Dark Halo),尤其在非白色背景上格外明显。


核心概念
两种 Alpha 混合方式的本质区别
◉传统 Alpha Blend
RGB 和 Alpha 独立存储,混合时线性计算
混合公式
src.rgb × src.a + dst.rgb × (1 - src.a)
问题:当纹理滤波时,Alpha 变化但 RGB 不变,导致边缘半透明区域采样错误
●预乘 Alpha (Premultiplied)
RGB 提前乘以 Alpha 值,一起存储和传输
混合公式
src.rgb + dst.rgb × (1 - src.a)
优势:RGB 和 Alpha 始终保持一致,滤波后边缘自然过渡
技术原理详解
为什么传统方式会有黑边?
让我们假设一个 50% 透明度 的红色像素:
| 存储方式 | RGB 值 | Alpha 值 | 视觉含义 |
|---|---|---|---|
| 传统 RGBA | (1.0, 0, 0) | 0.5 | 50% 透明度,但 RGB 仍为纯红 |
| 预乘 RGBA | (0.5, 0, 0) | 0.5 | 50% 透明度,RGB 已提前乘以 Alpha |
💡 关键洞察
预乘格式的 "预" 意味着 RGB 提前参与混合计算。 存储的 RGB 值已经包含了透明度信息,所以无论后续如何滤波/采样, RGB 和 Alpha 的比例关系始终保持正确。
双线性过滤的陷阱

💡
传统方式的问题:
双线性过滤在 A 和 B 之间插值时,RGB 取平均值 (1.0+0.5)/2=0.75, Alpha 也取平均 (1.0+0.5)/2=0.75。
但 0.75 × 0.75 = 0.56 ≠ 边界处应有的 0.5! 这导致了错误的暗边效果。
Unity URP 中的实现
1. 创建预乘材质
cs
Shader "Custom/PremultipliedAlpha"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
Pass
{
// 关键:启用预乘 Alpha 混合
Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
fixed4 _Color;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 预乘格式:纹理的 RGB 已经是 premultiplied
fixed4 col = tex2D(_MainTex, i.uv);
return col * _Color; // 直接相乘,保持预乘
}
ENDCG
}
}
}
📌 Blend 指令对照
| 模式 | Blend 命令 | 公式 |
|---|---|---|
| 传统 Alpha | Blend SrcAlpha OneMinusSrcAlpha |
src × a + dst × (1-a) |
| 预乘 Alpha | Blend One OneMinusSrcAlpha |
src + dst × (1-a) |
URP 材质设置
在 URP 的 Lit Shader 或 Unlit Shader 中, 只需勾选 Surface Type → Transparent 配合正确的 Blend Mode:

🎯 URP 2D 渲染器注意
如果使用 URP 2D 项目,确保 Sprite Shape 或 Sprite Renderer 的材质也配置了预乘设置。 在 Project Settings → Graphics → Tier Settings 中可以设置默认的透明混合模式。
UI 图集制作流程
STEP 1
导出设置
→
STEP 2
勾选预乘
→
STEP 3
Unity 导入
→
STEP 4
配置材质
- **Photoshop / Affinity Photo 导出:**存储时选择 "Straight" 编码,避免Premultiplied,否则需要反转
- **Texture Packer / Adobe Animate:**选择 premultiply alpha 选项,确保输出为预乘格式
- **Unity Import Settings:**sRGB 保持勾选,Alpha Source 选择 "From Gray Alpha"
- **运行时转换:**如需从普通纹理转换,可使用 Graphics.ConvertTexture() API
最佳实践建议
✓ 建议统一使用预乘格式的场景
- 所有 UI 图集和图标资源
- 2D 游戏中的角色和场景精灵
- 粒子系统和特效纹理
- 任何带有半透明边缘的 PNG/JPEG+Alpha 资源
- 需要叠加混合(Additive)的特效
⚠️
保持一致性的重要性
在同一个渲染队列中混合使用预乘和非预乘资源会导致颜色计算错误。 强烈建议整个项目统一使用预乘 Alpha 格式。
总结
| 对比项 | 传统 Alpha Blend | 预乘 Alpha |
|---|---|---|
| 边缘黑边 | ❌ 有 | ✓ 无 |
| 滤波质量 | ❌ 边缘失真 | ✓ 平滑过渡 |
| 合成公式 | src × a + dst × (1-a) | src + dst × (1-a) |
| Blend 设置 | SrcAlpha OneMinusSrcAlpha | One OneMinusSrcAlpha |
| 适用场景 | 特定后处理效果 | UI、2D 精灵、特效 |