Shader "IndianOcean/AbyssBuilding" { // 深渊边缘建筑 Shader v2 // // 改进(vs v1): // 1. 世界坐标 Y 替代 UV.y —— 所有建筑在同一世界高度被吞,不受尺寸/Pivot/动画影响 // 2. 颜色和 Alpha 一起渐变 —— 黑暗"侵蚀"进去,而不是硬切 // 3. 噪声扰动吞没线 —— 边缘破碎,不是直线 // 4. 边缘侵蚀发光 —— 过渡带泛幽光,和 AbyssEdgeGlow 衔接 // // Queue = Transparent(在 DarknessOverlay 之前渲染) // DarknessOverlay 乘法遮罩控制最终可见性 // // 搭配: // - AbyssEdgeGlow(Queue +200)放地图断层处 // - AbyssGlowParticle(Queue +200)在深渊里撒粒子 // - 建筑用此 shader,底部延伸到 _CutoffY 以下 Properties { _MainTex ("精灵贴图", 2D) = "white" {} _Color ("色调", Color) = (1,1,1,1) _CutoffY ("深渊吞没线(世界 Y)", Float) = 0.0 _Feather ("吞没渐变宽度(世界单位)", Float) = 1.5 _NoiseScale ("噪声缩放(越大越细碎)", Float) = 3.0 _NoiseAmount ("噪声强度 (0=直线 1=强烈破碎)", Range(0,1)) = 0.3 _EdgeColor ("边缘侵蚀色", Color) = (0.15, 0.5, 0.8, 1.0) _EdgeIntensity ("边缘亮度", Range(0, 5)) = 1.5 } SubShader { Tags { "RenderType" = "Transparent" "Queue" = "Transparent" "RenderPipeline" = "UniversalPipeline" "CanUseSpriteAtlas" = "true" } Cull Off ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Pass { Name "AbyssBuilding" 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; float4 color : COLOR; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float4 color : COLOR; float3 positionWS : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float4 _Color; float _CutoffY; float _Feather; float _NoiseScale; float _NoiseAmount; float4 _EdgeColor; float _EdgeIntensity; CBUFFER_END TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); // ---- 简单 2D Value Noise(世界空间一致)---- float hash21(float2 p) { p = frac(p * float2(123.34, 456.21)); p += dot(p, p + 34.345); return frac(p.x * p.y); } float noise2D(float2 p) { float2 i = floor(p); float2 f = frac(p); float a = hash21(i); float b = hash21(i + float2(1, 0)); float c = hash21(i + float2(0, 1)); float d = hash21(i + float2(1, 1)); float2 u = f * f * (3.0 - 2.0 * f); return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y); } Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); output.positionWS = TransformObjectToWorld(input.positionOS.xyz); output.positionCS = TransformWorldToHClip(output.positionWS); output.uv = input.uv; output.color = input.color; return output; } half4 frag(Varyings input) : SV_Target { half4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv); half3 albedo = tex.rgb * input.color.rgb * _Color.rgb; half alpha = tex.a * input.color.a * _Color.a; // ---- 世界坐标 Y 做吞没线 ---- float worldY = input.positionWS.y; // 噪声扰动吞没线高度(基于世界 XZ,跨建筑一致) float n = noise2D(input.positionWS.xz * _NoiseScale); float noisyCutoff = _CutoffY + (n - 0.5) * _NoiseAmount * _Feather * 2.0; // fade: 0 = 完全被吞, 1 = 完全可见 float fade = smoothstep( noisyCutoff - _Feather, noisyCutoff + _Feather, worldY ); // ---- 颜色和 Alpha 一起渐变 ---- // 黑暗"吃进去"而不是硬切 half3 finalColor = albedo * fade; half finalAlpha = alpha * fade; // ---- 边缘侵蚀发光 ---- // 在过渡带(fade ≈ 0.1~0.4)泛光,模拟深渊腐蚀边缘 float edge = smoothstep(0.0, 0.12, fade) * (1.0 - smoothstep(0.12, 0.45, fade)); finalColor += _EdgeColor.rgb * edge * _EdgeIntensity; // 边缘也补一点 Alpha,让发光看得见 finalAlpha += edge * _EdgeIntensity * 0.3; // 丢弃几乎全透明的像素 clip(finalAlpha - 0.001); return half4(finalColor, finalAlpha); } ENDHLSL } } FallBack Off }