TH1/Unity/Assets/Shaders/OutlineShader.shader
2025-07-17 18:26:28 +08:00

124 lines
3.9 KiB
Plaintext

Shader "Custom/Outline"
{
Properties
{
_MainTex ("Main Texture", 2D) = "white" {}
_OutlineColor ("Outline Color", Color) = (1,0.5,0,1)
_OutlineWidth ("Outline Width", Range(0, 0.5)) = 0.1
_GlowIntensity ("Glow Intensity", Range(0, 10)) = 3
_Falloff ("Falloff", Range(0.1, 5)) = 2
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Pass
{
Cull Off
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float2 scaledWidth : TEXCOORD1;
float2 uvSign : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _OutlineColor;
float _OutlineWidth;
float _GlowIntensity;
float _Falloff;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
// 计算缩放符号
float2 scaleSign = float2(
sign(unity_ObjectToWorld._m00),
sign(unity_ObjectToWorld._m11)
);
// 修正UV方向
o.uv = v.uv * scaleSign + (1 - scaleSign)/2;
o.uv = TRANSFORM_TEX(o.uv, _MainTex);
// 计算有效描边宽度(基于世界空间缩放)
float2 worldScale = float2(
length(unity_ObjectToWorld._m00_m10_m20),
length(unity_ObjectToWorld._m01_m11_m21)
);
o.scaledWidth = _OutlineWidth / abs(worldScale) * 0.5;
o.uvSign = scaleSign;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 基础颜色采样(处理镜像)
float2 baseUV = i.uv;
if(i.uvSign.x < 0) baseUV.x = 1 - baseUV.x;
if(i.uvSign.y < 0) baseUV.y = 1 - baseUV.y;
fixed4 col = tex2D(_MainTex, baseUV);
if(col.a > 0.99) return col;
// 渐变参数初始化
float maxDistance = length(i.scaledWidth);
float glow = 0;
// 多级采样实现渐变
const int steps = 8;
for(int s=1; s<=steps; s++)
{
float progress = s/(float)steps;
float currentWidth = progress * maxDistance;
// 环形采样
for(float angle=0; angle<6.283; angle+=1.047) // 60度步进
{
float2 dir = float2(cos(angle), sin(angle));
float2 sampleUV = baseUV + dir * currentWidth;
fixed4 sampleCol = tex2D(_MainTex, sampleUV);
if(sampleCol.a > 0.95)
{
// 距离衰减计算
float attenuation = 1 - pow(progress, _Falloff);
glow += attenuation * _GlowIntensity / steps;
break;
}
}
}
// 颜色混合(非线性插值)
float glowFactor = saturate(glow);
fixed4 final = col;
final.rgb = lerp(col.rgb, _OutlineColor.rgb, glowFactor);
final.a = max(col.a, glowFactor * _OutlineColor.a);
return final;
}
ENDCG
}
}
}