private List <MaiNeighbour> GetNeighbours(SimpleHeightArray heightArray, IntVector2 center) { var heightArrayBoundaries = heightArray.Boundaries; var neighbours = new List <MaiNeighbour>() { new MaiNeighbour() { Position = center + new IntVector2(-1, 0), DirectionIndex = MaiNeighbourDirection.LEFT }, new MaiNeighbour() { Position = center + new IntVector2(1, 0), DirectionIndex = MaiNeighbourDirection.RIGHT }, new MaiNeighbour() { Position = center + new IntVector2(0, 1), DirectionIndex = MaiNeighbourDirection.UP }, new MaiNeighbour() { Position = center + new IntVector2(0, -1), DirectionIndex = MaiNeighbourDirection.DOWN }, }.Where(c => { return(heightArrayBoundaries.AreValidIndexes(c.Position)); }).ToList(); return(neighbours); }
public void ErodeOneStep() { var currentHeightArray = SimpleHeightArray.FromHeightmap(_currentHeightmap); var eroder = new ThermalEroder(); var extremes = new ArrayExtremes(1517, 6161); var tParam = CalculateFromHillFactor(1, extremes, 24); Debug.Log("TPAN IS " + tParam); eroder.Erode(currentHeightArray, new ThermalErosionConfiguration() { StepCount = 5, CParam = 0.3f, TParam = tParam }); var doneTexture = HeightmapUtils.CreateTextureFromHeightmap( SimpleHeightArray.ToHeightmap(currentHeightArray)); //_go.GetComponent<MeshRenderer>().material.SetTexture("_HeightmapTex0", _oldDoneTexture); _go.GetComponent <MeshRenderer>().material.SetTexture("_HeightmapTex1", doneTexture); _oldDoneTexture = doneTexture; }
public void Erode(SimpleHeightArray inHeightArray, ThermalErosionConfiguration configuration) { var tParam = configuration.TParam; var cParam = configuration.CParam; var stepCount = configuration.StepCount; var thermalErosionGroundMover = configuration.GroundMover; var neighbourChooser = configuration.NeighboursChooser; var finalDifferenceArray = new SimpleHeightArray(inHeightArray.Width, inHeightArray.Height); for (int stepIndex = 0; stepIndex < stepCount; stepIndex++) { Parallel.For <SimpleHeightArray>(0, inHeightArray.Height, new ParallelOptions { MaxDegreeOfParallelism = 4 }, () => new SimpleHeightArray(inHeightArray.Width, inHeightArray.Height), (y, loop, localDifferenceArray) => { // Parallel.For(0, inHeightArray.Height,new ParallelOptions { MaxDegreeOfParallelism = 3 }, y => // for (int y = 0; y < inHeightArray.Height; y++) // { for (int x = 0; x < inHeightArray.Width; x++) { var point = new IntVector2(x, y); var thisValue = inHeightArray.GetValue(point); var neighbours = configuration.NeighbourFinder.Find(inHeightArray, point) .Select(n => new NeighbourInfo(n, thisValue - inHeightArray.GetValue(n))).ToList(); neighbours = neighbours.Where(c => neighbourChooser.Choose(c, configuration)).ToList(); if (!neighbours.Any()) { continue; } var changeArray = localDifferenceArray; //changeArray = finalDifferenceArray; thermalErosionGroundMover.Move(neighbours, configuration, changeArray, point); } return(localDifferenceArray); }, (localDifferenceArray) => { finalDifferenceArray.SumValue(localDifferenceArray); }); for (int y = 0; y < inHeightArray.Height; y++) { for (int x = 0; x < inHeightArray.Width; x++) { var point = new IntVector2(x, y); inHeightArray.AddValue(point, finalDifferenceArray.GetValue(point)); finalDifferenceArray.SetValue(point, 0); } } } }
public void SumValue(SimpleHeightArray localDifferenceArray) { for (int x = 0; x < localDifferenceArray.Width; x++) { for (int y = 0; y < localDifferenceArray.Height; y++) { AddValue(new IntVector2(x, y), localDifferenceArray.GetValue(x, y)); } } }
private DebMapValues DebugGetMapValues(int x, int y, SimpleHeightArray waterMap, SimpleHeightArray waterMap1, SimpleHeightArray waterMap2, MySimpleArray <Vector4> fluxMap, MySimpleArray <Vector2> velocityMap, SimpleHeightArray sedimentMap, SimpleHeightArray sedimentMap1) { return(new DebMapValues() { waterMapVal = waterMap.GetValue(x, y), waterMap1Val = waterMap1.GetValue(x, y), waterMap2Val = waterMap2.GetValue(x, y), fluxMapVal = fluxMap.GetValue(x, y), velocityMapVal = velocityMap.GetValue(x, y), sedimentMapVal = sedimentMap.GetValue(x, y), sedimentMap1Val = sedimentMap1.GetValue(x, y) }); }
public List <HeightmapArray> GenerateErodedArrays(HeightmapArray baseArray, List <MeiHydraulicEroderConfiguration> configurations) { var msw = new MyStopWatch(); List <HeightmapArray> outArray = new List <HeightmapArray>(); int i = 0; foreach (var aConfiguration in configurations) { var copyArray = MyArrayUtils.DeepClone(baseArray.HeightmapAsArray); var currentHeightArray = new SimpleHeightArray(copyArray); msw.StartSegment("eroding-" + i); var eroder = new MeiHydraulicEroder(); eroder.Erode(currentHeightArray, aConfiguration); msw.StopSegment(); outArray.Add(SimpleHeightArray.ToHeightmap(currentHeightArray)); i++; } Debug.Log("T22: " + msw.CollectResults()); return(outArray); }
public void AtOnceErode(SimpleHeightArray inHeightArray, ThermalErosionConfiguration configuration) { var tParam = configuration.TParam; var cParam = configuration.CParam; var stepCount = configuration.StepCount; for (int stepIndex = 0; stepIndex < stepCount; stepIndex++) { for (int y = 0; y < inHeightArray.Height; y++) { for (int x = 0; x < inHeightArray.Width; x++) { var point = new IntVector2(x, y); var thisValue = inHeightArray.GetValue(point); var neighbours = configuration.NeighbourFinder.Find(inHeightArray, point).Select(n => new { point = n, difference = thisValue - inHeightArray.GetValue(n) }).ToList(); neighbours = neighbours.Where(c => c.difference > tParam).ToList(); if (!neighbours.Any()) { continue; } var dTotal = neighbours.Sum(c => c.difference); var dMax = neighbours.Max(c => c.difference); foreach (var aNeighbour in neighbours) { var movedGround = cParam * (dMax - tParam) * (aNeighbour.difference / dTotal); inHeightArray.AddValue(aNeighbour.point, movedGround); inHeightArray.AddValue(point, -movedGround); } } } } }
public TerrainErosionDebugOutput ErodeWithDebug(SimpleHeightArray heightMap, MeiHydraulicEroderConfiguration configuration) { var debugOutput = new TerrainErosionDebugOutput(); var sb = new StringBuilder(); int stepCount = configuration.StepCount; float deltaT = configuration.DeltaT; float constantWaterAdding = configuration.ConstantWaterAdding; float A_pipeCrossSection = configuration.A_PipeCrossSection; float l_pipeLength = configuration.L_PipeLength; float g_GravityAcceleration = configuration.GravityAcceleration; float ks_DissolvingConstant = configuration.DissolvingConstant; float kd_DepositionConstant = configuration.DepositionConstant; float ke_EvaporationConstant = configuration.EvaporationConstant; float kc_SedimentCapacityConstant = configuration.SedimentCapacityConstant; Vector2 gridSize = configuration.GridSize; float lX = gridSize.x; float lY = gridSize.y; var waterMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var waterMap_1 = new SimpleHeightArray(heightMap.Width, heightMap.Height); var waterMap_2 = new SimpleHeightArray(heightMap.Width, heightMap.Height); var fluxMap = new Vector4ArrayTODO(heightMap.Width, heightMap.Height); var velocityMap = new VectorArrayTODO(heightMap.Width, heightMap.Height); var sedimentMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var sedimentMap_1 = new SimpleHeightArray(heightMap.Width, heightMap.Height); for (int i = 0; i < stepCount; i++) { if (i >= 0) { // water increment for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); var oldValue = waterMap.GetValue(aPoint); var newAmount = oldValue + deltaT * constantWaterAdding; waterMap_1.SetValue(aPoint, newAmount); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); int yyy = 2; } } } } else { MyArrayUtils.Copy(waterMap.Array, waterMap_1.Array); } debugOutput.AddArray("waterMap", SimpleHeightArray.ToHeightmap(waterMap_1), i); debugOutput.AddArray("heightMap", SimpleHeightArray.ToHeightmap(heightMap), i); debugOutput.AddArray("sedimentMap", SimpleHeightArray.ToHeightmap(sedimentMap), i); var speedMap = new float[sedimentMap.Width, sedimentMap.Height]; for (int x = 0; x < sedimentMap.Width; x++) { for (int y = 0; y < sedimentMap.Height; y++) { speedMap[x, y] = velocityMap.GetValue(x, y).magnitude; } } debugOutput.AddArray("speedMap", new HeightmapArray(speedMap), i); // flow simulation int onesCount = 0; for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); Debug.Log("T44. W0: " + waterMap.GetValue(aPoint) + " w1: " + waterMap_1.GetValue(aPoint)); int yyy = 2; } Vector4 newFlux = Vector4.zero; var neighbours = GetNeighbours(heightMap, aPoint); foreach (var neighbour in neighbours) { var d_difference = (heightMap.GetValue(aPoint) + waterMap_1.GetValue(aPoint)) - (heightMap.GetValue(neighbour.Position) + waterMap_1.GetValue(neighbour.Position)); var d_flux = fluxMap.GetValue(aPoint)[(int)neighbour.DirectionIndex]; var d_new_flux = Mathf.Max(0, d_flux + deltaT * A_pipeCrossSection * (g_GravityAcceleration * d_difference) / l_pipeLength); Preconditions.Assert(!float.IsNaN(d_new_flux), ""); newFlux[(int)neighbour.DirectionIndex] = d_new_flux; } var aD1 = waterMap_1.GetValue(aPoint); var fluxSum = VectorUtils.SumMembers(newFlux); float K_factor = 0; if (fluxSum != 0) { K_factor = Mathf.Min(1, aD1 * (lX * lY) / (fluxSum * deltaT)); } if (K_factor > 0.99999) { onesCount++; } fluxMap.SetValue(aPoint, K_factor * newFlux); } } Debug.Log("t66: onesCount is " + onesCount); // velocity calculation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); int yyy = 2; } var neighbours = GetNeighbours(heightMap, aPoint); var outFlow = VectorUtils.SumMembers(fluxMap.GetValue(aPoint)); var inFlow = neighbours.Select(c => fluxMap.GetValue(c.Position)[(int)c.DirectionIndex.GetOpposite()]) .Sum(); var aChangeOfWater = deltaT * (inFlow - outFlow); waterMap_2.SetValue(aPoint, Mathf.Max(0, waterMap_1.GetValue(aPoint) + aChangeOfWater / (lX * lY))); var horizontalFlux = GetFlux(fluxMap, neighbours, MaiNeighbourDirection.LEFT, MaiNeighbourDirection.RIGHT) - fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.LEFT] + fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.RIGHT] - GetFlux(fluxMap, neighbours, MaiNeighbourDirection.RIGHT, MaiNeighbourDirection.LEFT); var deltaWx = horizontalFlux / 2; var verticalFlux = GetFlux(fluxMap, neighbours, MaiNeighbourDirection.DOWN, MaiNeighbourDirection.UP) - fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.DOWN] + fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.UP] - GetFlux(fluxMap, neighbours, MaiNeighbourDirection.UP, MaiNeighbourDirection.DOWN); var deltaWy = verticalFlux / 2; var avgHeight = (waterMap_1.GetValue(aPoint) + waterMap_2.GetValue(aPoint)) / 2; var newVelocity = new Vector2( (deltaWx / (lX * avgHeight)), (deltaWy / (lY * avgHeight)) ); if (float.IsNaN(newVelocity.magnitude)) { newVelocity = Vector2.zero; } velocityMap.SetValue(aPoint, newVelocity); //todo ograniczenie CFL } } var erodedAmountMap = new float[sedimentMap.Width, sedimentMap.Height]; var depositionAmountMap = new float[sedimentMap.Width, sedimentMap.Height]; // sediment calc for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); int yyy = 2; } var aHeight = heightMap.GetValue(aPoint); Vector3 upDir = new Vector3(0, 0, lY); if (y != heightMap.Height - 1) { var upHeight = heightMap.GetValue(aPoint + new IntVector2(0, 1)); upDir[1] = upHeight - aHeight; } Vector3 rightDir = new Vector3(lX, 0, 0); if (x != heightMap.Width - 1) { var rightHeight = heightMap.GetValue(aPoint + new IntVector2(1, 0)); rightDir[1] = rightHeight - aHeight; } var aNormal = Vector3.Cross(upDir, rightDir); var baseNormal = new Vector3(0, 1, 0); var cosAlpha = Vector3.Dot(baseNormal, aNormal) / (baseNormal.magnitude * aNormal.magnitude); var sinAlpha = Math.Sqrt(1 - cosAlpha * cosAlpha); //////// OTHER CALCULATING var _o_notmal = new Vector3( heightMap.GetValueWithZeroInMissing(y, x + 1) - heightMap.GetValueWithZeroInMissing(y, x - 1), heightMap.GetValueWithZeroInMissing(y + 1, x) - heightMap.GetValueWithZeroInMissing(y - 1, x), 2); var o_normal2 = _o_notmal.normalized; Vector3 up = new Vector3(0, 1, 0); float cosa = Vector3.Dot(o_normal2, up); float o_sinAlpha = Mathf.Sin(Mathf.Acos(cosa)); // todo kontrolne zwiększenie wody var capacity = kc_SedimentCapacityConstant * Mathf.Max(o_sinAlpha, 0.1f) * velocityMap.GetValue(aPoint).magnitude; //todo set minimum alpha var suspendedSediment = sedimentMap.GetValue(aPoint); erodedAmountMap[x, y] = 0; depositionAmountMap[x, y] = 0; if (capacity > suspendedSediment) { var sedimentChangeAmount = (float)(ks_DissolvingConstant * (capacity - suspendedSediment)); erodedAmountMap[x, y] = sedimentChangeAmount; heightMap.AddValue(aPoint, -sedimentChangeAmount); sedimentMap_1.AddValue(aPoint, sedimentChangeAmount); } else { var sedimentChangeAmount = (float)(kd_DepositionConstant * (suspendedSediment - capacity)); depositionAmountMap[x, y] = sedimentChangeAmount; heightMap.AddValue(aPoint, sedimentChangeAmount); // sedimentChangeAmount jest ujemna, więc dodajemy teren sedimentMap_1.AddValue(aPoint, -sedimentChangeAmount); } } } debugOutput.AddArray("erodedAmount", new HeightmapArray(erodedAmountMap), i); debugOutput.AddArray("depositedAmount", new HeightmapArray(depositionAmountMap), i); // sediment transportation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); int yyy = 2; } var velocity = velocityMap.GetValue(aPoint); sedimentMap.SetValue(aPoint, sedimentMap_1.GetValueWithIndexClamped(aPoint.ToFloatVec() - velocity * deltaT)); } } //evaporation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { var settings = DebugGetMapValues(x, y, waterMap, waterMap_1, waterMap_2, fluxMap, velocityMap, sedimentMap, sedimentMap_1); int yyy = 2; } waterMap.SetValue(aPoint, waterMap_2.GetValue(aPoint) * (1 - ke_EvaporationConstant * deltaT)); } } } //for (int y = 0; y < heightMap.Height; y++) //{ // for (int x = 0; x < heightMap.Width; x++) // { // var aPoint = new IntVector2(x,y); // heightMap.AddValue(aPoint, sedimentMap.GetValue(aPoint)); // } //} //Debug.Log("t23: " + sb.ToString()); return(debugOutput); }
public void Erode(SimpleHeightArray heightMap, MeiHydraulicEroderConfiguration configuration) { //int stepCount = configuration.StepCount; //float deltaT = configuration.DeltaT; //float constantWaterAdding = configuration.ConstantWaterAdding; //float A_pipeCrossSection = configuration.A_PipeCrossSection; //float l_pipeLength = configuration.L_PipeLength; //float g_GravityAcceleration = configuration.GravityAcceleration; //float ks_DissolvingConstant = configuration.DissolvingConstant; //float kd_DepositionConstant = configuration.DepositionConstant; //float ke_EvaporationConstant = configuration.EvaporationConstant; //float kc_SedimentCapacityConstant = configuration.SedimentCapacityConstant; //Vector2 gridSize = configuration.GridSize; int stepCount = configuration.StepCount; float deltaT = configuration.DeltaT; float constantWaterAdding = configuration.ConstantWaterAdding; float A_pipeCrossSection = configuration.A_PipeCrossSection; float l_pipeLength = configuration.L_PipeLength; float g_GravityAcceleration = configuration.GravityAcceleration; float ks_DissolvingConstant = configuration.DissolvingConstant; float kd_DepositionConstant = configuration.DepositionConstant; float ke_EvaporationConstant = configuration.EvaporationConstant; float kc_SedimentCapacityConstant = configuration.SedimentCapacityConstant; Vector2 gridSize = configuration.GridSize; float lX = gridSize.x; float lY = gridSize.y; var waterMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var waterMap_1 = new SimpleHeightArray(heightMap.Width, heightMap.Height); var waterMap_2 = new SimpleHeightArray(heightMap.Width, heightMap.Height); var fluxMap = new MySimpleArray <Vector4>(heightMap.Width, heightMap.Height); var velocityMap = new MySimpleArray <Vector2>(heightMap.Width, heightMap.Height); var sedimentMap = new SimpleHeightArray(heightMap.Width, heightMap.Height); var sedimentMap_1 = new SimpleHeightArray(heightMap.Width, heightMap.Height); for (int i = 0; i < stepCount; i++) { // water increment for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); waterMap_1.SetValue(aPoint, waterMap.GetValue(aPoint) + deltaT * constantWaterAdding); } } // flow simulation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { int yyy = 2; } Vector4 newFlux = Vector4.zero; var neighbours = GetNeighbours(heightMap, aPoint); foreach (var neighbour in neighbours) { var d_difference = (heightMap.GetValue(aPoint) + waterMap_1.GetValue(aPoint)) - (heightMap.GetValue(neighbour.Position) + waterMap_1.GetValue(neighbour.Position)); var d_flux = fluxMap.GetValue(aPoint)[(int)neighbour.DirectionIndex]; var d_new_flux = Mathf.Max(0, d_flux + deltaT * A_pipeCrossSection * (g_GravityAcceleration * d_difference) / l_pipeLength); newFlux[(int)neighbour.DirectionIndex] = d_new_flux; } var aD1 = waterMap_1.GetValue(aPoint); var K_factor = Mathf.Min(1, aD1 * (lX * lY) / ((newFlux[0] + newFlux[1] + newFlux[2] + newFlux[3]) * deltaT)); fluxMap.SetValue(aPoint, K_factor * newFlux); } } // velocity calculation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { int yyy = 2; } var neighbours = GetNeighbours(heightMap, aPoint); var outFlow = VectorUtils.SumMembers(fluxMap.GetValue(aPoint)); var inFlow = neighbours.Select(c => fluxMap.GetValue(c.Position)[(int)c.DirectionIndex.GetOpposite()]) .Sum(); var aChangeOfWater = deltaT * (inFlow - outFlow); waterMap_2.SetValue(aPoint, Mathf.Max(0, waterMap_1.GetValue(aPoint) + aChangeOfWater / (lX * lY))); var horizontalFlux = GetFlux(fluxMap, neighbours, MaiNeighbourDirection.LEFT, MaiNeighbourDirection.RIGHT) - fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.LEFT] + fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.RIGHT] - GetFlux(fluxMap, neighbours, MaiNeighbourDirection.RIGHT, MaiNeighbourDirection.LEFT); var deltaWx = horizontalFlux / 2; var verticalFlux = GetFlux(fluxMap, neighbours, MaiNeighbourDirection.DOWN, MaiNeighbourDirection.UP) - fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.DOWN] + fluxMap.GetValue(aPoint)[(int)MaiNeighbourDirection.UP] - GetFlux(fluxMap, neighbours, MaiNeighbourDirection.UP, MaiNeighbourDirection.DOWN); var deltaWy = verticalFlux / 2; var avgHeight = (waterMap_1.GetValue(aPoint) + waterMap_2.GetValue(aPoint)) / 2; var newVelocity = new Vector2( (deltaWx / (lX * avgHeight)), (deltaWy / (lY * avgHeight)) ); velocityMap.SetValue(aPoint, newVelocity); //todo ograniczenie CFL } } // sediment calc for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { int yyy = 2; } var aHeight = heightMap.GetValue(aPoint); Vector3 upDir = new Vector3(0, 0, lY); if (y != heightMap.Height - 1) { var upHeight = heightMap.GetValue(aPoint + new IntVector2(0, 1)); upDir[1] = upHeight - aHeight; } Vector3 rightDir = new Vector3(lX, 0, 0); if (x != heightMap.Width - 1) { var rightHeight = heightMap.GetValue(aPoint + new IntVector2(1, 0)); rightDir[1] = rightHeight - aHeight; } var aNormal = Vector3.Cross(upDir, rightDir); var baseNormal = new Vector3(0, 1, 0); var cosAlpha = Vector3.Dot(baseNormal, aNormal) / (baseNormal.magnitude * aNormal.magnitude); var sinAlpha = Math.Sqrt(1 - cosAlpha * cosAlpha); //////// OTHER CALCULATING var _o_notmal = new Vector3( heightMap.GetValueWithZeroInMissing(y, x + 1) - heightMap.GetValueWithZeroInMissing(y, x - 1), heightMap.GetValueWithZeroInMissing(y + 1, x) - heightMap.GetValueWithZeroInMissing(y - 1, x), 2); var o_normal2 = _o_notmal.normalized; Vector3 up = new Vector3(0, 1, 0); float cosa = Vector3.Dot(o_normal2, up); float o_sinAlpha = Mathf.Sin(Mathf.Acos(cosa)); // todo kontrolne zwiększenie wody var capacity = kc_SedimentCapacityConstant * sinAlpha * velocityMap.GetValue(aPoint).magnitude; //todo set minimum alpha var suspendedSediment = sedimentMap.GetValue(aPoint); if (capacity > suspendedSediment) { var sedimentChangeAmount = (float)(ks_DissolvingConstant * (capacity - suspendedSediment)); heightMap.AddValue(aPoint, -sedimentChangeAmount); sedimentMap_1.AddValue(aPoint, sedimentChangeAmount); } else { var sedimentChangeAmount = (float)(kd_DepositionConstant * (suspendedSediment - capacity)); heightMap.AddValue(aPoint, sedimentChangeAmount); // sedimentChangeAmount jest ujemna, więc dodajemy teren sedimentMap_1.AddValue(aPoint, -sedimentChangeAmount); } } } // sediment transportation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { int yyy = 2; } var velocity = velocityMap.GetValue(aPoint); sedimentMap.SetValue(aPoint, sedimentMap_1.GetValueWithIndexClamped(aPoint.ToFloatVec() - velocity * deltaT)); } } //evaporation for (int y = 0; y < heightMap.Height; y++) { for (int x = 0; x < heightMap.Width; x++) { var aPoint = new IntVector2(x, y); if (x == 10 && y == 10) { int yyy = 2; } waterMap.SetValue(aPoint, waterMap_2.GetValue(aPoint) * (1 - ke_EvaporationConstant * deltaT)); } } } //for (int y = 0; y < heightMap.Height; y++) //{ // for (int x = 0; x < heightMap.Width; x++) // { // var aPoint = new IntVector2(x,y); // heightMap.AddValue(aPoint, sedimentMap.GetValue(aPoint)); // } //} }
public List <IntVector2> Find(SimpleHeightArray inHeightArray, IntVector2 point) { return(_findFunc(inHeightArray, point)); }
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 Move(List <ThermalEroder.NeighbourInfo> neighbours, ThermalErosionConfiguration configuration, SimpleHeightArray outArray, IntVector2 point) { _func(neighbours, configuration, outArray, point); }
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()); }
public void Start_Mai_Debug() { 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); //HeightmapArray workingHeightmap = LoadHeightmapFromTextureFile(@"C:\inz\cont\temp3.png"); HeightmapArray workingHeightmap = heightmap1; MyArrayUtils.Normalize(workingHeightmap.HeightmapAsArray); MyArrayUtils.InvertNormalized(workingHeightmap.HeightmapAsArray); HeightmapArray originalMap = new HeightmapArray(MyArrayUtils.DeepClone(workingHeightmap.HeightmapAsArray)); MyArrayUtils.Multiply(workingHeightmap.HeightmapAsArray, 400); var configuration = new MeiHydraulicEroderConfiguration() { StepCount = 50, A_PipeCrossSection = 0.05f, ConstantWaterAdding = 1 / 64f, GravityAcceleration = 9.81f, DeltaT = 1f, DepositionConstant = 0.0001f * 12 * 2f, DissolvingConstant = 0.0001f * 12 * 2f, EvaporationConstant = 0.05f * 10, GridSize = new Vector2(1, 1), L_PipeLength = 1, SedimentCapacityConstant = 250 }; var eroder = new MeiHydraulicEroder(); var debOutput = eroder.ErodeWithDebug(SimpleHeightArray.FromHeightmap(workingHeightmap), configuration); MyArrayUtils.Multiply(workingHeightmap.HeightmapAsArray, 1f / 400); debOutput.NormalizeInGroups(); _go = GameObject.CreatePrimitive(PrimitiveType.Quad); var material = new Material(Shader.Find("Custom/Terrain/Terrain_Mei_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(originalMap, 0); heightTextureArray.AddElementArray(workingHeightmap, 1); _go.GetComponent <MeshRenderer>().material .SetTexture("_HeightmapTexArray", heightTextureArray.ApplyAndRetrive()); var arrayListsCount = debOutput.OneArrayListCount; var arrayListsLength = debOutput.OneArrayListLength; MyHeightTextureArray detailHeightTexturesArray = new MyHeightTextureArray(240, 240, arrayListsCount * arrayListsLength, TextureFormat.ARGB32, false, true); foreach (var snapshot in debOutput.ArraysDict.Values.SelectMany(c => c)) { detailHeightTexturesArray.AddElementArray(snapshot); } _go.GetComponent <MeshRenderer>().material .SetTexture("_DetailTexArray", detailHeightTexturesArray.ApplyAndRetrive()); _go.GetComponent <MeshRenderer>().material.SetFloat("_DetailTexLength", arrayListsLength); }
public static HeightmapArray ToHeightmap(SimpleHeightArray sourceArray) { return(new HeightmapArray(sourceArray._array)); }
public void Erode(SimpleHeightArray inHeightArray, ThermalErosionConfiguration configuration) { var tParam = configuration.TParam; var cParam = configuration.CParam; var stepCount = configuration.StepCount; var finalDifferenceArray = new SimpleHeightArray(inHeightArray.Width, inHeightArray.Height); for (int stepIndex = 0; stepIndex < stepCount; stepIndex++) { Parallel.For <SimpleHeightArray>(0, inHeightArray.Height, new ParallelOptions { MaxDegreeOfParallelism = 4 }, () => new SimpleHeightArray(inHeightArray.Width, inHeightArray.Height), (y, loop, localDifferenceArray) => { // Parallel.For(0, inHeightArray.Height,new ParallelOptions { MaxDegreeOfParallelism = 3 }, y => // for (int y = 0; y < inHeightArray.Height; y++) // { for (int x = 0; x < inHeightArray.Width; x++) { var point = new IntVector2(x, y); var thisValue = inHeightArray.GetValue(point); var neighbours = configuration.NeighbourFinder.Find(inHeightArray, point).Select(n => new { point = n, difference = thisValue - inHeightArray.GetValue(n) }).ToList(); neighbours = neighbours.Where(c => c.difference < tParam && c.difference > 0).ToList(); if (!neighbours.Any()) { continue; } var dTotal = neighbours.Sum(c => c.difference); var dMax = neighbours.Max(c => c.difference); foreach (var aNeighbour in neighbours) { var movedGround = cParam * (dMax) * (aNeighbour.difference / dTotal); //finalDifferenceArray.AddValue(aNeighbour.point, movedGround); //finalDifferenceArray.AddValue(point, -movedGround); localDifferenceArray.AddValue(aNeighbour.point, movedGround); localDifferenceArray.AddValue(point, -movedGround); } } return(localDifferenceArray); }, (localDifferenceArray) => { finalDifferenceArray.SumValue(localDifferenceArray); }); for (int y = 0; y < inHeightArray.Height; y++) { for (int x = 0; x < inHeightArray.Width; x++) { var point = new IntVector2(x, y); inHeightArray.AddValue(point, finalDifferenceArray.GetValue(point)); finalDifferenceArray.SetValue(point, 0); } } } }