Files
DTrierFlood_New/Assets/FloodSWE/Scripts/Tests/SweTestUtils.cs

152 lines
4.2 KiB
C#

using System.Collections;
using NUnit.Framework;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;
internal static class SweTestUtils
{
public static bool SupportsGpu
{
get { return SystemInfo.supportsComputeShaders && SystemInfo.supportsAsyncGPUReadback; }
}
public static ComputeShader LoadComputeShader(string assetPath)
{
#if UNITY_EDITOR
return UnityEditor.AssetDatabase.LoadAssetAtPath<ComputeShader>(assetPath);
#else
return null;
#endif
}
public static SweTileSimulator CreateSimulator(
int gridRes,
float tileSizeMeters,
float tickSeconds,
bool damBreak,
float initialDepthLeft,
float initialDepthRight,
float rainRateMmPerHr)
{
ComputeShader ghost = LoadComputeShader("Assets/FloodSWE/Compute/SWE_GhostExchange.compute");
ComputeShader flux = LoadComputeShader("Assets/FloodSWE/Compute/SWE_Flux.compute");
if (ghost == null || flux == null)
{
return null;
}
GameObject go = new GameObject("SweTileSimulator_Test");
go.SetActive(false);
SweTileSimulator sim = go.AddComponent<SweTileSimulator>();
sim.ghostExchangeShader = ghost;
sim.fluxShader = flux;
sim.gridRes = gridRes;
sim.tileSizeMeters = tileSizeMeters;
sim.tickSeconds = tickSeconds;
sim.damBreak = damBreak;
sim.initialDepthLeft = initialDepthLeft;
sim.initialDepthRight = initialDepthRight;
sim.initialVelocity = Vector2.zero;
sim.rainRateMmPerHr = rainRateMmPerHr;
sim.logCfl = false;
sim.terrainHeight = null;
sim.porosity = null;
go.SetActive(true);
return sim;
}
public static IEnumerator WaitForSecondsRealtime(float seconds)
{
float endTime = Time.realtimeSinceStartup + seconds;
while (Time.realtimeSinceStartup < endTime)
{
yield return null;
}
}
public static IEnumerator Readback(RenderTexture rt, System.Action<NativeArray<ushort>> onData)
{
AsyncGPUReadbackRequest request = AsyncGPUReadback.Request(rt, 0);
while (!request.done)
{
yield return null;
}
if (request.hasError)
{
Assert.Fail("Async GPU readback failed.");
}
onData(request.GetData<ushort>());
}
public static float ComputeAverageDepth(NativeArray<ushort> data)
{
double sum = 0.0;
for (int i = 0; i < data.Length; i++)
{
sum += HalfToFloat(data[i]);
}
return (float)(sum / data.Length);
}
public static float ComputeFrontDistance(NativeArray<ushort> data, int gridRes, float dx, float threshold)
{
int center = gridRes / 2;
int frontX = center;
for (int x = center; x < gridRes; x++)
{
double sum = 0.0;
for (int y = 0; y < gridRes; y++)
{
int index = y * gridRes + x;
sum += HalfToFloat(data[index]);
}
float avg = (float)(sum / gridRes);
if (avg >= threshold)
{
frontX = x;
}
}
return Mathf.Max(0.0f, (frontX - center) * dx);
}
private static float HalfToFloat(ushort half)
{
uint sign = (uint)(half >> 15) & 0x00000001u;
int exp = (half >> 10) & 0x0000001F;
int mant = half & 0x000003FF;
if (exp == 0)
{
if (mant == 0)
{
return sign == 1 ? -0.0f : 0.0f;
}
exp = 1;
while ((mant & 0x00000400) == 0)
{
mant <<= 1;
exp--;
}
mant &= 0x000003FF;
}
else if (exp == 31)
{
uint infNaN = (sign << 31) | 0x7F800000u | ((uint)mant << 13);
return System.BitConverter.ToSingle(System.BitConverter.GetBytes(infNaN), 0);
}
uint fexp = (uint)(exp + (127 - 15));
uint fmant = (uint)(mant << 13);
uint bits = (sign << 31) | (fexp << 23) | fmant;
return System.BitConverter.ToSingle(System.BitConverter.GetBytes(bits), 0);
}
}