Package squidpony.squidmath
Class PhantomNoise
java.lang.Object
squidpony.squidmath.PhantomNoise
@Beta public class PhantomNoise extends Object
Arbitrary-dimensional continuous noise that maintains most of the same style even as the dimensionality gets fairly
high. If you know what dimension of noise you need, and it's covered by
The algorithm this uses is surprisingly simple. To produce N-D noise, it makes N+1 calls to N-D value noise, with each call using a different rotation of the same size of grid. It "domain warps" value noise calls after the first, adding the previous value noise result to one coordinate of the next value noise call. To get a PhantomNoise result, it averages all the value noise calls and curves the output range so it doesn't get more biased toward 0 with higher dimensions (which would happen with a pure average of a rising number of variables). The curving here uses adapted code from libGDX's Interpolation.Pow class; it looks like this for 2D, like this for 3D, and like this for 4D. There's some preparation this does in the constructor, which eliminates the need for allocations during noise generation. For N-D PhantomNoise, this makes N+1 double arrays, one for each rotation for a value noise call, and each rotation array has N items. The rotations match the vertices of an N-simplex, so a triangle in 2D, a tetrahedron in 3D, etc. It also stores two working-room arrays, each with N+1 double items, two frequently-edited int arrays of the floors of doubles it's using, and of modified versions of those floors to be hashed (each with N+1 items), and interestingly, a
At higher dimensions, Simplex noise (what
This is marked Beta because it's still pretty slow at higher dimensions, and if some optimization becomes available here, I'll take it and the output will change from this version.
FoamNoise
(meaning it's 2D, 3D, 4D,
or 6D noise), then using FoamNoise will give you a significantly faster version of approximately the same algorithm.
If your noise has an unknown dimension count, this won't really work either, since PhantomNoise needs to do some
preparation and allocation for a specific dimension in its constructor. But, if you know what the range of dimensions
is, and the lowest is at least 2D, you can make one PhantomNoise per dimension easily enough.
The algorithm this uses is surprisingly simple. To produce N-D noise, it makes N+1 calls to N-D value noise, with each call using a different rotation of the same size of grid. It "domain warps" value noise calls after the first, adding the previous value noise result to one coordinate of the next value noise call. To get a PhantomNoise result, it averages all the value noise calls and curves the output range so it doesn't get more biased toward 0 with higher dimensions (which would happen with a pure average of a rising number of variables). The curving here uses adapted code from libGDX's Interpolation.Pow class; it looks like this for 2D, like this for 3D, and like this for 4D. There's some preparation this does in the constructor, which eliminates the need for allocations during noise generation. For N-D PhantomNoise, this makes N+1 double arrays, one for each rotation for a value noise call, and each rotation array has N items. The rotations match the vertices of an N-simplex, so a triangle in 2D, a tetrahedron in 3D, etc. It also stores two working-room arrays, each with N+1 double items, two frequently-edited int arrays of the floors of doubles it's using, and of modified versions of those floors to be hashed (each with N+1 items), and interestingly, a
CrossHash.Yolk
hash functor, seeded in the PhantomNoise constructor.
At higher dimensions, Simplex noise (what
SeededNoise
produces) starts to change how it looks compared to
lower dimensions. PhantomNoise, on the other hand, maintains a fairly consistent blob-like organic look, such as
this 6D PhantomNoise sample. Red and purple mark the highest and lowest
possible values, respectively, and while they appear plenty in PhantomNoise, they are absent in
this 6D SeededNoise sample. There may be differences in how the inputs
are handled between the two samples, but 6D Simplex generally suffers from "the curse of dimensionality" more-so than
PhantomNoise (or Perlin noise like ClassicNoise
, somewhat surprisingly), with the "curse" affecting the
density of information in higher-dimensional space.
This is marked Beta because it's still pretty slow at higher dimensions, and if some optimization becomes available here, I'll take it and the output will change from this version.
-
Field Summary
Fields Modifier and Type Field Description int
dim
static double[][]
goldenDouble
static long[][]
goldenLong
static PhantomNoise
instance2D
static PhantomNoise
instance3D
static PhantomNoise
instance4D
static PhantomNoise
instance5D
static PhantomNoise
instance6D
static PhantomNoise
instance7D
static PhantomNoise
instance8D
-
Constructor Summary
Constructors Constructor Description PhantomNoise()
PhantomNoise(long seed, int dimension)
-
Method Summary
Modifier and Type Method Description double
getNoise(double... args)
double
getNoise2D(double x, double y)
protected double
valueNoise()
-
Field Details
-
Constructor Details
-
PhantomNoise
public PhantomNoise() -
PhantomNoise
-
-
Method Details