public DebuggableHydraulicEroderOutput Erode(SimpleHeightArray heightMap, HydraulicEroderConfiguration configuration, int snapshotFrequencies) { List <SimpleHeightArray> WaterSnapshots = new List <SimpleHeightArray>(); List <SimpleHeightArray> SedimentSnapshots = new List <SimpleHeightArray>(); float krParam = configuration.kr_ConstantWaterAddition; float ksParam = configuration.ks_GroundToSedimentFactor; float keParam = configuration.ke_WaterEvaporationFactor; float kcParam = configuration.kc_MaxSedimentationFactor; bool finalSedimentationToGround = configuration.FinalSedimentationToGround; int stepCount = configuration.StepCount; ErodedNeighbourFinder neighbourFinder = configuration.NeighbourFinder; var waterMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var sedimentMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var sedimentAdditionMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var waterAdditionMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); for (int i = 0; i < stepCount; i++) { for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var point = new IntVector2(x, y); if (configuration.WaterGenerator == HydraulicEroderWaterGenerator.FirstFrame) { if (i == 0) { waterMap.AddValue(point, krParam); } } else { waterMap.AddValue(point, krParam); } float amountChangedToSediment = ksParam * waterMap.GetValue(point); heightMap.AddValue(point, -amountChangedToSediment); sedimentMap.AddValue(point, amountChangedToSediment); } } if (i == 0) { WaterSnapshots.Add(new SimpleHeightArray(MyArrayUtils.DeepClone <float>(waterMap.Array))); SedimentSnapshots.Add(new SimpleHeightArray(MyArrayUtils.DeepClone <float>(sedimentMap.Array))); } for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var point = new IntVector2(x, y); var neighbourPoints = neighbourFinder.Find(heightMap, point); var pTotalHeight = heightMap.GetValue(point) + waterMap.GetValue(point); var neighbours = neighbourPoints.Select(nPoint => new { Point = nPoint, TotalHeight = heightMap.GetValue(nPoint) + waterMap.GetValue(nPoint), TotalHeightDifference = pTotalHeight - (heightMap.GetValue(nPoint) + waterMap.GetValue(nPoint)), }).Where(c => c.TotalHeightDifference > 0).ToList(); if (!neighbours.Any()) { continue; } var dTotalHeightDiffSum = neighbours.Sum(c => c.TotalHeightDifference); var avgTotalHeight = (neighbours.Sum(c => c.TotalHeight) + pTotalHeight) / (neighbours.Count + 1); var pSediment = sedimentMap.GetValue(point); var pWater = waterMap.GetValue(point); if (pWater < 0.00000001f) { continue; } var pDeltaA = pTotalHeight - avgTotalHeight; var pMin = Mathf.Min(pDeltaA, pWater); if (configuration.DestinationFinder == HydraulicEroderWaterDestinationFinder.OnlyBest) { var bestNeighbour = neighbours.OrderByDescending(c => c.TotalHeightDifference).First(); var nMovedWater = pMin; var addedSediment = pSediment * (nMovedWater / pWater); waterAdditionMap.AddValue(bestNeighbour.Point, nMovedWater); sedimentAdditionMap.AddValue(bestNeighbour.Point, addedSediment); sedimentAdditionMap.AddValue(point, -addedSediment); waterAdditionMap.AddValue(point, -pMin); } else { var movedSedimentSum = 0f; foreach (var aNeighbour in neighbours) { var nMovedWater = pMin * (aNeighbour.TotalHeightDifference / dTotalHeightDiffSum); var addedSediment = pSediment * (nMovedWater / pWater); movedSedimentSum += addedSediment; waterAdditionMap.AddValue(aNeighbour.Point, nMovedWater); sedimentAdditionMap.AddValue(aNeighbour.Point, addedSediment); } sedimentAdditionMap.AddValue(point, -movedSedimentSum); waterAdditionMap.AddValue(point, -pMin); } } } for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var point = new IntVector2(x, y); waterMap.AddValue(point, waterAdditionMap.GetValue(point)); waterAdditionMap.SetValue(point, 0); sedimentMap.AddValue(point, sedimentAdditionMap.GetValue(point)); sedimentAdditionMap.SetValue(point, 0); } } for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var point = new IntVector2(x, y); var pWater = waterMap.GetValue(point); var waterAfterEvaporation = pWater * (1 - keParam); waterMap.SetValue(point, waterAfterEvaporation); var pSedimentMax = kcParam * waterAfterEvaporation; var pSediment = sedimentMap.GetValue(point); var deltaSediment = Mathf.Max(0, pSediment - pSedimentMax); sedimentMap.AddValue(point, -deltaSediment); heightMap.AddValue(point, deltaSediment); } } if (i % snapshotFrequencies == 0) { WaterSnapshots.Add(new SimpleHeightArray(MyArrayUtils.DeepClone <float>(waterMap.Array))); SedimentSnapshots.Add(new SimpleHeightArray(MyArrayUtils.DeepClone <float>(sedimentMap.Array))); } } if (finalSedimentationToGround) { for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var point = new IntVector2(x, y); heightMap.AddValue(point, sedimentMap.GetValue(point)); } } } return(new DebuggableHydraulicEroderOutput() { SedimentSnapshots = SedimentSnapshots, WaterSnapshots = WaterSnapshots }); }
public void Start_Hydraulic_Debuggable() { var heightTexture1 = SavingFileManager.LoadPngTextureFromFile(@"C:\inz\cont\smallCut.png", 240, 240, TextureFormat.RGBA32, true, true); var heightmap1 = HeightmapUtils.CreateHeightmapArrayFromTexture(heightTexture1); //DiamondSquareCreator creator = new DiamondSquareCreator(new RandomProvider(22)); //var heightmap2 = creator.CreateDiamondSquareNoiseArray(new IntVector2(240, 240), 64); //MyArrayUtils.Multiply(heightmap2.HeightmapAsArray, 0.1f); var tParam = EroderDebugObject.CalculateFromHillFactor(1, new ArrayExtremes(0, 5000), 24); var extents = MyArrayUtils.CalculateExtremes(heightmap1.HeightmapAsArray); MyArrayUtils.Normalize(heightmap1.HeightmapAsArray); var configuration = new HydraulicEroderConfiguration() { StepCount = 20, NeighbourFinder = NeighbourFinders.Big9Finder, kr_ConstantWaterAddition = 0.001f, ks_GroundToSedimentFactor = 1f, ke_WaterEvaporationFactor = 0.05f, kc_MaxSedimentationFactor = 0.8f, FinalSedimentationToGround = false, WaterGenerator = HydraulicEroderWaterGenerator.FirstFrame, DestinationFinder = HydraulicEroderWaterDestinationFinder.OnlyBest }; var copyArray = MyArrayUtils.DeepClone(heightmap1.HeightmapAsArray); var currentHeightArray = new SimpleHeightArray(copyArray); var eroder = new DebuggableHydraulicEroder(); var debuggingOutput = eroder.Erode(currentHeightArray, configuration, 1); var sedimentExtentsArr = debuggingOutput.SedimentSnapshots .Select(c => MyArrayUtils.CalculateExtremes(c.Array)).ToList(); var sedimentExtents = new ArrayExtremes(sedimentExtentsArr.Min(c => c.Min), sedimentExtentsArr.Max(c => c.Max)); debuggingOutput.SedimentSnapshots.ForEach(c => MyArrayUtils.Normalize(c.Array, sedimentExtents)); var waterExtentsArr = debuggingOutput.WaterSnapshots.Select(c => MyArrayUtils.CalculateExtremes(c.Array)) .ToList(); var waterExtents = new ArrayExtremes(waterExtentsArr.Min(c => c.Min), waterExtentsArr.Max(c => c.Max)); debuggingOutput.WaterSnapshots.ForEach(c => MyArrayUtils.Normalize(c.Array, waterExtents)); _go = GameObject.CreatePrimitive(PrimitiveType.Quad); var material = new Material(Shader.Find("Custom/Terrain/Terrain_Debug_Comparision_StepByStep")); _go.GetComponent <MeshRenderer>().material = material; _go.name = "Terrain"; _go.transform.localRotation = Quaternion.Euler(0, 0, 0); _go.transform.localScale = new Vector3(10, 1, 10); _go.transform.localPosition = new Vector3(0, 0, 0); _go.GetComponent <MeshFilter>().mesh = PlaneGenerator.CreateFlatPlaneMesh(240, 240); MyHeightTextureArray heightTextureArray = new MyHeightTextureArray(240, 240, 2, TextureFormat.ARGB32, false, true); heightTextureArray.AddElementArray(heightmap1, 0); heightTextureArray.AddElementArray(new HeightmapArray(currentHeightArray.Array), 1); _go.GetComponent <MeshRenderer>().material .SetTexture("_HeightmapTexArray", heightTextureArray.ApplyAndRetrive()); MyHeightTextureArray waterArray = new MyHeightTextureArray(240, 240, debuggingOutput.WaterSnapshots.Count, TextureFormat.ARGB32, false, true); int i = 0; foreach (var waterSnapshot in debuggingOutput.WaterSnapshots) { waterArray.AddElementArray(new HeightmapArray(waterSnapshot.Array), i); i++; } _go.GetComponent <MeshRenderer>().material.SetTexture("_WaterArray", waterArray.ApplyAndRetrive()); MyHeightTextureArray sedimentArray = new MyHeightTextureArray(240, 240, debuggingOutput.SedimentSnapshots.Count, TextureFormat.ARGB32, false, true); int j = 0; foreach (var sedimentSnapshot in debuggingOutput.SedimentSnapshots) { sedimentArray.AddElementArray(new HeightmapArray(sedimentSnapshot.Array), j); j++; } _go.GetComponent <MeshRenderer>().material.SetTexture("_SedimentArray", sedimentArray.ApplyAndRetrive()); }