крутой шейдер
This commit is contained in:
parent
da648df1d9
commit
9245409fc9
@ -21,7 +21,7 @@ Material:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: EchoCloudMat
|
m_Name: EchoCloudMat
|
||||||
m_Shader: {fileID: -6465566751694194690, guid: d55932c1661b84243acfb93f7ba5a4b2, type: 3}
|
m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
|
||||||
m_Parent: {fileID: 0}
|
m_Parent: {fileID: 0}
|
||||||
m_ModifiedSerializedProperties: 0
|
m_ModifiedSerializedProperties: 0
|
||||||
m_ValidKeywords: []
|
m_ValidKeywords: []
|
||||||
@ -37,6 +37,10 @@ Material:
|
|||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
|
- _BaseMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
- unity_Lightmaps:
|
- unity_Lightmaps:
|
||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
@ -51,23 +55,34 @@ Material:
|
|||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
m_Ints: []
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
|
- _CloudBandWidth: 3.2
|
||||||
- _EchoOpacity1: 0
|
- _EchoOpacity1: 0
|
||||||
- _EchoOpacity2: 0
|
- _EchoOpacity2: 0
|
||||||
- _EchoOpacity3: 0
|
- _EchoOpacity3: 0
|
||||||
- _EchoRadius1: 0
|
- _EchoRadius1: 0
|
||||||
- _EchoRadius2: 0
|
- _EchoRadius2: 0
|
||||||
- _EchoRadius3: 0
|
- _EchoRadius3: 0
|
||||||
|
- _FresnelPower: 2.5
|
||||||
|
- _FresnelStrength: 0.4
|
||||||
|
- _LeadingEdgeSoftness: 1.2
|
||||||
- _LineDensity: 3
|
- _LineDensity: 3
|
||||||
- _LineThickness: 0.05
|
- _LineThickness: 0.05
|
||||||
|
- _NoiseDistortion: 1.3
|
||||||
|
- _NoiseScale: 0.35
|
||||||
|
- _NoiseSpeed: 0.2
|
||||||
- _QueueControl: 0
|
- _QueueControl: 0
|
||||||
- _QueueOffset: 0
|
- _QueueOffset: 0
|
||||||
- _RingWidth: 0.08
|
- _RingWidth: 0.08
|
||||||
|
- _RippleFrequency: 1.5
|
||||||
|
- _RippleStrength: 0.25
|
||||||
- _WaveRadius: 0
|
- _WaveRadius: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
- _EchoColor: {r: 4, g: 3.0263731, b: 1.0490564, a: 1}
|
- _BaseColor: {r: 0.015, g: 0.015, b: 0.02, a: 1}
|
||||||
- _EchoPosition1: {r: -24.5, g: -0.027898155, b: -4, a: 0}
|
- _EchoColor: {r: 4, g: 3.026, b: 1.049, a: 1}
|
||||||
- _EchoPosition2: {r: -19.5, g: -0.027898155, b: -8, a: 0}
|
- _EchoCoreColor: {r: 7.5, g: 5.5, b: 2.2, a: 1}
|
||||||
- _EchoPosition3: {r: 21.5, g: -0.027898155, b: 22, a: 0}
|
- _EchoPosition1: {r: 1.5618706, g: 1.0799999, b: -34.510273, a: 0}
|
||||||
|
- _EchoPosition2: {r: -1.1804235, g: 1.0799999, b: -35.782673, a: 0}
|
||||||
|
- _EchoPosition3: {r: -0.93470556, g: 1.0799999, b: -34.72166, a: 0}
|
||||||
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
|
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||||
m_BuildTextureStacks: []
|
m_BuildTextureStacks: []
|
||||||
m_AllowLocking: 1
|
m_AllowLocking: 1
|
||||||
|
|||||||
255
Assets/EchoCloudShader.shader
Normal file
255
Assets/EchoCloudShader.shader
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
Shader "Custom/EchoCloudShader"
|
||||||
|
{
|
||||||
|
Properties
|
||||||
|
{
|
||||||
|
[Header(Base Appearance)]
|
||||||
|
_BaseColor("Base Ambient Color", Color) = (0.015, 0.015, 0.02, 1.0)
|
||||||
|
_BaseMap("Base Map (Optional)", 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(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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Soft leading edge (smoothly fades into darkness ahead)
|
||||||
|
float leadingEdge = smoothstep(waveRadius + 0.2, waveRadius - _LeadingEdgeSoftness, distortedDist);
|
||||||
|
|
||||||
|
// Soft trailing cloud body (billowy tail behind the wavefront)
|
||||||
|
float trailingEdge = smoothstep(waveRadius - _CloudBandWidth, waveRadius - 0.2, distortedDist);
|
||||||
|
|
||||||
|
// Combined cloud puff shape
|
||||||
|
float cloudDensity = leadingEdge * trailingEdge;
|
||||||
|
|
||||||
|
// 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 (gives 3D depth to rooms)
|
||||||
|
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 ambient appearance (deep dark atmospheric tone)
|
||||||
|
half4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Color gradient: soft outer mist (_EchoColor) to glowing core (_EchoCoreColor)
|
||||||
|
half4 mistColor = _EchoColor * totalWave;
|
||||||
|
half4 coreBloom = _EchoCoreColor * pow(totalWave, 2.2);
|
||||||
|
|
||||||
|
half4 finalColor = baseCol + mistColor + coreBloom;
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
9
Assets/EchoCloudShader.shader.meta
Normal file
9
Assets/EchoCloudShader.shader.meta
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cc58e5b86cd79a04789774a9a4b0af75
|
||||||
|
ShaderImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
defaultTextures: []
|
||||||
|
nonModifiableTextures: []
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -8,7 +8,7 @@ Material:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: EchoMat
|
m_Name: EchoMat
|
||||||
m_Shader: {fileID: -6465566751694194690, guid: 504d814182b14b748a5afebbe6fcdb8c, type: 3}
|
m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
|
||||||
m_Parent: {fileID: 0}
|
m_Parent: {fileID: 0}
|
||||||
m_ModifiedSerializedProperties: 0
|
m_ModifiedSerializedProperties: 0
|
||||||
m_ValidKeywords: []
|
m_ValidKeywords: []
|
||||||
@ -24,6 +24,10 @@ Material:
|
|||||||
m_SavedProperties:
|
m_SavedProperties:
|
||||||
serializedVersion: 3
|
serializedVersion: 3
|
||||||
m_TexEnvs:
|
m_TexEnvs:
|
||||||
|
- _BaseMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
- unity_Lightmaps:
|
- unity_Lightmaps:
|
||||||
m_Texture: {fileID: 0}
|
m_Texture: {fileID: 0}
|
||||||
m_Scale: {x: 1, y: 1}
|
m_Scale: {x: 1, y: 1}
|
||||||
@ -38,19 +42,37 @@ Material:
|
|||||||
m_Offset: {x: 0, y: 0}
|
m_Offset: {x: 0, y: 0}
|
||||||
m_Ints: []
|
m_Ints: []
|
||||||
m_Floats:
|
m_Floats:
|
||||||
|
- _CloudBandWidth: 3.2
|
||||||
|
- _EchoOpacity1: 0
|
||||||
|
- _EchoOpacity2: 0
|
||||||
|
- _EchoOpacity3: 0
|
||||||
- _EchoRadius: 27.577322
|
- _EchoRadius: 27.577322
|
||||||
- _EchoRadius1: 0
|
- _EchoRadius1: 0
|
||||||
- _EchoRadius2: 0
|
- _EchoRadius2: 0
|
||||||
- _EchoRadius3: 0
|
- _EchoRadius3: 0
|
||||||
|
- _FresnelPower: 2.5
|
||||||
|
- _FresnelStrength: 0.4
|
||||||
|
- _LeadingEdgeSoftness: 1.2
|
||||||
|
- _LineDensity: 3
|
||||||
|
- _LineThickness: 0.05
|
||||||
|
- _NoiseDistortion: 1.3
|
||||||
|
- _NoiseScale: 0.35
|
||||||
|
- _NoiseSpeed: 0.2
|
||||||
- _QueueControl: 0
|
- _QueueControl: 0
|
||||||
- _QueueOffset: 0
|
- _QueueOffset: 0
|
||||||
- _RingWidth: 0.08
|
- _RingWidth: 0.08
|
||||||
|
- _RippleFrequency: 1.5
|
||||||
|
- _RippleStrength: 0.25
|
||||||
|
- _WaveRadius: 0
|
||||||
m_Colors:
|
m_Colors:
|
||||||
- _EchoColor: {r: 19.265432, g: 10.948601, b: 3.0170376, a: 1}
|
- _BaseColor: {r: 0.015, g: 0.015, b: 0.02, a: 1}
|
||||||
|
- _EchoColor: {r: 4, g: 3.026, b: 1.049, a: 1}
|
||||||
|
- _EchoCoreColor: {r: 7.5, g: 5.5, b: 2.2, a: 1}
|
||||||
- _EchoPosition: {r: -4.3227067, g: 1.08, b: -10.807251, a: 0}
|
- _EchoPosition: {r: -4.3227067, g: 1.08, b: -10.807251, a: 0}
|
||||||
- _EchoPosition1: {r: 0.78633124, g: 1.08, b: -10.874559, a: 0}
|
- _EchoPosition1: {r: 0.78633124, g: 1.08, b: -10.874559, a: 0}
|
||||||
- _EchoPosition2: {r: 0.7576918, g: 1.08, b: -11.912178, a: 0}
|
- _EchoPosition2: {r: 0.7576918, g: 1.08, b: -11.912178, a: 0}
|
||||||
- _EchoPosition3: {r: 0.95730513, g: 1.08, b: -16.5998, a: 0}
|
- _EchoPosition3: {r: 0.95730513, g: 1.08, b: -16.5998, a: 0}
|
||||||
|
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||||
m_BuildTextureStacks: []
|
m_BuildTextureStacks: []
|
||||||
m_AllowLocking: 1
|
m_AllowLocking: 1
|
||||||
--- !u!114 &3906604532312570773
|
--- !u!114 &3906604532312570773
|
||||||
|
|||||||
@ -95,27 +95,7 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: Assembly-CSharp::BlindMutantAI
|
m_EditorClassIdentifier: Assembly-CSharp::BlindMutantAI
|
||||||
walkSpeed: 2
|
walkSpeed: 2
|
||||||
runSpeed: 5
|
runSpeed: 5
|
||||||
patrolPoints:
|
patrolPoints: []
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
- {fileID: 0}
|
|
||||||
detectionRadius: 3.5
|
detectionRadius: 3.5
|
||||||
losePlayerDistance: 14
|
losePlayerDistance: 14
|
||||||
attackRange: 1.8
|
attackRange: 1.8
|
||||||
|
|||||||
Binary file not shown.
@ -12,6 +12,9 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
|
|
||||||
[Header("Патрулирование")]
|
[Header("Патрулирование")]
|
||||||
public Transform[] patrolPoints;
|
public Transform[] patrolPoints;
|
||||||
|
[Tooltip("Время паузы на точке патрулирования для прислушивания")]
|
||||||
|
public float waitTimeAtPoint = 1.5f;
|
||||||
|
private float waitTimer = 0f;
|
||||||
private int currentPatrolIndex;
|
private int currentPatrolIndex;
|
||||||
private bool isInvestigating = false;
|
private bool isInvestigating = false;
|
||||||
|
|
||||||
@ -30,7 +33,20 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
agent = GetComponent<NavMeshAgent>();
|
agent = GetComponent<NavMeshAgent>();
|
||||||
|
if (agent != null)
|
||||||
|
{
|
||||||
agent.speed = walkSpeed;
|
agent.speed = walkSpeed;
|
||||||
|
|
||||||
|
// Если агент чуть выше пола или не на сетке, привязываем его к ближайшей точке NavMesh
|
||||||
|
if (!agent.isOnNavMesh)
|
||||||
|
{
|
||||||
|
if (NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 5.0f, NavMesh.AllAreas))
|
||||||
|
{
|
||||||
|
agent.Warp(hit.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
animator = GetComponentInChildren<Animator>();
|
animator = GetComponentInChildren<Animator>();
|
||||||
|
|
||||||
// Автоматически находим игрока на сцене
|
// Автоматически находим игрока на сцене
|
||||||
@ -40,10 +56,37 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
targetPlayerHealth = playerObj;
|
targetPlayerHealth = playerObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patrolPoints != null && patrolPoints.Length > 0)
|
// Если точки патрулирования не заданы или массив состоит из null, ищем PatrolWaypoints на сцене
|
||||||
|
if (IsPatrolArrayEmptyOrNull())
|
||||||
{
|
{
|
||||||
|
AutoAssignPatrolWaypoints();
|
||||||
|
}
|
||||||
|
|
||||||
GoToNextPatrolPoint();
|
GoToNextPatrolPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsPatrolArrayEmptyOrNull()
|
||||||
|
{
|
||||||
|
if (patrolPoints == null || patrolPoints.Length == 0) return true;
|
||||||
|
for (int i = 0; i < patrolPoints.Length; i++)
|
||||||
|
{
|
||||||
|
if (patrolPoints[i] != null) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AutoAssignPatrolWaypoints()
|
||||||
|
{
|
||||||
|
var patrolRoot = GameObject.Find("PatrolWaypoints");
|
||||||
|
if (patrolRoot != null && patrolRoot.transform.childCount > 0)
|
||||||
|
{
|
||||||
|
patrolPoints = new Transform[patrolRoot.transform.childCount];
|
||||||
|
for (int i = 0; i < patrolRoot.transform.childCount; i++)
|
||||||
|
{
|
||||||
|
patrolPoints[i] = patrolRoot.transform.GetChild(i);
|
||||||
|
}
|
||||||
|
Debug.Log($"<color=cyan>[BlindMutantAI] Автоматически обнаружено {patrolPoints.Length} точек патрулирования в объекте 'PatrolWaypoints'.</color>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
@ -67,12 +110,14 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
private void UpdateAnimator()
|
private void UpdateAnimator()
|
||||||
{
|
{
|
||||||
if (animator == null) return;
|
if (animator == null) return;
|
||||||
float currentSpeed = agent != null && agent.enabled ? agent.velocity.magnitude : 0f;
|
float currentSpeed = agent != null && agent.enabled && agent.isOnNavMesh ? agent.velocity.magnitude : 0f;
|
||||||
animator.SetFloat("Speed", currentSpeed);
|
animator.SetFloat("Speed", currentSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePlayerChaseAndAttack()
|
private void HandlePlayerChaseAndAttack()
|
||||||
{
|
{
|
||||||
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
|
|
||||||
if (targetPlayerHealth != null && targetPlayerHealth.IsDead)
|
if (targetPlayerHealth != null && targetPlayerHealth.IsDead)
|
||||||
{
|
{
|
||||||
LosePlayerTarget();
|
LosePlayerTarget();
|
||||||
@ -138,26 +183,34 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
|
|
||||||
private void HandlePatrolAndInvestigation()
|
private void HandlePatrolAndInvestigation()
|
||||||
{
|
{
|
||||||
if (!agent.pathPending && agent.remainingDistance < 0.5f)
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
|
|
||||||
|
if (!agent.pathPending && agent.remainingDistance < 0.6f)
|
||||||
{
|
{
|
||||||
if (isInvestigating)
|
if (isInvestigating)
|
||||||
{
|
{
|
||||||
isInvestigating = false;
|
isInvestigating = false;
|
||||||
agent.speed = walkSpeed;
|
agent.speed = walkSpeed;
|
||||||
if (patrolPoints != null && patrolPoints.Length > 0)
|
waitTimer = waitTimeAtPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waitTimer > 0f)
|
||||||
{
|
{
|
||||||
|
waitTimer -= Time.deltaTime;
|
||||||
|
agent.isStopped = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
agent.isStopped = false;
|
||||||
|
waitTimer = waitTimeAtPoint;
|
||||||
GoToNextPatrolPoint();
|
GoToNextPatrolPoint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (patrolPoints != null && patrolPoints.Length > 0)
|
|
||||||
{
|
|
||||||
GoToNextPatrolPoint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EngagePlayer(Transform playerTransform)
|
private void EngagePlayer(Transform playerTransform)
|
||||||
{
|
{
|
||||||
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
|
|
||||||
targetPlayer = playerTransform;
|
targetPlayer = playerTransform;
|
||||||
if (targetPlayerHealth == null)
|
if (targetPlayerHealth == null)
|
||||||
{
|
{
|
||||||
@ -165,6 +218,7 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
isInvestigating = false;
|
isInvestigating = false;
|
||||||
|
waitTimer = 0f;
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
agent.speed = runSpeed;
|
agent.speed = runSpeed;
|
||||||
agent.SetDestination(targetPlayer.position);
|
agent.SetDestination(targetPlayer.position);
|
||||||
@ -174,22 +228,55 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
private void LosePlayerTarget()
|
private void LosePlayerTarget()
|
||||||
{
|
{
|
||||||
targetPlayer = null;
|
targetPlayer = null;
|
||||||
|
if (agent != null && agent.isOnNavMesh)
|
||||||
|
{
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
agent.speed = walkSpeed;
|
agent.speed = walkSpeed;
|
||||||
isInvestigating = false;
|
|
||||||
|
|
||||||
if (patrolPoints != null && patrolPoints.Length > 0)
|
|
||||||
{
|
|
||||||
GoToNextPatrolPoint();
|
|
||||||
}
|
}
|
||||||
|
isInvestigating = false;
|
||||||
|
waitTimer = 0f;
|
||||||
|
|
||||||
|
GoToNextPatrolPoint();
|
||||||
Debug.Log("Мутант потерял игрока и возвращается к патрулированию.");
|
Debug.Log("Мутант потерял игрока и возвращается к патрулированию.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GoToNextPatrolPoint()
|
private void GoToNextPatrolPoint()
|
||||||
{
|
{
|
||||||
if (patrolPoints == null || patrolPoints.Length == 0) return;
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
agent.destination = patrolPoints[currentPatrolIndex].position;
|
|
||||||
|
if (patrolPoints != null && patrolPoints.Length > 0)
|
||||||
|
{
|
||||||
|
for (int attempts = 0; attempts < patrolPoints.Length; attempts++)
|
||||||
|
{
|
||||||
|
var wp = patrolPoints[currentPatrolIndex];
|
||||||
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length;
|
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length;
|
||||||
|
|
||||||
|
if (wp != null)
|
||||||
|
{
|
||||||
|
agent.isStopped = false;
|
||||||
|
agent.speed = walkSpeed;
|
||||||
|
agent.SetDestination(wp.position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если точек нет вообще — свободное блуждание по комплексу
|
||||||
|
WanderRandomly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WanderRandomly()
|
||||||
|
{
|
||||||
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
|
|
||||||
|
Vector3 randomDir = Random.insideUnitSphere * 15f;
|
||||||
|
randomDir += transform.position;
|
||||||
|
if (NavMesh.SamplePosition(randomDir, out NavMeshHit hit, 15f, NavMesh.AllAreas))
|
||||||
|
{
|
||||||
|
agent.isStopped = false;
|
||||||
|
agent.speed = walkSpeed;
|
||||||
|
agent.SetDestination(hit.position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HearSound(Vector3 soundPosition)
|
public void HearSound(Vector3 soundPosition)
|
||||||
@ -200,7 +287,10 @@ public class BlindMutantAI : MonoBehaviour
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (agent == null || !agent.isOnNavMesh) return;
|
||||||
|
|
||||||
isInvestigating = true;
|
isInvestigating = true;
|
||||||
|
waitTimer = 0f;
|
||||||
agent.isStopped = false;
|
agent.isStopped = false;
|
||||||
agent.speed = runSpeed;
|
agent.speed = runSpeed;
|
||||||
agent.SetDestination(soundPosition);
|
agent.SetDestination(soundPosition);
|
||||||
|
|||||||
@ -71,21 +71,31 @@ public class EchoTrigger : MonoBehaviour
|
|||||||
if (waveActive[i])
|
if (waveActive[i])
|
||||||
{
|
{
|
||||||
waveRadii[i] += waveSpeed * Time.deltaTime;
|
waveRadii[i] += waveSpeed * Time.deltaTime;
|
||||||
echoMaterial.SetFloat("_EchoRadius" + (i + 1), waveRadii[i]);
|
float currentRadius = waveRadii[i];
|
||||||
|
float maxRadius = waveMaxRadii[i];
|
||||||
|
float progress = Mathf.Clamp01(currentRadius / maxRadius);
|
||||||
|
|
||||||
// ВЫЧИСЛЯЕМ ПРОЗРАЧНОСТЬ с учетом стартовой яркости
|
// Плавное появление (Fade-in): в первые 18% пути волна мягко разгорается (без резкой вспышки)
|
||||||
// Умножаем на waveIntensities[i], чтобы бег был ярче, а стелс тусклее
|
float fadeIn = Mathf.SmoothStep(0f, 1f, progress / 0.18f);
|
||||||
float opacity = (1f - (waveRadii[i] / waveMaxRadii[i])) * waveIntensities[i];
|
// Плавное рассеивание (Fade-out): к концу облако плавно растворяется в темноте
|
||||||
|
float fadeOut = Mathf.Pow(1f - progress, 1.4f);
|
||||||
|
|
||||||
// Mathf.Max не дает уйти в минус, но РАЗРЕШАЕТ быть больше 1 (для HDR свечения)
|
float opacity = (fadeIn * fadeOut) * waveIntensities[i];
|
||||||
opacity = Mathf.Max(0f, opacity);
|
opacity = Mathf.Max(0f, opacity);
|
||||||
|
|
||||||
|
echoMaterial.SetFloat("_EchoRadius" + (i + 1), currentRadius);
|
||||||
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), opacity);
|
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), opacity);
|
||||||
|
|
||||||
if (waveRadii[i] > waveMaxRadii[i])
|
Shader.SetGlobalFloat("_EchoRadius" + (i + 1), currentRadius);
|
||||||
|
Shader.SetGlobalFloat("_EchoOpacity" + (i + 1), opacity);
|
||||||
|
|
||||||
|
if (currentRadius >= maxRadius)
|
||||||
{
|
{
|
||||||
waveActive[i] = false;
|
waveActive[i] = false;
|
||||||
echoMaterial.SetFloat("_EchoRadius" + (i + 1), 0f);
|
echoMaterial.SetFloat("_EchoRadius" + (i + 1), 0f);
|
||||||
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), 0f);
|
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), 0f);
|
||||||
|
Shader.SetGlobalFloat("_EchoRadius" + (i + 1), 0f);
|
||||||
|
Shader.SetGlobalFloat("_EchoOpacity" + (i + 1), 0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +156,10 @@ public class EchoTrigger : MonoBehaviour
|
|||||||
waveRadii[waveIndex] = 0f;
|
waveRadii[waveIndex] = 0f;
|
||||||
waveActive[waveIndex] = true;
|
waveActive[waveIndex] = true;
|
||||||
|
|
||||||
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), targetIntensity);
|
// Начинаем плавно с 0, чтобы разгореться через fadeIn
|
||||||
|
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), 0f);
|
||||||
echoMaterial.SetVector("_EchoPosition" + (waveIndex + 1), position);
|
echoMaterial.SetVector("_EchoPosition" + (waveIndex + 1), position);
|
||||||
|
Shader.SetGlobalFloat("_EchoOpacity" + (waveIndex + 1), 0f);
|
||||||
|
Shader.SetGlobalVector("_EchoPosition" + (waveIndex + 1), position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -908,7 +908,10 @@ public static class LaboratoryLevelGenerator
|
|||||||
var ai = enemy.GetComponent<BlindMutantAI>();
|
var ai = enemy.GetComponent<BlindMutantAI>();
|
||||||
if (ai != null)
|
if (ai != null)
|
||||||
{
|
{
|
||||||
|
Undo.RecordObject(ai, "Setup Patrol Points");
|
||||||
ai.patrolPoints = transforms;
|
ai.patrolPoints = transforms;
|
||||||
|
EditorUtility.SetDirty(ai);
|
||||||
|
EditorUtility.SetDirty(enemy);
|
||||||
Debug.Log($"<color=green>Configured {transforms.Length} patrol points for SkinnyOrc BlindMutantAI in South Concourse (0, 0.08, -28)!</color>");
|
Debug.Log($"<color=green>Configured {transforms.Length} patrol points for SkinnyOrc BlindMutantAI in South Concourse (0, 0.08, -28)!</color>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user