Files
aibis-dream/Assets/Scripts/FixSystem/Scope/WaveformVisualizer.cs
T

333 lines
9.8 KiB
C#

using UnityEngine;
using System.Collections.Generic;
public enum WaveformType
{
Sine,
Square,
Triangle,
Sawtooth,
Noise,
Composite,
Pulse,
}
[RequireComponent(typeof(LineRenderer))]
public class WaveformVisualizer : MonoBehaviour
{
[HideInInspector]
public int samples = 1024;
[HideInInspector]
private float amplitude = 0.6f;
public float spatialFrequency = 1f;
public float temporalFrequency = 0.1f;
private float targetWaveformNoiseAmplitude = 0.1f;
public float noiseAmplitude = 0.5f;
[Range(0f, 1f)]
[HideInInspector]
public float clarity = 0f;
public Color noiseColor = Color.gray;
public Color clearColor = Color.green;
private LineRenderer lineRenderer;
[HideInInspector]
private SpriteRenderer spriteRenderer;
[HideInInspector]
public float spriteWidth;
[HideInInspector]
public float spriteHeight;
[HideInInspector]
public float[] waveformData;
private float[] noiseData;
[HideInInspector]
public float[] displayData;
private float[] antiWaveformData;
public int SpikeIndex => spikeIndex; // 使 spikeIndex 可通过属性访问
[HideInInspector]
public WaveformType waveformType = WaveformType.Sine;
public float amplitudeModulationFrequency = 0.5f;
public float amplitudeModulationDepth = 0.5f;
public float phaseShift = 0f; // 相位偏移
private bool isCaptured = false; // 是否已拍照(冻结波形)
private int spikeIndex; // 单个突刺位置
private bool isCorrect=true;
private bool isSpikeIndexSet = false; // 标志位,判断 spikeIndex 是否已设置
private TargetPointData targetdata;
public bool isErrorFind=false;
private LineRenderer scanLineRenderer; // 新的 LineRenderer
public float scanSpeed = 1f; // 扫描速度
private bool isScanning = false; // 是否正在扫描
void Start()
{
lineRenderer = GetComponent<LineRenderer>();
lineRenderer.positionCount = samples;
lineRenderer.useWorldSpace = false;
spriteRenderer = GetComponentInParent<SpriteRenderer>();
if (spriteRenderer != null)
{
spriteWidth = spriteRenderer.bounds.size.x;
spriteHeight = spriteRenderer.bounds.size.y;
lineRenderer.sortingLayerID = spriteRenderer.sortingLayerID;
lineRenderer.sortingOrder = spriteRenderer.sortingOrder + 3;
}
else
{
Debug.LogError("Could not find SpriteRenderer in parent object.");
}
waveformData = new float[samples];
noiseData = new float[samples];
displayData = new float[samples];
antiWaveformData = new float[samples];
DrawWaveform(); // 初始化波形
}
void Update()
{
GenerateNoiseData();
GenerateWaveformData();
if (phaseShift > 0)
{
GenerateAntiWaveformData();
}
for (int i = 0; i < samples; i++)
{
displayData[i] = Mathf.Lerp(noiseData[i], waveformData[i], clarity);
if (phaseShift > 0)
{
displayData[i] += antiWaveformData[i];
}
if (!isCorrect)
{
HandleErrorDisplay(i);
}
displayData[i] = Mathf.Clamp(displayData[i], -spriteHeight / 1.8f, spriteHeight / 1.8f);
}
if(!isCorrect)
{
CheckError();
}
DrawWaveform();
}
void GenerateNoiseData()
{
float adjustedNoiseAmplitude = Mathf.Lerp(noiseAmplitude, targetWaveformNoiseAmplitude, clarity);
for (int i = 0; i < samples; i++)
{
noiseData[i] = Random.Range(-adjustedNoiseAmplitude, adjustedNoiseAmplitude);
}
}
void GenerateWaveformData()
{
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
waveformData[i] = GetWaveformValue(t, 0) * clarity;
}
if(!isCorrect)
{
GenerateErrorData();
}
}
private void GenerateErrorData()
{
if (targetdata.spikeIndex != -1)
{
spikeIndex = targetdata.spikeIndex;
return;
}
if (isSpikeIndexSet) return; // 如果已设置,则不再随机
float threshold = 0.9f; // 80% 的阈值
// 找到波形数据中的最大绝对值
float maxAmplitude = 0f;
for (int i = 0; i < samples; i++)
{
maxAmplitude = Mathf.Max(maxAmplitude, Mathf.Abs(waveformData[i]));
}
// 计算超过 80% 最大值的阈值
float amplitudeThreshold = maxAmplitude * threshold;
// 找到所有超过阈值的点
List<int> candidateIndices = new List<int>();
for (int i = 0; i < samples; i++)
{
if (Mathf.Abs(waveformData[i]) > amplitudeThreshold)
{
candidateIndices.Add(i);
}
}
// 随机选择一个满足条件的点作为 spikeIndex
if (candidateIndices.Count > 0)
{
int randomIndex = Random.Range(0, candidateIndices.Count);
spikeIndex = candidateIndices[randomIndex];
isSpikeIndexSet = true; // 标志位设为 true,表示已设置过 spikeIndex
}
else
{
spikeIndex = 0; // 如果没有找到满足条件的点,则默认为 0
isSpikeIndexSet = true; // 即使没有找到满足条件的点,也将标志位设为 true
}
if (targetdata != null)
{
targetdata.spikeIndex = spikeIndex;
}
}
public void SetError(TargetPointData target)
{
isCorrect=false;
targetdata=target;
}
float GetWaveformValue(float t, float phaseOffset)
{
float time = Time.time * temporalFrequency;
//float amplitudeModulation = 1f + amplitudeModulationDepth * Mathf.Sin(2f * Mathf.PI * amplitudeModulationFrequency * Time.time);
float angle = t * Mathf.PI * 2f * spatialFrequency + phaseOffset;
float value = 0f;
// 计算波形值
switch (waveformType)
{
case WaveformType.Sine:
clearColor=Color.green;
value = Mathf.Sin(angle);
break;
case WaveformType.Square:
clearColor=Color.green;
value = Mathf.Sign(Mathf.Sin(angle));
break;
case WaveformType.Triangle:
clearColor=Color.green;
value = Mathf.PingPong(angle / Mathf.PI, 1f) * 2f - 1f;
break;
case WaveformType.Sawtooth:
clearColor=Color.green;
value = ((angle / (Mathf.PI * 2f)) % 1f) * 2f - 1f; // 统一周期为 2π
break;
case WaveformType.Pulse:
clearColor=Color.green;
value = Mathf.PingPong(angle / (Mathf.PI * 2f), 1f) > 0.5f ? 1f : -1f; // 统一周期为 2π
break;
case WaveformType.Noise:
clearColor=Color.red;
value = Mathf.PerlinNoise(angle / (Mathf.PI * 0.05f), Time.time * temporalFrequency*4) * 2f - 1f; // 统一周期为 2π
break;
case WaveformType.Composite:
clearColor=Color.green;
value = Mathf.Sin(angle) + Mathf.Sin(angle * 2f) * 0.5f; // 组合波形也统一周期
break;
default:
value = 0f;
break;
}
return value * amplitude; // 最终返回波形值
//return value * amplitude * amplitudeModulation; // 最终返回波形值
}
private void HandleErrorDisplay(int index)
{
float amplitudeScale = Mathf.Lerp(0.2f, 1f, clarity);
int distanceToSpike = Mathf.Abs(spikeIndex - index);
if (distanceToSpike <= 20) // 扩大扰动的半径
{
float attenuation = 1f - (float)distanceToSpike / 20f;
attenuation *= 0.9f; // 降低扰动强度
float baseAmplitude = displayData[index] * amplitudeScale * (spriteHeight / 2f);
float randomRange = (Mathf.Abs(baseAmplitude) - amplitude / 3f) * attenuation;
//isErrorFind = Mathf.Abs(baseAmplitude) < amplitude / 3;
if (Mathf.Abs(baseAmplitude) < amplitude / 3)
{
float randomOffset = Random.Range(-randomRange, randomRange);
displayData[index] += randomOffset; // 对 Y 值进行随机扰动
}
//displayData[index] += Random.Range(-attenuation * 0.5f, attenuation * 0.5f); // 添加随机扰动
}
}
private void CheckError()
{
isErrorFind=displayData[spikeIndex]<amplitude / 3f;
}
void GenerateAntiWaveformData()
{
for (int i = 0; i < samples; i++)
{
float t = (float)i / samples;
antiWaveformData[i] = -GetWaveformValue(t, phaseShift) * clarity;
}
}
void DrawWaveform()
{
for (int i = 0; i < samples; i++)
{
float x = ((float)i / (samples - 1)) * spriteWidth - (spriteWidth / 2f);
float amplitudeScale = Mathf.Lerp(0.2f, 1f, clarity);
// 获取波形值
float y = displayData[i] * amplitudeScale * (spriteHeight / 2f);
Vector3 position = new Vector3(x, y, 0);
lineRenderer.SetPosition(i, position);
}
Color waveColor = Color.Lerp(noiseColor, clearColor, clarity);
lineRenderer.startColor = waveColor;
lineRenderer.endColor = waveColor;
float startWidth = Mathf.Lerp(0.02f, 0.05f, clarity);
lineRenderer.startWidth = startWidth;
lineRenderer.endWidth = startWidth;
}
// 应用相位偏移
public void SetPhaseShift(float phaseShiftValue)
{
phaseShift = phaseShiftValue;
}
// 重置波形
public void ResetWaveform()
{
clearColor=Color.green;
isCaptured = false;
phaseShift = 0f;
spikeIndex=0;
isCorrect=true;
isSpikeIndexSet = false;
targetdata=null;
isErrorFind=false;
}
}