From my understanding, the turbulence in Perlin noise is to accumulate Perlin noise of different frequencies with different weights. Based on this understanding, the return value of turbulences should have the same range of color (or pixel).
However, in some implementations (Ray Tracing: The Next Week) the range of turbulence doesn't match the range of [0, 1]
double turb(const point3& p, int depth=7) const {
auto accum = 0.0;
auto temp_p = p;
auto weight = 1.0;
for (int i = 0; i < depth; i++) {
accum += weight*noise(temp_p);
weight *= 0.5;
temp_p *= 2;
}
return fabs(accum);
}
The initial value of weight
is 1, and the range of noise
is [-1, 1]. So it is possible that after the first iteration, accum
became 1, and the following iterations could make it larger than 1.
I also read through the related part in the original paper, however, the pseudocode seems very similar:
function turbulence(p)
t = 0
scale = 1
while (scale > pixelsize)
t += abs(Noise(p / scale) * scale)
scale /= 2
return t
And it seems like the color representation in Perlin's original paper is also in the range of [0, 1] according to the the following line:
For example, one possible pixel for the variable list [red green blue] is [0.5 0.3 0.7].
So I'm wondering if the turbulence
function is designed this way because of the extremely low probability of returning a value that is out of range. Or am I missing something?
Also, the description of Noise()
function in the original paper is pretty confusing. Perlin didn't explicitly write about the range of the returning value. But he used it this way:
By evaluating Noise() at visible surface points of simulated objects we may create a simple "random" surface texture (figure Spotted.Donut) : color = white * Noise(point)
So I'm assuming it should be [0, 1] which make the expression white * Noise(point)
in the range of [0, 1]
However, an abs()
function is added in the turbulence
function.
The range of a noise function or a turbulence function (also called fractal noise) depends a lot of it's implementation and its usage. For instance, a value noise consist in interpolating between uniformly spaced random values of range [0, 1] so its range is [0, 1] too. On the other side, gradient noise consist in interpolating between linear functions passing through the origin so its range is [-a, a] (I guess its [-1, 1] but I'm not sure). If the range doesn't correspond the application, it can simply be remapped.
The implementation of fractal noise I am familiar with uses noises of range [0, 1] and consists in adding noises of frequency k*2^i
multiplied by 1/2^(i+1)
with i
starting at 0 so its range is [0, a<1].
Also, as you said, if the probability of exceeding a value is very small (which is the case here because noises tend to have a small standard deviation), it is not that much of a problem in graphical applications since the result gets clamped between 0 and 1 anyways.