Uniformly Distributed Perlin Noise

Problem

Processing’s noise implementation has many issues:

  • Repeats after a very small cycle in the x and y axes.
  • Strange repeating motion in z axis.
  • Block-like pattern/artefacts
  • Normally distributed (bell-curve distribution). Sometimes this is good, but I’d say this is generally undesirable in creative coding, and particularly undesirable for color generation (as exemplified below).

Solution

To mainly solve the fourth point, I created a small library that outputs noise values that are uniformly distributed between [ 0, 1 ]. In most of my use-cases (in creative coding and elsewhere) this distribution is much more desirable. Not only that, the library wraps FastNoiseLite providing “much better quality” noise compared the abysmal offering in Processing.

Comparison

Images showing Processing’s noise() on the left verrsus UniformNoise on the right.

Octaves = 1

Octaves = 4

Octaves = 16

Small scale, octaves = 4

Sketch Code

Code...
import micycle.uniformnoise.*;

UniformNoise noise;

int octaves = 4;

void setup() {
  size(800, 800);
  loadPixels();
  noise = new UniformNoise();
  noiseDetail(octaves);
}

void draw() {
  float scale = 1;
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      float val;
      int col;
      if (x < width/2) {
        val = noise(x * 0.015f*scale, y * 0.015f*scale, frameCount*0.035f);
        col = hsbToRgb(val, 1, 1);
      } else {
        val = noise.uniformNoise(x * 0.0085f*scale, y * 0.0085f*scale, frameCount*0.01f, octaves, 0.5f);
        col  = hsbToRgb(val, 1, 1);
      }
      pixels[y * width + x] = col;
    }
  }
  updatePixels();
}

public static int hsbToRgb(float hue, float saturation, float value) {
  float r = 0, g = 0, b = 0;

  int h = (int)(hue * 6);
  float f = hue * 6 - h;
  float p = value * (1 - saturation);
  float q = value * (1 - f * saturation);
  float t = value * (1 - (1 - f) * saturation);

  if (h == 0) {
    r = value;
    g = t;
    b = p;
  } else if (h == 1) {
    r = q;
    g = value;
    b = p;
  } else if (h == 2) {
    r = p;
    g = value;
    b = t;
  } else if (h == 3) {
    r = p;
    g = q;
    b = value;
  } else if (h == 4) {
    r = t;
    g = p;
    b = value;
  } else if (h <= 6) {
    r = value;
    g = p;
    b = q;
  }
  return -16777216 | ((int) (r*255) << 16 | (int) (g*255) << 8 | (int) (b*255));
}
13 Likes

This may provide some context to the use of Perlin noise in Processing:

Processing reference:

:)

1 Like

I thought I would compare JRubyArt noise (derived from KdotJPG OpenSimplex2) to see how that would fare, here is the test code:-

load_library :uniform_noise

java_import 'micycle.uniformnoise.UniformNoise'
java_import 'java.awt.Color'

OCTAVES = 4

def setup
  sketch_title 'Uniform Noise Test'
  load_pixels
  @unoise = UniformNoise.new
end

def draw
  grid(width, height) do |x, y|
    val = if x < width / 2
            (noise(x * 0.015, y * 0.015, frame_count * 0.035) + 1) / 2
          else
            @unoise.uniform_noise(x * 0.0085, y * 0.0085, frame_count * 0.01, OCTAVES, 0.5)
          end
    col = Color.HSBtoRGB(val, 1, 1)
    pixels[y * width + x] = col
  end
  update_pixels
end

def settings
  size(800, 800)
end

Here is the result

The uniform noise is clearly the winner here, but OpenSimplex2 is an improvement over the processing “perlin noise”. There is even a variation that is more suitable for creating terrains.

5 Likes

This is immensely useful to me. Thanks for writing the library and sharing it. Now, pardon me being a total Java n00b, but how do I install UniformNoise in my Processing 4 library folder? Can’t seem to find it via the Contribution Manager. Thanks!

I don’t think @micycle had published it there yet.

Either download & drag the “.jar” file from the link below into your sketch:

Or download all the “.java” files and paste them into your sketch’s root folder:

1 Like

I really appreciate your fast response, @GoToLoop. I have dragged all the .java (no .jar file AFAIK) files to the root folder of my sketch. They show up as separate tabs, and the sketch compiles and runs just fine, but I’m not sure what to do from here. Attempting to call uniformNoise(1.0, 1.0) returns an error stating that "The function uniformNoise(float, float) does not exist." Am I missing an import statement here, or do I need to make an instance of the UniformNoise class?

Any hints on how to proceed?

Follow up: I commented out the package part of the .java files, and successfully called uniformNoise() from a manually created instance of UniformNoise.

So for now I got it to work. Great. But I might have violated a few conventions and good practice norms in the process. Please let me know if there’s a more common approach that I should follow.

YA follow up: So, it appears my “hack” doesn’t work with Processing’s Tweak Mode, which I am very reliant on. The code in the imported .java files throws a "tweakmode_int cannot be resolved to a variable" error when I attempt to run the sketch in Tweak Mode. I suspect replacing the imported .java with a .jar would fix this issue. Trouble is, I have absolutely ZERO clue on how to compile .java files into a .jar that’ll work with Processing. Any takers on this one?

Classes & interfaces within files w/ extension “.java” needs to be imported before usage.

You should keep the package statements.
Within file “UniformNoise.java” we have package micycle.uniformnoise;
That means in order to import its public class UniformNoise in our “.pde” file we do:
import micycle.uniformnoise.UniformNoise;
Which is the combination of package path + class name:

You can install it as a library yourself in the Processing libraries folder:

On windows:

Thank you for the clarification @GoToLoop. I followed your advise and it works like a charm despite throwing an initial “No library found for micycle.uniformnoise” error.

There’s still an issue with me not being able to run the sketch in Tweak Mode, but I’ll work out a way to circumvent this.

Thanks for chiming in on this thread and thanks for making the library @micycle! I might have missed something, but I can’t find a .jar file in zip I download from your Github repo. Where did you get the .jar file from?

The .jar is right there in releases section.

1 Like

Doh! It’s been right in front of me the whole time. Mea culpa :sweat_smile:

Notice though this “.jar” file is just those 3 “.java” files but pre-compiled together.

Simplest way to use a “.jar” file in Processing is to drag it into the sketch and it automatically creates a subfolder named “code/”.

1 Like

These are basically all the same and relate to the functions periodicity. I wouldn’t call them “issues” exactly. The period isn’t really a problem and, in fact, it can be useful.

If you want to avoid repetition (or extend the period) the way to do it is with your scaling factor(s). Most of the examples you’ll find will use scales of something like 0.02 or 0.05 or 0.1… and these will extend the period, but not really by that much. If you want much longer periods, use a scalar that doesn’t easily divide into the period lengths (which are powers of 2, btw.) So… instead of 0.02 pick 0.0217 or instead of 0.05 pick 0.493 or something.

However, isn’t noise most often used as a form of randomness, in which case the periodicity would be generally regarded as an unfortunate artifact, even though it might sometimes be useful?

1 Like

Looks like we are having this conversation in two threads now. :slight_smile: As I said above and in the other is that I believe you can essentially extend the period (and possibly make it very long indeed) by using a noise scale that doesn’t divide into the period… like choose 0.0217 instead of 0.02.

1 Like

Yeah, that’s true. But they are both good threads. :slight_smile: We can follow your lead regarding which one to continue within.

Can you demonstrate what you mean by this? Using any scaling factor (whether an irrational number or not) simply zooms/scales the noise and doesn’t alleviate the problems I listed.