OpenSimplexNoise is a bit too slow

#1

Hello everyone,

I’m currently trying to make an animation using perlin noise. It was too slow so I tried with OpenSimplexNoise and it was better, but still not fast enough.
I’m juste looping through 2D slices of 3D noise in order to create a smooth color changing effect, and I’m doing this on the three rgb channels.
When I put my window in 300x300 it works fine, but beyond 500x500 it becomes laggy.
Is there any way to optimize my code so it isn’t laggy ?
Thanks for your help.

Here’s my code :

float noise_increase = 0.1; // speed of the animation
float definition = 180;
float[] z; // z component that is changing over time for the three rgb channels

OpenSimplexNoise noise;

void setup() 
{
  size(300, 300);
  
  noise = new OpenSimplexNoise();
  
  z = new float[3];
      
  for(int i = 0; i < 3; i++)
  {
    z[i] = random(0,1000);
  }
}

void draw()
{ 
  drawNoise();
}

void drawNoise()
{
  for(int i = 0; i < 3; i++) // increase z component of 3D perlin noise to get the next 2D slice
  { 
    z[i] += noise_increase;
  }
        
  for(int x = 0; x < width; x++)
    for(int y = 0; y < height; y++)
    {   
      float r = map((float) noise.eval(x / definition, y / definition, z[0]), -1, 1, 0, 255);
      float g = map((float) noise.eval(x / definition, y / definition, z[1]), -1, 1, 0, 255);
      float b = map((float) noise.eval(x / definition, y / definition, z[2]), -1, 1, 0, 255);
     
      set(x,y,color(r,g,b));
    }
}

By the way you can find the OpenSimplexNoise source code here : https://gist.github.com/KdotJPG/b1270127455a94ac5d19

1 Like

#2

besides the load / update Pixels code i show you
Weird behaviour with loadPixels() and updatePixels() already
also you could just reduce the amount of calculations…

like ( untested )

  for(int x = 0; x < width; x++)  {
    float xdef = x / definition;
    for(int y = 0; y < height; y++)  {
      float ydef = y / definition;   
      float r = map((float) noise.eval(xdef, ydef, z[0]), -1, 1, 0, 255);
      float g = map((float) noise.eval(xdef, ydef, z[1]), -1, 1, 0, 255);
      float b = map((float) noise.eval(xdef, ydef, z[2]), -1, 1, 0, 255);
     
      //set(x,y,color(r,g,b));
      changePixelColor(x, y, r, g, b,d)
    }
}

and replace the map ?

float r = ( (float)noise.eval(xdef, ydef, z[0]) + 1.0 )*127;

and setting a

colorMode(RGB, 2.0);
//...
float r = (float)noise.eval(xdef, ydef, z[0]) + 1.0 ;

might also work;

1 Like

#3

@kll You told Kazuya_Yoshimisu to use the set function in that other thread which they did here. Why did you change it back now? To me it seems that extra function call would be unnecessary.

Replacing the map function by setting the colorMode appropriately is a good suggestion!

@Kazuya_Yoshimisu Other than that I think you can’t speed it up much unless you want to precompute a large set of noise values :sweat_smile:
The noise computation itself should be the most costly thing here.
I have recently experimented with noise generated on the gpu via shaders in Unity and that runs a LOT faster, but I have no idea how or if you can do gpu calculations in processing. It’s a whole different level of complexity though.

0 Likes

#4

i just give that option, as

set(x,y,color);

https://processing.org/reference/set_.html
find:

Setting the color of a single pixel with set(x, y) is easy, but not as fast as putting the data directly into pixels[] .

and we talk about speed here?

so why not test both and compare the FPS?

1 Like

#5

Ah, yeah, you are right. I think calling your own extra function to write to pixels[] is the same as using the set(x,y) function though (or worse). I would suggest writing to pixels[] directly within the for loops. Thanks for the clarification :slight_smile:

0 Likes

#6

can you help? fill that with FPS numbers
+++ but give detailed info about

  • OS and
  • used hardware
  • canvas size
  • noSmooth() in setup()
  • other options you know ???

ok, i might have found something

using my limited hardware that was a big step in FPS
i cut the noise calc to 1/3 just by play with Hsb mode?
not sure it looks like expected.

float noise_increase = 0.1; // speed of the animation
float definition = 180;
float z;
int d=1;

OpenSimplexNoise noise;

void setup() {
  size(300, 300);
  noise = new OpenSimplexNoise();
  colorMode(HSB,255);
  pixelDensity(d);
  noSmooth();
   z = random(0, 1000);
  println("use key [f] for fps");
}

void draw() {   
  drawNoise();
}

void drawNoise() {
  z += noise_increase; // increase z component of 3D perlin noise to get the next 2D slice
  loadPixels();
  for (int x = 0; x < width; x++) {
    float xdef = x / definition;
    for (int y = 0; y < height; y++) { 
      float ydef = y / definition; 
      float h = ((float)noise.eval(xdef, ydef, z)+1.0)*127;
      pixels[x + y * width*d] = color(h,255,255);
    }
  }
  updatePixels();
}

void keyPressed() {
  if ( key == 'f' ) println(nf(frameRate, 1, 1));
}

SNAG-0070

0 Likes

#7

Thanks for all your suggestions !

using set() is the same as using loadPixels() and updatePixels().
But xdef, ydef, colorMode(RGB,2.0) and replacing map() were significant improvements.

Also, using only one noise calculation with colorMode(HSB,255) was a great idea, but that isn’t what I was aiming for.

I think at this point I juste have to give up. When I’m running in 600x600, the time elapsed between each frame is approximatively 130ms and when removing all 3 noises it takes only 10-20ms so the main problem is definitely the noise function.

Still fun to watch it smoothly running in 300x300 though !

1 Like

#8

Fullscreen, full resolution noise, 3 times per pixel. Yeah, that sounds quite impossible to get running smoothly. Even on high-end hardware and with gpu code.
Depending on what you aim to achieve there are some places you could optimize though.

If you generate noise at half the width and height (quarter the resolution) you can offset the values for each of the layers R G B by one pixel (one layer horizontally and the other vertically). That way perceived loss of resolution is minimal because pixels next to each other still end up having different resulting colors.

You could also (and even in combination with the above) generate your noise at a lower resolution and scale it up. That will show in your result but again, depending on what you’re trying to achieve, you might not need maximum resolution.

If you can get away with a limited set of noise you could pregenerate the noise or the resulting images before showing the animation.

The most acceleration you can achieve in my opinion would be generating the images on the GPU, but like I said, I don’t know if that’s possible in Processing. And even then there are limitations to how much information you can get back from the GPU. Displaying the image on screen is fine, doing more computations back on the CPU won’t be possible.

0 Likes