public class BlueNoise
extends java.lang.Object
FastNoise
. The blue-noise distribution has the practical effect that a value
only appears next to a similar value very rarely. For a quick introduction, see
Alan Wolfe's blog, which has many more
useful posts and links that often relate to blue noise and its relatives, like low-discrepancy sequences (which
SquidLib calls quasi-random sequences, like VanDerCorputQRNG
).
TRI_NOISE
, and major edits on
Bart
Wronski's Numpy code to produce TILE_NOISE
and TILE_TRI_NOISE
.
Modifier and Type | Field and Description |
---|---|
static byte[][] |
ALT_NOISE
Raw data this class uses, as 64 1D byte arrays.
|
static GreasedRegion[] |
LEVELS
A 256-element array of
GreasedRegion s, each 64x64, where the first GreasedRegion has an impossibly strict
threshold on what points to include (it is empty), but the second has some points far apart, the third has more,
and so on until the last element includes almost all points. |
static byte[][] |
RAW_2D
Stores the same values as
RAW_NOISE if considered [x][y] indexed; available for convenient usage by
Region and other classes that can use 2D byte arrays. |
static byte[] |
RAW_NOISE
The raw data this class uses, as a 1D byte array.
|
static byte[][] |
TILE_NOISE
Raw data this class uses for omni-tiling blue noise, as 64 1D byte arrays.
|
static byte[][] |
TILE_TRI_NOISE
Raw data this class uses for omni-tiling triangular-mapped blue noise, as 64 1D byte arrays.
|
static byte[][] |
TRI_NOISE
Raw data this class uses for triangularly-distributed blue noise, as 64 1D byte arrays.
|
Modifier and Type | Method and Description |
---|---|
static int[][] |
blueSpill(int[][] toFill,
int spillerLimit,
IRNG rng)
Modifies
toFill in-place by filling it with the (seeded variant) blue noise of this class, finding any
points with values less than spillerLimit when brought into a 0-255 range, and then expanding those
points pseudo-randomly while keeping the same value for any expanded range as its original point. |
static int[][] |
blueSpill(int width,
int height,
int spillerLimit,
IRNG rng)
Generates a 2D int array (as with
new int[width][height] ) and fills it with the (seeded variant) blue
noise of this class, finding any points with values less than spillerLimit when brought into a 0-255
range, and then expanding those points pseudo-randomly while keeping the same value for any expanded range as its
original point. |
static byte |
get(int x,
int y)
Gets a byte from the raw data this stores, treating it as an infinite 2D plane of tiling 64x64 regions.
|
static byte |
get(int x,
int y,
byte[] noiseData)
Gets a byte from some raw data at least 4096 bytes in length, treating it as an infinite 2D plane of tiling 64x64
regions.
|
static byte |
get(int x,
int y,
int z)
Gets a byte from the raw data this stores, treating it as an infinite 3D space of tiling 64x64x64 regions.
|
static byte |
getChosen(int x,
int y,
int seed)
A mix of white noise and blue noise that has very few patterns detectable in frequency space, though it has some
artifacts detectable to the human eye.
|
static byte |
getChosen(int x,
int y,
int seed,
byte[][] noises)
A mix of white noise and blue noise that has very few patterns detectable in frequency space, though it has some
artifacts detectable to the human eye.
|
static byte |
getSeeded(int x,
int y,
int seed)
Gets a modified byte from the raw data this stores, using seed to adjust repeated sections of blue noise so
patterns are much less noticeable.
|
static byte |
getSeeded(int x,
int y,
int seed,
byte[] noiseData)
Gets a modified byte from some raw noise data in an array of at least 4096 bytes, using seed to adjust repeated
sections of noise so patterns are much less noticeable.
|
static byte |
getSeededOmniTiling(int x,
int y,
int seed)
Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 64x64 square of blue
noise is drawn from
TILE_NOISE . |
static byte |
getSeededTriangular(int x,
int y,
int seed)
Gets a modified byte from the triangular-mapped blue noise this stores in
TRI_NOISE , using seed to
adjust repeated sections of noise so patterns are much less noticeable. |
static byte |
getSeededTriOmniTiling(int x,
int y,
int seed)
Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 64x64 square of blue
noise is drawn from
TILE_TRI_NOISE (which is blue noise with a triangular mapping). |
static void |
indexedBlueNoisePoint(double[] dest,
int index,
double strength)
Implements this algorithm by Martin Roberts.
|
public static final byte[][] ALT_NOISE
get(int, int, byte[])
or getSeeded(int, int, int, byte[])
as their noiseData parameter. This
group of byte arrays is static, which is probably OK even on Android as long as no one writes to it, and
decodes itself from a String.
Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed.public static final byte[][] TRI_NOISE
get(int, int, byte[])
or getSeeded(int, int, int, byte[])
as their
noiseData parameter, which will make those methods produce a different, more centrally-biased distribution of
noise results. This group of byte arrays is static, which is probably OK even on Android as long as no one writes
to it, and decodes itself from a String.
Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed.public static final byte[][] TILE_NOISE
getSeededOmniTiling(int, int, int)
. Any of the 1D arrays this
holds can be passed to get(int, int, byte[])
or getSeeded(int, int, int, byte[])
as their
noiseData parameter, which will make get() produce noise in 64x64 tiling blocks and getSeeded() produce...
something. This group of byte arrays is static, which is probably OK even on Android as long as no one writes
to it, and decodes itself from a String.
Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed.
getSeededOmniTiling(int, int, int)
.public static final byte[][] TILE_TRI_NOISE
getSeededTriOmniTiling(int, int, int)
. Any of the 1D
arrays this holds can be passed to get(int, int, byte[])
or getSeeded(int, int, int, byte[])
as
their noiseData parameter, which will make get() produce noise in 64x64 tiling blocks and getSeeded() produce...
something. This group of byte arrays is static, which is probably OK even on Android as long as no one writes
to it, and decodes itself from a String.
Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed.
getSeededTriOmniTiling(int, int, int)
.public static final byte[] RAW_NOISE
public static final byte[][] RAW_2D
RAW_NOISE
if considered [x][y] indexed; available for convenient usage by
Region and other classes that can use 2D byte arrays.public static final GreasedRegion[] LEVELS
GreasedRegion
s, each 64x64, where the first GreasedRegion has an impossibly strict
threshold on what points to include (it is empty), but the second has some points far apart, the third has more,
and so on until the last element includes almost all points.public static byte get(int x, int y)
x
- x position, can be any int; results will repeat every 64 cellsy
- y position, can be any int; results will repeat every 64 cellspublic static byte get(int x, int y, int z)
x
- x position, can be any int; results will repeat every 64 cellsy
- y position, can be any int; results will repeat every 64 cellsz
- z position, can be any int; results will repeat every 64 cells, but this is different from x and ypublic static byte get(int x, int y, byte[] noiseData)
ALT_NOISE
or TRI_NOISE
.x
- x position, can be any int; results will repeat every 64 cellsy
- y position, can be any int; results will repeat every 64 cellsnoiseData
- a byte array with minimum length 4096; probably from ALT_NOISE
or TRI_NOISE
public static byte getChosen(int x, int y, int seed)
getSeededOmniTiling(int, int, int)
; it is better in every way. The rest of the
notes here are outdated.
getSeeded(int, int, int)
,
the "progressive" quality of the blue noise this uses is preserved better, meaning if you get the set of points
with values under or over a certain value, that set is still usually blue noise. (Keeping this quality is quite
hard for blue noise textures generated from combining existing tiles!)
x
- x position, can be any int; results will not repeat for a very long timey
- y position, can be any int; results will not repeat for a very long timeseed
- seed value, can be any int; should be the same for all calls that should be from the same 2D planepublic static byte getChosen(int x, int y, int seed, byte[][] noises)
getSeededOmniTiling(int, int, int)
; it is better in every way. The rest of the
notes here are outdated.
ALT_NOISE
or TRI_NOISE
to this
and it will be fine (unlike getSeeded(int, int, int, byte[])
). This works by choosing from one of four
nearby blue noise tiles and using it as-is, with the choice determined by an initial blue noise sample from a
non-tiling blue noise tile, weighted heavily based on how close a pixel is to a border between the four noise
tiles. Compared to getSeeded(int, int, int)
, the "progressive" quality of the blue noise this uses is
preserved better, meaning if you get the set of points with values under or over a certain value, that set is
still usually blue noise. (Keeping this quality is quite hard for blue noise textures generated from combining
existing tiles!)
x
- x position, can be any int; results will not repeat for a very long timey
- y position, can be any int; results will not repeat for a very long timeseed
- seed value, can be any int; should be the same for all calls that should be from the same 2D planenoises
- a 64-element (or longer) array of byte arrays, with each inner byte array 4096 or longer in length.
This is almost always ALT_NOISE
or TRI_NOISE
.public static byte getSeeded(int x, int y, int seed)
get(int, int)
, this won't repeat every 64 cells on x or y, but
it isn't as correct at matching blue-noise frequencies, and tends to look "scratchy" in places, like TV static.
getSeededOmniTiling(int, int, int)
; it is better in every way.
ALT_NOISE
based on the seed, and the same seed will use the same sub-array
in all locations. This tends to look less scratchy than getChosen(int, int, int)
, but has worse measured
repetitive qualities. The "progressive" quality of the blue noise this uses is not well-preserved, meaning if you
get the set of points with values under or over a certain value, that set doesn't usually resemble blue noise.
Blue noise at left, magnitude histogram at right.x
- x position, can be any int; results will not repeat for a very long timey
- y position, can be any int; results will not repeat for a very long timeseed
- seed value, can be any int; should be the same for all calls that should be from the same 2D planepublic static byte getSeeded(int x, int y, int seed, byte[] noiseData)
get(int, int)
, this won't repeat every 64
cells on x or y, but it isn't as correct at matching blue-noise frequencies, and tends to look "scratchy" in
places, like TV static.
getSeededOmniTiling(int, int, int)
; it is better in every way.
ALT_NOISE
or
TRI_NOISE
; unlike getSeeded(int, int, int)
, this won't choose a different byte array, and will
always use the given noiseData
. The "progressive" quality of the blue noise this uses is not
well-preserved, meaning if you get the set of points with values under or over a certain value, that set doesn't
usually resemble blue noise.x
- x position, can be any int; results will not repeat for a very long timey
- y position, can be any int; results will not repeat for a very long timeseed
- seed value, can be any int; should be the same for all calls that should be from the same 2D planenoiseData
- a byte array with minimum length 4096; probably from ALT_NOISE
or TRI_NOISE
public static byte getSeededTriangular(int x, int y, int seed)
TRI_NOISE
, using seed to
adjust repeated sections of noise so patterns are much less noticeable. Unlike get(int, int)
, this won't
repeat every 64 cells on x or y, but it isn't as correct at matching blue-noise frequencies, and tends to look
"scratchy" in places, like TV static.
getSeededTriOmniTiling(int, int, int)
; it is better in every way.
TRI_NOISE
based on the seed, and the same seed will use the same sub-array
in all locations. This tends to look less scratchy than getChosen(int, int, int)
, but has worse measured
repetitive qualities. The "progressive" quality of the blue noise this uses is not well-preserved, meaning if you
get the set of points with values under or over a certain value, that set doesn't usually resemble blue noise.
Blue noise at left, magnitude histogram at right. There is an odd
"patchwork" quality to the noise with the triangular mapping; it is not present when using
getChosen(int, int, int, byte[][])
with TRI_NOISE
as the last parameter.x
- x position, can be any int; results will not repeat for a very long timey
- y position, can be any int; results will not repeat for a very long timeseed
- seed value, can be any int; should be the same for all calls that should be from the same 2D planepublic static byte getSeededOmniTiling(int x, int y, int seed)
TILE_NOISE
. Because each square of TILE_NOISE can tile with any other from that
group, this can choose those squares randomly, and it does so using a simplistic hash based on Cantor's pairing
function. Unlike earlier attempts here to make aperiodic tilings of blue noise, this makes high-quality blue
noise that satisfies the progressive quality. Big thanks to Bart Wronski for making Ulichney's Void and Cluster
algorithm accessible to me!
x
- x coordinate, in grid cells, pixels, or some other fine-grained measurementy
- y coordinate, in grid cells, pixels, or some other fine-grained measurementseed
- only the low 18 bits will be usedpublic static byte getSeededTriOmniTiling(int x, int y, int seed)
TILE_TRI_NOISE
(which is blue noise with a triangular mapping). The triangular
mapping may improve the appearance of the blue noise when used for dithering or other smoothly-fading gradients.
Because each square of TILE_TRI_NOISE can tile with any other from that group, this can choose those squares
randomly, and it does so using a simplistic hash based on Cantor's pairing function. Unlike earlier attempts here
to make aperiodic tilings of blue noise, this makes high-quality blue noise that satisfies the progressive
quality. Big thanks to Bart Wronski for making Ulichney's Void and Cluster algorithm accessible to me!
x
- x coordinate, in grid cells, pixels, or some other fine-grained measurementy
- y coordinate, in grid cells, pixels, or some other fine-grained measurementseed
- only the low 18 bits will be usedpublic static int[][] blueSpill(int width, int height, int spillerLimit, IRNG rng)
new int[width][height]
) and fills it with the (seeded variant) blue
noise of this class, finding any points with values less than spillerLimit
when brought into a 0-255
range, and then expanding those points pseudo-randomly while keeping the same value for any expanded range as its
original point.width
- the width of the 2D array to returnheight
- the height of the 2D array to returnspillerLimit
- the upper exclusive bound for the values that will be present in toFill when this finishesrng
- any IRNG to generate random values during expansion, such as RNG
or GWTRNG
spillerLimit
(exclusive)public static int[][] blueSpill(int[][] toFill, int spillerLimit, IRNG rng)
toFill
in-place by filling it with the (seeded variant) blue noise of this class, finding any
points with values less than spillerLimit
when brought into a 0-255 range, and then expanding those
points pseudo-randomly while keeping the same value for any expanded range as its original point.toFill
- a 2D int array that will be modified in-place and entirely replaced; its contents don't matterspillerLimit
- the upper exclusive bound for the values that will be present in toFill when this finishesrng
- any IRNG to generate random values during expansion, such as RNG
or GWTRNG
toFill
, after modificationspublic static void indexedBlueNoisePoint(double[] dest, int index, double strength)
dest
- will be modified and must have at least 2 length; the first element will store x, the second yindex
- which point to generate; must be non-negativestrength
- typically 1.0; can be smaller to produce less jitter and weaker blue-noise propertiesCopyright © Eben Howard 2012–2022. All rights reserved.