Unity Shader 预乘 Alpha 完全指南 解决半透明纹理边缘黑边问题,让你的 UI 渲染更干净

问题:传统 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.550% 透明度,但 RGB 仍为纯红
预乘 RGBA(0.5, 0, 0)0.550% 透明度,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. 创建预乘材质

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 命令公式
传统 AlphaBlend SrcAlpha OneMinusSrcAlphasrc × a + dst × (1-a)
预乘 AlphaBlend One OneMinusSrcAlphasrc + 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 OneMinusSrcAlphaOne OneMinusSrcAlpha
适用场景特定后处理效果UI、2D 精灵、特效
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值