Прежде всего, вам нужно вычислить преобразование расстояния вашего изображения. Лучше всего использовать алгоритм jump flooding .
1) Укажите значимые пиксели, например, с помощью функции шага.
fixed4 frag (v2f i) : SV_Target
{
return step( _Threshold, tex2D( _MainTex, i.uv ).a );
}
2) Визуализация начального изображения для алгоритма скачкообразного затопления. В начальном изображении кодируйте (0,0) для значимых пикселей и фактическое положение УФ для незначительных (на изображении выше, RG кодирует U, а BA кодирует V с точностью 16 бит).
fixed4 frag (v2f i) : SV_Target
{
return lerp(
fixed4( 0.0, 0.0, 0.0, 0.0 ),
fixed4( EncodeFloatRG( i.uv.x ), EncodeFloatRG( i.uv.y ) ),
1.0 - step( 0.01, tex2D( _MainTex, i.uv ).r )
);
}
3-10) Прыжки с шагами. На каждом шаге вы должны перебирать «соседние» пиксели и находить, какой из них содержит закодированную позицию UV, ближайшую к позиции UV текущего пикселя. Наводнение должно начинаться с самых дальних «соседей», а затем постепенно уменьшать расстояние поиска.
void JumpFlooding(half2 uv, half2 duv, inout half2 nearestPos, inout half nearestDist)
{
fixed4 seed = tex2D( _MainTex, uv + duv * _MainTex_TexelSize.xy );
half2 pos = half2( DecodeFloatRG( seed.xy ), DecodeFloatRG( seed.zw ) );
if( length(pos) > 0.0 )
{
half dist = distance( uv, pos );
if( dist < nearestDist )
{
nearestDist = dist;
nearestPos = pos;
}
}
}
fixed4 frag (v2f i) : SV_Target
{
half2 nearestPos = half2( 0, 0 );
half nearestDist = 2.0;
JumpFlooding( i.uv, half2( -_Offset, -_Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( -_Offset, 0 ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( -_Offset, _Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( 0, _Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( _Offset, _Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( _Offset, 0 ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( _Offset, -_Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( 0, -_Offset ), nearestPos, nearestDist );
JumpFlooding( i.uv, half2( 0, 0 ), nearestPos, nearestDist );
return fixed4( EncodeFloatRG( nearestPos.x ), EncodeFloatRG( nearestPos.y ) );
}
11) Наконец, последний результат алгоритма скачкообразного затопления закодирован в поле расстояния.
fixed4 frag (v2f i) : SV_Target
{
fixed4 seed = tex2D( _MainTex, i.uv );
half2 pos = half2( DecodeFloatRG( seed.xy ), DecodeFloatRG( seed.zw ) );
float dist = distance( i.uv, pos );
return EncodeFloatRGBA( dist );
}
И теперь вы можете использовать поле расстояния для рисования внутренней тени.
fixed4 frag (v2f i) : SV_Target
{
half4 color = _ShadowColor;
half dist = DecodeFloatRGBA( tex2D(_DistTex, i.uv) );
color.a *= ( 1.0 - smoothstep( _ShadowMinRange, _ShadowMaxRange, dist ) );
return color;
}