public void ApplyErosion() { if (TerrainInfo.GenerationType == GenerationType.kUpdating) { Debug.LogWarning("You are applying erosion in runtime. Switching to single mode"); TerrainInfo.GenerationType = GenerationType.kSingleRun; } switch (TerrainInfo.ErosionType) { case ErosionGeneration.ErosionType.kThermalErosion: TerrainInfo.HeightMap = ErosionGeneration.ThermalErosion(TerrainInfo); break; case ErosionGeneration.ErosionType.kHydraulicErosion: TerrainInfo.HeightMap = ErosionGeneration.HydraulicErosion(TerrainInfo); break; case ErosionGeneration.ErosionType.kImprovedErosion: TerrainInfo.HeightMap = ErosionGeneration.ImprovedThermalErosion(TerrainInfo); break; case ErosionGeneration.ErosionType.kNone: break; default: break; } InitializeTerrain(); GenerateTerrainAfterErosion(); }
public static float[,] GenerateTerrain(TerrainInfo info) { float[,] currentTerrain = new float[info.TerrainWidth, info.TerrainHeight]; // localScale is used when calculating how big the hills will be in the same area (highter the localScale, the more even the terrain) float localScale = info.NoiseScale <= 0 ? 0.0001f : info.NoiseScale; float minNoiseHeight = float.MaxValue; float maxNoiseHeight = float.MinValue; Vector2[] octaveOffsets = GenerateOctaveOffsets(info.Seed, info.NumberOfOctaves, info.UserOffset); // generate the terrain using perlin noise for (int y = 0; y < info.TerrainHeight; y++) { for (int x = 0; x < info.TerrainWidth; x++) { // the amplitude is used to generate hills of different heights, the higher the amplitude the bigger the hill float amplitude = 1.0f; // noiseHeight tells us the current height ranging from -1 to 1 float noiseHeight = 0.0f; float localFrequency = info.BaseFrequency; for (int i = 0; i < info.NumberOfOctaves; i++) { // when combining this with frequency we now control the number of big hills per area float nx = (float)(x - info.TerrainWidth / 2) / localScale * localFrequency + octaveOffsets[i].x; float ny = (float)(y - info.TerrainHeight / 2) / localScale * localFrequency + octaveOffsets[i].y; float perlinValue = GenerateTerrainPerlinNoise(nx, ny); // the current height value in our area noiseHeight += perlinValue * amplitude; // persistance controlles the amplitude, tells us how many big hills we actually have (smaller persistance less big hills) amplitude *= info.Persistance; // lacunarity controlls the frequency, tells us how many hills we have in an area (smaller lacunarity less dense hills) localFrequency *= info.Lacunarity; } if (maxNoiseHeight < noiseHeight) { maxNoiseHeight = noiseHeight; } else if (minNoiseHeight > noiseHeight) { minNoiseHeight = noiseHeight; } currentTerrain[x, y] = noiseHeight; } } // apply custom functions to the terrain heights for (int y = 0; y < info.TerrainHeight; y++) { for (int x = 0; x < info.TerrainWidth; x++) { float final_value = 0.0f; switch (info.CustomFunction) { case CustomFunctionType.kSin: final_value = Mathf.Pow(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]), Mathf.Sin(currentTerrain[x, y])); break; case CustomFunctionType.kCos: final_value = Mathf.Pow(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]), Mathf.Cos(currentTerrain[x, y])); break; case CustomFunctionType.kEps: final_value = Mathf.Pow(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]), Mathf.Epsilon); break; case CustomFunctionType.kCustom: final_value = Mathf.Pow(Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]), info.CustomExponent) + info.GlobalNoiseAddition; break; case CustomFunctionType.kNone: final_value = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]) + info.GlobalNoiseAddition; break; default: final_value = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, currentTerrain[x, y]) + info.GlobalNoiseAddition; break; } if (final_value > 1.0f) { final_value = 1.0f; } else if (final_value < 0.0f) { final_value = 0.0f; } currentTerrain[x, y] = final_value; } } // erode the terrain, this is currently in runtime if (info.RuntimeErosion) { switch (info.ErosionType) { case ErosionGeneration.ErosionType.kThermalErosion: ErosionGeneration.ThermalErosion(info); break; case ErosionGeneration.ErosionType.kHydraulicErosion: ErosionGeneration.ImprovedThermalErosion(info); break; case ErosionGeneration.ErosionType.kImprovedErosion: ErosionGeneration.HydraulicErosion(info); break; case ErosionGeneration.ErosionType.kNone: break; default: break; } } return(currentTerrain); }