@[toc]【Unity Shader URP】溶解效果(Dissolve)实战教程
0. 效果预览


溶解(Dissolve)是游戏中最常用的消失/出现特效之一:角色死亡燃烧消散、传送门边缘腐蚀、道具拾取后溶解消失,都是它。核心视觉特征是从噪声纹理驱动的不规则边缘逐步裁剪像素,边缘带一圈发光色带。
1. 原理简述
溶解的本质:用一张噪声纹理的灰度值和一个阈值做比较,低于阈值的像素直接
clip丢弃;刚好在阈值附近的像素染上边缘发光色。
关键伪代码:
hlsl
float noise = tex2D(_NoiseTex, uv).r; // 0~1 噪声值
clip(noise - _DissolveAmount); // 低于阈值的像素被丢弃
// 边缘发光:阈值附近的窄带
float edge = smoothstep(_DissolveAmount, _DissolveAmount + _EdgeWidth, noise);
color = lerp(_EdgeColor, baseColor, edge);
_DissolveAmount 从 0 → 1,物体从完整逐渐消失。噪声纹理的分布决定了溶解的形状------Perlin noise 出来是自然燃烧感,Voronoi 出来是晶格碎裂感。
2. 功能点
- 噪声驱动裁剪 :用噪声纹理 + 阈值
clip像素,产生不规则溶解边缘 - 边缘发光色带:溶解边缘处叠加可自定义的发光颜色,支持 HDR
- 溶解进度控制 :
_DissolveAmount(0~1)控制溶解程度,可用脚本/动画驱动 - 边缘宽度可调 :
_EdgeWidth控制发光带的粗细 - 双面渲染 :
Cull Off,溶解过程中可以看到模型内侧
3. 完整 Shader(可直接用)
hlsl
Shader "Custom/Dissolve_URP"
{
Properties
{
// 主贴图(物体原始外观)
_BaseMap ("Base Map", 2D) = "white" {}
// 主颜色叠乘
_BaseColor ("Base Color", Color) = (1,1,1,1)
// 噪声纹理(灰度,决定溶解形状;推荐 Perlin / Simplex / Voronoi)
_NoiseTex ("Noise Texture", 2D) = "white" {}
// 噪声 UV 缩放(值越大,溶解碎片越细小)
_NoiseScale ("Noise Scale", Float) = 1.0
// 溶解进度(0 = 完整,1 = 完全消失)
_DissolveAmount ("Dissolve Amount", Range(0, 1)) = 0.0
// 边缘发光颜色(建议用 HDR 颜色,配合 Bloom 后处理更好看)
[HDR] _EdgeColor ("Edge Color", Color) = (3, 0.5, 0, 1)
// 边缘发光带宽度(占噪声值的比例,越大发光带越宽)
_EdgeWidth ("Edge Width", Range(0.01, 0.2)) = 0.05
}
SubShader
{
Tags
{
"RenderPipeline" = "UniversalRenderPipeline"
"Queue" = "AlphaTest" // 用 AlphaTest 队列,clip 不需要排序
"RenderType" = "TransparentCutout"
}
Pass
{
Name "DissolvePass"
Tags { "LightMode" = "UniversalForward" }
Cull Off // 双面渲染:溶解时能看到模型内侧
ZWrite On // 写深度:不透明裁剪不需要关深度
Blend Off // 不透明混合
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// GPU Instancing(可选,多实例时有用)
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// =========================================================
// 贴图声明
// =========================================================
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
TEXTURE2D(_NoiseTex); SAMPLER(sampler_NoiseTex);
// =========================================================
// 材质属性(与 Properties 一一对应)
// =========================================================
float4 _BaseMap_ST;
float4 _BaseColor;
float _NoiseScale;
float _DissolveAmount;
float4 _EdgeColor;
float _EdgeWidth;
struct Attributes
{
float4 positionOS : POSITION; // 模型空间顶点
float2 uv : TEXCOORD0; // UV 坐标
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionHCS : SV_POSITION; // 裁剪空间位置
float2 uv : TEXCOORD0; // 传递 UV
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
// =========================================================
// 顶点着色器:标准变换,无特殊操作
// =========================================================
Varyings vert(Attributes v)
{
Varyings o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_TRANSFER_INSTANCE_ID(v, o);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionHCS = TransformObjectToHClip(v.positionOS.xyz);
o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
return o;
}
// =========================================================
// 片元着色器:核心溶解逻辑
// =========================================================
half4 frag(Varyings i) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(i);
// 1) 采样噪声纹理(用缩放后的 UV)
float2 noiseUV = i.uv * _NoiseScale;
float noise = SAMPLE_TEXTURE2D(_NoiseTex, sampler_NoiseTex, noiseUV).r;
// 2) clip:噪声值低于溶解阈值的像素直接丢弃
// noise - _DissolveAmount < 0 → 像素被裁剪
clip(noise - _DissolveAmount);
// 3) 采样主贴图
half4 baseCol = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv);
baseCol *= (half4)_BaseColor;
// 3.5) 裁掉原始贴图中透明的像素(sprite 透明区域 alpha ≈ 0)
clip(baseCol.a - 0.01);
// 4) 计算边缘发光:噪声值刚好在阈值附近的窄带
// diff = 当前噪声值距离裁剪线的距离
float diff = noise - _DissolveAmount;
// edgeFactor:0 = 正好在裁剪线上(最亮),1 = 远离裁剪线(无发光)
float edgeFactor = saturate(diff / _EdgeWidth);
// 在边缘带内,用 lerp 混合边缘发光色和原始颜色
half3 finalColor = lerp(_EdgeColor.rgb, baseCol.rgb, edgeFactor);
return half4(finalColor, baseCol.a);
}
ENDHLSL
}
}
}
4. 使用方法
- 在 Unity 项目的
Assets/Shaders/下新建文件Dissolve_URP.shader,粘贴上方完整代码。 - 新建材质(Create → Material),Shader 选择
Custom/Dissolve_URP。 - 准备贴图:
Base Map:物体的主贴图(漫反射纹理)Noise Texture:一张灰度噪声图(推荐 256×256 或 512×512,Perlin noise 效果最自然)
- 将材质赋给场景中的物体(Cube、角色模型等均可)。
- 在 Inspector 中调节
Dissolve Amount滑条(0 → 1),观察溶解过程。 - 调节
Edge Color(建议用 HDR 颜色如(3, 0.5, 0)橙色火焰感)和Edge Width控制发光带表现。

