2011/07/15

Noise (processing教學)

之前跳過沒講的p130-132的noise在好好看完CCC提供的資料後(謝謝老師),
總算從從完全不懂到似懂非懂了 ....................
其實有時候指令就是這樣子,你知道它在幹麻,但你不知道它為什麼這樣,
就跟劉子千的唸你MV一樣,你知道他在拍MV,但不知道它為什麼拍成這樣.


以下我會對noise做簡單的註解,也不能說一定對,只能說是我的推論,
至於說可以拿來幹麻,我還真不知道.


----------------------------------------------------------------------------------------------------------------------------




processing的noise指令原理是來自Perlin noise,是由一個叫做Ken Perlin的人所提出的,
也就是上圖右邊那位跟吳老合照的人兄,你不要看他貌似瘋瘋癲癲,
他除了獲獎無數外,還用他的noise參與了第一代Tron的製作.


noise基本上可以說是一種演算法,噪聲演算法.
而它所產生的基本圖形就像以前偷偷轉到鎖碼頻道一樣,
結果電視不但一直沙沙沙的鬼叫外,還會產生一堆黑芝麻的畫面如圖,令人不勝唏噓.
因為再介紹下去就太數學性,我會想嘔吐,
所以有興趣知道的朋友可以參考以下的網站多加了解. 


http://zh.wikipedia.org/wiki/Perlin%E5%99%AA%E5%A3%B0


----------------------------------------------------------------------------------------------------------------------------


透過CCC提供的線索下(黃金傳奇?),
我找到了一個我覺得在說noise上較課本清楚的網站,
是由一個叫Anthony Mattox的數位藝術家的blog
http://anthonymattox.com/perlin-noise


在交互參考課本與網站之後,
我理解上是說noise基本上是random的一種,
但相較於random, noise還帶有方向性, 很詭異吧?
這也是為什麼p130的noise有(x,y,z),
同時noise的數值永遠應介於0到1之間的,
所以他就像sin,cos一般,當我們使用它時,
通常都還會給他乘以更大的數來做rescale的效果.


以下我會針對p131的15-09來講三個例子,
因為15-08太簡單自己看就可以,15-10又太難非我族類 .............


----------------------------------------------------------------------------------------------------------------------------

這是課本的範例




size(200,200);
background(255);
smooth();


float xnoise = 0; 
float ynoise = 0;
//因為是做2D圖面,所以只需noise(x,y),
//同時我們知道noise是random的一種,所以性質為float
float inc = 0.04;
//這行只是讓作者方便一次改 += 多少

noiseSeed(0); 
//跟random有randomSeed一樣,
//noise也有noiseSeed,但如果在跑動畫時是不能寫這行的.

for(int y = 0; y <= height; y += 1){
  for(int x = 0; x <= width; x += 1){
    xnoise += inc; //本來是xnoise = xnoise + inc;
    float k = noise(xnoise,ynoise) * 255; //因為k是要拿來當顏色的值,所以要再乘以255
    stroke(k); //單純的灰階
    point(x,y);
  }

  xnoise = 0;
  ynoise += inc; //本來是ynoise = ynoise + inc;
}

//saveFrame("p131-2-##.jpg");


這範例比較麻煩的是你會看到
xnoise = 0;
ynoise += inc;
出現在外層的for loop.
因為noise本身也有向度性,所以就像我們之前做一整片方塊排列一樣,
xnoise(x向度)要先算,之後再算ynoise(y向度).

因為一開始已設
float xnoise = 0; 
float ynoise = 0;
所以在先算x的for loop時,
ynosie會永遠為0,但因為xnoise有寫xnoise += inc;
所以會先算好x軸的noise,(也就是一排點構成的)
但當要算外圈y的for loop時,
如果xnoise同時在變,那效果就是那條一路順y軸重覆
這也就是為什麼除了設ynoise += inc;之外還要設xnoise = 0;
可能有點難理解,但只要移動看看ynoise += inc;的位置或//它你可能比較好懂





所以我們如果要改寫成一個超短比較好理解的noise程式的話,
以下是個好範例


