Il rumore di Perlin è un effetto visuale che produce una casualità organica utile per simulare elementi naturali. E' stato sviluppato da Ken Perlin lavorando per il film Tron (1982) di Disney. Nel 1997, Perlin vinse un Academy Award for Technical Achievement (Oscar) da parte della Academy of Motion Picture Arts and Sciences per il suo contributo all'arte cinematografica.
Vediamo un esempio incrementale. Lo sketch Keplero1 disegna una ellisse punto dopo punto.
/* * Disegna una ellisse */ float a; // semiasse maggiore dell'ellisse float b; // semiasse minore dell'ellisse float alpha; // angolo float lastx, lasty, x, y; // coordinate precedenti e correnti void setup() { size(600, 400); background(255); smooth(); stroke(20, 50, 70); strokeWeight(5); a = 200; b = 100; // punto iniziale alpha = 0; x = width/2 + a; y = height/2; } void draw() { lastx = x; lasty = y; // calcolo le coordinate di un punto sull'ellisse x = width/2 + a * cos(alpha); y = height/2 + b * sin(alpha); // unisco con una linea il punto corrente e quello precedente line(x, y, lastx, lasty); // incremento l'angolo di un grado alpha = alpha + radians(1); }
Non è difficile passare da una ellisse ad una spirale ellittica (Keplero2).
/* * Disegna una spirale ellittica */ float a; // semiasse maggiore dell'ellisse float b; // semiasse minore dell'ellisse float alpha; // angolo float lastx, lasty, x, y; // coordinate precedenti e correnti float stepa, stepb; // incrementi degli assi void setup() { size(600, 400); background(255); smooth(); stroke(20, 50, 70); strokeWeight(5); a = 0; b = 0; stepa = 0.2; stepb = 0.1; // punto iniziale alpha = 0; x = width/2; y = height/2; } void draw() { lastx = x; lasty = y; // calcolo le coordinate di un punto sull'ellisse x = width/2 + a * cos(alpha); y = height/2 + b * sin(alpha); // unisco con una linea il punto corrente e quello precedente line(x, y, lastx, lasty); // incremento l'angolo di un grado alpha = alpha + radians(1); // incremento gli assi dell'ellisse a = a + stepa; b = b + stepb; }
Usando la variabilità organica ci muoviamo nella direzione del caos e cediamo parte del controllo alla macchina (Keplero3).
/* * Disegna una spirale ellittica mostrando la differenza tra casualità e rumore di Perlin */ float a; // semiasse maggiore dell'ellisse float b; // semiasse minore dell'ellisse float alpha; // angolo float stepa, stepb; // incrementi degli assi float lastx, lasty, x, y; // coordinate precedenti e correnti float noi; // rumore di Perlin float variance; // varianza degli assi void setup() { size(600, 400); background(255); smooth(); stroke(20, 50, 70); strokeWeight(5); a = 0; b = 0; stepa = 0.2; stepb = 0.1; // punto iniziale alpha = 0; x = width/2; y = height/2; // seme iniziale scelto in modo casuale noi = random(10); variance = 200; } void draw() { lastx = x; lasty = y; float mya, myb; // rumore mya = a + (noise(noi) - 0.5) * variance; myb = b + (noise(noi) - 0.5) * variance; // casualità //mya = a + (random(1) - 0.5) * variance; //myb = b + (random(1) - 0.5) * variance; // calcolo le coordinate di un punto sull'ellisse x = width/2 + mya * cos(alpha); y = height/2 + myb * sin(alpha); // unisco con una linea il punto corrente e quello precedente line(x, y, lastx, lasty); // incremento l'angolo alpha = alpha + radians(1); // incremento gli assi dell'ellisse a = a + stepa; b = b + stepb; // incremento il seme del rumore di Perlin noi = noi + 0.05; }
Moltiplichiamo per 100 e aggiungiamo un po' di casualità (Keplero4).
/* * Disegna 100 spirali ellittiche */ float a; // semiasse maggiore dell'ellisse float b; // semiasse minore dell'ellisse float stepa, stepb; // incrementi degli assi float lastx, lasty, x, y; // coordinate precedenti e correnti float noi; // rumore di Perlin float variance; // varianza degli assi float startAngle; // angolo iniziale float endAngle; // angolo finale float stepAngle; // incremento dell'angolo void setup() { size(500, 500); background(255); smooth(); variance = 200; stepa = 0.5; stepb = 0.5; for (int i=0; i < 100; i++) { a = 10; b = 10; strokeWeight(random(2)); noi = random(10); color col = color(random(200), random(200), random(200)); float trasp = random(200); stroke(col, trasp); startAngle = radians(random(360)); endAngle = radians(360 * 4 + random(360 * 4)); stepAngle = radians(random(3, 8)); x = width/2 + a * cos(startAngle); y = height/2 + b * sin(startAngle); drawSpiral(); } } void drawSpiral() { float mya, myb; for (float alpha = startAngle; alpha < endAngle; alpha += stepAngle) { lastx = x; lasty = y; mya = a + (noise(noi) - 0.5) * variance; myb = b + (noise(noi) - 0.5) * variance; // calcolo le coordinate di un punto sull'ellisse x = width/2 + mya * cos(alpha); y = height/2 + myb * sin(alpha); // unisco con una linea il punto corrente e quello precedente line(x, y, lastx, lasty); // incremento gli assi dell'ellisse a = a + stepa; b = b + stepb; // incremento il seme del rumore di Perlin noi = noi + 0.05; } } void draw() {} void mouseReleased() { save("Keplero.gif"); }
Qualcosa di più bello che usa il rumore di Perlin per decostruire una sfera tridimensionale: Frosti (2010) di Matt Pearson.