Class BlueNoise
java.lang.Object
com.github.yellowstonegames.grid.BlueNoise
Provides access to precalculated tiling planes of 2D blue noise, that is, noise without high-frequency components,
as well as seeded mixes of different blue noise planes that make it have even fewer patterns. This doesn't
produce continuous noise such as Perlin or Simplex noise, instead producing noise in the signal-to-noise sense. 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 (also called quasi-random sequences, QRNGs, or sub-random sequences).
This uses 64x64 blue noise textures generated by a "test" in SquidSquad, using code adapted from Bart Wronski's Colab notebook in Python. The big contribution here is that all the textures generated can seamlessly tile with each other, as if they were meant to tile with the other tile, for any of the 64 tiles. I call this "omni-tiling" because unlike a Wang tiling, which only permits half or fewer of tiles to match a particular edge, all the tiles can appear to be seamless when laid out in a grid, even when randomly selected. Normally, just placing blue noise textures next to each other produces clear seams or "breaks" in the blue noise, so this is a nice thing to have.
Big thanks to Bart Wronski for making Ulichney's Void and Cluster algorithm accessible to me, and Alan Wolfe for helping me understand how useful blue noise is in the first place!
This uses 64x64 blue noise textures generated by a "test" in SquidSquad, using code adapted from Bart Wronski's Colab notebook in Python. The big contribution here is that all the textures generated can seamlessly tile with each other, as if they were meant to tile with the other tile, for any of the 64 tiles. I call this "omni-tiling" because unlike a Wang tiling, which only permits half or fewer of tiles to match a particular edge, all the tiles can appear to be seamless when laid out in a grid, even when randomly selected. Normally, just placing blue noise textures next to each other produces clear seams or "breaks" in the blue noise, so this is a nice thing to have.
Big thanks to Bart Wronski for making Ulichney's Void and Cluster algorithm accessible to me, and Alan Wolfe for helping me understand how useful blue noise is in the first place!
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final byte[][]Stores the same values as the first element inTILE_NOISEif considered [x][y] indexed; available for convenient usage by code that uses 2D byte arrays.static final byte[][]Raw data this class uses for omni-tiling blue noise, as 32 1D byte arrays.static final byte[][]Raw data this class uses for omni-tiling triangular-mapped blue noise, as 32 1D byte arrays. -
Method Summary
Modifier and TypeMethodDescriptionstatic intfullHash(int x, int y) Gets a unique int hash code given x and y that are validshortnumbers, or a likely-unique hash if they are larger thanshort.static byteget(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 byteget(int x, int y, byte[] noiseData) Gets a byte from some raw data at least 16384 bytes in length, treating it as an infinite 2D plane of tiling 128x128 regions.static byteget(int x, int y, int z) Gets a byte from the raw data this stores, treating it as an infinite 3D space of tiling 128x128x32 regions.static bytegetSeeded(int x, int y, int seed) Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 128x128 square of blue noise is drawn fromTILE_NOISE.static bytegetSeededTriangular(int x, int y, int seed) Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 128x128 square of blue noise is drawn fromTILE_TRI_NOISE(which is blue noise with a triangular mapping).
-
Field Details
-
TILE_NOISE
public static final byte[][] TILE_NOISERaw data this class uses for omni-tiling blue noise, as 32 1D byte arrays. The omni-tiling property here means that you can place any of the 1D arrays here in a grid with any other 1D array from here next to it, and no seam will be visible. This is used bygetSeeded(int, int, int). This group of byte arrays is static, which is probably OK even on Android as long as no one writes to it, and usesStandardCharsetsto decode itself from a String, which only works on GWT 2.8.2 and newer (current version used by libGDX is 2.11.0). Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed. -
TILE_TRI_NOISE
public static final byte[][] TILE_TRI_NOISERaw data this class uses for omni-tiling triangular-mapped blue noise, as 32 1D byte arrays. The omni-tiling property here means that you can place any of the 1D arrays here in a grid with any other 1D array from here next to it, and no seam will be visible. This is used bygetSeededTriangular(int, int, int). This group of byte arrays is static, which is probably OK even on Android as long as no one writes to it, and usesStandardCharsetsto decode itself from a String, which only works on GWT 2.8.2 and newer. Each byte array can be considered [x][y] indexed or [y][x] indexed; the original images were [y][x] indexed. -
RAW_2D
public static final byte[][] RAW_2DStores the same values as the first element inTILE_NOISEif considered [x][y] indexed; available for convenient usage by code that uses 2D byte arrays.
-
-
Method Details
-
get
public 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. You can interpret the blue noise in many ways, but it is meant to be used with a threshold to select mostly widely-spaced points when the threshold requires values greater than 100 or less than -100, or irregularly-shaped patterns of points when the threshold is in the middle, like for values less than 0. This tiles extremely well, or at least it appears so for a human; computers can detect the repetitive nature of this blue noise quite easily. Blue noise at left, magnitude histogram at right.- Parameters:
x- x position, can be any int; results will repeat every 64 cellsy- y position, can be any int; results will repeat every 64 cells- Returns:
- a byte that obeys a blue-noise distribution, so a value is only next to a similar value very rarely
-
get
public 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 128x128x32 regions. You can interpret the blue noise in many ways, but it is meant to be used with a threshold to select mostly widely-spaced points when the threshold requires values greater than 100 or less than -100, or irregularly-shaped patterns of points when the threshold is in the middle, like for values less than 0. This tiles extremely well, or at least it appears so for a human; computers can detect the repetitive nature of this blue noise quite easily. The blue noise property is only really preserved for slices of noise with the same z; changing z can be used to select a 2D noise plane as well.
This uses any and all elements ofTILE_NOISE, so it has a uniform blue noise distribution.- Parameters:
x- x position, can be any int; results will repeat every 128 cellsy- y position, can be any int; results will repeat every 128 cellsz- z position, can be any int; results will repeat every 32 cells, but this is different from x and y- Returns:
- a byte that obeys a blue-noise distribution, so a value is only next to a similar value very rarely
-
get
public static byte get(int x, int y, byte[] noiseData) Gets a byte from some raw data at least 16384 bytes in length, treating it as an infinite 2D plane of tiling 128x128 regions. Most usage gets the noiseData from an element ofTILE_NOISEorTILE_TRI_NOISE.- Parameters:
x- x position, can be any int; results will repeat every 128 cellsy- y position, can be any int; results will repeat every 128 cellsnoiseData- a byte array with length 16384; probably fromTILE_NOISEorTILE_TRI_NOISE- Returns:
- a byte drawn from noiseData by treating it as a 128x128 grid, with x in the least significant 7 bits
-
getSeeded
public static byte getSeeded(int x, int y, int seed) Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 128x128 square of blue noise is drawn fromTILE_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 (and fast) hash based on the Rosenberg-Strong pairing function. Unlike earlier attempts here to make aperiodic tilings of blue noise, this makes high-quality blue noise that satisfies the progressive quality. This also tolerates both positive and negative inputs for x and y.
Blue noise at left, magnitude histogram at right.- Parameters:
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 25 bits will be used, so this should probably be between 0 and 33554431- Returns:
- a byte obeying a blue noise distribution
-
getSeededTriangular
public static byte getSeededTriangular(int x, int y, int seed) Gets a point in a potentially-infinite aperiodically-tiling plane of blue noise, where each 128x128 square of blue noise is drawn fromTILE_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 (and fast) hash based on the Rosenberg-Strong pairing function. Unlike earlier attempts here to make aperiodic tilings of blue noise, this makes high-quality blue noise that satisfies the progressive quality. This also tolerates both positive and negative inputs for x and y.
Blue noise at left, magnitude histogram at right.- Parameters:
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 25 bits will be used, so this should probably be between 0 and 33554431- Returns:
- a byte obeying a triangular-mapped blue noise distribution
-
fullHash
public static int fullHash(int x, int y) Gets a unique int hash code given x and y that are validshortnumbers, or a likely-unique hash if they are larger thanshort. Uses the Rosenberg-Strong pairing function, with inputs masked so it produces different values for(x,y),(-x,y),(x,-y), and(-x,-y).- Parameters:
x- ideally in the range -32768 to 32767y- ideally in the range -32768 to 32767- Returns:
- an int that combines the arguments to make a unique result for x and y in the ideal range
-