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.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 ShaderUnlit 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 精灵、特效
相关推荐
小贺儿开发9 小时前
Unity 程序员编曲花絮:汪峰《河流》细节修复
科技·学习·unity·程序员·音乐·demo·写代码
598866753@qq.com10 小时前
Unity UniText笔记
unity·unitext
杨丰玮41810 小时前
从零手写Java飞机躲障碍游戏|Swing绘图、鼠标跟随、计时器碰撞检测实战(五)
java·python·游戏·游戏引擎·图形渲染·动画·贴图
鼎艺创新科技1 天前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
huihui3611 天前
校友网管理软件技术选型框架:基于功能核验与系统架构的量化评估
unity·系统架构·游戏引擎
五仁烧饼1 天前
Unity性能优化系列设置篇 - URP 移动端设置基线与分档策略
unity·游戏引擎
新手unity自用笔记1 天前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎
心前阳光1 天前
Unity之XR Interaction Toolkit | IPointerDownHandler问题
unity·游戏引擎·xr
帅_shuai_2 天前
unity 静态字段内存查找工具
unity·游戏引擎
郝学胜-神的一滴3 天前
[简化版 GAMES 104] 现代游戏引擎 06:从Tick时序到邮局模型,拆解确定性世界的底层密码
开发语言·c++·游戏引擎·图形渲染·软件开发·opengl