Skip to content

Instantly share code, notes, and snippets.

@LeLocTai
Last active March 16, 2023 23:04
Show Gist options
  • Save LeLocTai/6a3b03838aafcf0eb9192dac8819a38f to your computer and use it in GitHub Desktop.
Save LeLocTai/6a3b03838aafcf0eb9192dac8819a38f to your computer and use it in GitHub Desktop.
Some custom shader for True Shadow

https://youtu.be/XNPqcRGQlCM

The first out-of-beta release of my UI soft shadow asset added a feature that let you use custom shader on the shadows. These are the example shaders I included as demo.

These shader are made for True Shadow texture format, which is a bit different than normal UI texture. That mean they can't be used directly for normal UIs. Particularly, True Shadow use per-multiplied alpha for accurate blending. It should not be too much effort to convert them for use in normal UIs. If you're interested, here they are: https://gist.github.com/LeLocTai/6a3b03838aafcf0eb9192dac8819a38f

Shader "UI/Bubble"
{
Properties
{
_Scale ("Scale", Float) = 80
_Bubbling ("Bubbling", Float) = 25
_Scroll ("Scroll", Vector) = (0, 1, 0, 0)
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_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
[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 One OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#include "../../../Resources/Shaders/TrueShadow.cginc"
#pragma vertex vert
#pragma fragment frag_custom
#define mod(x, y) (x - y * floor(x / y))
// Cellular noise ("Worley noise") in 3D in GLSL.
// Copyright (c) Stefan Gustavson 2011-04-19. All rights reserved.
// This code is released under the conditions of the MIT license.
// See LICENSE file for details.
// Permutation polynomial: (34x^2 + x) mod 289
half4 permute(half4 x)
{
return mod((34.0 * x + 1.0) * x, 289.0);
}
half3 permute(half3 x)
{
return mod((34.0 * x + 1.0) * x, 289.0);
}
// Cellular noise, returning F1 and F2 in a half2.
// Speeded up by using 2x2x2 search window instead of 3x3x3,
// at the expense of some pattern artifacts.
// F2 is often wrong and has sharp discontinuities.
// If you need a good F2, use the slower 3x3x3 version.
half2 cellular2x2x2(half3 P)
{
#define K 0.142857142857 // 1/7
#define Ko 0.428571428571 // 1/2-K/2
#define K2 0.020408163265306 // 1/(7*7)
#define Kz 0.166666666667 // 1/6
#define Kzo 0.416666666667 // 1/2-1/6*2
#define jitter 0.8 // smaller jitter gives less errors in F2
half3 Pi = mod(floor(P), 289.0);
half3 Pf = frac(P);
half4 Pfx = Pf.x + half4(0.0, -1.0, 0.0, -1.0);
half4 Pfy = Pf.y + half4(0.0, 0.0, -1.0, -1.0);
half4 p = permute(Pi.x + half4(0.0, 1.0, 0.0, 1.0));
p = permute(p + Pi.y + half4(0.0, 0.0, 1.0, 1.0));
half4 p1 = permute(p + Pi.z); // z+0
half4 p2 = permute(p + Pi.z + 1.0); // z+1
half4 ox1 = frac(p1 * K) - Ko;
half4 oy1 = mod(floor(p1 * K), 7.0) * K - Ko;
half4 oz1 = floor(p1 * K2) * Kz - Kzo; // p1 < 289 guaranteed
half4 ox2 = frac(p2 * K) - Ko;
half4 oy2 = mod(floor(p2 * K), 7.0) * K - Ko;
half4 oz2 = floor(p2 * K2) * Kz - Kzo;
half4 dx1 = Pfx + jitter * ox1;
half4 dy1 = Pfy + jitter * oy1;
half4 dz1 = Pf.z + jitter * oz1;
half4 dx2 = Pfx + jitter * ox2;
half4 dy2 = Pfy + jitter * oy2;
half4 dz2 = Pf.z - 1.0 + jitter * oz2;
half4 d1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1; // z+0
half4 d2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2; // z+1
// Sort out the two smallest distances (F1, F2)
#if 1
// Cheat and sort out only F1
d1 = min(d1, d2);
d1.xy = min(d1.xy, d1.wz);
d1.x = min(d1.x, d1.y);
return sqrt(d1.xx);
#else
// Do it right and sort out both F1 and F2
half4 d = min(d1,d2); // F1 is now in d
d2 = max(d1,d2); // Make sure we keep all candidates for F2
d.xy = (d.x < d.y) ? d.xy : d.yx; // Swap smallest to d.x
d.xz = (d.x < d.z) ? d.xz : d.zx;
d.xw = (d.x < d.w) ? d.xw : d.wx; // F1 is now in d.x
d.yzw = min(d.yzw, d2.yzw); // F2 now not in d2.yzw
d.y = min(d.y, d.z); // nor in d.z
d.y = min(d.y, d.w); // nor in d.w
d.y = min(d.y, d2.x); // F2 is now in d.y
return sqrt(d.xy); // F1 and F2
#endif
}
half _Scale;
half _Bubbling;
half2 _Scroll;
fixed4 frag_custom(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
half2 resInvariantUV = IN.vertex.xy / ((_ScreenParams.x + _ScreenParams.y) / 2);
half2 cell = cellular2x2x2(half3(resInvariantUV * _Scale + _Scroll * _Time.y, _Time.y * _Bubbling));
half a2 = smoothstep(.2, .0, color.a);
half n = smoothstep(0.5, 0.3, cell.x + a2);
color.rgb = color.rgb / max(color.a, 1e-9) * IN.color.rgb * n;
color.a = IN.color.a * n;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
Shader "UI/Code"
{
Properties
{
_Columns ("Columns", Float) = 120
_Speed ("Speed", Float) = -20
_Text_Color ("Text Color", Color) = (0,1,0,1)
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_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
[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 One OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#include "../../../Resources/Shaders/TrueShadow.cginc"
#pragma vertex vert
#pragma fragment frag_custom
/// Adapted from https://thebookofshaders.com/examples/?chapter=08
half random(half x)
{
return frac(sin(x) * 43758.5453);
}
half random(half2 p)
{
float3 p3 = frac(float3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return frac((p3.x + p3.y) * p3.z);
}
half rchar(half2 outer, half2 inner)
{
half grid = 5.;
half2 margin = half2(.2, .05);
half seed = 23.184;
half2 borders = step(margin, inner) * step(margin, 1. - inner);
return step(.5, random(outer * seed + floor(inner * grid))) * borders.x * borders.y;
}
half _Columns;
half _Speed;
half code(half2 st)
{
half2 ipos = floor(st * _Columns);
ipos += half2(.0, floor(_Time.y * _Speed * random(ipos.x)));
half2 fpos = frac(st * _Columns);
half2 center = .5 - fpos;
half pct = random(ipos);
half glow = (1. - dot(center, center) * 3.) * 2.0;
return rchar(ipos, fpos) * pct * glow;
}
half4 _Text_Color;
fixed4 frag_custom(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
half2 resInvariantUV = IN.vertex.xy / ((_ScreenParams.x + _ScreenParams.y) / 2);
color.rgb += lerp(half3(0,0,0), _Text_Color.rgb * _Text_Color.a, code(resInvariantUV)) * color.a;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
Shader "UI/Grain"
{
Properties
{
_Amount ("Amount", Range(0,1)) = .2
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_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
[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 One OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#include "../../../Resources/Shaders/TrueShadow.cginc"
#pragma vertex vert
#pragma fragment frag_custom
half hash(half3 p)
{
p = frac(p * 1031.);
p += dot(p, p.zyx + 31.32);
return frac((p.x + p.y) * p.z);
}
float _Amount;
half grain(half2 p)
{
half noise = hash(half3(p, _Time.y));
return lerp(-.5, .5, noise) * _Amount;
}
fixed4 frag_custom(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
half2 resInvariantUV = IN.vertex.xy / ((_ScreenParams.x + _ScreenParams.y) / 2);
color += grain(resInvariantUV) * color.a;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
Shader "UI/Stripe"
{
Properties
{
_Angle ("Angle", Float) = 45
_StripeCount ("Stripe Count", Float) = 60
_Speed ("Speed", Float) = -.1
_ColorA ("ColorA", Color) = (0,0,0,1)
_ColorB ("ColorB", Color) = (1,1,1,1)
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_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
[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 One OneMinusSrcAlpha
ColorMask [_ColorMask]
Pass
{
CGPROGRAM
#include "../../../Resources/Shaders/TrueShadow.cginc"
#pragma vertex vert
#pragma fragment frag_custom
inline half2 rot2d(half2 dir, half angle)
{
half s, c;
sincos(angle, s, c);
return half2(c * dir.x - s * dir.y,
s * dir.x + c * dir.y);
}
half _Angle;
half _StripeCount;
half _Speed;
half stripe(half2 p)
{
p.y += _Speed * _Time.y;
p = rot2d(p, radians(_Angle));
half stripe = frac(p.y * _StripeCount / 2);
return stripe < .7 ? smoothstep(stripe, stripe + .05, .5) : 1. - smoothstep(stripe, stripe + .05, .95);
}
half4 _ColorA;
half4 _ColorB;
fixed4 frag_custom(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
half2 resInvariantUV = IN.vertex.xy / ((_ScreenParams.x + _ScreenParams.y) / 2);
color *= lerp(_ColorA, _ColorB, stripe(resInvariantUV));
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
#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 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
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.a = v.color.a;
OUT.color.rgb = v.color.rgb * v.color.a;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
float4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#ifdef UNITY_UI_CLIP_RECT
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
#ifdef DO_BLEND_POSTPROCESS
DO_BLEND_POSTPROCESS
#endif
return color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment