257 lines
7.4 KiB
Plaintext
257 lines
7.4 KiB
Plaintext
Shader "Hidden/MicroVerse/JumpFloodSDF"
|
|
{
|
|
Properties
|
|
{
|
|
_MainTex ("Texture", 2D) = "white" {}
|
|
_Zoom ("Zoom", Float) = 1
|
|
}
|
|
SubShader
|
|
{
|
|
Tags { "PreviewType" = "Plane" }
|
|
Cull Off ZWrite Off ZTest Always
|
|
|
|
CGINCLUDE
|
|
|
|
|
|
#define FLOOD_NULL_POS -1.0
|
|
#define FLOOD_NULL_POS_FLOAT2 float2(FLOOD_NULL_POS, FLOOD_NULL_POS)
|
|
|
|
|
|
ENDCG
|
|
|
|
Pass // 0
|
|
{
|
|
Name "JUMPFLOODINIT"
|
|
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
#include_with_pragmas "UnityCG.cginc"
|
|
|
|
#pragma target 4.5
|
|
|
|
int _Channel;
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
sampler2D _MainTex;
|
|
float4 _MainTex_TexelSize;
|
|
|
|
v2f vert (appdata v)
|
|
{
|
|
v2f o;
|
|
o.pos = UnityObjectToClipPos(v.vertex);
|
|
o.uv = v.uv;
|
|
return o;
|
|
}
|
|
|
|
float2 frag (v2f i) : SV_Target {
|
|
|
|
// sample silhouette texture for sobel
|
|
half3x3 values;
|
|
UNITY_UNROLL
|
|
for(int u=0; u<3; u++)
|
|
{
|
|
UNITY_UNROLL
|
|
for(int v=0; v<3; v++)
|
|
{
|
|
float2 sampleUV = clamp(i.uv + _MainTex_TexelSize.xy * float2(u-1, v-1), float2(0,0), float2(1,1));
|
|
values[u][v] = tex2D(_MainTex, sampleUV)[_Channel];
|
|
}
|
|
}
|
|
|
|
// calculate output position for this pixel
|
|
float2 outPos = i.uv;
|
|
|
|
// interior, return position
|
|
if (values._m11 > 0.99)
|
|
return outPos;
|
|
|
|
// exterior, return no position
|
|
if (values._m11 < 0.01)
|
|
return FLOOD_NULL_POS_FLOAT2;
|
|
|
|
// sobel to estimate edge direction
|
|
float2 dir = -float2(
|
|
values[0][0] + values[0][1] * 2.0 + values[0][2] - values[2][0] - values[2][1] * 2.0 - values[2][2],
|
|
values[0][0] + values[1][0] * 2.0 + values[2][0] - values[0][2] - values[1][2] * 2.0 - values[2][2]
|
|
);
|
|
|
|
// 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 outPos;
|
|
|
|
// normalize direction
|
|
dir = normalize(dir);
|
|
|
|
// sub pixel offset
|
|
float2 offset = dir * (1.0 - values._m11);
|
|
|
|
// output encoded offset position
|
|
return (i.uv.xy + offset * _MainTex_TexelSize.xy);
|
|
}
|
|
ENDCG
|
|
}
|
|
|
|
Pass // 1
|
|
{
|
|
Name "JUMPFLOOD"
|
|
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
#include_with_pragmas "UnityCG.cginc"
|
|
|
|
#pragma target 4.5
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
sampler _MainTex;
|
|
float4 _MainTex_TexelSize;
|
|
int _StepWidth;
|
|
|
|
v2f vert (appdata v)
|
|
{
|
|
v2f o;
|
|
o.pos = UnityObjectToClipPos(v.vertex);
|
|
o.uv = v.uv;
|
|
return o;
|
|
}
|
|
|
|
float2 frag (v2f i) : SV_Target
|
|
{
|
|
// initialize best distance at infinity
|
|
float bestDist = 1.#INF;
|
|
float2 bestCoord;
|
|
|
|
// jump samples
|
|
UNITY_UNROLL
|
|
for(int u=-1; u<=1; u++)
|
|
{
|
|
UNITY_UNROLL
|
|
for(int v=-1; v<=1; v++)
|
|
{
|
|
// calculate offset sample position
|
|
|
|
float2 offsetUV = i.uv + int2(u, v) * _MainTex_TexelSize.xy * _StepWidth;
|
|
|
|
// .Load() acts funny when sampling outside of bounds, so don't
|
|
offsetUV = clamp(offsetUV, 0, 1);
|
|
|
|
// decode position from buffer
|
|
float2 offsetPos = tex2D(_MainTex, offsetUV).rg * _MainTex_TexelSize.zw;
|
|
|
|
// the offset from current position
|
|
float2 disp = i.uv * _MainTex_TexelSize.zw - offsetPos;
|
|
|
|
// square distance
|
|
float dist = dot(disp, disp);
|
|
|
|
// if offset position isn't a null position or is closer than the best
|
|
// set as the new best and store the position
|
|
if (offsetPos.y != FLOOD_NULL_POS && dist < bestDist)
|
|
{
|
|
bestDist = dist;
|
|
bestCoord = offsetPos;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if not valid best distance output null position, otherwise output encoded position
|
|
|
|
return isinf(bestDist) ? FLOOD_NULL_POS_FLOAT2 : bestCoord * _MainTex_TexelSize.xy;
|
|
}
|
|
ENDCG
|
|
}
|
|
|
|
// technically optional, as you can just decode distance in the shader and not do this pass.
|
|
Pass // 2
|
|
{
|
|
Name "JUMPFLOODSDF"
|
|
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
#include_with_pragmas "UnityCG.cginc"
|
|
|
|
#pragma target 4.5
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 pos : SV_POSITION;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
Texture2D _MainTex;
|
|
float4 _MainTex_TexelSize;
|
|
float _Zoom;
|
|
|
|
|
|
v2f vert (appdata v)
|
|
{
|
|
v2f o;
|
|
o.pos = UnityObjectToClipPos(v.vertex);
|
|
o.uv = v.uv;
|
|
return o;
|
|
}
|
|
|
|
float frag (v2f i) : SV_Target
|
|
{
|
|
float fac = (1 + (_Zoom-1)*2);
|
|
i.uv /= fac;
|
|
i.uv += (1.0 / fac) * (_Zoom-1);
|
|
|
|
// integer pixel position
|
|
int2 uvInt = i.uv * _MainTex_TexelSize.zw;
|
|
|
|
// load encoded position
|
|
float2 encodedPos = _MainTex.Load(int3(uvInt, 0)).rg;
|
|
|
|
// early out if null position
|
|
if (encodedPos.y == -1)
|
|
return half4(99999,99999,99999,99999);
|
|
|
|
// decode closest position
|
|
float2 nearestPos = encodedPos * _MainTex_TexelSize.zw;
|
|
|
|
// current pixel position
|
|
float2 currentPos = i.uv.xy * _MainTex_TexelSize.zw;
|
|
|
|
// distance in pixels to closest position
|
|
half dist = distance(nearestPos, currentPos);
|
|
return dist / 256;
|
|
}
|
|
ENDCG
|
|
}
|
|
}
|
|
} |