上一篇介紹了Perlin Noise,但僅限一維的Perlin Noise,一維的概念是由傳入俱有連續性的參數去產生noise,不過這有一個限制在於,你所能建構出的noise,只會與他的上一個noise與下一個noise產生關聯,如圖:
但如果是使用二維的方式,他的四面八方都可以與它產生關聯,如下圖:
如果我們可以控制一的點臨近八個方向的像素,使他們產生關聯,就可以用來模擬自然界中的紋路,那要怎麼在程式中做到呢?
我們可以先從Random開始,用巢狀迴圈將每個像素給一個隨機的灰度值,建立一個二維的隨機雜訊圖,如下
void setup(){
size(300,300);
loadPixels();
for (int x = 0; x < width; x++) {
float yoff = 0.0;
for (int y = 0; y < height; y++) {
float bright = random(255);
pixels[x+y*width] = color(bright);
}
}
updatePixels();
}
loadPixel()與updatePixels()使之前沒看過的兩個方法,loadPixel()的主要功用是將目前畫面上的像素load進pixels[]的array中,之後就可以進行更改,
並用updatePixels(),更新到畫面上。
上面的方式因為使用random()作為產生noise的方式,所以結果就會像電視的雜訊一樣,非常雜訊~
如果要讓每一個像素之間產生關聯,只需要將random()替換成noise的方法,並mapping到灰度的範圍(0 ~ 255)上。
map( noise(x,y), 0, 1, 0, 255)
結果如下:
還是有一點怪怪的,不是那麼的平滑,預計想要產生的圖形是類似雲狀的,那為什麼沒有產生預期的結果呢?
是因為在迴圈中,noise所帶入的參數相差太多,這一次的x值與下一次的x值相差是1,因此生出的圖像像素之間關聯性還是很低,解決的辦法是必須另外寫兩個參數去管理代入noise的值,創出xOffset與yOffset,在迴圈內讓他們只增加0.01,這樣就可以了
void setup(){
float xOffset = 0.0;
size(300,300);
loadPixels();
for (int x = 0; x < width; x++) {
float yOffset = 0.0;
for (int y = 0; y < height; y++) {
// float bright = random(255);
// float bright = map( noise(x,y), 0, 1, 0, 255);
float bright = map(noise(xOffset, yOffset),0,1,0,255);
pixels[x+y*width] = color(bright);
yOffset += 0.01;
}
xOffset += 0.01;
}
updatePixels();
}
圖案如下:
這是一個雲狀的圖形,但是我們可以藉由改變參數,例如noise代入的參數每次所增加值,或是增加色參數的控制,去改變產生的圖形,模擬出如大理石、木頭... 等等的材質。
上面是我改變了y軸的參數,讓他每次增加0.1,有點像木頭質地了,真是神奇,加上褐色應該會更像。
介紹完了一系列關於機率(propability)、分佈(distribution)與噪聲(noise),書上所說,這些不過只是產生“數值”的方法,實際上可以把它應用在各個不同的情境,比如說Perlin Noise也可以應用在枝葉的搖擺、或是控制物體流動的速度與方向。
下一篇開始介紹向量(Vector)