- Home /
Procedural terrain generation issues
Hi guys, i am trying to get along with procedural generation, i definitely not a pro in unity, however i was following this guide: click and got some results. For now i have 2 problems, i have some basic idea how to resolve them, however i would like to hear some other opinions.
First of all: gaps between chunks:
they kinda disappear if i will zoom, however textures remain unfit and it is remarkable.
The second, as you can see i have a problem with red (i don't really know how to call it) marks on the ground. I ahve tried to use material from guide, but got same effect.
Besides, Perlin Noise ( i know that i can use Diamond square or simplex) is pseudo-random algorithm, so it will return the same values for the same input parametrs, so does it mean that my chunks will always be the same?
My code ( i am using LibNoise library from guide):
void Awake() { var settings = new TerrainChunkSettings(129, 129, 100, 40, FlatTexture, SteepTexture, TerrainMaterial); var noiseProvider = new NoiseProvider(); for (var i = 0; i < 4; i++) for (var j = 0; j < 4; j++) new TerrainChunk(settings, noiseProvider, i, j).CreateTerrain(); }
public class TerrainChunkSettings { public int HeightmapResolution { get; private set; } public int AlphamapResolution { get; private set; } public int Length { get; private set; } public int Height { get; private set; } public Texture2D FlatTexture { get; private set; } public Texture2D SteepTexture { get; private set; } public Material TerrainMaterial { get; private set; } public TerrainChunkSettings(int heightmapResolution, int alphamapResolution, int length, int height, Texture2D flatTexture, Texture2D steepTexture, Material terrainMaterial) { HeightmapResolution = heightmapResolution; AlphamapResolution = alphamapResolution; Length = length; Height = height; FlatTexture = flatTexture; SteepTexture = steepTexture; TerrainMaterial = terrainMaterial; } }
public class TerrainChunk { private Terrain Terrain { get; set; } private TerrainChunkSettings Settings { get; set; } private NoiseProvider NoiseProvider { get; set; } public int X { get; private set; } public int Z { get; private set; } private TerrainData Data { get; set; } private float[,] Heightmap { get; set; } public TerrainChunk(TerrainChunkSettings settings, NoiseProvider noiseProvider, int x, int z) { X = x; Z = z; Settings = settings; NoiseProvider = noiseProvider; } public void CreateTerrain() { var terrainData = new TerrainData(); terrainData.heightmapResolution = Settings.HeightmapResolution; terrainData.alphamapResolution = Settings.AlphamapResolution; var heightmap = GetHeightmap(); terrainData.SetHeights(0, 0, heightmap); ApplyTextures(terrainData); terrainData.size = new Vector3(Settings.Length, Settings.Height, Settings.Length); var newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData); newTerrainGameObject.transform.position = new Vector3(X * Settings.Length, 0, Z * Settings.Length); Terrain = newTerrainGameObject.GetComponent<Terrain>(); Terrain.Flush(); } private float[,] GetHeightmap() { var heightmap = new float[Settings.HeightmapResolution, Settings.HeightmapResolution]; for (var zRes = 0; zRes < Settings.HeightmapResolution; zRes++) { for (var xRes = 0; xRes < Settings.HeightmapResolution; xRes++) { var xCoordinate = X + (float)xRes / (Settings.HeightmapResolution - 1); var zCoordinate = Z + (float)zRes / (Settings.HeightmapResolution - 1); heightmap[zRes, xRes] = NoiseProvider.GetValue(xCoordinate, zCoordinate); } } return heightmap; } private void ApplyTextures(TerrainData terrainData) { var flatSplat = new SplatPrototype(); var steepSplat = new SplatPrototype(); flatSplat.texture = Settings.FlatTexture; steepSplat.texture = Settings.SteepTexture; terrainData.splatPrototypes = new SplatPrototype[] { flatSplat, steepSplat }; terrainData.RefreshPrototypes(); var splatMap = new float[terrainData.alphamapResolution, terrainData.alphamapResolution, 2]; for (var zRes = 0; zRes < terrainData.alphamapHeight; zRes++) { for (var xRes = 0; xRes < terrainData.alphamapWidth; xRes++) { var normalizedX = (float)xRes / (terrainData.alphamapWidth - 1); var normalizedZ = (float)zRes / (terrainData.alphamapHeight - 1); var steepness = terrainData.GetSteepness(normalizedX, normalizedZ); var steepnessNormalized = Mathf.Clamp(steepness / 1.5f, 0, 1f); splatMap[zRes, xRes, 0] = 1f - steepnessNormalized; splatMap[zRes, xRes, 1] = steepnessNormalized; } } terrainData.SetAlphamaps(0, 0, splatMap); } }
public interface INoiseProvider { float GetValue(float x, float z); } public class NoiseProvider : INoiseProvider { private Perlin PerlinNoiseGenerator; public NoiseProvider() { PerlinNoiseGenerator = new Perlin(); } public float GetValue(float x, float z) { return (float)(PerlinNoiseGenerator.GetValue(x, 0, z) / 2f) + 0.5f; } }