152 lines
4.2 KiB
C#
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);
|
|
}
|
|
}
|