用脚本驱动溶解动画:
csharp
using UnityEngine;
public class DissolveController : MonoBehaviour
{
[SerializeField] private Material dissolveMaterial;
[SerializeField] private float duration = 2.0f;
private float _progress = 0f;
private bool _dissolving = false;
// 外部调用:开始溶解
public void StartDissolve()
{
_progress = 0f;
_dissolving = true;
}
void Update()
{
if (!_dissolving) return;
_progress += Time.deltaTime / duration;
_progress = Mathf.Clamp01(_progress);
dissolveMaterial.SetFloat("_DissolveAmount", _progress);
if (_progress >= 1f)
{
_dissolving = false;
// 溶解完成后可以隐藏物体或销毁
// gameObject.SetActive(false);
}
}
}
5. 参数说明
| 参数 | 类型 | 范围/默认值 | 说明 |
|---|---|---|---|
_BaseMap |
2D | white | 物体主贴图 |
_BaseColor |
Color | (1,1,1,1) | 主颜色叠乘 |
_NoiseTex |
2D | white | 噪声纹理(灰度),决定溶解形状 |
_NoiseScale |
Float | 1.0 | 噪声 UV 缩放,越大碎片越细 |
_DissolveAmount |
Range(0,1) | 0.0 | 溶解进度:0=完整,1=完全消失 |
_EdgeColor |
Color [HDR] | (3,0.5,0,1) | 边缘发光颜色,建议 HDR 值 |
_EdgeWidth |
Range(0.01,0.2) | 0.05 | 边缘发光带宽度 |
6. 变体与扩展
6.1 方向溶解(从下往上)
不用噪声纹理,改用世界空间 Y 坐标做阈值,实现从脚到头的溶解:
hlsl
// 在 Varyings 中增加世界坐标
float3 positionWS : TEXCOORD1;
// vert 中赋值
o.positionWS = TransformObjectToWorld(v.positionOS.xyz);
// frag 中替换噪声采样
float dissolveValue = (i.positionWS.y - _YMin) / (_YMax - _YMin);
clip(dissolveValue - _DissolveAmount);
可以和噪声混合使用:float finalValue = dissolveValue * 0.7 + noise * 0.3;,方向感 + 不规则边缘兼得。
6.2 双色边缘(内焰 + 外焰)
模拟火焰:外圈橙色、内圈白热:
hlsl
float edgeFactor = saturate(diff / _EdgeWidth);
// 内外两层颜色
half3 innerColor = half3(1, 1, 0.8); // 白热
half3 outerColor = _EdgeColor.rgb; // 橙色
half3 edgeBlend = lerp(innerColor, outerColor, edgeFactor);
half3 finalColor = lerp(edgeBlend, baseCol.rgb, step(0.99, edgeFactor));
6.3 溶解出现(反向)
只需要把 clip 条件反过来:
hlsl
clip(_DissolveAmount - noise); // Amount 从 0→1 时物体逐渐出现
float diff = _DissolveAmount - noise;
7. 常见问题
Q: 物体整体突然消失,没有渐进溶解效果?
A: 检查噪声纹理是否是纯白或纯黑。纯色意味着所有像素的噪声值相同,会在同一个阈值同时被 clip。换一张有灰度分布的 Perlin noise 纹理。
Q: 边缘发光颜色看起来很暗,不像火焰?
A: _EdgeColor 需要用 HDR 值(RGB 分量 > 1),比如 (3, 0.5, 0)。同时需要开启 URP 的 Bloom 后处理,否则 HDR 颜色显示不出过曝效果。
Q: 溶解进度调到 1 了但还有残留像素?
A: 噪声纹理中可能存在纯白像素(值 = 1.0),clip(1.0 - 1.0) = clip(0) 刚好不会被裁剪。解决办法:把 clip 改为 clip(noise - _DissolveAmount - 0.001),或者确保噪声纹理最大值 < 1.0。
Q: 模型背面是黑色的?
A: 确认 Cull Off 已生效。如果需要背面也有正确光照,这个 Unlit 版本不含光照计算------背面显示的是纹理本身颜色。如需光照,需要结合 Lit Shader 或双 Pass 方案。
Q: 噪声纹理的 Import Settings 有讲究吗?
A: 推荐设置:Wrap Mode = Repeat (如果模型 UV 超出 0-1 范围)、Filter Mode = Bilinear 、关闭 sRGB(勾选 Linear,因为噪声值是数据不是颜色)。
8. 性能建议
- 噪声图尺寸:128×128 或 256×256 足够,溶解效果不需要高精度噪声。512 以上浪费。
- AlphaTest 队列 :本 Shader 用的是
clip而非透明混合,不需要排序,性能优于 Transparent 队列。 - Shader 变体控制 :如果项目中同时需要"有边缘发光"和"无边缘发光"两种模式,用
[Toggle]+shader_feature_local做编译期开关,避免运行时if。 - 远距离关闭:远处物体溶解效果几乎看不到细节,可以用 LOD 或脚本在远距离直接隐藏物体,省掉 clip 的 GPU 开销。
- 合批注意:clip 会打断 Early-Z 优化(GPU 无法提前跳过被遮挡的像素),大量溶解物体同时出现时注意 Overdraw。