112 lines
4.8 KiB
C#
112 lines
4.8 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|