Kursach_StealthAction/Assets/Scripts/MenuEchoWaveRenderer.cs
2026-10-23 15:44:09 +03:00

112 lines
4.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Процедурный рендерер объемных, мягких облачных волн эхолокации для Главного Меню.
/// Формирует многослойный шлейф с плавным гауссовым рассеиванием и органическими пульсациями,
/// в точности повторяя эффект стелс-эхолокации из геймплея.
/// </summary>
[RequireComponent(typeof(CanvasRenderer))]
public class MenuEchoWaveRenderer : MaskableGraphic
{
[Range(36, 120)]
public int segments = 72;
[Tooltip("Текущий радиус волны в пикселях")]
public float radius = 0f;
[Tooltip("Широкая полоса рассеивания тумана")]
public float thickness = 180f;
[Tooltip("Общая прозрачность волны (0 - 1)")]
[Range(0f, 1f)]
public float waveAlpha = 1f;
[Header("Цветовая палитра тумана")]
public Color waveColor = new Color(1.00f, 0.82f, 0.20f, 0.40f); // Рассеянный золотой туман
public Color coreColor = new Color(1.00f, 0.94f, 0.50f, 0.70f); // Мягкое ядро свечения
public void SetWave(float currentRadius, float currentThickness, float currentAlpha, Color baseColor, Color highlightColor)
{
radius = currentRadius;
thickness = currentThickness;
waveAlpha = Mathf.Clamp01(currentAlpha);
waveColor = baseColor;
coreColor = highlightColor;
SetVerticesDirty();
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
if (radius <= 1f || thickness <= 1f || waveAlpha <= 0.002f) return;
// Коэффициенты распределения слоев для мягкого профиля "облака"
// 6 колец = 5 полос плавного спада (хвост тумана -> ядро -> мягкий передний фронт)
float[] ringOffsets = new float[] { -0.65f, -0.32f, -0.05f, 0.15f, 0.38f, 0.60f };
float[] ringAlphas = new float[] { 0.00f, 0.30f, 0.65f, 0.75f, 0.25f, 0.00f };
int ringCount = ringOffsets.Length;
Color[] ringColors = new Color[ringCount];
for (int r = 0; r < ringCount; r++)
{
float t = (float)r / (ringCount - 1);
// Плавное смешивание базового цвета дымки и ядра
Color col = Color.Lerp(waveColor, coreColor, Mathf.Sin(t * Mathf.PI));
col.a = ringAlphas[r] * waveAlpha;
ringColors[r] = col;
}
float angleStep = 360f / segments;
// Предварительный буфер для двух шагов угла (текущий и следующий)
Vector2[] pts1 = new Vector2[ringCount];
Vector2[] pts2 = new Vector2[ringCount];
CalculateRingPoints(0f, ringOffsets, pts1);
for (int i = 0; i < segments; i++)
{
float a2 = (i + 1) * angleStep * Mathf.Deg2Rad;
CalculateRingPoints(a2, ringOffsets, pts2);
// Соединяем соседние кольца квадами (2 треугольника на слой)
for (int r = 0; r < ringCount - 1; r++)
{
int vIdx = vh.currentVertCount;
vh.AddVert(pts1[r], ringColors[r], Vector2.zero);
vh.AddVert(pts1[r + 1], ringColors[r + 1], Vector2.zero);
vh.AddVert(pts2[r + 1], ringColors[r + 1], Vector2.zero);
vh.AddVert(pts2[r], ringColors[r], Vector2.zero);
vh.AddTriangle(vIdx, vIdx + 1, vIdx + 2);
vh.AddTriangle(vIdx, vIdx + 2, vIdx + 3);
}
// Переносим точки для следующего шага
for (int r = 0; r < ringCount; r++)
{
pts1[r] = pts2[r];
}
}
}
private void CalculateRingPoints(float radAngle, float[] offsets, Vector2[] outPts)
{
Vector2 dir = new Vector2(Mathf.Cos(radAngle), Mathf.Sin(radAngle));
// Органическая деформация облака: легкие акустические неровности и клубы
float billow1 = Mathf.Sin(radAngle * 4f + radius * 0.015f) * (thickness * 0.07f);
float billow2 = Mathf.Cos(radAngle * 7f - radius * 0.010f) * (thickness * 0.04f);
float organicRadius = radius + billow1 + billow2;
for (int r = 0; r < offsets.Length; r++)
{
float ringR = Mathf.Max(0f, organicRadius + offsets[r] * thickness);
outPts[r] = dir * ringR;
}
}
}