您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
191 行
7.4 KiB
191 行
7.4 KiB
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.MegaCity.Utils
|
|
{
|
|
/// <summary>
|
|
/// keeps the data for Line Doppler and applies according to the delay parameters.
|
|
/// </summary>
|
|
public class DelayLineDopplerHack : MonoBehaviour
|
|
{
|
|
public AudioListener m_Listener;
|
|
|
|
public GameObject m_Proto;
|
|
|
|
public int m_NumSources = 30;
|
|
|
|
public float m_MaxDistance = 1.0f;
|
|
public float m_Haas = 2000.0f;
|
|
public float m_EnvelopeSpeed = 2.0f;
|
|
public float m_PanAmount = 2.0f;
|
|
public float m_Radius = 500.0f;
|
|
public float m_SwitchTimeMin = 0.01f;
|
|
public float m_SwitchTimeMax = 4.0f;
|
|
public float m_DopplerLevel = 1.0f;
|
|
|
|
struct SourceData
|
|
{
|
|
public GameObject m_Object;
|
|
public float[] m_Attenuation;
|
|
public float m_Distance;
|
|
public float m_InterpolatedDistance;
|
|
public float[] m_InterpolatedAttenuation;
|
|
public Vector3 m_Follow;
|
|
public Vector3 m_Target;
|
|
public float m_TimeUntilNextUpdate;
|
|
public float m_MoveTime;
|
|
}
|
|
|
|
SourceData[] m_SourceData;
|
|
float[] m_Delay = new float[0x40000];
|
|
int m_WritePos;
|
|
int m_SampleRate;
|
|
bool m_Ready;
|
|
|
|
// Start is called before the first frame update
|
|
void Start()
|
|
{
|
|
m_SampleRate = 44100;
|
|
m_SourceData = new SourceData[m_NumSources];
|
|
}
|
|
|
|
System.Random r = new System.Random();
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
if (!m_Ready)
|
|
{
|
|
for (int i = 0; i < m_SourceData.Length; i++)
|
|
{
|
|
var s = m_SourceData[i];
|
|
s.m_Object = Object.Instantiate(m_Proto);
|
|
s.m_Attenuation = new float[2];
|
|
s.m_InterpolatedAttenuation = new float[2];
|
|
m_SourceData[i] = s;
|
|
}
|
|
|
|
m_Proto.SetActive(false);
|
|
}
|
|
|
|
for (int i = 0; i < m_SourceData.Length; i++)
|
|
{
|
|
var s = m_SourceData[i];
|
|
s.m_TimeUntilNextUpdate -= Time.deltaTime;
|
|
|
|
if (s.m_TimeUntilNextUpdate <= 0.0f)
|
|
{
|
|
s.m_MoveTime = m_SwitchTimeMin + (m_SwitchTimeMax - m_SwitchTimeMin) * (float)r.NextDouble();
|
|
s.m_TimeUntilNextUpdate += s.m_MoveTime;
|
|
|
|
var x = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
var y = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
var z = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
s.m_Target = new Vector3(x, y, z);
|
|
if (!m_Ready)
|
|
{
|
|
s.m_Follow = s.m_Target;
|
|
s.m_Object.transform.position = s.m_Target;
|
|
x = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
y = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
z = ((float)r.NextDouble() * 2.0f - 1.0f) * m_Radius;
|
|
s.m_Target = new Vector3(x, y, z);
|
|
}
|
|
}
|
|
|
|
m_SourceData[i] = s;
|
|
}
|
|
|
|
float distanceScale = 1.0f / m_MaxDistance;
|
|
|
|
for (int i = 0; i < m_SourceData.Length; i++)
|
|
{
|
|
var target = m_SourceData[r.Next(m_SourceData.Length - 1)].m_Object.transform.position;
|
|
var s = m_SourceData[i];
|
|
float moveSpeed = 1.0f - Mathf.Pow(0.1f, Time.deltaTime / s.m_MoveTime);
|
|
s.m_Follow += (s.m_Target - s.m_Follow) * moveSpeed;
|
|
var delta = (s.m_Follow - s.m_Object.transform.position) * moveSpeed;
|
|
s.m_Object.transform.position += delta;
|
|
s.m_Object.transform.rotation = Quaternion.LookRotation(-delta.normalized);
|
|
var dir = m_Listener.transform.worldToLocalMatrix.MultiplyVector(s.m_Object.transform.position);
|
|
var len = dir.magnitude;
|
|
var leftDir = 0.5f * dir.z - dir.x;
|
|
var rightDir = 0.5f * dir.z + dir.x;
|
|
var attenuation = 1.0f / (1.0f + s.m_Distance * distanceScale);
|
|
s.m_Attenuation[0] = attenuation * (0.65f + m_PanAmount * 0.45f *
|
|
Mathf.Clamp(leftDir * Mathf.Abs(leftDir) / (len + 0.001f), -1.0f, 1.0f));
|
|
s.m_Attenuation[1] = attenuation * (0.65f + m_PanAmount * 0.45f *
|
|
Mathf.Clamp(rightDir * Mathf.Abs(rightDir) / (len + 0.001f), -1.0f, 1.0f));
|
|
s.m_Distance = (m_Listener.transform.position - s.m_Object.transform.position).magnitude;
|
|
m_SourceData[i] = s;
|
|
}
|
|
|
|
if (!m_Ready)
|
|
{
|
|
for (int i = 0; i < m_SourceData.Length; i++)
|
|
{
|
|
var s = m_SourceData[i];
|
|
s.m_InterpolatedDistance = s.m_Distance;
|
|
m_SourceData[i] = s;
|
|
}
|
|
|
|
m_Ready = true;
|
|
}
|
|
}
|
|
|
|
void OnAudioFilterRead(float[] data, int numChannels)
|
|
{
|
|
if (!m_Ready)
|
|
{
|
|
for (int n = 0; n < data.Length; n++)
|
|
data[n] = 0.0f;
|
|
return;
|
|
}
|
|
|
|
float envelopeSpeed = 1.0f - Mathf.Pow(0.001f, 1.0f / (m_EnvelopeSpeed * m_SampleRate));
|
|
|
|
int maxLength = (int)(m_Delay.Length / numChannels) - 1;
|
|
|
|
float dopplerSamples = m_DopplerLevel * m_SampleRate / 340.0f;
|
|
|
|
for (int n = 0; n < data.Length; n += numChannels)
|
|
{
|
|
for (int c = 0; c < numChannels; c++)
|
|
{
|
|
m_Delay[m_WritePos] = data[n + c];
|
|
if (++m_WritePos == m_Delay.Length)
|
|
m_WritePos = 0;
|
|
data[n + c] = 0.0f;
|
|
}
|
|
|
|
for (int i = 0; i < m_SourceData.Length; i++)
|
|
{
|
|
var s = m_SourceData[i];
|
|
|
|
s.m_InterpolatedDistance += (s.m_Distance - s.m_InterpolatedDistance) * envelopeSpeed;
|
|
|
|
int delaySamplesBase = (int)(s.m_InterpolatedDistance * dopplerSamples);
|
|
|
|
for (int c = 0; c < numChannels; c++)
|
|
{
|
|
var haasDelay = (int)((s.m_Attenuation[0] - s.m_Attenuation[1]) * m_Haas * (c * 2 - 1));
|
|
var delaySamples = Mathf.Clamp(delaySamplesBase + haasDelay, 0, maxLength);
|
|
|
|
int readPos = m_WritePos - numChannels - delaySamples * numChannels;
|
|
if (readPos < 0)
|
|
readPos += m_Delay.Length;
|
|
|
|
s.m_InterpolatedAttenuation[c] +=
|
|
(s.m_Attenuation[c] - s.m_InterpolatedAttenuation[c]) * envelopeSpeed;
|
|
data[n + c] += m_Delay[readPos] * s.m_InterpolatedAttenuation[c];
|
|
if (++readPos >= m_Delay.Length)
|
|
readPos = 0;
|
|
}
|
|
|
|
m_SourceData[i] = s;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|