Firstborn/Library/PackageCache/com.unity.terrain-tools@4.0.5/Editor/TerrainTools/Erosion/WindEroder.cs

425 lines
20 KiB
C#
Raw Normal View History

2023-03-28 13:24:16 -04:00
using UnityEngine;
using System;
using System.Collections.Generic;
namespace UnityEditor.TerrainTools.Erosion
{
[Serializable]
internal class WindEroder : ITerrainEroder
{
//we store all our compute shaders in a dictionary
Dictionary<string, ComputeShader> m_ComputeShaders = new Dictionary<string, ComputeShader>();
ComputeShader GetComputeShader(string name)
{
ComputeShader s = null;
try
{
s = m_ComputeShaders[name];
}
catch
{
s = ComputeUtility.GetShader(name);
if (s != null)
{
m_ComputeShaders[name] = s;
}
}
return s;
}
[SerializeField]
public TerrainFloatMinMaxValue m_WindSpeed = new TerrainFloatMinMaxValue(Erosion.Styles.m_WindSpeed, 1.7f, 0.0f, 10.0f);
[SerializeField]
public float m_WindSpeedJitter = 0.0f;
[SerializeField]
private TerrainFloatMinMaxValue m_dt = new TerrainFloatMinMaxValue(Erosion.Styles.m_TimeDelta, 0.006f, 0.001f, 0.01f);
public Vector4 m_WindVel = Vector4.zero;
[SerializeField]
private TerrainIntMinMaxValue m_Iterations = new TerrainIntMinMaxValue(Erosion.Styles.m_NumIterations, 12, 1, 100);
[SerializeField]
private TerrainFloatMinMaxValue m_SimulationScale = new TerrainFloatMinMaxValue(Erosion.Styles.m_SimulationScale, 10.0f, 0.0f, 100.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_DiffusionRate = new TerrainFloatMinMaxValue(Erosion.Styles.m_DiffusionRate, 0.0001f, 0.0f, 0.01f);
[SerializeField]
private TerrainFloatMinMaxValue m_Viscosity = new TerrainFloatMinMaxValue(Erosion.Styles.m_Viscosity, 0.00075f, 0.0f, 0.01f);
[SerializeField]
private int m_ProjectionSteps = 2;
[SerializeField]
private int m_DiffuseSteps = 1;
[SerializeField]
private TerrainFloatMinMaxValue m_AdvectionVelScale = new TerrainFloatMinMaxValue(Erosion.Styles.m_AdvectionVelScale, 10.0f, 0.0f, 25.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_SuspensionRate = new TerrainFloatMinMaxValue(Erosion.Styles.m_SuspensionRate, 22.0f, 0.0f, 25.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_DepositionRate = new TerrainFloatMinMaxValue(Erosion.Styles.m_DepositionRate, 10.0f, 0.0f, 25.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_SlopeFactor = new TerrainFloatMinMaxValue(Erosion.Styles.m_SlopeFactor, 1.0f, 0.0f, 10.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_DragCoefficient = new TerrainFloatMinMaxValue(Erosion.Styles.m_DragCoefficient, 0.5f, 0.0f, 10.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_ReflectionCoefficient = new TerrainFloatMinMaxValue(Erosion.Styles.m_ReflectionCoefficient, 23.0f, 0.0f, 50.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_AbrasivenessCoefficient = new TerrainFloatMinMaxValue(Erosion.Styles.m_AbrasivenessCoefficient, 0.0f, 0.0f, 10.0f);
[SerializeField]
private TerrainFloatMinMaxValue m_ThermalTimeDelta = new TerrainFloatMinMaxValue(Erosion.Styles.m_ThermalDTScalar, 0.004f, 0.0f, 0.1f);
[SerializeField]
private int m_ThermalIterations = 3;
[SerializeField]
private float m_AngleOfRepose = 45.0f;
//Analytics Setup
public int ProjectionSteps => m_ProjectionSteps;
public int DiffuseSteps => m_DiffuseSteps;
public int ThermalIterations => m_ThermalIterations;
public float AngleOfRepose => m_AngleOfRepose;
public TerrainFloatMinMaxValue TimeInterval => m_dt;
public TerrainIntMinMaxValue Iterations => m_Iterations;
public TerrainFloatMinMaxValue SimulationScale => m_SimulationScale;
public TerrainFloatMinMaxValue DiffusionRate => m_DiffusionRate;
public TerrainFloatMinMaxValue Viscosity => m_Viscosity;
public TerrainFloatMinMaxValue AdvectionVelScale => m_AdvectionVelScale;
public TerrainFloatMinMaxValue SuspensionRate => m_SuspensionRate;
public TerrainFloatMinMaxValue DepositionRate => m_DepositionRate;
public TerrainFloatMinMaxValue SlopeFactor => m_SlopeFactor;
public TerrainFloatMinMaxValue DragCoefficient => m_DragCoefficient;
public TerrainFloatMinMaxValue ReflectionCoefficient => m_ReflectionCoefficient;
public TerrainFloatMinMaxValue AbrasivenessCoefficient => m_AbrasivenessCoefficient;
public TerrainFloatMinMaxValue ThermalTimeDelta => m_ThermalTimeDelta;
public WindEroder() { ResetSettings(); }
public Dictionary<string, RenderTexture> inputTextures { get; set; } = new Dictionary<string, RenderTexture>();
public void OnEnable() { }
public void ErodeHeightmap(RenderTexture dest, Vector3 terrainDimension, Rect domainRect, Vector2 texelSize, bool invertEffect = false)
{
ErodeHelper(dest, terrainDimension, domainRect, texelSize, invertEffect, false);
}
private void ErodeHelper(RenderTexture dest, Vector3 terrainScale, Rect domainRect, Vector2 texelSize, bool invertEffect, bool lowRes)
{
RenderTexture tmpRT = UnityEngine.RenderTexture.active;
//this one is mandatory
if (!inputTextures.ContainsKey("Height"))
{
throw (new Exception("No input heightfield specified!"));
}
//Find Compute Kernels
ComputeShader advectionCS = GetComputeShader("Advection");
ComputeShader projectionCS = GetComputeShader("Projection");
ComputeShader diffusionCS = GetComputeShader("Diffusion");
ComputeShader utilityCS = GetComputeShader("ImageUtility");
ComputeShader aeolianCS = GetComputeShader("Aeolian");
ComputeShader thermalCS = GetComputeShader("Thermal");
int advectKernelIdx = advectionCS.FindKernel("Advect");
int divergenceKernelIdx = projectionCS.FindKernel("Divergence");
int gradientSubtractKernelIdx = projectionCS.FindKernel("GradientSubtract");
int diffuseKernelIdx = diffusionCS.FindKernel("Diffuse");
int remapKernelIdx = utilityCS.FindKernel("RemapValues");
int addConstantIdx = utilityCS.FindKernel("AddConstant");
int applyDragKernelIdx = aeolianCS.FindKernel("ApplyHeightfieldDrag");
int erodeKernelIdx = aeolianCS.FindKernel("WindSedimentErode");
int thermalKernelIdx = thermalCS.FindKernel("ThermalErosion");
int[] numWorkGroups = { 1, 1, 1 };
int xRes = (int)inputTextures["Height"].width;
int yRes = (int)inputTextures["Height"].height;
var r = RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat);
var rg = RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RGFloat);
var heightmapRT = RTUtils.GetTempHandle(r);
var heightmapPrevRT = RTUtils.GetTempHandle(r);
var collisionRT = RTUtils.GetTempHandle(r);
var sedimentPrevRT = RTUtils.GetTempHandle(r);
var sedimentRT = RTUtils.GetTempHandle(r);
var windVelRT = RTUtils.GetTempHandle(rg);
var windVelPrevRT = RTUtils.GetTempHandle(rg);
var divergenceRT = RTUtils.GetTempHandle(r);
var thermalSedimentRT = RTUtils.GetTempHandle(r);
//Setup input textures, clear the render textures
Graphics.Blit(Texture2D.blackTexture, sedimentRT);
Graphics.Blit(Texture2D.blackTexture, collisionRT);
Graphics.Blit(Texture2D.blackTexture, windVelRT);
Graphics.Blit(Texture2D.blackTexture, windVelPrevRT);
Graphics.Blit(inputTextures["Height"], heightmapPrevRT);
Graphics.Blit(inputTextures["Height"], heightmapRT);
//precompute some values on the CPU (these become uniform constants in the shader)
float dx = (float)texelSize.x * m_SimulationScale.value;
float dy = (float)texelSize.y * m_SimulationScale.value;
float dxy = Mathf.Sqrt(dx * dx + dy * dy);
Vector4 dxdy = new Vector4(dx, dy, 1.0f / dx, 1.0f / dy); //TODO: make this the same for all compute shaders
advectionCS.SetFloat("dt", m_dt.value);
advectionCS.SetFloat("velScale", m_AdvectionVelScale.value);
advectionCS.SetVector("dxdy", dxdy);
advectionCS.SetVector("DomainRes", new Vector4((float)xRes, (float)yRes, 1.0f / (float)xRes, 1.0f / (float)yRes));
diffusionCS.SetFloat("dt", m_dt.value);
projectionCS.SetVector("dxdy", dxdy);
aeolianCS.SetFloat("dt", m_dt.value);
aeolianCS.SetFloat("SuspensionRate", m_SuspensionRate.value);
aeolianCS.SetFloat("DepositionRate", m_DepositionRate.value);
aeolianCS.SetFloat("SlopeFactor", m_SlopeFactor.value);
aeolianCS.SetFloat("DragCoefficient", m_DragCoefficient.value);
aeolianCS.SetFloat("ReflectionCoefficient", m_ReflectionCoefficient.value);
aeolianCS.SetFloat("AbrasivenessCoefficient", m_AbrasivenessCoefficient.value * 1000.0f);
aeolianCS.SetVector("DomainDim", new Vector4((float)xRes, (float)yRes, 0.0f, 0.0f));
aeolianCS.SetVector("terrainScale", new Vector4(terrainScale.x, terrainScale.y, terrainScale.z, 0.0f));
aeolianCS.SetVector("dxdy", dxdy);
//use full tile res here?
diffusionCS.SetVector("texDim", new Vector4((float)inputTextures["Height"].width, (float)inputTextures["Height"].height, 0.0f, 0.0f));
for (int i = 0; i < m_Iterations.value; i++)
{
//Velocity step
utilityCS.SetTexture(addConstantIdx, "OutputTex", windVelPrevRT);
utilityCS.SetVector("Constant", m_WindVel);
utilityCS.Dispatch(addConstantIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
//Apply drag from heightfield
aeolianCS.SetTexture(applyDragKernelIdx, "InHeightMap", heightmapPrevRT);
aeolianCS.SetTexture(applyDragKernelIdx, "WindVel", windVelPrevRT);
aeolianCS.SetTexture(applyDragKernelIdx, "OutWindVel", windVelRT);
aeolianCS.Dispatch(applyDragKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
//Diffuse Velocity
diffusionCS.SetFloat("diff", m_Viscosity.value);
for (int j = 0; j < m_DiffuseSteps; j++)
{
diffusionCS.SetTexture(diffuseKernelIdx, "InputTex", windVelRT);
diffusionCS.SetTexture(diffuseKernelIdx, "OutputTex", windVelPrevRT);
diffusionCS.Dispatch(diffuseKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
Graphics.Blit(windVelPrevRT, windVelRT);
}
//Project Velocity
for (int j = 0; j < m_ProjectionSteps; j++)
{
projectionCS.SetTexture(divergenceKernelIdx, "VelocityTex2D", windVelRT);
projectionCS.SetTexture(divergenceKernelIdx, "DivergenceTex2D", divergenceRT);
projectionCS.Dispatch(divergenceKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
projectionCS.SetTexture(gradientSubtractKernelIdx, "PressureTex2D", divergenceRT);
projectionCS.SetTexture(gradientSubtractKernelIdx, "VelocityTex2D", windVelRT);
projectionCS.SetTexture(gradientSubtractKernelIdx, "VelocityOutTex2D", windVelPrevRT);
projectionCS.Dispatch(gradientSubtractKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
Graphics.Blit(windVelPrevRT, windVelRT);
}
//Advect velocity along previous iteration's velocity field
advectionCS.SetTexture(advectKernelIdx, "InputTex", windVelRT);
advectionCS.SetTexture(advectKernelIdx, "OutputTex", windVelPrevRT);
advectionCS.SetTexture(advectKernelIdx, "VelocityTex", windVelRT);
advectionCS.Dispatch(advectKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
Graphics.Blit(windVelPrevRT, windVelRT);
//Density Step
//Diffuse Sediment
diffusionCS.SetFloat("diff", m_DiffusionRate.value);
for (int j = 0; j < m_DiffuseSteps; j++)
{
diffusionCS.SetTexture(diffuseKernelIdx, "InputTex", sedimentRT);
diffusionCS.SetTexture(diffuseKernelIdx, "OutputTex", sedimentPrevRT);
diffusionCS.Dispatch(diffuseKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
Graphics.Blit(sedimentPrevRT, sedimentRT);
}
//Advect Sediment
advectionCS.SetTexture(advectKernelIdx, "InputTexFloat", sedimentRT);
advectionCS.SetTexture(advectKernelIdx, "OutputTexFloat", sedimentPrevRT);
advectionCS.SetTexture(advectKernelIdx, "VelocityTex", windVelRT);
advectionCS.Dispatch(advectKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
//Erosion Step
//Erode Sediment (pick sediment up off the heightmap and store in sediment RT)
aeolianCS.SetTexture(erodeKernelIdx, "InHeightMap", heightmapPrevRT);
aeolianCS.SetTexture(erodeKernelIdx, "InSediment", sedimentPrevRT);
aeolianCS.SetTexture(erodeKernelIdx, "WindVel", windVelRT);
aeolianCS.SetTexture(erodeKernelIdx, "OutSediment", sedimentRT);
aeolianCS.SetTexture(erodeKernelIdx, "OutHeightMap", heightmapRT);
aeolianCS.Dispatch(erodeKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
//Thermal/Diffusion step
thermalCS.SetFloat("dt", m_ThermalTimeDelta.value * m_dt.value);
thermalCS.SetFloat("InvDiagMag", 1.0f / Mathf.Sqrt(dx * dx + dy * dy));
thermalCS.SetVector("dxdy", new Vector4(dx, dy, 1.0f / dx, 1.0f / dy));
thermalCS.SetVector("terrainDim", new Vector4(terrainScale.x, terrainScale.y, terrainScale.z));
thermalCS.SetVector("texDim", new Vector4((float)xRes, (float)yRes, 0.0f, 0.0f));
thermalCS.SetTexture(thermalKernelIdx, "TerrainHeightPrev", heightmapPrevRT);
thermalCS.SetTexture(thermalKernelIdx, "TerrainHeight", heightmapRT);
thermalCS.SetTexture(thermalKernelIdx, "Sediment", thermalSedimentRT);
thermalCS.SetTexture(thermalKernelIdx, "ReposeMask", collisionRT); //TODO
thermalCS.SetTexture(thermalKernelIdx, "Collision", collisionRT);
thermalCS.SetTexture(thermalKernelIdx, "Hardness", collisionRT); //TODO
Graphics.Blit(heightmapRT, heightmapPrevRT);
for (int j = 0; j < m_ThermalIterations; j++)
{
Vector2 m = new Vector2(Mathf.Tan(m_AngleOfRepose * Mathf.Deg2Rad), Mathf.Tan(m_AngleOfRepose * Mathf.Deg2Rad));
thermalCS.SetVector("angleOfRepose", new Vector4(m.x, m.y, 0.0f, 0.0f));
thermalCS.Dispatch(thermalKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
Graphics.Blit(heightmapRT, heightmapPrevRT);
}
//swap buffers for next iteration
//Graphics.Blit(heightmapRT, heightmapPrevRT);
Graphics.Blit(sedimentRT, sedimentPrevRT);
}
Graphics.Blit(heightmapRT, dest);
RTUtils.Release(heightmapRT);
RTUtils.Release(heightmapPrevRT);
RTUtils.Release(collisionRT);
RTUtils.Release(sedimentRT);
RTUtils.Release(sedimentPrevRT);
RTUtils.Release(windVelRT);
RTUtils.Release(windVelPrevRT);
RTUtils.Release(divergenceRT);
RTUtils.Release(thermalSedimentRT);
UnityEngine.RenderTexture.active = tmpRT;
}
bool m_ShowControls = true;
bool m_ShowAdvancedUI = false;
bool m_ShowThermalUI = false;
public void OnInspectorGUI()
{
m_ShowControls = TerrainToolGUIHelper.DrawHeaderFoldoutForErosion(Erosion.Styles.m_WindErosionControls, m_ShowControls, ResetSettings);
if (m_ShowControls)
{
EditorGUILayout.BeginVertical("GroupBox");
m_SimulationScale.DrawInspectorGUI();
m_WindSpeed.DrawInspectorGUI();
EditorGUI.indentLevel++;
m_ShowAdvancedUI = TerrainToolGUIHelper.DrawSimpleFoldout(new GUIContent("Advanced"), m_ShowAdvancedUI);
if (m_ShowAdvancedUI)
{
m_dt.DrawInspectorGUI();
m_Iterations.DrawInspectorGUI();
m_SuspensionRate.DrawInspectorGUI();
m_DepositionRate.DrawInspectorGUI();
m_SlopeFactor.DrawInspectorGUI();
m_AdvectionVelScale.DrawInspectorGUI();
m_DragCoefficient.DrawInspectorGUI();
m_ReflectionCoefficient.DrawInspectorGUI();
m_DiffusionRate.DrawInspectorGUI();
m_AbrasivenessCoefficient.DrawInspectorGUI();
m_Viscosity.DrawInspectorGUI();
EditorGUI.indentLevel++;
m_ShowThermalUI = TerrainToolGUIHelper.DrawSimpleFoldout(new GUIContent("Thermal Smoothing"), m_ShowThermalUI, 1);
if (m_ShowThermalUI)
{
m_ThermalIterations = EditorGUILayout.IntSlider("# Iterations", m_ThermalIterations, 0, 100);
m_ThermalTimeDelta.DrawInspectorGUI();
m_AngleOfRepose = EditorGUILayout.Slider(Erosion.Styles.m_AngleOfRepose, m_AngleOfRepose, 0.0f, 89.0f);
}
}
EditorGUILayout.EndVertical();
}
}
public void ResetSettings()
{
m_WindSpeed.value = 100.0f;
m_WindSpeed.minValue = 0.0f;
m_WindSpeed.maxValue = 500.0f;
m_WindSpeedJitter = 0.0f;
m_dt.value = 0.001f;
m_dt.minValue = 0.00001f;
m_dt.maxValue = 0.05f;
m_WindVel = Vector4.zero; //ToDo: User specified? Flow map?
m_Iterations.value = 3;
m_Iterations.minValue = 1;
m_Iterations.maxValue = 10;
m_SimulationScale.value = 10.0f;
m_SimulationScale.minValue = 0.0f;
m_SimulationScale.maxValue = 100.0f;
m_DiffusionRate.value = 0.1f;
m_DiffusionRate.minValue = 0.0f;
m_DiffusionRate.maxValue = 0.5f;
m_Viscosity.value = 0.15f;
m_Viscosity.minValue = 0.0f;
m_Viscosity.maxValue = 0.5f;
m_ProjectionSteps = 2;
m_DiffuseSteps = 2;
m_AdvectionVelScale.value = 10.0f;
m_AdvectionVelScale.value = 10.0f;
m_AdvectionVelScale.minValue = 0.0f;
m_AdvectionVelScale.maxValue = 25.0f;
m_SuspensionRate.value = 100.0f;
m_SuspensionRate.minValue = 0.0f;
m_SuspensionRate.maxValue = 200.0f;
m_DepositionRate.value = 25.0f;
m_DepositionRate.minValue = 0.0f;
m_DepositionRate.maxValue = 200.0f;
m_SlopeFactor.value = 1.0f;
m_SlopeFactor.minValue = 0.5f;
m_SlopeFactor.maxValue = 4.0f;
m_DragCoefficient.value = 0.5f;
m_DragCoefficient.minValue = 0.0f;
m_DragCoefficient.maxValue = 10.0f;
m_ReflectionCoefficient.value = 5.0f;
m_ReflectionCoefficient.minValue = 0.0f;
m_ReflectionCoefficient.maxValue = 10.0f;
m_AbrasivenessCoefficient.value = 0.0f;
m_AbrasivenessCoefficient.minValue = 0.0f;
m_AbrasivenessCoefficient.maxValue = 10.0f;
m_ThermalTimeDelta.value = 2.0f;
m_ThermalTimeDelta.minValue = 0.0f;
m_ThermalTimeDelta.maxValue = 10.0f;
m_ThermalIterations = 2;
m_AngleOfRepose = 5.0f;
}
}
}