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 } } }