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.
(I have already posted this question on Unity answers, however I have got no response at all, if there is some missing information or it is impossible to explain in a few words, please let me know or give some advice how to find this information)
The main issue is : 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 have 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 parameters, 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;
}
}