java - Output range of Perlin noise -
i'm investigating few of various implementations coherent noise (i know there libraries, own edification , curiosity) , how can use it, , there's 1 problem have original perlin noise thing.
according this linked math faq, output range between -1
, 1
, don't understand how value gets in range.
as understand it, algorithm this: each grid point has associated random gradient vector of length 1
. then, each point, 4 surrounding grid points, calculate dot product of random gradient , vector going grid-point. use fancy ease curve , linear interpolation down 1 value.
but, here's problem: these dot-products are, occasionally, going outside range [-1, 1]
, , since linear interpolation between dot products, doesn't mean final value will, on occasion, outside range of [-1, 1]
?
say, instance, 1 of random vectors (sqrt(2)/2, sqrt(2)/2)
(which has length of 1) , (0.8, 0.8)
(which in unit square), result of 1.131
. if value used in linear interpolation, it's entirely possible value generated greater 1
. and, indeed, straight-forward implementation, happens quite frequently.
am missing here?
for reference, here's code in java. vec
simple class simple 2d vector arithmetic, fade()
ease curve, lerp()
linear interpolation, , gradient(x, y)
gives gradient grid-point vec
. gridsize
variable gives size of grid in pixels (it has type double):
public double getpoint(int x, int y) { vec p = new vec(x / gridsize, y / gridsize); vec d = new vec(math.floor(p.x), math.floor(p.y)); int x0 = (int)d.x, y0 = (int)d.x; double d00 = gradient(x0 , y0 ).dot(p.sub(x0 , y0 )), d01 = gradient(x0 , y0 + 1).dot(p.sub(x0 , y0 + 1)), d10 = gradient(x0 + 1, y0 ).dot(p.sub(x0 + 1, y0 )), d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1)); double fadex = fade(p.x - d.x), fadey = fade(p.y - d.y); double i1 = lerp(fadex, d00, d10), i2 = lerp(fadex, d01, d11); return lerp(fadey, i1, i2); }
edit: here's code generating random gradients:
double theta = gen.nextdouble() * 2 * math.pi; gradients[i] = new vec(math.cos(theta), math.sin(theta));
where gen
java.util.random
.
you have y0 = (int)d.x;
, mean d.y
. affect output range, , reason seeing such largely out-of-range values.
that said, output range of perlin noise not [-1, 1]. while i'm not quite sure of math myself (i must getting old), this rather lengthy discussion works out actual range [-sqrt(n)/2, sqrt(n)/2], n dimensionality (2 in case). output range of 2d perlin noise function should [-0.707, 0.707]. somehow related fact both d
, interpolation parameters function of p
. if read through discussion, may find precise explanation looking (particularly, post #7).
i testing implementation using following program (which hacked example, pardon weird use of gridcells
, gridsize
):
import java.util.random; public class perlin { static final int gridsize = 200; static final int gridcells = 20; static final vec[][] gradients = new vec[gridcells + 1][gridcells + 1]; static void initializegradient () { random rand = new random(); (int r = 0; r < gridcells + 1; ++ r) { (int c = 0; c < gridcells + 1; ++ c) { double theta = rand.nextfloat() * math.pi; gradients[c][r] = new vec(math.cos(theta), math.sin(theta)); } } } static class vec { double x; double y; vec (double x, double y) { this.x = x; this.y = y; } double dot (vec v) { return x * v.x + y * v.y; } vec sub (double x, double y) { return new vec(this.x - x, this.y - y); } } static double fade (double v) { // easing doesn't matter range sample test. // v = 3 * v * v - 2 * v * v * v; return v; } static double lerp (double p, double a, double b) { return (b - a) * p + a; } static vec gradient (int c, int r) { return gradients[c][r]; } // function, y0 fixed. note gridsize not double yours. public static double getpoint(int x, int y) { vec p = new vec(x / (double)gridsize, y / (double)gridsize); vec d = new vec(math.floor(p.x), math.floor(p.y)); int x0 = (int)d.x, y0 = (int)d.y; double d00 = gradient(x0 , y0 ).dot(p.sub(x0 , y0 )), d01 = gradient(x0 , y0 + 1).dot(p.sub(x0 , y0 + 1)), d10 = gradient(x0 + 1, y0 ).dot(p.sub(x0 + 1, y0 )), d11 = gradient(x0 + 1, y0 + 1).dot(p.sub(x0 + 1, y0 + 1)); double fadex = fade(p.x - d.x), fadey = fade(p.y - d.y); double i1 = lerp(fadex, d00, d10), i2 = lerp(fadex, d01, d11); return lerp(fadey, i1, i2); } public static void main (string[] args) { // loop forever, regenerating gradients , resampling range. while (true) { initializegradient(); double minz = 0, maxz = 0; (int x = 0; x < gridsize * gridcells; ++ x) { (int y = 0; y < gridsize * gridcells; ++ y) { double z = getpoint(x, y); if (z < minz) minz = z; else if (z > maxz) maxz = z; } } system.out.println(minz + " " + maxz); } } }
i seeing values within theoretical range of [-0.707, 0.707], although seeing values between -0.6 , 0.6; consequence of value distribution , low sampling rate.
Comments
Post a Comment