Shader "IndianOcean/DarknessOverlay" { // 黑暗遮罩 Shader v2 —— 乘法混合版(纯黑暗 + 光源,不含回声) // 回声描边已独立到 SpriteEchoOutline shader,由 EchoSystem 全局参数驱动。 // // 乘法混合:finalColor = srcColor * dstColor // 黑暗区域:sceneColor * 0 = 纯黑(精灵完全看不见) // 光照区域:sceneColor * 1 = 原色(完全可见) Properties { _DarknessColor ("黑暗底色(夜间微光色调)", Color) = (0.01, 0.01, 0.02, 1) _MinBrightness ("最小亮度(0=纯黑不可见, 0.05=微光)", Range(0, 0.3)) = 0.0 _LightSoftness ("光线柔和度(边缘渐变宽度)", Range(0.01, 1.0)) = 0.35 } SubShader { Tags { "RenderType" = "Transparent" "Queue" = "Transparent+100" "RenderPipeline" = "UniversalPipeline" } Blend DstColor Zero ZWrite Off ZTest Always Cull Off Pass { Name "DarknessOverlay" HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 worldPos : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; CBUFFER_START(UnityPerMaterial) float4 _DarknessColor; float _MinBrightness; float _LightSoftness; CBUFFER_END // 光源数据数组:xy = 世界坐标 XZ, z = 半径, w = 强度(0~1) float4 _LightData[64]; int _LightCount; Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = input.uv; output.worldPos = TransformObjectToWorld(input.positionOS.xyz); return output; } half4 frag(Varyings input) : SV_Target { // 2.5D 俯视角:用世界坐标的 XZ 平面计算距离 float2 worldPos = input.worldPos.xz; float lightAmount = 0.0; // 常规光源 for (int i = 0; i < _LightCount; i++) { float2 lightPos = _LightData[i].xy; float radius = _LightData[i].z; float intensity= _LightData[i].w; float dist = distance(worldPos, lightPos); float innerRadius = radius * (1.0 - _LightSoftness); float light = 1.0 - smoothstep(innerRadius, radius, dist); light *= intensity; lightAmount = max(lightAmount, light); } // 最小亮度:全黑区域是否允许微微看到东西 lightAmount = max(lightAmount, _MinBrightness); // 从黑暗底色插值到白色 float3 maskColor = lerp(_DarknessColor.rgb, float3(1.0, 1.0, 1.0), lightAmount); return half4(maskColor, 1.0); } ENDHLSL } } FallBack Off }