示例#1
0
    Color[,] GenerateMap(float scale)
    {
        var seamlessNoise = new SeamlessNoise(Random.Range(0, 50000), c_size, 1);

        var noiseMap = new Color[c_size, c_size];

        for (var y = 0; y < c_size; y++)
        {
            for (var x = 0; x < c_size; x++)
            {
                var alpha = seamlessNoise.Perlin(0, c_size / 8, x * scale, y * scale) * 0.5f + 0.5f;
                //var alpha = Mathf.PerlinNoise( x * scale, y * scale );

                noiseMap[y, x] = new Color(alpha, alpha, alpha, 1.0f);
            }
        }

        return(noiseMap);
    }
        public static List <float[, ]> makeTerrain(
            Texture2D elevation,
            float[,] noise,
            topologyOptions options
            )
        {
            if (elevation == null)
            {
                elevation = blacktexture(2049);
            }

            float[,] first = DiamondSquare.getFractal(elevation.width, options.seed);

            float[,] second = fadeEdges(2049, 1);

            float[,] biomes = SeamlessNoise.Generate(2048, 3);


            List <float[, ]> ret = new List <float[, ]>();

            float[,] map     = new float[first.GetLength(0), first.GetLength(1)];
            float[,] splat   = new float[first.GetLength(0), first.GetLength(1)];
            float[,] foliage = new float[first.GetLength(0), first.GetLength(1)];
            float[,] trees   = new float[first.GetLength(0), first.GetLength(1)];

            int size = first.GetLength(1);
            int y    = 0;

            while (y < size)
            {
                int x = 0;
                while (x < size)
                {
                    if (elevation.GetPixel(x, y).r > 0 && elevation.GetPixel(x, y).r < 1)
                    {
                        if (options.seaLevel < options.centerPoint + options.elevationHigh)
                        {
                            map [x, y] = options.elevationHigh - elevation.GetPixel(x, y).r / 20f;
                            if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                            {
                                map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                            }

                            splat [x, y] = 3;
                        }
                        else
                        {
                            map [x, y] = options.elevationHigh - elevation.GetPixel(x, y).r / 20f;
                            if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                            {
                                map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                            }
                            foliage [x, y] = noise [x, y] / 3f;
                            splat [x, y]   = 6;
                        }
                    }
                    else if (elevation.GetPixel(x, y).r >= 1.0f)
                    {
                        if (options.seaLevel < options.centerPoint + options.elevationHigh)
                        {
                            map [x, y] = options.elevationLow;
                            if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                            {
                                map [x, y] += noise [(int)x, (int)y] / options.coarseNoise;
                            }
                            splat [x, y] = 0;
                        }
                        else
                        {
                            map [x, y] = options.elevationLow;
                            if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                            {
                                map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                            }
                            splat [x, y]   = 6;
                            foliage [x, y] = noise [x, y] / 3f;
                        }
                    }
                    else if (elevation.GetPixel(x, y).r <= 0.0f)
                    {
                        if (options.island)
                        {
                            second [x, y] = Mathf.Pow(second [x, y], 3);
                            if (second [x, y] > 0.0 && second [x, y] < 1f)
                            {
                                map [x, y] = options.elevationHigh - second [x, y] / 20f;
                                if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                                {
                                    map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                                }
                                splat [x, y] = 3;
                            }
                            else if (second [x, y] >= 1f)
                            {
                                map [x, y] = options.elevationLow;
                                if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                                {
                                    map [x, y] += noise [(int)x, (int)y] / options.coarseNoise;
                                }
                                splat [x, y] = 0;
                            }
                            else
                            {
                                map [x, y] = options.elevationHigh;
                                if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                                {
                                    map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                                }
                                splat [x, y]   = 6;
                                foliage [x, y] = noise [x, y] / 3f;
                            }
                        }
                        else
                        {
                            map [x, y] = options.elevationHigh;
                            if (x > 0 && y > 0 && x < size - 1 && y < size - 1)
                            {
                                map [x, y] += noise [(int)x, (int)y] / options.flatNoise;
                            }
                            splat [x, y]   = 6;
                            foliage [x, y] = noise [x, y] / 3f;
                        }
                    }

                    float landscape = first[x, y] - second [x, y];

                    if (landscape < 0)
                    {
                        landscape = 0;
                    }
                    if (landscape > 0)
                    {
                        if (landscape > 0.2f)
                        {
                            map [x, y]    += landscape / 2 * (biomes [x, y] / 2) + noise [(int)x, (int)y] / options.coarseNoise;
                            foliage [x, y] = 2f / 3f + noise [x, y] / 3f;
                            splat [x, y]  += 2;
                        }
                        else
                        {
                            foliage [x, y] = 1f / 3f + noise [x, y] / 3f;
                            splat [x, y]  += 1;
                            map [x, y]    += landscape / 2 * (biomes [x, y] / 2) + noise [(int)x, (int)y] / options.flatNoise;
                        }
                    }
                    if (splat [x, y] == 6 && noise [x, y] > 0.5)
                    {
                        if (noise [x, y] > 0.7)
                        {
                            trees [x, y] = 1;
                        }
                        else
                        {
                            splat [x, y] = 9;
                        }
                    }

                    x++;
                }
                y++;
            }

            ret.Add(map);
            ret.Add(splat);
            ret.Add(foliage);
            ret.Add(trees);
            return(ret);
        }
    public float[,] Process(float[,] sourceElevation, float minimumElevation, float xyScaleToMeters, float zScaleToMeters, float rainWaterAmount, float sedimentCapacity, float gravityConstant, float frictionConstant, float evaporationConstant, float depositionConstant, float dissolvingConstant, float stepDeltaTime, int finalBlurRadius)
    {
        UnityEngine.Debug.Log("*** Hydraulic Erosion Process ***");

        UnityEngine.Debug.Log("Gravity constant = " + gravityConstant + " m/s^2");
        UnityEngine.Debug.Log("Rain Water Amount = " + rainWaterAmount + " m^3");

        var stopwatch = new Stopwatch();

        stopwatch.Start();

        var parallelOptions = new ParallelOptions()
        {
            MaxDegreeOfParallelism = -1
        };

        m_outputElevationWidth     = sourceElevation.GetLength(1);
        m_outputElevationHeight    = sourceElevation.GetLength(0);
        m_outputElevationWidthMask = m_outputElevationWidth - 1;

        // remember constants
        m_minimumElevation = minimumElevation * zScaleToMeters;
        m_xyScaleToMeters  = xyScaleToMeters;
        m_zScaleToMeters   = zScaleToMeters;
        m_rainWaterAmount  = rainWaterAmount;
        m_sedimentCapacity = sedimentCapacity;

        m_gravityConstant     = gravityConstant;
        m_frictionConstant    = 1.0f - (frictionConstant * stepDeltaTime);
        m_evaporationConstant = 1.0f - (evaporationConstant * stepDeltaTime);
        m_depositionConstant  = depositionConstant * stepDeltaTime;
        m_dissolvingConstant  = dissolvingConstant * stepDeltaTime;

        m_stepDeltaTime = stepDeltaTime;

        // allocate terrain level buffer
        m_outputElevation = new float[m_outputElevationHeight, m_outputElevationWidth];

        // initialize terrain level buffer
        for (var y = 0; y < m_outputElevationHeight; y++)
        {
            for (var x = 0; x < m_outputElevationWidth; x++)
            {
                m_outputElevation[y, x] = sourceElevation[y, x] * zScaleToMeters;
            }
        }

        UnityEngine.Debug.Log("Initialize Terrain Level - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // perlin noise for generating the twist buffer
        var noise = new SeamlessNoise(50, 256, 1);

        // allocate twist buffer
        m_twistBuffer = new int[m_outputElevationHeight, m_outputElevationWidth];

        // initialize twist buffer
        Parallel.For(0, m_outputElevationHeight, parallelOptions, y =>
        {
            for (var x = 0; x < m_outputElevationWidth; x++)
            {
                var sample = noise.Perlin(0, 256, x * 128.0f / m_outputElevationWidth, y * 64.0f / m_outputElevationHeight);

                m_twistBuffer[y, x] = Mathf.RoundToInt(sample * 31.0f);
            }
        });

        UnityEngine.Debug.Log("Generate Twist Buffer - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // allocate direction vector buffer
        m_directionVector = new Vector3[512];

        // initialize direction vector buffer
        for (int i = 0; i < 512; i++)
        {
            var angle = i * Mathf.PI * 2.0f / 512.0f;

            var x = Mathf.Sin(angle) * m_xyScaleToMeters;
            var y = Mathf.Cos(angle) * m_xyScaleToMeters;

            m_directionVector[i] = new Vector3(x, 0.0f, y);
        }

        UnityEngine.Debug.Log("Generate Direction Vectors - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // allocate, initialize, and shuffle random xy field
        var randomXYSize = m_outputElevationHeight / 2;

        var randomXYSizeSquared = randomXYSize * randomXYSize;

        var randomXY = new Vector2Int[randomXYSizeSquared];

        for (var y = 0; y < randomXYSize; y++)
        {
            for (var x = 0; x < randomXYSize; x++)
            {
                randomXY[y * randomXYSize + x] = new Vector2Int(x, y);
            }
        }

        Random.InitState(100);

        for (var i = 0; i < randomXYSizeSquared; i++)
        {
            int x = Random.Range(i, randomXYSizeSquared);

            var tmp = randomXY[i];

            randomXY[i] = randomXY[x];
            randomXY[x] = tmp;
        }

        UnityEngine.Debug.Log("Generate Random XY - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // do erosion steps
        var snapshotInterval = 2048;
        var snapshotSteps    = randomXYSizeSquared / snapshotInterval;

        for (var step = 0; step < snapshotSteps; step++)
        {
            // show progress bar
            if (EditorUtility.DisplayCancelableProgressBar("Planet Generator", "Making it rain...", (float)step / (snapshotSteps - 1)))
            {
                return(null);
            }

            var offset = step * snapshotInterval;

            Parallel.For(0, 8, parallelOptions, j =>
            {
                var dx = randomXYSize * (j % 4);
                var dy = randomXYSize * (j / 4);

                for (var i = 0; i < snapshotInterval; i++)
                {
                    var x = randomXY[i + offset].x + dx;
                    var y = randomXY[i + offset].y + dy;

                    var drop = new Drop(x, y, m_rainWaterAmount, 0.0f, Vector3.zero);

                    while (drop.Update())
                    {
                    }
                }
            });
        }

        UnityEngine.Debug.Log("Erosion Steps - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // remove original elevation and remove scale (prep for blur)
        var inverseScaleToMeters = 1.0f / m_zScaleToMeters;

        for (var y = 0; y < m_outputElevationHeight; y++)
        {
            for (var x = 0; x < m_outputElevationWidth; x++)
            {
                var newElevation = Mathf.Max(0.0f, m_outputElevation[y, x] * inverseScaleToMeters);

                var delta = newElevation - sourceElevation[y, x];

                m_outputElevation[y, x] = Mathf.Min(0.0f, delta);
            }
        }

        UnityEngine.Debug.Log("Convert to Height Deltas - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // pole smoothing
        for (var y = 0; y < m_outputElevationHeight; y++)
        {
            var p1 = m_outputElevationHeight * 0.1f;
            var p2 = m_outputElevationHeight * 0.2f;
            var p3 = m_outputElevationHeight * 0.8f;
            var p4 = m_outputElevationHeight * 0.9f;

            var poleMultiplier = Mathf.SmoothStep(0.0f, 1.0f, (y - p1) / (p2 - p1)) * Mathf.SmoothStep(1.0f, 0.0f, (y - p3) / (p4 - p3));

            for (var x = 0; x < m_outputElevationWidth; x++)
            {
                m_outputElevation[y, x] *= poleMultiplier;
            }
        }

        UnityEngine.Debug.Log("Pole Smoothing - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        stopwatch.Restart();

        // final blur to get rid of the jaggies in the delta heights
        var gaussianBlur = new PG_GaussianBlurElevation();

        m_outputElevation = gaussianBlur.Process(m_outputElevation, finalBlurRadius, finalBlurRadius);

        // put original elevation back in
        for (var y = 0; y < m_outputElevationHeight; y++)
        {
            for (var x = 0; x < m_outputElevationWidth; x++)
            {
                m_outputElevation[y, x] += sourceElevation[y, x];
            }
        }

        UnityEngine.Debug.Log("Final Blur - " + stopwatch.ElapsedMilliseconds + " milliseconds");

        // return the processed buffer
        return(m_outputElevation);
    }