使用電腦模擬真實世界,是數學與程式最自然的結合,透過觀察自然現象,化為數學公式、實現為程式的過程,可獲取基礎元素的挖掘、組合、變化等能力,對於數學或程式面的思考,都有極大的助益。

弦波與噪聲

談到用電腦來模擬真實世界,其中的地形模擬,可能是最為人熟知的對象,畢竟就算不寫程式的人,在玩遊戲的過程中,也會接觸到地形產生器之類的東西,而我在先前專欄〈隨機演算之美〉談過的Perlin噪聲,其具有連續性與隨機性,就是用來模擬地形的方式之一。

有沒有可能自己設計個噪聲呢?連續性是噪聲的特色之一,談到連續性,可以想到弦波,若試著將正弦波與餘弦波組合為z(x,y)=sin(x)*cos(y),使用程式畫出每個(x,y,z)點,就會有點地形起伏的感覺,若試著加上可調整的振幅a與頻率f,成為f(x,y,a,f)=sin(x*f)*cos(y*f)*a,就可以有不同的波狀地形。

不過,就算是調整了振幅與頻率,波狀地形的規律性太容易觀察出來,缺少了隨機地形的感覺,可以試著隨機產生頻率f,例如使用1到1.5間的隨機數作為f的值,地形就不再規律了,若需要的解析度不用很高,看來就有點像隨機地形。

然而,如果要求較高的解析度,就會發現連續性被破壞了。為了要保有連續性,我們可以選擇在一段弦波上,疊加較小振幅、較高頻率的小弦波,弦波疊加不會破壞連續性,而由於大小弦波間的振幅可能相加或相抵,就會產生隨機地形的感覺。

不過,如果在適當的振幅與頻率之下,或者是產生了極大範圍的地形,還是容易看出弦波的週期性,若想避免這類問題,我們可試著以相同策略持續疊加弦波,進而創造出繪圖範圍內難以察覺週期性的地形。

Perlin噪聲的出發點其實就有點類似弦波,選擇等距的點就像是選擇頻率,只不過每個點產生的梯度本身就是隨機,而振幅透過梯度來內插計算,以保有對連續性的需求,因為梯度本身就是隨機,基本上,就不用再透過疊加來取得隨機性。

碎形布朗運動

雖然Perlin噪聲本身就具有隨機性與連續性,不過,相較於實際地形來說,還是少了許多細節,也就是噪聲形成的地形過於光滑了,實際山岳取其中一小塊區域來看,還是會有巨岩、湖泊、碎石等細微的起伏。

既然Perlin噪聲的出發點類似弦波,而弦波可以疊加,那麼,來疊加Perlin噪聲如何?低頻、振幅高的噪聲是山,更高頻、更低振幅的噪聲陸續疊加其上,就可成為巨石、湖泊、碎石等,而疊加的層次越多,地形就越細緻。

就程式撰寫來說,可將每次噪聲疊加視為一次循環,每次循環以一定倍數增加頻率,並以一定比率降低振幅,隨著循環次數的增加,地形細節就越多,而且,若將某局部地形放大來看,會發現和整體看來很相似。

若將這個疊加的過程套用在一維正弦波,在多次疊加之後,取其中一段曲線,此時,我們會發現整體來說是正弦波,而從該曲線再取一小段放大來看,還是像正弦波,也就是說,這種疊加產生了自相似性,若真能無限次地疊加,就會符合碎形(fractal)的定義了。

疊加過程若套用在Perlin噪聲,由於每個點的梯度具有隨機性,這就像是布朗運動的粒子運動方式,沒有規則可循,然而最終得到的地形仍會呈現一定程度的自相似性,這就構成了布朗運動的擴展,也就是最後會得到符合碎形布朗運動(Fractional Brownian motion)定義的地形。

若想看看波的疊加,以及碎形布朗運動的效果,我們可以參考《The Book of Shaders》的〈Fractal Brownian Motion〉,試著改變程式範例中的頻率、振幅等參數,看看呈現出來的效果。

碎形噪聲與Worley噪聲

透過程式設計,我們對於疊加過程的處理,可以設計為通用函式,而參數有三個,每次的循環稱為一個八度(octaves),此名稱源於音樂中每個音程是一個八度;頻率的倍數稱為間隙(lacunarity),在幾何中,是用來度量圖案(特別是指碎形)如何填充空間;至於振幅的倍數,則稱為增益(gain)。

有的程式庫作者將這類函式,直接命名為碎形噪聲(fractal noise);若將碎形噪聲這類函式的實現,拿來套用在弦波,在多次疊加後,雖然沒有隨機性而不符合碎形布朗運動,然而就小範圍來說,也是具有噪聲效果了。

擁有隨機性的噪聲不只有Perlin噪聲,在Perlin噪聲發表六年左右,Steven Worley基於Voronoi的原理,發表了Worley噪聲,最初版本是以像素至最近隨機點的距離作為噪聲值,若將噪聲值作為像素的灰階值,最後形成的圖案就是Voronoi圖,因此,又常稱為Voronoi噪聲、細胞噪聲等。

然而,Worley噪聲主要是作為創建材質效果,若每個像素都要對全部隨機點進行距離判斷,隨機點越多,計算量就越龐大。

而為了減少計算量,我們可以將空間分為網格,在各網格當中,隨機產生一個不超出網格的點,而像素只要從包含自身的鄰近九個網格,判斷最短距離就可以了。若不在意產生的Voronoi圖中,各細胞大小是相近的,這種作法的確可以大幅減輕計算的負擔。

Worley噪聲演算不一定要以最短距離為噪聲,距離取法可以是第二鄰近點的距離,或是第一減去第二的距離,也可以是曼哈頓(Manhattan)距離、柴比雪夫距離(Chebyshev distance)等,若要令Voronoi圖的細胞邊緣明顯,還可以取第一、第二鄰近細包的邊界距離。

不同的距離策略,會產生不同的圖案效果,實際上求得的最近細胞位置,也可以是噪聲的一種,此資訊經常用於為每個細胞著色。若有興趣操作Worley噪聲的效果,我們可以參考《The Book of Shaders》的〈Cellular Noise〉

從基礎元素到變化

在研究噪聲、碎形,或像是碎形噪聲之類的函式實現過程中,我們可以發現不少共通的基礎元素,像是像素處理、疊加性、網格分割技巧等,這類技巧在其他場合也可以變化應用。

例如,關於網格分割的技巧,也適用於使用凸多邊型交集求Voronoi圖的場合,然而必須擴充為求鄰近21個網格,雖說如此,相對於求全部隨機點的交集來說,這已經大幅減輕了計算的負擔!

《The Book of Shaders》屬於著色器(Shader)處理的介紹,若這離你太遠,可以試著探討衍生藝術(Generative art)。事實上,在程式設計領域,原本為了以視覺化方式學習程式語言而生的Processing,就有不少的衍生藝術資源,像是Perlin噪聲之類的函式,Processing本身就內建。

Processing社群本身也有各式各樣衍生藝術的程式作品,如果需要系統性地(從Processing)學習衍生藝術,我們可以參考《The Nature of Code》,當中除了談到噪聲、碎形,還包含了粒子系統、物理程式庫、神經網路等的探討,是個相當不錯的資源。

專欄作者

熱門新聞

Advertisement