Beispiel #1
0
        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);
                    }
                }
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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));
            //    }
            //}
        }
Beispiel #4
0
        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
            });
        }
Beispiel #5
0
        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);
                    }
                }
            }
        }