예제 #1
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);
        }