I am trying to generate terrain with discrete height levels using Unity's built in 2D Perlin noise function. The output is a float in [0,1]. I then scale the float linearly to a range [minimum Height, Maximum Height], and round it to the nearest integer.
The problem is that this results in artifacts at rounding boundaries, as can be seen in the following image:
As you can see, the ridge line partially marked in red should not be there. It is created because that's the rounding boundary, meaning that this is the line between x.49 and x.50 (x is integer), so the x.49 is rounded to x, while the x.50 is rounded to x+1.
I'll demonstrate that by zooming to a part of the image and showing the height value of different blocks:
The height of Block 1 is 14.48
The height of Block 2 is 14.52
The height of Block 3 is 15.6
The height of Block 4 is 14.6
As you can see, the only reason there is a ridge between Block 1 and Block 2, is because 1's height is rounded to 14, while 2's height is rounded to 15. This is unlike Blocks 3 and 4, which should have an elevation difference between them as per the Perlin noise function.
I can of course use Floor or Ceil or other methods to turn the float result from the Perlin Noise function into an integer, but that simply results in artifact lines appearing at other places.
Any help in solving this issue would be greatly appreciated.
Thank you.
Edit:
Here is how I get the height of each column:
float grassHeightFloat = WorldGenMath.getNoise(x + grassHeightRandOffSet, z + grassHeightRandOffSet,
grassSmoothness, grassMinHeight, grassMaxHeight)
uint grassHeight = Convert.ToUInt32(grassHeightFloat);
WorldGenMath is:
private static float scaleNoise(float value, float minScale, float maxScale)
{
return scale(value, 0, 1, minScale, maxScale);
}
private static float scale(float value, float min, float max, float minScale, float maxScale)
{
float scaled = minScale + (float)(value - min) / (max - min) * (maxScale - minScale);
return scaled;
}
public static float getNoise(uint x, uint z, float smoothFactor, int minScale, int maxScale)
{
float noise = Mathf.PerlinNoise(x * smoothFactor, z * smoothFactor);
return scaleNoise(noise, minScale, maxScale);
}
public static float getNoise(long x, long z, float smoothFactor, int minScale, int maxScale) {
return getNoise(Convert.ToUInt32(x), Convert.ToUInt32(z), smoothFactor, minScale, maxScale);
}