- Home /
Distribution of Unity perlin noise values
Hi,
I'm working on a procedural terrain generator and I'm (of course) using the integrated UnityEngine.Mathf.PerlinNoise() method as a basis. For various reasons I wanted to know more about the value distribution and after some experiments (like generating a texture and analyzing its histogram in GIMP or writing a script that dumps 1000 values from random parts of the noise map into a text file) it occured to me that the noise distribution is kinda weird. It doesn't follow the usual generic Perlin distribution of a plateau with sloped sides, it looks more like a Normal distribution with several peaks placed symmetrically around the center.
But that isn't the worst thing (actually I'd say that makes it slightly better, if anything). I first noticed it in the GIMP histogram, but I thought it's just an artifact of how I used a screenshot of the generated noise and put that into GIMP. But no, even when I used the script and put the data into excell (well, LibreOffice Calc, but I don't think that really matters here), it's still there - the noise seems to generate assymetrically, with bias towards lower values.
This is the code I used to generate the data (it's in the Start() method of a script I added to the terrain generator object), output size is 1000:
noise = new float[outputSize];
for (int i = 0; i < outputSize; i++)
{
float x = Random.Range(-1000f, 1000f);
float y = Random.Range(-1000f, 1000f);
noise[i] = Mathf.PerlinNoise(x, y);
}
// Output noise into a file
foreach (float value in noise)
{
output += value.ToString();
output += ";\n";
}
File.WriteAllText("noiseData.txt", output);
Debug.Log("Noise data written to " + Directory.GetCurrentDirectory());
And this is the distribution after I copy-pasted the data from 3 different attempts (the first two have a range of sampling location -10000 to 10000, the third one just -1000 to 1000) into a table, sorted from lowest to highest and made a point graph:
As you can see there's very little difference between the three runs and all of them have more values below 0.5 than above. What's more, there are no values above 1 (or even really close to it), which contradicts the common knowledge that the values can get both below 0 and above 1 in some rare cases.
So my question is: Does anyone know more about this? Is this some mistake in my code, my analysis, or is this a real thing about the Unity noise generation that nobody really cares / knows about? And more importantly, what is the actual range of the noise? Does anyone know?
Update:
Inspired by Eno-Khaon's reply I slightly rewrote the code to input only integers into the PerlinNoise mehod, which should in theory always generate the median value of the noise (so 0.5 for [0..1] range noise, like the theoretical "perfect" Unity noise or zero for [-1..1] implemetations). The rest of the code stayed the same and voila! All of the generated values are indeed the same. What were they, you ask?
Turns out the median value that I'm generating is 0.4652731, so about 0.0347269 below the 0.5 that it should be.
Just to be sure that the noise doesn't repeat every 1 unit (like Eno-Khaon suggested) I added 0.5 to each randomized integer coordinate. And while it doesn't repeat the same value every time, there seems to be a certain set of values that are repeated in random intervals. My guess is this has to do with the gradient vectors not being completely random, but chosen from a certain set which a common optimisation of Perlin noise. Obviously choosing just values from Int+0.5 coordinates isn't the best way to generate noise maps.
I went a step further and counted the number of instances of each value, here's the data and an actual distribution graph:
You can see that the most common value is the "median" one (though it's not really a median) with a small area of symmetry around the peak and then again, slightly more values towards the lower end of the range than towards the higher end. (Even after adding the 0.0347269 offset from above, there are only seven values higher than 1. They are all 1.0057316)
So that's it from me, I think it would really help if someone else tried to replicate these results to see if there's some mistake on my side or if the Unity noise is just that weird. At least now I have a better idea about the values the noise can return and their frequency.
Answer by Eno-Khaon · May 27 at 05:41 PM
Unity's Perlin Noise implementation Math.PerlinNoise(float, float) repeats every 1.0 unit. If you feed in integers, you'll always get the same value as output.
In other words, your [-1000f to 1000f] noise input range repeats the same numeric output 2000 times (per axis), while losing relative accuracy the closer you get to each extent of that input range.
I'm not sure I understand your point.
The noise doesn't repeat every unit, it just has a baseline value (0.5 for Unity noise, at least theoretically, and 0 for implementations with [-1..1] output range - actually that gives me an idea for another test...) at integer coordinates, but that's common for all Perlin noise implementations. And yes, that means that mid-range values will be more common, but that's kinda the point of normal (and some others too) distribution.
Also I'm not sure what you mean by losing realtive accuracy? Are you talking about floating point precision errors? I really don't think those are significant at this scale.
By the way, 1 unit on the noise map is the average size of a "blob". If that was all there is, that would make for a very small noise map.
Anyway, thanks for the answer, at least it gave me an idea for the next test (which exact values it spits out if I only feed it integers). I will update this thread afterwards.
Your answer
Follow this Question
Related Questions
How To Add Fallof to perlin? 0 Answers
How can i make this noise generated terrain more interesting? 1 Answer
How to use Perlin Noise for waves 0 Answers
Understanding how infinite terrain works 0 Answers
How to scale perlin noise 2 Answers