281 lines
12 KiB
GLSL
281 lines
12 KiB
GLSL
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"
|
|
}
|