Shader "Custom/EchoCloudShader" { Properties { [Header(Base Appearance)] _BaseColor("Base Ambient Color", Color) = (0.015, 0.015, 0.02, 1.0) [MainTexture] _BaseMap("Base Map (Optional)", 2D) = "white" {} [HideInInspector] _MainTex("MainTex", 2D) = "white" {} [Header(Echo Cloud Visuals)] [HDR] _EchoColor("Echo Mist Color", Color) = (4.0, 3.026, 1.049, 1.0) [HDR] _EchoCoreColor("Echo Core Bloom", Color) = (7.5, 5.5, 2.2, 1.0) _CloudBandWidth("Cloud Thickness / Tail (m)", Range(0.5, 8.0)) = 3.2 _LeadingEdgeSoftness("Leading Edge Softness", Range(0.1, 3.0)) = 1.2 [Header(Cloud Noise and Billows)] _NoiseScale("Cloud Noise Scale", Range(0.05, 1.5)) = 0.35 _NoiseDistortion("Cloud Billow Distortion", Range(0.0, 3.0)) = 1.3 _NoiseSpeed("Cloud Drift Speed", Range(0.0, 2.0)) = 0.2 [Header(Acoustic Ripples and Edge Glow)] _RippleFrequency("Acoustic Ripple Frequency", Range(0.1, 5.0)) = 1.5 _RippleStrength("Acoustic Ripple Strength", Range(0.0, 1.0)) = 0.25 _FresnelPower("Edge Rim Power", Range(0.5, 5.0)) = 2.5 _FresnelStrength("Edge Rim Strength", Range(0.0, 2.0)) = 0.4 [Header(Momentary Color Reveal on Wave)] _ColorRevealIntensity("Color Reveal Brightness", Range(0.0, 4.0)) = 1.6 _ColorRevealSharpness("Color Reveal Sharpness", Range(0.5, 4.0)) = 1.0 _WaveTintWeight("Yellow Wave Tint Blend", Range(0.0, 1.0)) = 0.45 [Header(Wave Inputs from Script)] _EchoPosition1("Echo Position 1", Vector) = (0, 0, 0, 0) _EchoPosition2("Echo Position 2", Vector) = (0, 0, 0, 0) _EchoPosition3("Echo Position 3", Vector) = (0, 0, 0, 0) _EchoRadius1("Echo Radius 1", Float) = 0 _EchoRadius2("Echo Radius 2", Float) = 0 _EchoRadius3("Echo Radius 3", Float) = 0 _EchoOpacity1("Echo Opacity 1", Float) = 0 _EchoOpacity2("Echo Opacity 2", Float) = 0 _EchoOpacity3("Echo Opacity 3", Float) = 0 // Legacy compatibility properties [HideInInspector] _RingWidth("Ring Width", Float) = 0.08 [HideInInspector] _LineDensity("Line Density", Float) = 3.0 [HideInInspector] _LineThickness("Line Thickness", Float) = 0.05 [HideInInspector] _WaveCenter("Wave Center", Vector) = (0, 0, 0, 0) [HideInInspector] _WaveRadius("Wave Radius", Float) = 0 [HideInInspector] _QueueOffset("Queue Offset", Float) = 0 [HideInInspector] _QueueControl("Queue Control", Float) = 0 } SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" } LOD 200 Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" } ZWrite On ZTest LEqual Cull Back HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 uv : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float3 positionWS : TEXCOORD0; float3 normalWS : TEXCOORD1; float2 uv : TEXCOORD2; float fogFactor : TEXCOORD3; }; TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); CBUFFER_START(UnityPerMaterial) half4 _BaseColor; half4 _EchoColor; half4 _EchoCoreColor; float _CloudBandWidth; float _LeadingEdgeSoftness; float _NoiseScale; float _NoiseDistortion; float _NoiseSpeed; float _RippleFrequency; float _RippleStrength; float _FresnelPower; float _FresnelStrength; float _ColorRevealIntensity; float _ColorRevealSharpness; float _WaveTintWeight; float4 _EchoPosition1; float4 _EchoPosition2; float4 _EchoPosition3; float _EchoRadius1; float _EchoRadius2; float _EchoRadius3; float _EchoOpacity1; float _EchoOpacity2; float _EchoOpacity3; float4 _BaseMap_ST; float _RingWidth; float _LineDensity; float _LineThickness; float4 _WaveCenter; float _WaveRadius; float _QueueOffset; float _QueueControl; CBUFFER_END // 3D Hash and Value Noise float3 Hash33(float3 p) { p = float3(dot(p, float3(127.1, 311.7, 74.7)), dot(p, float3(269.5, 183.3, 246.1)), dot(p, float3(113.5, 271.9, 124.6))); return frac(sin(p) * 43758.5453123); } float ValueNoise3D(float3 p) { float3 i = floor(p); float3 f = frac(p); float3 u = f * f * (3.0 - 2.0 * f); float n000 = dot(Hash33(i + float3(0,0,0)) - 0.5, f - float3(0,0,0)); float n100 = dot(Hash33(i + float3(1,0,0)) - 0.5, f - float3(1,0,0)); float n010 = dot(Hash33(i + float3(0,1,0)) - 0.5, f - float3(0,1,0)); float n110 = dot(Hash33(i + float3(1,1,0)) - 0.5, f - float3(1,1,0)); float n001 = dot(Hash33(i + float3(0,0,1)) - 0.5, f - float3(0,0,1)); float n101 = dot(Hash33(i + float3(1,0,1)) - 0.5, f - float3(1,0,1)); float n011 = dot(Hash33(i + float3(0,1,1)) - 0.5, f - float3(0,1,1)); float n111 = dot(Hash33(i + float3(1,1,1)) - 0.5, f - float3(1,1,1)); float nx00 = lerp(n000, n100, u.x); float nx10 = lerp(n010, n110, u.x); float nx01 = lerp(n001, n101, u.x); float nx11 = lerp(n011, n111, u.x); float nxy0 = lerp(nx00, nx10, u.y); float nxy1 = lerp(nx01, nx11, u.y); return lerp(nxy0, nxy1, u.z) + 0.5; } float GetCloudNoise(float3 worldPos) { float3 p1 = worldPos * _NoiseScale + float3(0, _Time.y * _NoiseSpeed, 0); float n1 = ValueNoise3D(p1); float3 p2 = worldPos * (_NoiseScale * 2.2) - float3(0, _Time.y * (_NoiseSpeed * 1.4), 0); float n2 = ValueNoise3D(p2); return n1 * 0.65 + n2 * 0.35; } float CalculateSingleWave(float3 worldPos, float3 normalWS, float3 viewDirWS, float3 waveCenter, float waveRadius, float waveOpacity, float noiseVal) { if (waveOpacity <= 0.001 || waveRadius <= 0.01) return 0.0; float rawDist = distance(worldPos, waveCenter); // Organic cloud boundary distortion via 3D noise float distortedDist = rawDist + (noiseVal - 0.5) * _NoiseDistortion; float distFromWave = distortedDist - waveRadius; // Ahead of wavefront (distFromWave > 0): smooth drop-off into darkness float aheadFade = 1.0 - saturate(distFromWave / max(0.01, _LeadingEdgeSoftness)); // Behind wavefront (distFromWave < 0): smooth cloud tail float behindFade = 1.0 - saturate(-distFromWave / max(0.1, _CloudBandWidth)); // Pulse profile peaking right at the wave crest float cloudDensity = (distFromWave > 0.0) ? aheadFade : behindFade; cloudDensity = smoothstep(0.0, 1.0, cloudDensity); // Subtle acoustic harmonic ripples inside the cloud float ripple = sin((rawDist - waveRadius) * _RippleFrequency) * 0.5 + 0.5; cloudDensity *= lerp(1.0, ripple, _RippleStrength); // Subtle edge rim glow on surfaces facing away float NdotV = saturate(dot(normalWS, viewDirWS)); float rim = pow(1.0 - NdotV, _FresnelPower) * _FresnelStrength; cloudDensity += cloudDensity * rim; return saturate(cloudDensity) * waveOpacity; } Varyings vert(Attributes input) { Varyings output = (Varyings)0; VertexPositionInputs vertexInputs = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInputs = GetVertexNormalInputs(input.normalOS); output.positionCS = vertexInputs.positionCS; output.positionWS = vertexInputs.positionWS; output.normalWS = normalInputs.normalWS; output.uv = TRANSFORM_TEX(input.uv, _BaseMap); output.fogFactor = ComputeFogFactor(vertexInputs.positionCS.z); return output; } half4 frag(Varyings input) : SV_Target { float3 worldPos = input.positionWS; float3 normalWS = normalize(input.normalWS); float3 viewDirWS = normalize(GetCameraPositionWS() - worldPos); // Base diffuse texture from object half4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv); // Deep dark ambient appearance in shadows half4 baseCol = texColor * _BaseColor; // 3D procedural noise float noiseVal = GetCloudNoise(worldPos); // Evaluate all 3 simultaneous echo waves float w1 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition1.xyz, _EchoRadius1, _EchoOpacity1, noiseVal); float w2 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition2.xyz, _EchoRadius2, _EchoOpacity2, noiseVal); float w3 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition3.xyz, _EchoRadius3, _EchoOpacity3, noiseVal); float totalWave = saturate(w1 + w2 + w3); // --- МОМЕНТАЛЬНОЕ ПРОЯВЛЕНИЕ СОБСТВЕННОГО ЦВЕТА ПРЕДМЕТА ПРИ ПРОХОЖДЕНИИ ВОЛНЫ --- // Мягкое затенение граней по нормали к камере для 3D-объема half NdotV = saturate(dot(normalWS, viewDirWS)); half3 surfaceLighting = half3(1, 1, 1) * (NdotV * 0.35 + 0.65); // Собственный цвет текстуры объекта, активируемый ровно в момент прохождения волны half revealFactor = pow(totalWave, _ColorRevealSharpness); half3 naturalRevealedColor = texColor.rgb * surfaceLighting * (_ColorRevealIntensity * revealFactor); // Желтая акустическая волна (гребень и ядро эхолокации) half4 mistColor = _EchoColor * totalWave; half4 coreBloom = _EchoCoreColor * pow(totalWave, 2.5) * 0.35; half3 waveGlow = mistColor.rgb * _WaveTintWeight + coreBloom.rgb; // Итог: темная база + проявленный собственный цвет предмета + золотистый ореол волны half3 finalRgb = baseCol.rgb + naturalRevealedColor + waveGlow; half4 finalColor = half4(finalRgb, 1.0); // Apply scene fog finalColor.rgb = MixFog(finalColor.rgb, input.fogFactor); return finalColor; } ENDHLSL } UsePass "Universal Render Pipeline/Lit/ShadowCaster" UsePass "Universal Render Pipeline/Lit/DepthOnly" } FallBack "Hidden/Universal Render Pipeline/FallbackError" }