using UnityEngine; namespace AibisDream.MiniGame.HuoShan { /// /// 波形渲染器 - 单个波形的渲染 /// 支持噪波效果和清晰度控制,像录音软件中的声波 /// [ExecuteInEditMode] [RequireComponent(typeof(LineRenderer))] public class WaveformRenderer : MonoBehaviour { public enum PreviewMode { Clean, // 清晰波形,无噪波 WithNoise, // 显示噪波效果 Runtime // 模拟运行时(噪波+清晰度) } public enum ConfigPreviewType { None, // 不使用Config,使用下方的手动设置 Emotion, // 预览情绪波形配置 Logic, // 预览逻辑波形配置 Joke, // 预览笑话波形配置 FilterOutput, // 预览滤波器输出配置 NormalOutput // 预览正常输出配置 } [Header("═══ 从Config预览(拖入Config后选择类型即可预览)═══")] [Tooltip("拖入WaveformConfig资源")] [SerializeField] private WaveformConfig previewConfig; [Tooltip("选择要预览的波形类型(选择后立即生效)")] [SerializeField] private ConfigPreviewType previewFromConfig = ConfigPreviewType.None; [Header("═══ 预览效果 ═══")] [SerializeField] private PreviewMode editorPreviewMode = PreviewMode.Clean; [Tooltip("勾选强制刷新波形显示")] [SerializeField] private bool forceRefresh = false; [Header("═══ 波形设置(手动调整或从Config应用)═══")] [SerializeField] private WaveformType waveType = WaveformType.Emotion; [SerializeField] private float waveHeight = 1f; [SerializeField] private float waveWidth = 10f; [SerializeField] private float waveSpeed = 2f; [SerializeField] private float frequency = 1f; [Header("噪波设置")] [SerializeField] private float noiseAmount = 0.8f; // 噪波强度 (0=无噪波, 1=完全噪波) [SerializeField] private float noiseFrequency = 15f; // 噪波频率 [SerializeField] private float noiseSpeed = 5f; // 噪波变化速度 [Header("清晰度设置")] [SerializeField] private float clarity = 0f; // 清晰度 (0=模糊, 1=完全清晰) [SerializeField] private float clarityPosition = 0.5f; // 清晰位置 (0-1) [SerializeField] private float clarityWidth = 0.1f; // 清晰区域宽度 [Header("绘图设置")] [SerializeField] private int resolution = 200; [SerializeField] private float lineWidth = 0.05f; [Header("颜色设置")] [SerializeField] private Color primaryColor = Color.cyan; [SerializeField] private Color secondaryColor = Color.blue; [SerializeField] private Color noiseColor = new Color(0.5f, 0.5f, 0.5f, 0.5f); [Tooltip("清晰区域使用主色调的高亮版本")] [SerializeField] private bool useBrightenedClearColor = true; [SerializeField] private float clearColorBrighten = 0.3f; [Header("发光点")] [SerializeField] private bool showGlowPoint = true; [SerializeField] private SpriteRenderer glowPointRenderer; [SerializeField] private float glowSize = 0.15f; [Header("扫描线设置")] [SerializeField] private Color scanLineColor = new Color(0.2f, 0.9f, 1f, 1f); [SerializeField] private float scanLineWidthMultiplier = 0.8f; // 相对于波形线宽的倍数(更细) [SerializeField] private Color limitLineColor = new Color(1f, 0.8f, 0.2f, 1f); [SerializeField] private float limitLineWidthMultiplier = 0.6f; // 相对于波形线宽的倍数(更细) [SerializeField] private string scanLineSortingLayer = "Tools"; [SerializeField] private int scanLineSortingOrderOffset = 1; // 在Tools层级上+1 [Header("复古示波器质感(可选)")] [Tooltip("开启后会添加轻微的CRT抖动/亮度呼吸,让观感更像老式示波器/仪表屏")] [SerializeField] private bool enableOscilloscopeArtifacts = true; [Tooltip("亮度/透明度轻微闪烁强度(0-0.2建议)")] [Range(0f, 0.2f)] [SerializeField] private float crtFlickerAmount = 0.04f; [Tooltip("垂直微抖动强度(以波形高度为基准的比例)")] [Range(0f, 0.05f)] [SerializeField] private float crtVerticalJitter = 0.008f; [Tooltip("50/60Hz嗡鸣感(用于模拟电源纹波)")] [Range(10f, 90f)] [SerializeField] private float crtHumHz = 50f; private LineRenderer _lineRenderer; private LineRenderer _scanLineRenderer; private LineRenderer _upperLimitLineRenderer; private LineRenderer _lowerLimitLineRenderer; private Vector3[] _points; private float _phaseOffset = 0f; private float _noisePhase = 0f; private float _transformProgress = 0f; private WaveformType _transformFromType; private WaveformType _transformToType; private bool _isTransforming = false; private float _currentAlpha = 1f; private float _crtAlphaMul = 1f; // 变换效果参数 private float _transformDistortion = 0f; // 变换时的扭曲程度 private float _transformCompression = 1f; // 变换时的压缩程度 // 随机噪波种子 private float[] _noiseSeed; // 合成模式参数 private float _logicWeight = 0.3f; private float _jokeWeight = 0.85f; private float _synthesisProgress = 1f; // 情绪波形谐波参数(可通过配置调整) private float _harmonicA1 = 0.55f; // 基波振幅 private float _harmonicA2 = 0.28f; // 二次谐波振幅 private float _harmonicA3 = 0.12f; // 三次谐波振幅 private float _harmonicPhase2 = 0.3f; // 二次谐波相位 private float _harmonicPhase3 = 0.5f; // 三次谐波相位 private float _verticalOffset = -0.08f; // 整体偏移 public WaveformType WaveType => waveType; public bool IsTransforming => _isTransforming; public float Clarity => clarity; public float ClarityPosition => clarityPosition; public float ClarityWidth => clarityWidth; public float NoiseAmount => noiseAmount; public Color PrimaryColor => primaryColor; public Color SecondaryColor => secondaryColor; public float CurrentAlpha => _currentAlpha; private void Awake() { InitializeLineRenderer(); SetupGlowPoint(); InitializeNoise(); InitializeScanLines(); } /// /// 响应 Inspector 中的值变化 /// private void OnValidate() { // 确保在编辑器中能即时预览 if (_lineRenderer == null) { _lineRenderer = GetComponent(); } if (_lineRenderer != null) { _lineRenderer.startWidth = lineWidth; _lineRenderer.endWidth = lineWidth; if (_points == null || _points.Length != resolution) { _points = new Vector3[resolution]; _lineRenderer.positionCount = resolution; } UpdateColors(); } // 检查Config预览设置 if (previewFromConfig != ConfigPreviewType.None && previewConfig == null) { Debug.LogWarning("WaveformRenderer: 请先拖入 WaveformConfig 资源到 Preview Config 字段!"); } // 强制刷新按钮 if (forceRefresh) { forceRefresh = false; InitializeNoise(); // 显示实际使用的参数 if (previewFromConfig != ConfigPreviewType.None && previewConfig != null) { var settings = GetPreviewSettings(); if (settings != null) { Debug.Log($"WaveformRenderer: 预览Config [{previewFromConfig}] - 类型:{settings.waveType}, 高度:{settings.waveHeight}, 速度:{settings.waveSpeed}, 频率:{settings.frequency}"); } } else { Debug.Log($"WaveformRenderer: 使用本地参数 - 类型:{waveType}, 高度:{waveHeight}, 速度:{waveSpeed}, 频率:{frequency}"); } } if (_noiseSeed == null || _noiseSeed.Length != resolution) { InitializeNoise(); } // 在编辑器中立即更新波形 if (!Application.isPlaying) { UpdateWaveform(); } } private void InitializeLineRenderer() { _lineRenderer = GetComponent(); if (_lineRenderer == null) return; _lineRenderer.useWorldSpace = false; _lineRenderer.positionCount = resolution; _lineRenderer.startWidth = lineWidth; _lineRenderer.endWidth = lineWidth; _points = new Vector3[resolution]; UpdateColors(); } private void InitializeNoise() { _noiseSeed = new float[resolution]; for (int i = 0; i < resolution; i++) { _noiseSeed[i] = Random.Range(0f, 100f); } } private void SetupGlowPoint() { if (!showGlowPoint) return; if (glowPointRenderer == null) { GameObject glowObj = new GameObject("GlowPoint"); glowObj.transform.SetParent(transform); glowObj.transform.localPosition = Vector3.zero; glowPointRenderer = glowObj.AddComponent(); Texture2D texture = new Texture2D(32, 32); Color[] colors = new Color[32 * 32]; for (int i = 0; i < colors.Length; i++) { float x = (i % 32) / 31f; float y = (i / 32) / 31f; float distance = Vector2.Distance(new Vector2(x, y), new Vector2(0.5f, 0.5f)); colors[i] = new Color(1, 1, 1, Mathf.Clamp01(1 - distance * 2)); } texture.SetPixels(colors); texture.Apply(); Sprite sprite = Sprite.Create(texture, new Rect(0, 0, 32, 32), new Vector2(0.5f, 0.5f)); glowPointRenderer.sprite = sprite; } glowPointRenderer.color = primaryColor; glowPointRenderer.transform.localScale = Vector3.one * glowSize; } private void Update() { if (_lineRenderer == null) InitializeLineRenderer(); if (_points == null) _points = new Vector3[resolution]; if (_noiseSeed == null) InitializeNoise(); // 获取实际波形速度(优先使用Config预览) float actualWaveSpeed = waveSpeed; bool isEditor = !Application.isPlaying; if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null) { WaveformSettings settings = GetPreviewSettings(); if (settings != null) { actualWaveSpeed = settings.waveSpeed; } } _phaseOffset += Time.deltaTime * actualWaveSpeed; _noisePhase += Time.deltaTime * noiseSpeed; // 轻微“电源纹波/亮度呼吸”,用于提升拟真仪表屏质感 if (enableOscilloscopeArtifacts && Application.isPlaying) { // 使用低成本噪声 + 50Hz正弦混合,避免过于规律 float t = Time.time; float hum = Mathf.Sin(t * Mathf.PI * 2f * crtHumHz) * 0.5f + 0.5f; // 0..1 float rand = Mathf.PerlinNoise(t * 4.2f, 0.13f); // 0..1 float mix = Mathf.Lerp(hum, rand, 0.6f); // 0..1 _crtAlphaMul = Mathf.Clamp(1f - crtFlickerAmount + mix * crtFlickerAmount * 2f, 0.7f, 1.15f); } else { _crtAlphaMul = 1f; } UpdateWaveform(); } private void UpdateWaveform() { if (_lineRenderer == null || _points == null) return; // 确定当前使用的预览模式 bool isEditor = !Application.isPlaying; PreviewMode currentMode = isEditor ? editorPreviewMode : PreviewMode.Runtime; // 获取实际使用的参数(优先使用Config预览) WaveformType actualWaveType = waveType; float actualFrequency = frequency; float actualWaveHeight = waveHeight; float actualWaveSpeed = waveSpeed; if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null) { WaveformSettings settings = GetPreviewSettings(); if (settings != null) { actualWaveType = settings.waveType; actualFrequency = settings.frequency; actualWaveHeight = settings.waveHeight; actualWaveSpeed = settings.waveSpeed; } } for (int i = 0; i < resolution; i++) { float x = ((float)i / resolution) * waveWidth - waveWidth * 0.5f; float normalizedX = (float)i / resolution; float timeOffset = normalizedX * actualFrequency + _phaseOffset; // 获取基础波形值 float baseWaveValue; if (_isTransforming) { baseWaveValue = GetTransformingWaveValue(timeOffset, normalizedX); } else { baseWaveValue = GetWaveValue(actualWaveType, timeOffset, normalizedX); } float finalValue; switch (currentMode) { case PreviewMode.Clean: // 清晰模式:直接显示波形 finalValue = baseWaveValue; break; case PreviewMode.WithNoise: // 噪波模式:只显示噪波效果,不考虑清晰度 float noise = GenerateNoise(i, normalizedX); finalValue = Mathf.Lerp(noise, baseWaveValue, 1f - noiseAmount); break; case PreviewMode.Runtime: default: // 运行时模式:应用噪波和清晰度 float localClarity = CalculateLocalClarity(normalizedX); float runtimeNoise = GenerateNoise(i, normalizedX); finalValue = Mathf.Lerp(runtimeNoise, baseWaveValue, localClarity); break; } // 复古示波器:给“非清晰区域”加一点点垂直抖动(更像硬件采样/显示抖动) if (enableOscilloscopeArtifacts && Application.isPlaying && currentMode == PreviewMode.Runtime) { float localClarity = CalculateLocalClarity(normalizedX); float jitterMask = Mathf.Clamp01(1f - localClarity); float n = (Mathf.PerlinNoise(_noisePhase * 1.7f, normalizedX * 8.0f) - 0.5f) * 2f; // -1..1 float hum = Mathf.Sin((Time.time * crtHumHz + normalizedX * 3.5f) * Mathf.PI * 2f); // -1..1 float jitter = (n * 0.7f + hum * 0.3f) * crtVerticalJitter * jitterMask; finalValue += jitter; } _points[i] = new Vector3(x, finalValue * actualWaveHeight, 0f); } _lineRenderer.SetPositions(_points); UpdateLineColors(); if (showGlowPoint && glowPointRenderer != null && resolution > 0) { glowPointRenderer.transform.localPosition = _points[resolution - 1]; } } /// /// 获取当前预览的Config设置 /// private WaveformSettings GetPreviewSettings() { if (previewConfig == null) return null; switch (previewFromConfig) { case ConfigPreviewType.Emotion: return previewConfig.emotionWaveform; case ConfigPreviewType.Logic: return previewConfig.logicWaveform; case ConfigPreviewType.Joke: return previewConfig.jokeWaveform; case ConfigPreviewType.FilterOutput: return previewConfig.filterOutputWaveform; case ConfigPreviewType.NormalOutput: return previewConfig.normalOutputWaveform; default: return null; } } /// /// 计算指定位置的局部清晰度 /// private float CalculateLocalClarity(float normalizedX) { // 基础清晰度 float baseClarity = clarity; // 如果清晰度大于0,在清晰位置附近更清晰 if (clarity > 0) { float distanceFromClear = Mathf.Abs(normalizedX - clarityPosition); float clearZone = 1f - Mathf.Clamp01(distanceFromClear / clarityWidth); baseClarity = Mathf.Max(clarity, clearZone); } return Mathf.Clamp01(baseClarity); } /// /// 生成噪波(像录音软件中的声波) /// private float GenerateNoise(int index, float normalizedX) { float seed = _noiseSeed[index]; // 多层噪波叠加,产生声波效果 float noise = 0f; // 低频噪波 - 整体起伏 noise += Mathf.PerlinNoise(seed + _noisePhase * 0.3f, normalizedX * 2f) * 0.6f; // 中频噪波 - 细节 noise += Mathf.PerlinNoise(seed * 2f + _noisePhase * 0.7f, normalizedX * 5f) * 0.3f; // 高频噪波 - 毛刺 noise += (Mathf.PerlinNoise(seed * 3f + _noisePhase, normalizedX * noiseFrequency) - 0.5f) * 0.4f; // 随机尖峰(像声波的峰值) float spike = Mathf.Sin((normalizedX + _noisePhase * 0.1f) * Mathf.PI * 20f); spike = Mathf.Pow(Mathf.Abs(spike), 3f) * Mathf.Sign(spike); noise += spike * 0.2f; // 归一化到 -1 到 1 noise = (noise - 0.5f) * 2f * noiseAmount; return Mathf.Clamp(noise, -1f, 1f); } /// /// 更新线条颜色(清晰区域显示高亮的主色调) /// private void UpdateLineColors() { if (_lineRenderer == null) return; Gradient gradient = new Gradient(); float effectiveAlpha = Mathf.Clamp01(_currentAlpha * _crtAlphaMul); if (clarity > 0.5f) { // 有清晰区域时,显示清晰位置的颜色变化 float clearStart = Mathf.Clamp01(clarityPosition - clarityWidth); float clearEnd = Mathf.Clamp01(clarityPosition + clarityWidth); // 使用高亮的主色调作为清晰区域颜色(不再使用绿色) Color brightenedColor = GetBrightenedClearColor(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(primaryColor, 0f), new GradientColorKey(primaryColor, clearStart), new GradientColorKey(brightenedColor, clarityPosition), new GradientColorKey(primaryColor, clearEnd), new GradientColorKey(secondaryColor, 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(effectiveAlpha, 0f), new GradientAlphaKey(effectiveAlpha, 1f) } ); } else { gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(primaryColor, 0f), new GradientColorKey(secondaryColor, 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(effectiveAlpha, 0f), new GradientAlphaKey(effectiveAlpha, 1f) } ); } _lineRenderer.colorGradient = gradient; } /// /// 获取高亮的清晰区域颜色(基于主色调) /// private Color GetBrightenedClearColor() { if (!useBrightenedClearColor) { return primaryColor; } // 将主色调提亮 Color.RGBToHSV(primaryColor, out float h, out float s, out float v); v = Mathf.Clamp01(v + clearColorBrighten); s = Mathf.Clamp01(s * 0.8f); // 稍微降低饱和度使其更亮 Color brightened = Color.HSVToRGB(h, s, v); brightened.a = primaryColor.a; return brightened; } private float GetWaveValue(WaveformType type, float time, float normalizedX) { switch (type) { case WaveformType.Emotion: return GenerateEmotionWave(time, normalizedX); case WaveformType.Logic: return GenerateLogicWave(time); case WaveformType.Joke: return GenerateJokeWave(time, normalizedX); case WaveformType.FilterOutput: return GenerateFilterOutput(time, normalizedX); case WaveformType.NormalOutput: return GenerateNormalOutput(time, normalizedX); default: return Mathf.Sin(time * Mathf.PI * 2f); } } #region 波形生成 /// /// 情绪波形 - 基于谐波叠加的简洁实现 /// 采用傅里叶合成:基波 + 二次谐波 + 三次谐波 /// 特征:低频、缓慢、通过谐波叠加表达悲伤/压抑情绪 /// 谐波参数可通过 WaveformSettings 配置 /// private float GenerateEmotionWave(float time, float normalizedX) { // 慢速时间,体现低沉感 float slowTime = time * 0.4f; float t = slowTime * Mathf.PI * 2f; // 基频角度 // 傅里叶合成:基波 + 二次谐波 + 三次谐波(使用可配置参数) float fundamental = Mathf.Sin(t) * _harmonicA1; // 基波 float harmonic2 = Mathf.Sin(2f * t + _harmonicPhase2) * _harmonicA2; // 二次谐波 float harmonic3 = Mathf.Sin(3f * t + _harmonicPhase3) * _harmonicA3; // 三次谐波 // 叠加得到最终波形 float result = fundamental + harmonic2 + harmonic3; // 整体偏移(负值表示下沉,体现压抑感) result += _verticalOffset; return Mathf.Clamp(result, -1f, 1f); } /// /// 逻辑波形 - 清晰的方波 /// private float GenerateLogicWave(float time) { float t = time % 1f; if (t < 0) t += 1f; float amplitude = 0.7f; float squareWave = t < 0.5f ? amplitude : -amplitude; // 非常短的边缘过渡 float edgeSmooth = 0.015f; if (t < edgeSmooth) { squareWave = Mathf.Lerp(-amplitude, amplitude, t / edgeSmooth); } else if (t > 0.5f - edgeSmooth && t < 0.5f + edgeSmooth) { float localT = (t - (0.5f - edgeSmooth)) / (edgeSmooth * 2f); squareWave = Mathf.Lerp(amplitude, -amplitude, localT); } else if (t > 1f - edgeSmooth) { squareWave = Mathf.Lerp(-amplitude, amplitude, (t - (1f - edgeSmooth)) / edgeSmooth); } return squareWave; } /// /// 笑话波形 - 高频、尖锐、跳动 /// 特征:快速的脉冲、突然的尖峰、亢奋的跳动 /// private float GenerateJokeWave(float time, float normalizedX) { // 使用更快的时间,让波形看起来更尖锐跳动 float fastTime = time * 2.5f; // 快2.5倍 float t = fastTime % 1f; if (t < 0) t += 1f; // 快速三角脉冲(尖锐的笑声节奏) float pulsePhase = (t * 4f) % 1f; // 每周期4个脉冲 float pulse = 0f; if (pulsePhase < 0.1f) { // 非常快速的上升 pulse = pulsePhase / 0.1f; } else if (pulsePhase < 0.2f) { // 快速下降 pulse = 1f - (pulsePhase - 0.1f) / 0.1f; } pulse *= 0.9f; // 高频振荡(尖锐感) float highFreq = Mathf.Sin(t * Mathf.PI * 12f) * 0.35f; // 随机尖峰(突然的"笑点"爆发) float spike = 0f; float spikeT = (t * 7f) % 1f; if (spikeT < 0.08f) { spike = Mathf.Sin(spikeT / 0.08f * Mathf.PI) * 0.5f; } // 额外的高频颤动(亢奋感) float tremor = Mathf.Sin(t * Mathf.PI * 25f + normalizedX * 5f) * 0.12f; float result = pulse + highFreq + spike + tremor; return Mathf.Clamp(result, -1f, 1f); } private float GenerateFilterOutput(float time, float normalizedX) { float logic = GenerateLogicWave(time); float joke = GenerateJokeWave(time, normalizedX); float effectiveLogicWeight = _logicWeight; float effectiveJokeWeight = _jokeWeight * _synthesisProgress; float result = logic * effectiveLogicWeight + joke * effectiveJokeWeight; return Mathf.Clamp(result, -1f, 1f); } private float GenerateNormalOutput(float time, float normalizedX) { float logic = GenerateLogicWave(time) * 0.4f; float emotion = GenerateEmotionWave(time, normalizedX) * 0.4f; float result = logic + emotion; result += Mathf.Sin(time * Mathf.PI * 3f) * 0.1f; return Mathf.Clamp(result, -1f, 1f); } #endregion #region 公共方法 /// /// 设置清晰度(0=完全噪波, 1=完全清晰) /// public void SetClarity(float value) { clarity = Mathf.Clamp01(value); } /// /// 设置清晰位置(进度条位置,0-1) /// public void SetClarityPosition(float position) { clarityPosition = Mathf.Clamp01(position); } /// /// 设置清晰区域宽度 /// public void SetClarityWidth(float width) { clarityWidth = Mathf.Clamp(width, 0.01f, 0.5f); } /// /// 设置噪波强度 /// public void SetNoiseAmount(float amount) { noiseAmount = Mathf.Clamp01(amount); } /// /// 检查当前位置是否清晰(用于锁定检测) /// public bool IsPositionClear(float position, float threshold = 0.8f) { float localClarity = CalculateLocalClarity(position); return localClarity >= threshold; } public void ApplySettings(WaveformSettings settings) { waveType = settings.waveType; waveHeight = settings.waveHeight; waveSpeed = settings.waveSpeed; frequency = settings.frequency; primaryColor = settings.primaryColor; secondaryColor = settings.secondaryColor; // 应用谐波配置(用于情绪波形的傅里叶合成) _harmonicA1 = settings.harmonicA1; _harmonicA2 = settings.harmonicA2; _harmonicA3 = settings.harmonicA3; _harmonicPhase2 = settings.harmonicPhase2; _harmonicPhase3 = settings.harmonicPhase3; _verticalOffset = settings.verticalOffset; UpdateColors(); } public void SetWaveType(WaveformType type) { waveType = type; _isTransforming = false; } public void SetColors(Color primary, Color secondary) { primaryColor = primary; secondaryColor = secondary; UpdateColors(); } public void StartTransform(WaveformType fromType, WaveformType toType) { _transformFromType = fromType; _transformToType = toType; _transformProgress = 0f; _transformDistortion = 0f; _transformCompression = 1f; _isTransforming = true; } public void UpdateTransformProgress(float progress) { _transformProgress = Mathf.Clamp01(progress); // 计算变换过程中的效果参数 // 0-0.3: 开始扭曲,波形开始不稳定 // 0.3-0.7: 最大扭曲+压缩,波形被"挤压" // 0.7-1.0: 扭曲消退,新波形稳定 if (_transformProgress < 0.3f) { float t = _transformProgress / 0.3f; _transformDistortion = Mathf.Sin(t * Mathf.PI) * 0.5f; _transformCompression = 1f; } else if (_transformProgress < 0.7f) { float t = (_transformProgress - 0.3f) / 0.4f; _transformDistortion = 0.5f + Mathf.Sin(t * Mathf.PI * 3f) * 0.3f; // 压缩效果:低频被压缩成高频的感觉 _transformCompression = Mathf.Lerp(1f, 2.5f, t); } else { float t = (_transformProgress - 0.7f) / 0.3f; _transformDistortion = Mathf.Lerp(0.5f, 0f, t); _transformCompression = Mathf.Lerp(2.5f, 1f, t); } if (_transformProgress >= 1f) { waveType = _transformToType; _isTransforming = false; _transformDistortion = 0f; _transformCompression = 1f; } } public void FinishTransform() { waveType = _transformToType; _transformProgress = 1f; _isTransforming = false; _transformDistortion = 0f; _transformCompression = 1f; } /// /// 获取变换过程中的波形值(带有戏剧性的过渡效果) /// private float GetTransformingWaveValue(float timeOffset, float normalizedX) { float fromValue = GetWaveValue(_transformFromType, timeOffset, normalizedX); float toValue = GetWaveValue(_transformToType, timeOffset * _transformCompression, normalizedX); // 基础混合 float blendedValue = Mathf.Lerp(fromValue, toValue, _transformProgress); // 添加扭曲效果(波形被挤压、扭曲的感觉) if (_transformDistortion > 0) { // 添加不规则的高频扰动 float distortion = Mathf.Sin(timeOffset * 15f + normalizedX * 10f) * _transformDistortion; distortion += Mathf.Sin(timeOffset * 23f) * _transformDistortion * 0.5f; // 压缩效果:让波形看起来像是被挤压 float compressionEffect = Mathf.Sin(normalizedX * Mathf.PI * _transformCompression * 2f) * _transformDistortion * 0.3f; blendedValue += distortion + compressionEffect; } return Mathf.Clamp(blendedValue, -1.2f, 1.2f); // 允许稍微超出范围增加戏剧感 } public void SetSynthesisWeights(float logicWeight, float jokeWeight) { _logicWeight = Mathf.Clamp01(logicWeight); _jokeWeight = Mathf.Clamp01(jokeWeight); } public void SetSynthesisProgress(float progress) { _synthesisProgress = Mathf.Clamp01(progress); } public void SetVisible(bool visible) { if (_lineRenderer != null) _lineRenderer.enabled = visible; if (glowPointRenderer != null) glowPointRenderer.enabled = visible; } public void SetAlpha(float alpha) { _currentAlpha = Mathf.Clamp01(alpha); if (_lineRenderer == null) return; Color startColor = primaryColor; Color endColor = secondaryColor; startColor.a = _currentAlpha; endColor.a = _currentAlpha; Gradient gradient = new Gradient(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(startColor, 0f), new GradientColorKey(endColor, 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(_currentAlpha, 0f), new GradientAlphaKey(_currentAlpha, 1f) } ); _lineRenderer.colorGradient = gradient; if (glowPointRenderer != null) { Color glowColor = primaryColor; glowColor.a = _currentAlpha; glowPointRenderer.color = glowColor; } } private void UpdateColors() { if (_lineRenderer == null) return; // 获取实际颜色(优先使用Config预览) Color actualPrimaryColor = primaryColor; Color actualSecondaryColor = secondaryColor; bool isEditor = !Application.isPlaying; if (isEditor && previewFromConfig != ConfigPreviewType.None && previewConfig != null) { WaveformSettings settings = GetPreviewSettings(); if (settings != null) { actualPrimaryColor = settings.primaryColor; actualSecondaryColor = settings.secondaryColor; } } Gradient gradient = new Gradient(); gradient.SetKeys( new GradientColorKey[] { new GradientColorKey(actualPrimaryColor, 0f), new GradientColorKey(actualSecondaryColor, 1f) }, new GradientAlphaKey[] { new GradientAlphaKey(_currentAlpha, 0f), new GradientAlphaKey(_currentAlpha, 1f) } ); _lineRenderer.colorGradient = gradient; if (glowPointRenderer != null) { glowPointRenderer.color = actualPrimaryColor; } } #endregion #region 扫描线系统 /// /// 初始化扫描线 /// private void InitializeScanLines() { // 确保主LineRenderer已初始化 if (_lineRenderer == null) { _lineRenderer = GetComponent(); } // 计算扫描线宽度(相对于波形线宽,更细一点) float scanWidth = lineWidth * scanLineWidthMultiplier; float limitWidth = lineWidth * limitLineWidthMultiplier; // 创建垂直扫描线(用于屏蔽词检测) _scanLineRenderer = CreateScanLineRenderer("ScanLine", scanLineColor, scanWidth); if (_scanLineRenderer != null) _scanLineRenderer.gameObject.SetActive(false); // 创建上限线(用于限幅检测) _upperLimitLineRenderer = CreateScanLineRenderer("UpperLimitLine", limitLineColor, limitWidth); if (_upperLimitLineRenderer != null) _upperLimitLineRenderer.gameObject.SetActive(false); // 创建下限线(用于限幅检测) _lowerLimitLineRenderer = CreateScanLineRenderer("LowerLimitLine", limitLineColor, limitWidth); if (_lowerLimitLineRenderer != null) _lowerLimitLineRenderer.gameObject.SetActive(false); Debug.Log($"WaveformRenderer: 扫描线初始化完成 - ScanLine:{_scanLineRenderer != null}, UpperLimit:{_upperLimitLineRenderer != null}, LowerLimit:{_lowerLimitLineRenderer != null}, ScanWidth:{scanWidth:F4}, LimitWidth:{limitWidth:F4}"); } private LineRenderer CreateScanLineRenderer(string name, Color color, float width) { GameObject lineObj = new GameObject(name); lineObj.transform.SetParent(transform); lineObj.transform.localPosition = Vector3.zero; lineObj.transform.localScale = Vector3.one; LineRenderer lr = lineObj.AddComponent(); // 使用主LineRenderer的材质,或者创建一个简单的材质 if (_lineRenderer != null && _lineRenderer.material != null) { lr.material = new Material(_lineRenderer.material); } else { // 回退方案:使用内置的UI shader Shader shader = Shader.Find("UI/Default"); if (shader == null) shader = Shader.Find("Sprites/Default"); if (shader == null) shader = Shader.Find("Unlit/Color"); lr.material = new Material(shader); } lr.startColor = color; lr.endColor = color; lr.startWidth = width; lr.endWidth = width; lr.positionCount = 2; lr.useWorldSpace = false; // 设置层级:Tools层 + offset lr.sortingLayerName = scanLineSortingLayer; lr.sortingOrder = scanLineSortingOrderOffset; return lr; } /// /// 显示垂直扫描线在指定位置 /// public void ShowScanLine(float normalizedX, float height = -1f) { if (_scanLineRenderer == null) { Debug.LogWarning("WaveformRenderer: 扫描线未初始化!尝试重新初始化..."); InitializeScanLines(); if (_scanLineRenderer == null) return; } float actualHeight = height > 0 ? height : waveHeight * 1.5f; float xPos = (normalizedX - 0.5f) * waveWidth; _scanLineRenderer.SetPosition(0, new Vector3(xPos, -actualHeight, 0)); _scanLineRenderer.SetPosition(1, new Vector3(xPos, actualHeight, 0)); _scanLineRenderer.gameObject.SetActive(true); Debug.Log($"WaveformRenderer: 显示扫描线 - X:{xPos:F2}, Height:{actualHeight:F2}, WaveWidth:{waveWidth}, WaveHeight:{waveHeight}"); } /// /// 隐藏垂直扫描线 /// public void HideScanLine() { if (_scanLineRenderer != null) { _scanLineRenderer.gameObject.SetActive(false); } } /// /// 设置扫描线位置(用于动画) /// public void SetScanLinePosition(float normalizedX) { if (_scanLineRenderer == null || !_scanLineRenderer.gameObject.activeSelf) return; float xPos = (normalizedX - 0.5f) * waveWidth; Vector3 pos0 = _scanLineRenderer.GetPosition(0); Vector3 pos1 = _scanLineRenderer.GetPosition(1); _scanLineRenderer.SetPosition(0, new Vector3(xPos, pos0.y, 0)); _scanLineRenderer.SetPosition(1, new Vector3(xPos, pos1.y, 0)); } /// /// 显示限幅线(上下限) /// public void ShowLimitLines(float upperLimit = -1f, float lowerLimit = -1f) { if (_upperLimitLineRenderer == null || _lowerLimitLineRenderer == null) { Debug.LogWarning("WaveformRenderer: 限幅线未初始化!尝试重新初始化..."); InitializeScanLines(); if (_upperLimitLineRenderer == null || _lowerLimitLineRenderer == null) return; } float actualUpper = upperLimit > 0 ? upperLimit : waveHeight * 0.8f; float actualLower = lowerLimit > 0 ? lowerLimit : -waveHeight * 0.8f; float halfWidth = waveWidth * 0.5f; // 上限线 _upperLimitLineRenderer.SetPosition(0, new Vector3(-halfWidth, actualUpper, 0)); _upperLimitLineRenderer.SetPosition(1, new Vector3(halfWidth, actualUpper, 0)); _upperLimitLineRenderer.gameObject.SetActive(true); // 下限线 _lowerLimitLineRenderer.SetPosition(0, new Vector3(-halfWidth, actualLower, 0)); _lowerLimitLineRenderer.SetPosition(1, new Vector3(halfWidth, actualLower, 0)); _lowerLimitLineRenderer.gameObject.SetActive(true); Debug.Log($"WaveformRenderer: 显示限幅线 - Upper:{actualUpper:F2}, Lower:{actualLower:F2}, Width:{halfWidth * 2:F2}"); } /// /// 隐藏限幅线 /// public void HideLimitLines() { if (_upperLimitLineRenderer != null) { _upperLimitLineRenderer.gameObject.SetActive(false); } if (_lowerLimitLineRenderer != null) { _lowerLimitLineRenderer.gameObject.SetActive(false); } } /// /// 设置限幅线透明度(用于闪烁动画) /// public void SetLimitLinesAlpha(float alpha) { Color color = limitLineColor; color.a = alpha; if (_upperLimitLineRenderer != null) { _upperLimitLineRenderer.startColor = color; _upperLimitLineRenderer.endColor = color; } if (_lowerLimitLineRenderer != null) { _lowerLimitLineRenderer.startColor = color; _lowerLimitLineRenderer.endColor = color; } } /// /// 设置扫描线颜色 /// public void SetScanLineColor(Color color) { if (_scanLineRenderer != null) { _scanLineRenderer.startColor = color; _scanLineRenderer.endColor = color; } } #endregion } }