237 lines
10 KiB
GLSL
237 lines
10 KiB
GLSL
Shader "AIBIS/KiteFocusSprite"
|
|
{
|
|
Properties
|
|
{
|
|
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
|
|
_Color ("Tint", Color) = (1, 1, 1, 1)
|
|
|
|
[Header(Focus Blur)]
|
|
_BlurAmount ("Blur Amount", Range(0, 1)) = 0
|
|
_BlurSize ("Blur Size", Range(0, 0.05)) = 0.012
|
|
[HideInInspector] _UseSoftFocus ("Use Soft Focus", Float) = 0
|
|
_DefocusBloom ("Defocus Highlight Bloom", Range(0, 1)) = 0.32
|
|
_HaloStrength ("Large Circle Halo", Range(0, 0.6)) = 0.22
|
|
_ChromaticFringe ("Lens Color Fringe", Range(0, 0.6)) = 0.14
|
|
_DefocusVeil ("Defocus White Veil", Range(0, 0.3)) = 0.055
|
|
|
|
// Required for SpriteMask (same contract as Sprites-Default / UI.Mask)
|
|
[HideInInspector][PerRendererData] _StencilComp ("Stencil Comparison", Float) = 8
|
|
[HideInInspector][PerRendererData] _Stencil ("Stencil ID", Float) = 0
|
|
[HideInInspector][PerRendererData] _StencilOp ("Stencil Operation", Float) = 0
|
|
[HideInInspector][PerRendererData] _StencilWriteMask ("Stencil Write Mask", Float) = 255
|
|
[HideInInspector][PerRendererData] _StencilReadMask ("Stencil Read Mask", Float) = 255
|
|
[HideInInspector] _ColorMask ("Color Mask", Float) = 15
|
|
}
|
|
|
|
SubShader
|
|
{
|
|
Tags
|
|
{
|
|
"Queue" = "Transparent"
|
|
"IgnoreProjector" = "True"
|
|
"RenderType" = "Transparent"
|
|
"PreviewType" = "Plane"
|
|
"CanUseSpriteAtlas" = "True"
|
|
}
|
|
|
|
Cull Off
|
|
Lighting Off
|
|
ZWrite Off
|
|
Blend One OneMinusSrcAlpha
|
|
ColorMask [_ColorMask]
|
|
|
|
Stencil
|
|
{
|
|
Ref [_Stencil]
|
|
Comp [_StencilComp]
|
|
Pass [_StencilOp]
|
|
ReadMask [_StencilReadMask]
|
|
WriteMask [_StencilWriteMask]
|
|
}
|
|
|
|
Pass
|
|
{
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#pragma target 3.0
|
|
#include "UnityCG.cginc"
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION;
|
|
float4 color : COLOR;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
struct v2f
|
|
{
|
|
float4 vertex : SV_POSITION;
|
|
fixed4 color : COLOR;
|
|
float2 uv : TEXCOORD0;
|
|
};
|
|
|
|
sampler2D _MainTex;
|
|
float4 _MainTex_TexelSize;
|
|
fixed4 _Color;
|
|
float _BlurAmount;
|
|
float _BlurSize;
|
|
float _UseSoftFocus;
|
|
float _DefocusBloom;
|
|
float _HaloStrength;
|
|
float _ChromaticFringe;
|
|
float _DefocusVeil;
|
|
|
|
v2f vert(appdata v)
|
|
{
|
|
v2f o;
|
|
o.vertex = UnityObjectToClipPos(v.vertex);
|
|
o.color = v.color * _Color;
|
|
o.uv = v.uv;
|
|
return o;
|
|
}
|
|
|
|
half4 sampleTex(float2 uv)
|
|
{
|
|
// 边界外按透明,避免 saturate 夹边造成硬切
|
|
if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0)
|
|
return half4(0, 0, 0, 0);
|
|
return tex2D(_MainTex, uv);
|
|
}
|
|
|
|
half4 samplePremultiplied(float2 uv)
|
|
{
|
|
half4 color = sampleTex(uv);
|
|
color.rgb *= color.a;
|
|
return color;
|
|
}
|
|
|
|
// 圆形光圈核:比高斯更接近真实镜头的弥散圆,且不会出现十字形拖影。
|
|
half4 ApertureDisc(float2 uv, float radius)
|
|
{
|
|
half4 result = samplePremultiplied(uv) * 0.12;
|
|
const half w = 0.044;
|
|
|
|
// 内圈
|
|
result += samplePremultiplied(uv + float2( 0.38, 0.00) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.38, 0.00) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.00, 0.38) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.00, -0.38) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.27, 0.27) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.27, 0.27) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.27, -0.27) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.27, -0.27) * radius) * w;
|
|
|
|
// 外圈使用不规则角度,避免规则采样形成振铃或星芒。
|
|
result += samplePremultiplied(uv + float2( 0.98, 0.05) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.82, 0.55) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.43, 0.90) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.16, 0.98) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.69, 0.72) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.99, 0.10) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.80, -0.58) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.36, -0.92) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.22, -0.97) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.72, -0.68) * radius) * w;
|
|
result += samplePremultiplied(uv + float2( 0.94, -0.31) * radius) * w;
|
|
result += samplePremultiplied(uv + float2(-0.48, 0.86) * radius) * w;
|
|
return result;
|
|
}
|
|
|
|
half4 WideHalo(float2 uv, float radius)
|
|
{
|
|
half4 result = 0;
|
|
result += samplePremultiplied(uv + float2( 1.00, 0.00) * radius);
|
|
result += samplePremultiplied(uv + float2( 0.71, 0.71) * radius);
|
|
result += samplePremultiplied(uv + float2( 0.00, 1.00) * radius);
|
|
result += samplePremultiplied(uv + float2(-0.71, 0.71) * radius);
|
|
result += samplePremultiplied(uv + float2(-1.00, 0.00) * radius);
|
|
result += samplePremultiplied(uv + float2(-0.71, -0.71) * radius);
|
|
result += samplePremultiplied(uv + float2( 0.00, -1.00) * radius);
|
|
result += samplePremultiplied(uv + float2( 0.71, -0.71) * radius);
|
|
return result * 0.125;
|
|
}
|
|
|
|
half4 SoftFocusBlur(float2 uv, float radius)
|
|
{
|
|
float nearRadius = radius * 0.48;
|
|
half4 result = samplePremultiplied(uv) * 0.20;
|
|
|
|
result += samplePremultiplied(uv + float2( nearRadius, 0)) * 0.08;
|
|
result += samplePremultiplied(uv + float2(-nearRadius, 0)) * 0.08;
|
|
result += samplePremultiplied(uv + float2(0, nearRadius)) * 0.08;
|
|
result += samplePremultiplied(uv + float2(0, -nearRadius)) * 0.08;
|
|
|
|
result += samplePremultiplied(uv + float2( nearRadius, nearRadius)) * 0.055;
|
|
result += samplePremultiplied(uv + float2(-nearRadius, nearRadius)) * 0.055;
|
|
result += samplePremultiplied(uv + float2( nearRadius, -nearRadius)) * 0.055;
|
|
result += samplePremultiplied(uv + float2(-nearRadius, -nearRadius)) * 0.055;
|
|
|
|
result += samplePremultiplied(uv + float2( radius, 0)) * 0.04;
|
|
result += samplePremultiplied(uv + float2(-radius, 0)) * 0.04;
|
|
result += samplePremultiplied(uv + float2(0, radius)) * 0.04;
|
|
result += samplePremultiplied(uv + float2(0, -radius)) * 0.04;
|
|
|
|
result += samplePremultiplied(uv + float2( radius, radius)) * 0.025;
|
|
result += samplePremultiplied(uv + float2(-radius, radius)) * 0.025;
|
|
result += samplePremultiplied(uv + float2( radius, -radius)) * 0.025;
|
|
result += samplePremultiplied(uv + float2(-radius, -radius)) * 0.025;
|
|
return result;
|
|
}
|
|
|
|
fixed4 frag(v2f i) : SV_Target
|
|
{
|
|
float blurAmt = saturate(_BlurAmount);
|
|
half4 sharp = sampleTex(i.uv);
|
|
|
|
if (blurAmt < 0.001)
|
|
{
|
|
half4 col = sharp * i.color;
|
|
col.rgb *= col.a;
|
|
return col;
|
|
}
|
|
|
|
float2 texel = max(abs(_MainTex_TexelSize.xy), float2(1e-5, 1e-5));
|
|
float radius = (length(texel) * 0.5 + _BlurSize) * (0.28 + blurAmt * 1.72);
|
|
|
|
if (_UseSoftFocus > 0.5)
|
|
{
|
|
half4 softBlurred = SoftFocusBlur(i.uv, radius);
|
|
half4 softSharp = sharp;
|
|
softSharp.rgb *= softSharp.a;
|
|
half4 softColor = lerp(softSharp, softBlurred, smoothstep(0.0, 1.0, blurAmt));
|
|
softColor.rgb *= i.color.rgb * i.color.a;
|
|
softColor.a *= i.color.a;
|
|
return softColor;
|
|
}
|
|
|
|
half4 disc = ApertureDisc(i.uv, radius);
|
|
half4 halo = WideHalo(i.uv, radius * 1.85);
|
|
half4 blurred = lerp(disc, halo, saturate(_HaloStrength * blurAmt));
|
|
|
|
// 很轻的 RGB 焦平面差异,避免单纯软件模糊的塑料感。
|
|
float2 fringe = float2(0.73, 0.41) * radius * _ChromaticFringe * blurAmt;
|
|
half4 fringeR = samplePremultiplied(i.uv + fringe);
|
|
half4 fringeB = samplePremultiplied(i.uv - fringe);
|
|
blurred.r = lerp(blurred.r, fringeR.r, _ChromaticFringe * blurAmt);
|
|
blurred.b = lerp(blurred.b, fringeB.b, _ChromaticFringe * blurAmt);
|
|
|
|
// 参考片中的失焦会让亮部扩散并稍微泛白,但保留在物体 alpha 内。
|
|
half luminance = dot(blurred.rgb, half3(0.2126, 0.7152, 0.0722));
|
|
half highlight = saturate(luminance - blurred.a * 0.42);
|
|
blurred.rgb += highlight * _DefocusBloom * blurAmt;
|
|
blurred.rgb += blurred.a * _DefocusVeil * blurAmt;
|
|
|
|
half4 sharpPremul = sharp;
|
|
sharpPremul.rgb *= sharpPremul.a;
|
|
float mixT = smoothstep(0.0, 1.0, blurAmt);
|
|
half4 col = lerp(sharpPremul, blurred, mixT);
|
|
col.rgb *= i.color.rgb * i.color.a;
|
|
col.a *= i.color.a;
|
|
return col;
|
|
}
|
|
ENDCG
|
|
}
|
|
}
|
|
}
|