Class BlueNoise

java.lang.Object
squidpony.squidmath.BlueNoise

public class BlueNoise
extends Object
Provides access to a precalculated, tiling plane of 2D blue noise, that is, noise without high-frequency components, as well as seeded modifications to that tiling blue noise plane that make it have even fewer patterns. Not actually a noise class like 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).
This uses 64x64 grayscale textures 0 through 63 from Christoph Peters' invaluable blue noise resource. It may use more of the textures from that site in the future.
Created by Tommy Ettinger on 10/15/2019.
  • Field Summary

    Fields 
    Modifier and Type Field Description
    static byte[][] ALT_NOISE
    Raw data this class uses, as 64 1D byte arrays.
    static GreasedRegion[] LEVELS
    A 256-element array of GreasedRegions, 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 GreasedRegion and other classes that can use 2D byte arrays.
    static byte[] RAW_NOISE
    The raw data this class uses, as a 1D byte array.
  • Method Summary

    Modifier and Type Method 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 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 void indexedBlueNoisePoint​(double[] dest, int index, double strength)
    Implements http://extremelearning.com.au/a-simple-method-to-construct-isotropic-quasirandom-blue-noise-point-sequences/ .

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • ALT_NOISE

      public static final byte[][] ALT_NOISE
      Raw data this class uses, as 64 1D byte arrays. 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. This group of byte arrays is static, which is probably OK even on Android as long as no one writes to it, and uses StandardCharsets to 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_NOISE

      public static final byte[] RAW_NOISE
      The raw data this class uses, as a 1D byte array. You probably don't want to use this field, but you might, so it is public... but don't write to it. It's static, which is probably OK even on Android as long as no one changes it, and uses StandardCharsets to decode itself from a String, which only works on GWT 2.8.2 and newer. This can be considered [x][y] indexed or [y][x] indexed; the original image was [y][x] indexed.
    • RAW_2D

      public static final byte[][] RAW_2D
      Stores the same values as RAW_NOISE if considered [x][y] indexed; available for convenient usage by GreasedRegion and other classes that can use 2D byte arrays.
    • LEVELS

      public static final GreasedRegion[] LEVELS
      A 256-element array of GreasedRegions, 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.
  • 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 cells
      y - 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 64x64x64 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. Blue noise at left, magnitude histogram at right.
      Parameters:
      x - x position, can be any int; results will repeat every 64 cells
      y - y position, can be any int; results will repeat every 64 cells
      z - z position, can be any int; results will repeat every 64 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 4096 bytes in length, treating it as an infinite 2D plane of tiling 64x64 regions. You probably want to get the noiseData from an element of ALT_NOISE.
      Parameters:
      x - x position, can be any int; results will repeat every 64 cells
      y - y position, can be any int; results will repeat every 64 cells
      noiseData - a byte array with minimum length 4096; probably from ALT_NOISE
      Returns:
      a byte that obeys a blue-noise distribution, so a value is only next to a similar value very rarely
    • getChosen

      public 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. Blue noise at left, magnitude histogram at right. 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!)
      This was changed somewhat on April 28, 2020 to a version with softer line artifacts that don't persist as long. It tends to look like it has less artifacts to human observers now, and about the same to signal processing. Upon closer inspection, it actually has many more line artifacts, but they are small, irregularly-spaced, and blend easily into their surroundings. This seems to be a tradeoff with this kind of blue noise. You can make an obvious grid of badly-stitched-together blue noise textures, and the frequencies will be good, but it will look terrible to humans; you could instead improve the appearance to humans by using just one blue noise texture, but that gets detected immediately by a computer as a pattern.
      Parameters:
      x - x position, can be any int; results will not repeat for a very long time
      y - y position, can be any int; results will not repeat for a very long time
      seed - seed value, can be any int; should be the same for all calls that should be from the same 2D plane
      Returns:
      a byte that obeys an almost-blue-noise distribution, so a value is only next to a similar value rarely
    • getSeeded

      public 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. 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. This chooses a sub-array from 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.
      Parameters:
      x - x position, can be any int; results will not repeat for a very long time
      y - y position, can be any int; results will not repeat for a very long time
      seed - seed value, can be any int; should be the same for all calls that should be from the same 2D plane
      Returns:
      a byte that obeys an almost-blue-noise distribution, so a value is only next to a similar value rarely
    • getSeeded

      public 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. 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. You probably want to get the noiseData from an element of ALT_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.
      Parameters:
      x - x position, can be any int; results will not repeat for a very long time
      y - y position, can be any int; results will not repeat for a very long time
      seed - seed value, can be any int; should be the same for all calls that should be from the same 2D plane
      noiseData - a byte array with minimum length 4096; probably from ALT_NOISE
      Returns:
      a byte that obeys an almost-blue-noise distribution, so a value is only next to a similar value rarely
    • blueSpill

      public 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.
      Parameters:
      width - the width of the 2D array to return
      height - the height of the 2D array to return
      spillerLimit - the upper exclusive bound for the values that will be present in toFill when this finishes
      rng - any IRNG to generate random values during expansion, such as RNG or GWTRNG
      Returns:
      a 2D int array containing ints from 0 (inclusive) to spillerLimit (exclusive)
    • blueSpill

      public 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.
      Parameters:
      toFill - a 2D int array that will be modified in-place and entirely replaced; its contents don't matter
      spillerLimit - the upper exclusive bound for the values that will be present in toFill when this finishes
      rng - any IRNG to generate random values during expansion, such as RNG or GWTRNG
      Returns:
      toFill, after modifications
    • indexedBlueNoisePoint

      public static void indexedBlueNoisePoint​(double[] dest, int index, double strength)
      Implements http://extremelearning.com.au/a-simple-method-to-construct-isotropic-quasirandom-blue-noise-point-sequences/ .
      Parameters:
      dest - will be modified and must have at least 2 length; the first element will store x, the second y
      index - which point to generate; must be non-negative
      strength - typically 1.0; can be smaller to produce less jitter and weaker blue-noise properties