I generate terrains from heightmaps but results look "blocky".
It works if I sample the PerlinNoise
method for the grayscale value but not when I read it from a texture. Debugging shows a smooth output (0.0 - 1.0) with no shears. I have tried PNG and JPEG formats as well as normalized and remapped grayscale heightmaps.
public class TerrainTut : MonoBehaviour
{
[SerializeField] private Texture2D _heightmap;
private void Start()
{
Terrain t = GetComponent<Terrain>();
t.terrainData = GenerateTerrainData(t.terrainData);
}
private TerrainData GenerateTerrainData(TerrainData terrainData)
{
terrainData.SetHeights(0,0, GenerateHeights(terrainData.heightmapResolution));
return terrainData;
}
private float[,] GenerateHeights(int heightmapRes)
{
float[,] heights = new float[heightmapRes, heightmapRes];
for (int x = 0; x < heightmapRes; x++)
{
for (int y = 0; y < heightmapRes; y++)
{
//heights[x, y] = CalculateNoiseHeight(x, y, heightmapRes);//smooth?
heights[x, y] = CalculateTextureHeight(x, y, heightmapRes);//not smooth?
}
}
return heights;
}
private float CalculateNoiseHeight(int x, int y, int heightmapRes, float noiseScale = 20f)
{
float noiseX = ((float)x / heightmapRes) * noiseScale;
float noiseY = ((float)y / heightmapRes) * noiseScale;
return Mathf.PerlinNoise(noiseX, noiseY);
}
private float CalculateTextureHeight(int x, int y, int heightmapRes)
{
float noiseX = ((float)x / heightmapRes) * _heightmap.width;
float noiseY = ((float)y / heightmapRes) * _heightmap.height;
return _heightmap.GetPixel(x, y).grayscale;//tried using neighbour pixels but its the same
}
}
Terrain and heightmap:
You're picking exact colors from your height-map without blending them. GetPixel
jumps directly from one pixel's height to another.
Use GetPixelBilinear
(it blends or interpolates between pixels) and remove _heightmap.width
and _heightmap.height
because GetPixelBilinear
requires values in the range of 0 to 1 (like a percentage):
private float CalculateTextureHeight(int x, int y, int heightmapRes)
{
float noiseX = (float)x / heightmapRes;
float noiseY = (float)y / heightmapRes;
return _heightmap.GetPixelBilinear(noiseX, noiseY).grayscale;
}