private double perlin(double x, double y, double z)
{
if (repeat > 0)
{ // If we have any repeat on, change the coordinates to their "local" repetitions
x = x % repeat;
y = y % repeat;
z = z % repeat;
}
int xi = (int)x & 255; // Calculate the "unit cube" that the point asked will be located in
int yi = (int)y & 255; // The left bound is ( |_x_|,|_y_|,|_z_| ) and the right bound is that
int zi = (int)z & 255; // plus 1. Next we calculate the location (from 0.0 to 1.0) in that cube.
double xf = x - (int)x;
double yf = y - (int)y;
double zf = z - (int)z;
int aaa, aba, aab, abb, baa, bba, bab, bbb;
aaa = p[p[p[xi] + yi] + zi];
aba = p[p[p[xi] + inc(yi)] + zi];
aab = p[p[p[xi] + yi] + inc(zi)];
abb = p[p[p[xi] + inc(yi)] + inc(zi)];
baa = p[p[p[inc(xi)] + yi] + zi];
bba = p[p[p[inc(xi)] + inc(yi)] + zi];
bab = p[p[p[inc(xi)] + yi] + inc(zi)];
bbb = p[p[p[inc(xi)] + inc(yi)] + inc(zi)];
double u = Numbers.fade(xf);
double v = Numbers.fade(yf);
double w = Numbers.fade(zf);
double x1, x2, y1, y2;
x1 = Numbers.lerp(
Numbers.grad(aaa, xf, yf, zf), // The gradient function calculates the dot product between a pseudorandom
Numbers.grad(baa, xf - 1, yf, zf), // gradient vector and the vector from the input coordinate to the 8
u); // surrounding points in its unit cube.
x2 = Numbers.lerp(
Numbers.grad(aba, xf, yf - 1, zf), // This is all then lerped together as a sort of weighted average based on the faded (u,v,w)
Numbers.grad(bba, xf - 1, yf - 1, zf), // values we made earlier.
u);
y1 = Numbers.lerp(x1, x2, v);
x1 = Numbers.lerp(
Numbers.grad(aab, xf, yf, zf - 1),
Numbers.grad(bab, xf - 1, yf, zf - 1),
u);
x2 = Numbers.lerp(
Numbers.grad(abb, xf, yf - 1, zf - 1),
Numbers.grad(bbb, xf - 1, yf - 1, zf - 1),
u);
y2 = Numbers.lerp(x1, x2, v);
return (Numbers.lerp(y1, y2, w) + 1) / 2; // For convenience we bind the result to 0 - 1 (theoretical min/max before is [-1, 1])
}