size(200,200);
background(255);
smooth();
noiseDetail(22,0.6); //這是一個課本沒有但官網有的指令,下面會詳加介紹
noiseSeed(17);

for(float y = 0; y <= height; y += 1){
  for(float x = 0; x <= width; x += 1){
    float k = noise(x/200,y/200) * 255;
    //單純取消掉xnoise跟ynoise,讓x,y直接代替,就無需煩惱雙層for loop的問題
    stroke(k);
    point(x,y);
  }
}

//saveFrame("p131-3-##.jpg");



noiseDetail(octaves, falloff)這指令是控制我們所設的noise密度跟均勻度.
官網的介紹如下


Adjusts the character and level of detail produced by the Perlin noise function.
它是用來調整noise的性質和細節的功能

Similar to harmonics in physics, noise is computed over several octaves.
有點類似於物理學中的和聲學(蝦米?),而noise即是由幾個八度音來產生的

Lower octaves contribute more to the output signal and as such define the overal intensity of the noise,
whereas higher octaves create finer grained details in the noise sequence.
較低的八度音控制nosie整體的粒子強度,而高八度音則加強noise的細膩度

By default, noise is computed over 4 octaves with each octave contributing exactly half than its predecessor,
starting at 50% strength for the 1st octave.
在processing的預設裡,noise是由4個八度音所組成的,
而每個八度音為前一次強度的50%(預設的,可更改)

This falloff amount can be changed by adding an additional function parameter.
也就是每下一次八度音的衰弱率可被設置,不一定為預設的50%
Eg. falloff factor of 0.75 means each octave will now have 75% impact (25% less) of the previous lower octave.
例如衰減係數為0.75意味著每個八度音將有前一次八度音75%的強度 

Any value between 0.0 and 1.0 is valid,
however note that values greater than 0.5 might result in greater than 1.0 values returned by noise().
任何衰減係數介於0.0至1.0之間是有效的,但是請注意,
值大於0.5,可能會導致返回值大於1.0的noise
(這裡我不懂,請自己參悟,或是就不要設超過0.5,但我範例設0.6也沒事)

也就是說noise裡的兩個數,第一個是有幾個八度音,第二個是每下一個八度音會衰減多少.
透過這功能我們可以控制noise的細節跟強度來達到我們的需求.



最後一個案例就是把noise直接變成void draw的動畫,基本架構其實沒什麼差別.


void setup() {
  size(200,200);
  noiseDetail(8,0.4);
}

float age = 0;
void draw() {
 
  frameRate(50);
  background(255);
  age += 0.02;
 
  for (float x=0; x<=width; x++) {
    for (float y=0; y<=height; y++) {
      stroke(noise(x/200,y/200,age)*255);
      point(x,y);
    }
  }
 
  //if(frameCount < 201){
  //  saveFrame("p131-4-###.jpg");
  //} 
}

noise基本上就是random的一種,就像sin與cos一樣也可以是一種-1至1的數,
都是用來改變向量或正負的,應該是這樣子吧吧吧吧吧?
所以簡單應用一下我們也可以偵測敵軍   ..............



void setup() {
  size(200,200);
  noiseDetail(6,0.4);
  smooth();
}

float age = 0;
float a = 0;

void draw() {
 
  frameRate(50);
 
  age += 0.02;
  a += 10;
 
  for (float x=0; x<=width; x++) {
    for (float y=0; y<=height; y++) {
      stroke(noise(x/200,y/200,age)*255);
      point(x,y);
    }
  }
 
  stroke(255,150);
  strokeWeight(1.5);
  noFill();
  ellipse(100,100,160,160);
  ellipse(100,100,120,120);
  ellipse(100,100,80,80);
  ellipse(100,100,40,40);
 
  pushMatrix();
  translate(100,100);
  rotate(radians(a));
  line(0,0,170,170);
  line(0,0,170,0);
  popMatrix();
 
  stroke(255,0,0,150);
  strokeWeight(8);
  point(random(40,160),random(40,160));
  point(random(40,160),random(40,160));
  point(random(40,160),random(40,160));
 
  //if(frameCount < 201){
  //  saveFrame("p131-5-###.jpg");
  //} 
}


Try it. :)

沒有留言:

張貼留言