Files
Cielonos/Assets/OtherPlugins/ChocDino/UIFX/Runtime/Shaders/Resources/DistanceMap.shader
SoulliesOfficial d94241f36c 场景设计
2026-01-12 03:22:16 -05:00

458 lines
11 KiB
GLSL

Shader "Hidden/ChocDino/UIFX/DistanceMap"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
[PerRendererData] _InsideTex ("Inside Texture", 2D) = "white" {}
_StepSize ("Step Size", Vector) = (1.0, 1.0, 0.0, 0.0)
_DownSample ("Down Sample", Int) = 1
[KeywordEnum(Square,Diamond,Circle)] Dist("Dist",int) = 0
}
CGINCLUDE
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
uniform sampler2D _MainTex;
uniform sampler2D _InsideTex;
uniform float4 _MainTex_TexelSize;
uniform float2 _StepSize;
uniform int _DownSample;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
// Manhattan distance
float distanceDiamond(float2 a, float2 b)
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
// Chebyshev distance
float distanceSquare(float2 a, float2 b)
{
return max(abs(a.x - b.x), abs(a.y - b.y));
}
#define NULL_PIXEL -1.0
float2 fragAlphaToUV(v2f i) : SV_Target
{
float2 offset = _MainTex_TexelSize.xy;
float2 result = i.uv;
float alpha = tex2D(_MainTex, i.uv).a;
if (alpha > 0.99)
{
return result;
}
// Changed this from 0.01 to 0.016 to filter out some very tiny values introduced in some textues when using HIGH compression setting
if (alpha < 0.016)
{
return NULL_PIXEL;
}
// For intermediate alpha values use sobel filter to estimate the fractional offset of the subpixel
// Credit for this idea to Ben Golus "The Quest for Very Wide Outlines".
float c00 = tex2D(_MainTex, i.uv - offset.xy).a;
float c10 = tex2D(_MainTex, i.uv + float2(0.0, -offset.y)).a;
float c20 = tex2D(_MainTex, i.uv + float2(offset.x, -offset.y)).a;
float c01 = tex2D(_MainTex, i.uv + float2(-offset.x, 0.0)).a;
float c21 = tex2D(_MainTex, i.uv + float2(offset.x, 0.0)).a;
float c02 = tex2D(_MainTex, i.uv + float2(-offset.x, offset.y)).a;
float c12 = tex2D(_MainTex, i.uv + float2(0.0, offset.y)).a;
float c22 = tex2D(_MainTex, i.uv + float2(offset.x, offset.y)).a;
// Sobel gradient to estimate edge direction
float sobelX = c00 + c01 * 2.0 + c02 - c20 - c21 * 2.0 - c22;
float sobelY = c00 + c10 * 2.0 + c20 - c02 - c12 * 2.0 - c22;
float2 dir = -float2(sobelX, sobelY);
// If dir length is small, this is either a sub pixel dot or line
// no way to estimate sub pixel edge, so output position
if (abs(dir.x) <= 0.005 && abs(dir.y) <= 0.005)
{
return result;
}
// normalize direction
dir = normalize(dir);
// sub pixel offset
offset *= dir * (1.0 - alpha);
result = (i.uv + offset);
return result;
}
float2 fragInvAlphaToUV(v2f i) : SV_Target
{
float2 offset = _MainTex_TexelSize.xy;
float2 result = i.uv;
float alpha = 1.0-tex2D(_MainTex, i.uv).a;
if (alpha > 0.99)
{
return result;
}
if (alpha < 0.01)
{
return NULL_PIXEL;
}
// For intermediate alpha values use sobel filter to estimate the fractional offset of the subpixel
// Credit for this idea to Ben Golus "The Quest for Very Wide Outlines".
float c00 = tex2D(_MainTex, i.uv - offset.xy).a;
float c10 = tex2D(_MainTex, i.uv + float2(0.0, -offset.y)).a;
float c20 = tex2D(_MainTex, i.uv + float2(offset.x, -offset.y)).a;
float c01 = tex2D(_MainTex, i.uv + float2(-offset.x, 0.0)).a;
float c21 = tex2D(_MainTex, i.uv + float2(offset.x, 0.0)).a;
float c02 = tex2D(_MainTex, i.uv + float2(-offset.x, offset.y)).a;
float c12 = tex2D(_MainTex, i.uv + float2(0.0, offset.y)).a;
float c22 = tex2D(_MainTex, i.uv + float2(offset.x, offset.y)).a;
// Sobel gradient to estimate edge direction
float sobelX = c00 + c01 * 2.0 + c02 - c20 - c21 * 2.0 - c22;
float sobelY = c00 + c10 * 2.0 + c20 - c02 - c12 * 2.0 - c22;
float2 dir = float2(sobelX, sobelY);
// If dir length is small, this is either a sub pixel dot or line
// no way to estimate sub pixel edge, so output position
if (abs(dir.x) <= 0.005 && abs(dir.y) <= 0.005)
{
return result;
}
// normalize direction
dir = normalize(dir);
// sub pixel offset
offset *= dir * (1.0 - alpha);
result = (i.uv + offset);
return result;
}
float2 fragJumpFlood(v2f i) : SV_Target
{
float2 pixelScale = _MainTex_TexelSize.zw;
float2 offset = _MainTex_TexelSize.xy * _StepSize;
float2 closest = NULL_PIXEL;
// NOTE: this value should be big enough, as using 1.#INF was causing problems with some console compilers
#if SHADER_API_GLES || SHADER_API_MOBILE || SHADER_API_SWITCH
float minDist = 32768.0;
#else
float minDist = 16777216.0;
#endif
float2 p0 = tex2D(_MainTex, i.uv).xy;
if (p0.x > NULL_PIXEL)
{
float2 v3 = (p0 - i.uv) * pixelScale;
float dd = dot(v3, v3);
if (dd < 2)//(abs(p0.x - i.uv.x) < _MainTex_TexelSize.x*1.5) && (abs(p0.y - i.uv.y) < _MainTex_TexelSize.y*1.5))
{
return p0;
}
closest = p0;
#if DIST_CIRCLE
minDist = dd;//dot(v2, v2);
//float sd = distance(p * pixelScale, i.uv * pixelScale);
#elif DIST_DIAMOND
minDist = distanceDiamond(p0 * pixelScale, i.uv * pixelScale);
#elif DIST_SQUARE
minDist = distanceSquare(p0 * pixelScale, i.uv * pixelScale);
#endif
}
UNITY_UNROLL
for (int y = -1; y <= 1; y++)
{
UNITY_UNROLL
for (int x = -1; x <= 1; x++)
{
if (x == 0 && y == 0) continue;
float2 p = tex2D(_MainTex, i.uv + offset * float2(x, y)).xy;
if (p.x > NULL_PIXEL)
{
float sd = 0.0;
#if DIST_CIRCLE
float2 v = (p - i.uv) * pixelScale;
sd = dot(v, v);
//float sd = distance(p * pixelScale, i.uv * pixelScale);
#elif DIST_DIAMOND
sd = distanceDiamond(p * pixelScale, i.uv * pixelScale);
#elif DIST_SQUARE
sd = distanceSquare(p * pixelScale, i.uv * pixelScale);
#endif
if (sd < minDist)
{
minDist = sd;
closest = p;
}
}
}
}
return closest;
}
float2 fragJumpFloodSingleAxis(v2f i) : SV_Target
{
float2 pixelScale = _MainTex_TexelSize.zw;
float2 offset = _MainTex_TexelSize.xy * _StepSize;
float2 closest = NULL_PIXEL;
// NOTE: this value should be big enough, as using 1.#INF was causing problems with some console compilers
#if SHADER_API_GLES || SHADER_API_MOBILE || SHADER_API_SWITCH
float minDist = 32768.0;
#else
float minDist = 16777216.0;
#endif
float2 p0 = tex2D(_MainTex, i.uv).xy;
if (p0.x > NULL_PIXEL)
{
float2 v3 = (p0 - i.uv) * pixelScale;
float dd = dot(v3, v3);
if (dd < 2)//(abs(p0.x - i.uv.x) < _MainTex_TexelSize.x*1.5) && (abs(p0.y - i.uv.y) < _MainTex_TexelSize.y*1.5))
{
return p0;
}
closest = p0;
#if DIST_CIRCLE
//float2 v2 = (p0 - i.uv) * pixelScale;
minDist = dd;//dot(v2, v2);
//float sd = distance(p * pixelScale, i.uv * pixelScale);
#elif DIST_DIAMOND
minDist = distanceDiamond(p0 * pixelScale, i.uv * pixelScale);
#elif DIST_SQUARE
minDist = distanceSquare(p0 * pixelScale, i.uv * pixelScale);
#endif
}
UNITY_UNROLL
for (int x = -1; x <= 1; x++)
{
if (x == 0) continue;
float2 p = tex2D(_MainTex, i.uv + offset * float2(x, x)).xy;
if (p.x > NULL_PIXEL)
{
float sd = 0.0;
#if DIST_CIRCLE
float2 v = (p - i.uv) * pixelScale;
sd = dot(v, v);
//float sd = distance(p * pixelScale, i.uv * pixelScale);
#elif DIST_DIAMOND
sd = distanceDiamond(p * pixelScale, i.uv * pixelScale);
#elif DIST_SQUARE
sd = distanceSquare(p * pixelScale, i.uv * pixelScale);
#endif
if (sd < minDist)
{
minDist = sd;
closest = p;
}
}
}
return closest;
}
// NOTE: In GLES2.0 if you return float it gives an error "Type mismatch, cannot convert from 'float' to 'vec4'", so just return float4
float4 fragResolveDistance(v2f i) : SV_Target
{
float2 pixelScale = _MainTex_TexelSize.zw;
float2 p0 = i.uv * pixelScale;
float2 p1 = tex2D(_MainTex, i.uv).xy * pixelScale;
float d = 0.0;
//if (p1.x > NULL_PIXEL)
{
#if DIST_CIRCLE
d = distance(p0, p1);
#elif DIST_DIAMOND
d = distanceDiamond(p0, p1);
#elif DIST_SQUARE
d = distanceSquare(p0, p1);
#endif
// Subtract to eliminate noise where distances are almost equal
// TODO: ideally shouldn't even write these pixels, just zero them
//d = max(0, d - 2.0);
}
return d * _DownSample;
}
// NOTE: In GLES2.0 if you return float it gives an error "Type mismatch, cannot convert from 'float' to 'vec4'", so just return float4
float4 fragResolveDistanceIOnOutMax(v2f i) : SV_Target
{
float2 pixelScale = _MainTex_TexelSize.zw;
float2 p0 = i.uv * pixelScale;
float2 p1 = tex2D(_MainTex, i.uv).xy * pixelScale;
float dOut = 0.0;
#if DIST_CIRCLE
dOut = distance(p0, p1);
#elif DIST_DIAMOND
dOut = distanceDiamond(p0, p1);
#elif DIST_SQUARE
dOut = distanceSquare(p0, p1);
#endif
p1 = tex2D(_InsideTex, i.uv).xy * pixelScale;
float dIn = 0.0;
#if DIST_CIRCLE
dIn = distance(p0, p1);
#elif DIST_DIAMOND
dIn = distanceDiamond(p0, p1);
#elif DIST_SQUARE
dIn = distanceSquare(p0, p1);
#endif
float d = max(dOut, dIn);
return (d * _DownSample);
}
// NOTE: In GLES2.0 if you return float it gives an error "Type mismatch, cannot convert from 'float' to 'vec4'", so just return float4
float4 fragResolveDistanceSDF(v2f i) : SV_Target
{
float2 pixelScale = _MainTex_TexelSize.zw;
float2 p0 = i.uv * pixelScale;
float2 p1 = tex2D(_MainTex, i.uv).xy * pixelScale;
float dOut = 0.0;
#if DIST_CIRCLE
dOut = distance(p0, p1);
#elif DIST_DIAMOND
dOut = distanceDiamond(p0, p1);
#elif DIST_SQUARE
dOut = distanceSquare(p0, p1);
#endif
p1 = tex2D(_InsideTex, i.uv).xy * pixelScale;
float dIn = 0.0;
#if DIST_CIRCLE
dIn = distance(p0, p1);
#elif DIST_DIAMOND
dIn = distanceDiamond(p0, p1);
#elif DIST_SQUARE
dIn = distanceSquare(p0, p1);
#endif
float d = dOut - dIn;
return (d * _DownSample);
}
ENDCG
SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}
Cull Off
ZWrite Off
ZTest Always
Pass
{
Name "AlphaToUV"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragAlphaToUV
ENDCG
}
Pass
{
Name "InvAlphaToUV"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragInvAlphaToUV
ENDCG
}
Pass
{
Name "JumpFlood"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragJumpFlood
#pragma multi_compile_local_fragment DIST_SQUARE DIST_DIAMOND DIST_CIRCLE
ENDCG
}
Pass
{
Name "JumpFloodSingleAxis"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragJumpFloodSingleAxis
#pragma multi_compile_local_fragment DIST_SQUARE DIST_DIAMOND DIST_CIRCLE
ENDCG
}
Pass
{
Name "ResolveDistance"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragResolveDistance
#pragma multi_compile_local_fragment DIST_SQUARE DIST_DIAMOND DIST_CIRCLE
ENDCG
}
Pass
{
Name "ResolveDistanceInOutMax"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragResolveDistanceIOnOutMax
#pragma multi_compile_local_fragment DIST_SQUARE DIST_DIAMOND DIST_CIRCLE
ENDCG
}
Pass
{
Name "ResolveDistanceSDF"
CGPROGRAM
#pragma vertex vert
#pragma fragment fragResolveDistanceSDF
#pragma multi_compile_local_fragment DIST_SQUARE DIST_DIAMOND DIST_CIRCLE
ENDCG
}
}
}