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); }