JiNanCementPlantForUnity/Assets/3rdPart/Ocean/Scripts/WavesGenerator.cs

161 lines
5.0 KiB
C#

using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
public class WavesGenerator : MonoBehaviour
{
public WavesCascade cascade0;
public WavesCascade cascade1;
public WavesCascade cascade2;
// must be a power of 2
[SerializeField]
int size = 256;
[SerializeField]
WavesSettings wavesSettings;
[SerializeField]
bool alwaysRecalculateInitials = false;
[SerializeField]
float lengthScale0 = 250;
[SerializeField]
float lengthScale1 = 17;
[SerializeField]
float lengthScale2 = 5;
[SerializeField]
ComputeShader fftShader;
[SerializeField]
ComputeShader initialSpectrumShader;
[SerializeField]
ComputeShader timeDependentSpectrumShader;
[SerializeField]
ComputeShader texturesMergerShader;
Texture2D gaussianNoise;
FastFourierTransform fft;
Texture2D physicsReadback;
private void Awake()
{
Application.targetFrameRate = -1;
fft = new FastFourierTransform(size, fftShader);
gaussianNoise = GetNoiseTexture(size);
cascade0 = new WavesCascade(size, initialSpectrumShader, timeDependentSpectrumShader, texturesMergerShader, fft, gaussianNoise);
cascade1 = new WavesCascade(size, initialSpectrumShader, timeDependentSpectrumShader, texturesMergerShader, fft, gaussianNoise);
cascade2 = new WavesCascade(size, initialSpectrumShader, timeDependentSpectrumShader, texturesMergerShader, fft, gaussianNoise);
InitialiseCascades();
physicsReadback = new Texture2D(size, size, TextureFormat.RGBAFloat, false);
}
void InitialiseCascades()
{
float boundary1 = 2 * Mathf.PI / lengthScale1 * 6f;
float boundary2 = 2 * Mathf.PI / lengthScale2 * 6f;
cascade0.CalculateInitials(wavesSettings, lengthScale0, 0.0001f, boundary1);
cascade1.CalculateInitials(wavesSettings, lengthScale1, boundary1, boundary2);
cascade2.CalculateInitials(wavesSettings, lengthScale2, boundary2, 9999);
Shader.SetGlobalFloat("LengthScale0", lengthScale0);
Shader.SetGlobalFloat("LengthScale1", lengthScale1);
Shader.SetGlobalFloat("LengthScale2", lengthScale2);
}
private void Update()
{
if (alwaysRecalculateInitials)
{
InitialiseCascades();
}
cascade0.CalculateWavesAtTime(Time.time);
cascade1.CalculateWavesAtTime(Time.time);
cascade2.CalculateWavesAtTime(Time.time);
RequestReadbacks();
}
Texture2D GetNoiseTexture(int size)
{
string filename = "GaussianNoiseTexture" + size.ToString() + "x" + size.ToString();
Texture2D noise = Resources.Load<Texture2D>("GaussianNoiseTextures/" + filename);
return noise ? noise : GenerateNoiseTexture(size, true);
}
Texture2D GenerateNoiseTexture(int size, bool saveIntoAssetFile)
{
Texture2D noise = new Texture2D(size, size, TextureFormat.RGFloat, false, true);
noise.filterMode = FilterMode.Point;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
noise.SetPixel(i, j, new Vector4(NormalRandom(), NormalRandom()));
}
}
noise.Apply();
#if UNITY_EDITOR
if (saveIntoAssetFile)
{
string filename = "GaussianNoiseTexture" + size.ToString() + "x" + size.ToString();
string path = "Assets/Resources/GaussianNoiseTextures/";
AssetDatabase.CreateAsset(noise, path + filename + ".asset");
Debug.Log("Texture \"" + filename + "\" was created at path \"" + path + "\".");
}
#endif
return noise;
}
float NormalRandom()
{
return Mathf.Cos(2 * Mathf.PI * Random.value) * Mathf.Sqrt(-2 * Mathf.Log(Random.value));
}
private void OnDestroy()
{
cascade0.Dispose();
cascade1.Dispose();
cascade2.Dispose();
}
void RequestReadbacks()
{
AsyncGPUReadback.Request(cascade0.Displacement, 0, TextureFormat.RGBAFloat, OnCompleteReadback);
}
public float GetWaterHeight(Vector3 position)
{
Vector3 displacement = GetWaterDisplacement(position);
displacement = GetWaterDisplacement(position - displacement);
displacement = GetWaterDisplacement(position - displacement);
return GetWaterDisplacement(position - displacement).y;
}
public Vector3 GetWaterDisplacement(Vector3 position)
{
Color c = physicsReadback.GetPixelBilinear(position.x / lengthScale0, position.z / lengthScale0);
return new Vector3(c.r, c.g, c.b);
}
void OnCompleteReadback(AsyncGPUReadbackRequest request) => OnCompleteReadback(request, physicsReadback);
void OnCompleteReadback(AsyncGPUReadbackRequest request, Texture2D result)
{
if (request.hasError)
{
Debug.Log("GPU readback error detected.");
return;
}
if (result != null)
{
result.LoadRawTextureData(request.GetData<Color>());
result.Apply();
}
}
}