Skip to content

Instantly share code, notes, and snippets.

@benloong
Forked from nukeop/dissolve.shader
Last active April 17, 2024 20:30
Show Gist options
  • Save benloong/b25066cb140398b402f2ad8295a28d42 to your computer and use it in GitHub Desktop.
Save benloong/b25066cb140398b402f2ad8295a28d42 to your computer and use it in GitHub Desktop.
Dissolve shader for Unity

dissolveeffect

Add this texture to the second slot. Set it to alpha from grayscale and alpha is transparency. Your texture goes in the first one.

Make a new material with this shader and play with the sliders and colours. You can create cool animated effects if you change dissolution level and/or edge width gradually over time.

Example of the shader in action:

anim

Shader "Unlit/DissolveEffectShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_NoiseTex ("Texture", 2D) = "white" {}
[MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
_EdgeColour1 ("Edge colour 1", Color) = (1.0, 1.0, 1.0, 1.0)
_EdgeColour2 ("Edge colour 2", Color) = (1.0, 1.0, 1.0, 1.0)
_Level ("Dissolution level", Range (0.0, 1.0)) = 0.1
_Edges ("Edge width", Range (0.0, 1.0)) = 0.1
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
LOD 100
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Lighting Off
ZWrite Off
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile DUMMY PIXELSNAP_ON
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
sampler2D _NoiseTex;
float4 _EdgeColour1;
float4 _EdgeColour2;
float _Level;
float _Edges;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
#ifdef PIXELSNAP_ON
o.vertex = UnityPixelSnap (o.vertex);
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
float cutout = tex2D(_NoiseTex, i.uv).r;
fixed4 col = tex2D(_MainTex, i.uv);
if (cutout < _Level)
discard;
if(cutout < col.a && cutout < _Level + _Edges)
col =lerp(_EdgeColour1, _EdgeColour2, (cutout-_Level)/_Edges );
return col;
}
ENDCG
}
}
}
Shader "UI/Dissolve"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255
_ColorMask ("Color Mask", Float) = 15
_NoiseTex ("Texture", 2D) = "white" {}
_EdgeColour1 ("Edge colour 1", Color) = (1.0, 1.0, 1.0, 1.0)
_EdgeColour2 ("Edge colour 2", Color) = (1.0, 1.0, 1.0, 1.0)
_Level ("Dissolution level", Range (0.0, 1.0)) = 0.1
_Edges ("Edge width", Range (0.0, 1.0)) = 0.1
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}
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
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#include "UnityUI.cginc"
#pragma multi_compile_local _ UNITY_UI_CLIP_RECT
#pragma multi_compile_local _ UNITY_UI_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
sampler2D _NoiseTex;
float4 _EdgeColour1;
float4 _EdgeColour2;
float _Level;
float _Edges;
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
float cutout = tex2D(_NoiseTex, IN.texcoord).r;
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
if (cutout <= _Level) {
color.a = 0;
}
else {
if(cutout < color.a && cutout < _Level + _Edges){
color = lerp(_EdgeColour1, _EdgeColour2, (cutout - _Level) / _Edges);
}
}
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
@hammanandre
Copy link

Made a quick Lit one for purpose of having the same functionality but lit, can't do PR on gist apparently, so here it is, feel free to add or disregard

Shader "Custom/DissolveInOut" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_DissolveTex("Dissolve Texture", 2D) = "white" {}
_Level("Dissolution level", Range(0.0, 1.0)) = 0.1
_EdgeColour1("Edge colour 1", Color) = (1.0, 1.0, 1.0, 1.0)
_EdgeColour2("Edge colour 2", Color) = (1.0, 1.0, 1.0, 1.0)
_Edges("Edge width", Range(0.0, 1.0)) = 0.1

	_Glossiness ("Smoothness", Range(0,1)) = 0.5
	_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader {
		Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }
		LOD 100
		
		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows alpha:blend
		#pragma target 3.0

		sampler2D _MainTex;
		sampler2D _DissolveTex;
		
		struct Input {
			float2 uv_MainTex;
			float2 uv_DissolveTex;
		};

		float4 _Color;
		half _Glossiness;
		half _Metallic;
		float4 _EdgeColour1;
		float4 _EdgeColour2;
		float _Level;
		float _Edges;



		void surf(Input IN, inout SurfaceOutputStandard o) {
			fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
			fixed4 cutout = tex2D(_DissolveTex, IN.uv_MainTex).g;

			o.Albedo = c.rgb;

			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			if (_Level == 0) {
				o.Alpha = 0;
			}
			else {
				o.Alpha = lerp(_EdgeColour1, _EdgeColour2, (cutout.a - _Level) / _Edges);
			}
		}
		ENDCG
}
FallBack "Transparent"

}

@dkeele
Copy link

dkeele commented Nov 24, 2020

Thanks for this! Any chance I could get an update to have it working as the child of a UI mask?

@benloong
Copy link
Author

benloong commented Nov 24, 2020

@dkeele checkout it!
UIDissolve.shader

@BaronRector
Copy link

I'm curious if this is possible with an Unlit shader graph in URP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment