Unity Shader 预乘 Alpha 完全指南 解决半透明纹理边缘黑边问题,让你的 UI 渲染更干净
问题传统 Alpha Blend 的黑边你遇到过这种情况吗在使用 PNG 图标、UI 图集或半透明特效时边缘总是出现难看的黑色轮廓Dark Halo尤其在非白色背景上格外明显。核心概念两种 Alpha 混合方式的本质区别◉传统 Alpha BlendRGB 和 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.00.5)/20.75 Alpha 也取平均(1.00.5)/20.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 { QueueTransparent RenderTypeTransparent } 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 3Unity 导入→STEP 4配置材质Photoshop / Affinity Photo 导出存储时选择 Straight 编码避免Premultiplied否则需要反转Texture Packer / Adobe Animate选择 premultiply alpha 选项确保输出为预乘格式Unity Import SettingssRGB 保持勾选Alpha Source 选择 From Gray Alpha运行时转换如需从普通纹理转换可使用 Graphics.ConvertTexture() API最佳实践建议✓ 建议统一使用预乘格式的场景所有 UI 图集和图标资源2D 游戏中的角色和场景精灵粒子系统和特效纹理任何带有半透明边缘的 PNG/JPEGAlpha 资源需要叠加混合Additive的特效⚠️保持一致性的重要性在同一个渲染队列中混合使用预乘和非预乘资源会导致颜色计算错误。强烈建议整个项目统一使用预乘 Alpha 格式。总结对比项传统 Alpha Blend预乘 Alpha边缘黑边❌ 有✓ 无滤波质量❌ 边缘失真✓ 平滑过渡合成公式src × a dst × (1-a)src dst × (1-a)Blend 设置SrcAlpha OneMinusSrcAlphaOne OneMinusSrcAlpha适用场景特定后处理效果UI、2D 精灵、特效