Unity2D图片溶解扩散效果shader
·
先上效果
溶解效果
再上代码
Shader "Custom/BarrierDissolve"
{
Properties
{
[Header(Base)]
[PerRendererData] _MainTex ("Main Texture", 2D) = "white" {}
[HDR] _Color ("Tint Color", Color) = (1,1,1,1)
[Header(Dissolve Settings)]
_NoiseTex ("Noise Texture", 2D) = "gray" {}
_Progress ("Progress (0=Center, 1=Full)", Range(0, 1.5)) = 0.0
_MaxDistance ("Max Distance (Screen Corner)", Float) = 0.8
_Center ("Center Point (UV)", Vector) = (0.5, 0.5, 0, 0)
[Header(Edge Settings)]
_NoiseStrength ("Noise Distortion Strength", Range(0, 1)) = 0.2
_EdgeWidth ("Edge Width", Range(0.01, 0.5)) = 0.1
[HDR] _EdgeColor ("Edge Color", Color) = (0, 1, 1, 1)
[HideInInspector] _StencilComp ("Stencil Comparison", Float) = 8
[HideInInspector] _Stencil ("Stencil ID", Float) = 0
[HideInInspector] _StencilOp ("Stencil Operation", Float) = 0
[HideInInspector] _StencilWriteMask ("Stencil Write Mask", Float) = 255
[HideInInspector] _StencilReadMask ("Stencil Read Mask", Float) = 255
[HideInInspector] _ColorMask ("Color Mask", Float) = 15
}
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}
Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float2 uv_noise : TEXCOORD1;
fixed4 color : COLOR;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _NoiseTex;
float4 _NoiseTex_ST;
fixed4 _Color;
float _Progress;
float _MaxDistance;
float4 _Center;
float _NoiseStrength;
float _EdgeWidth;
fixed4 _EdgeColor;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.uv_noise = TRANSFORM_TEX(v.uv, _NoiseTex);
o.color = v.color * _Color;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 计算像素到中心的距离 (UV空间)
float dist = distance(i.uv, _Center.xy);
// 采样噪声 (0~1)
float noise = tex2D(_NoiseTex, i.uv_noise).r;
// 计算当前的扩散半径阈值
float currentRadius = _Progress * (_MaxDistance + _NoiseStrength);
// 可见性判定值
float val = currentRadius - (noise * _NoiseStrength) - dist;
// 裁剪
if (val < 0)
{
discard;
}
// 采样主纹理,并乘以顶点颜色
fixed4 col = tex2D(_MainTex, i.uv) * i.color;
// 计算边缘发光
float edgeFactor = 1.0 - smoothstep(0.0, _EdgeWidth, val);
// 叠加边缘颜色
col.rgb += _EdgeColor.rgb * edgeFactor;
// 让边缘的 Alpha 也受影响,保证边缘发光是不透明的
col.a = max(col.a, edgeFactor * _EdgeColor.a);
return col;
}
ENDCG
}
}
}
附带一张噪声图

附一个代码进度用法
using UnityEngine;
using PrimeTween;
public class BarrierDissolve : MonoBehaviour
{
private Material _material;
private int _progressId;
private const string PropertyName = "_Progress";
private const float Duration = 1.0f;
private const float TargetValue = 1.5f;
private Tween _tween;
private void Awake()
{
_progressId = Shader.PropertyToID(PropertyName);
// 尝试获取 SpriteRenderer 或 MeshRenderer
var rend = GetComponent<Renderer>();
if (rend != null)
{
// Renderer.material 会自动实例化材质,不影响其他物体
_material = rend.material;
}
if (_material == null)
{
Debug.LogError($"[BarrierDissolve]没有Render在{gameObject.name}物体身上, 或者材质丢失");
}
}
private void OnEnable()
{
if (_material == null) return;
// 停止之前的动画(如果有)
if (_tween.isAlive) _tween.Stop();
// 初始值
_material.SetFloat(_progressId, 0f);
// 使用 PrimeTween 从 0 到 TargetValue 变化
_tween = Tween.Custom(0f, TargetValue, Duration, onValueChange: val =>
{
_material.SetFloat(_progressId, val);
});
}
private void OnDisable()
{
// 禁用时停止动画
if (_tween.isAlive) _tween.Stop();
}
private void OnDestroy()
{
// 停止动画
if (_tween.isAlive) _tween.Stop();
// 销毁实例化的材质,防止内存泄漏
if (_material != null)
{
Destroy(_material);
_material = null;
}
}
}
更多推荐

所有评论(0)