confused about perlin animation result

I am trying to get a random swarm-like animation using Perlin noise. In what I tried below, I am getting this periodic behavior where all the points simultaneously stop and then change direction, instead of moving continuously.

Could anyone help me understand why this is happening, or what I could do to get a different result? I have used Perlin noise for a 1d array, and 2d map and remember getting confused in the past with what variables and iterators where in the noise function, but this time I'm really drawing a blank.

Thanks for any help!


var a = 0; var w = 500; var h = 500; function setup(){ createCanvas(w,h); background(100); stroke(255); noFill(); } function draw(){ background(100); a += 0.005; for (var i = 0; i < 80; i++) { ellipse(noise(i, a)*w,noise(2000+i, 2000+a)*w,5, 5); } }
Tagged:

Answers

  • edited April 2017

    @gordano --

    Your problem might be that you are trying to pass noise different sampling regions by adding ints -- like 2000 -- but your noise surface tiles at integer points, so you get simple periodic repeated values (untested). You also scan your noise horizontally to generate both your x and y offsets.

    Instead:

    1. sample at small increments like .1 or .05, not whole integers.
    2. sample in two directions (horizontally and vertically)

    Give each particle its own x-band across the noise like y=i*0.1. Also give each particle its own y-band across the noise, like x=i*0.1. Vary these over time by a and get an animated cloud of particles. This should give you a swarm:

    ellipses(noise(a, i*0.1)*w,noise(i*0.1,a)*w,5, 5);
    

    For fun, make the sampling bands very close together (0.01) to make each particle closely related to its neighbor, turning your swarm into a snake:

    ellipses(noise(a, i*0.01)*w,noise(i*0.01,a)*w,5, 5);
    

    Keep in mind that the characteristics of the noise being sampled can be controlled with noiseDetail() and that if correlations between different samples is a problem you can also add a dimension (3D noise) or switch back and forth between different noise sets with noiseSeed().

  • I am getting this periodic behavior where all the points simultaneously stop and then change direction, instead of moving continuously.

    You're not getting that, you're getting jerky movement yes, but they point's aren't "jerking in sync".

  • @prince_polka -- I think the problem in the original code might be that both the x and y offsets are periodically trending to zero every few seconds -- and in sync with each other -- so the swarm collapses to an-almost point.

  • edited April 2017

    @jeremydouglass I think you're right that the scans are all periodically hitting the same region. I tried dropping in your code, and I still got the same effect, so I think changing the increment size and scan direction still isn't enough.

    What I ended up doing was throwing a second iterator into the mix at a different rate so the two scans are more free running. I still see the points synchronize every once in a while but it's less noticeable:

    a += 0.003; b+=0.0001;
    for (var i = 0; i < 80; i++) {
        ellipse(noise(i+b, a)*w*1.3,noise(2000+i+b, 2000+a+b)*w*1.3,5, 5);
    }
    

    I'm not sure if it's just that all points are hitting large zero regions, or it's actually a repetition on the perlin noise, I guess the former is more likely. It's a bit fuzzy as whats going on, but this seems to work.

  • Ah, I see -- you are worried not just about the collapsing, but about the stop-reverse stutter-step.

    I don't think you are going to be able to get away from the fact that x motion will drop to 0 when a=1.0, 2.0, 3.0 etc. and that y motion will drop to 0 when b=1.0,2.0,3.0 etc. You can offset them to hide the effect on independent axis, but each axis will still be stuttering on integers if you are scanning Perlin noise.

    If you want truly random swarm behavior you may want to use the standard particle objects approach and random-walk each particle.

  • Ah, I didn't know the classic Perlin noise algorithm had that property. I skimmed a few articles including the intro in Perlin's paper that introduced simplex noise that seemed like they are describing that property of repeating integer index values. I experimented with the a and b increments and found something I like. I can at least have the different scan values happen upon the integer points in less synchronized way.

  • edited April 2017

    @gordano -- here's a smoothing hack to accelerate through the dead spots in the noise. Perlin noise neighbor movements will always be partially correlated (that's what makes them "organic") but the whole production won't start and stop as dramatically.

    if (a%1.0 >= 0.975 || a%1.0 < 0.025){ a+=0.045;}
    

    You can turn it off and on to see how it stops (or not) every 3.3 seconds (1 / 0.005 / 60fps = 3.3). Here is a test sketch:

    float a = 0;
    float w = 500;
    float h = 500;
    boolean smoother = true;
    void setup() {   
      size(500, 500);
      background(100);
      stroke(255);
      noFill();
    }
    void draw() {
      background(100);
      a+=0.005;
      if(smoother){
        if (a%1.0 >= 0.975 || a%1.0 < 0.025){ a+=0.045;}
      }
      for (int i = 0; i < 80; i++) {
        ellipse(noise(a, i*0.1)*w, noise(i*0.1, a)*w, 5, 5);
      }
    }
    void keyReleased(){
      smoother=!smoother;
    }
    
Sign In or Register to comment.