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