Perlin 噪聲（Perlin noise，又稱為柏林噪聲）指由 Ken Perlin 發明的自然噪聲生成演算法，具有在函式上的連續性，並可在多次呼叫時給出一致的數值。 在電子遊戲領域中可以透過使用 Perlin 噪聲生成具連續性的地形；或是在藝術領域中使用 Perlin 噪聲生成圖樣。由於 Perlin 本人的失誤，Perlin 噪聲這個名詞現在被同時用於指代兩種有一定聯絡的的噪聲生成演算法。這兩種演算法都廣泛地應用於計算機圖形學，因此人們對這兩種演算法的稱呼存在一定誤解。下文中的 Simplex 噪聲和分形噪聲都曾在嚴肅學術論文中被單獨的稱作 Perlin 噪聲。 本文僅討論灰度圖的情況。對於彩色影像的噪聲生成，只要將同樣的方法分別應用於各個顏色分量上，再加以合成即可。 Simplex 噪聲 生成噪聲最通常的想法是為每個畫素賦予一個隨機的灰度值。如此產生的影像如下圖左。 FileRandomNoise2Dpng 使用隨機方法產生的白噪聲 FileRandomNoise2DFFTpng 左圖的頻譜 FileRandomNoiseSmoothed2Dpng 對隨機噪聲進行柔化 FileRandomNoiseSmoothed2DFFTpng 左圖的頻譜 用隨機法產生的噪聲影像和顯然自然界物體的隨機噪聲有很大差別，不夠真實。1985 年 Ken Perlin 指出，一個理想的噪聲應該具有以下性質： 對旋轉具有統計不變性； 能量在頻譜上集中於一個窄帶，即：影像是連續的，高頻分量受限； 對變換具有統計不變性。 對於計算機圖形學中的普遍應用，噪聲應該是偽隨機的，兩次呼叫應得到同樣的結果。 上圖的噪聲之所以不夠真實是因為它的能量在頻譜中平均分佈，即它是白噪聲。對白噪聲進行柔化處理後限制了噪聲的頻譜，比之前者和自然界中的噪聲現象更加接近，但是依然不能令人滿意。 經典 Perlin 噪聲 Perlin 在上述文章中提出了一種產生符合要求的一維噪聲函式的簡單方法，這是後續工作的基礎： 在一維座標軸上，選擇等距的無窮個點，將值空間劃分為等長的線段（為方便起見，選擇座標值為整數的點），為每個點隨機指定一個值； 對於座標值為整數的點，將該點對應的值作為噪聲影像上該點的值；對於座標值不為整數的點，將相鄰兩點的值進行插值運算，獲得該點的數值 灰度。 插值使用的函式是一個在 0 處為 1，在 1 處為 0，在 05 處為 05 的連續單調減函式。例如，設 c_0 c_1 為左右兩整數點的數值，t 為該點距離左邊點的距離，使用 1t 作為插值函式，則該點的值為 c_1 1t c_0t。 1t 是線性插值，得到的結果人工痕跡嚴重，且在整數點上不連續。Perlin 建議使用 3t2 2t3 作為插值函式 ，後來又建議使用 6t515t410t3 作為插值函式；事實上，只要是在區間 01 內連續的函式 f，有 f 01，f 10 且 f0f10 的函式皆可做為插值函式。實際應用如下：設 f 為插值函式，插值結果為 c_0f 1t c_1f t。 對於二維的情況，可以將上述演算法進行推廣，即： 為所有座標為 x y 且 x y 都是整數的點指定一個值，同時指定一個梯度，這些點將空間分成方格； 對於座標軸為整數的點，即上述方格的頂點，將為它指定的值作為該點的值；對於某個方格內部的點 x y，用所在方格四個頂點的值和梯度進行插值。 例如，對於點 x y，令 i lfloor x rfloor j lfloor y rfloor 它所在方格的四個頂點分別為： i j、i1 j、i1 j1、i j1。令 uxi v yj，這四個頂點對點 x y 的貢獻可以用它們的梯度（g_00 g_10 g_11 g_01）和 x y 點與這四個頂點的方向（u v、u1 v、u1 v1、u v1）進行點積獲得。但是在二維的情況下，插值更為複雜。首先需要對 i j 和 i1 j 兩點在 x 方向插值，得到點 x j 的值；之後對 i j1 和 i1 j1 兩點在 x 方向插值，得到點 x j1 的值；最後對 x j 和 x j1 在 y 方向插值，得到 x y 的值。 在三維的情況下，需要進行七次插值。可以證明，插值次數隨著維數的增長指數增長。 經典 Perlin 噪聲基本滿足 Perlin 提出的噪聲條件。但是由於 3t2 2t3 導數中含有線性分量，在計算相鄰點差時會體現出人工效果，不夠自然。經典 Perlin 噪聲在進行下文的分形和運算後效果不夠自然。 經典 Perlin 噪聲的軟體實現 為了達到偽隨機性，經典 Perlin 噪聲（和隨後的 Simplex 噪聲）透過在一個轉置陣列中查詢點的座標求每個點的梯度，而不使用隨機數發生器。這樣兩次呼叫可以獲得同樣的結果，達到偽隨機性。理論上轉置陣列可以任意指定，但是後續的實現都使用 Perlin 最初提出的陣列： unsigned char perm 256 151160137919015 13113201959653194233722514036103306914289937240211023 19061482471202347502619762942522192031173511325717733 882371495687174201251361711686817574165711341394827166 7714615823183111229122602111332302201059241554624540244 1021435465256316112168073209761321872088918169200196 1351301161881598616410010919817318636452217226250124123 520238147118126255828521220720659227471658171821892842 22318317021311924815224415416370221153101155167431729 129223925319981081107911322423217818511210421824697228 2513424219323821014412191179162241815114523524914239107 49192214311811991061571848420417611512150451274150254 1382362059322211467292472243141128195786621561156180 以下用 python 示例如何生成一維 Perlin 噪聲，更高維的情形可以在這個基礎去推廣： from math import floor Perlin 最初提出的陣列 SEQ 151160137919015 13113201959653194233722514036103306914289937240211023 19061482471202347502619762942522192031173511325717733 882371495687174201251361711686817574165711341394827166 7714615823183111229122602111332302201059241554624540244 1021435465256316112168073209761321872088918169200196 1351301161881598616410010919817318636452217226250124123 520238147118126255828521220720659227471658171821892842 22318317021311924815224415416370221153101155167431729 129223925319981081107911322423217818511210421824697228 2513424219323821014412191179162241815114523524914239107 49192214311811991061571848420417611512150451274150254 1382362059322211467292472243141128195786621561156180 插值函式 def _blending t return ttt10t156t 6t5 15t4 10t3 def noise pos if pos1 0 對於整數點，直接從數列中取得數值即可。 return SEQ int pos256 else 對於非整數的點，由左右的整數進行插值運算得出數值。 x0x1 floor pos256floor pos1256 取得非整數點旁的兩個整數。 c0c1 SEQ x0SEQ x1 從數列中取得兩個整數點的數值。 t pos256 x0 計算非整數點離左邊整數點的距離。 return c0_blending 1tc1_blending t 使用插值函式計算非整數點的數值並輸出。 使用以上示例中的 noise 函式便可生成 Perlin 噪聲。 在生成梯度時，理論上應該任意生成一個長度為 1 的向量。在實現中，一維的情況下可以在 8 7 6 5 4 3 2 1 1 2 3 4 5 6 7 8 這 16 個整數中任選一個作為斜率，這樣可以方便的透過對座標值進行位操作實現。二維的情況下，梯度可以從 12 21 12 2 1 1 2 2 1 1 2 2 1 這 8 個向量之中隨機選擇一個。這 8 個向量具有相同的長度，因此點積後的歸一化計算可以省略。三維的情況下，梯度可以從以原點為中心，邊長為 2 的正方體每邊的中點共 12 個向量中選擇，即從 0 1 1 0 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 0 1 1 0 1 1 0 1 1 0 中選擇一個。在實際實現 時也可以透過位操作進行。 Simplex 噪聲 FileSimplexNoise2Dpng 使用 Simplex 方法產生噪聲 FileSimplexNoise2DFFTpng 左圖的頻譜 為了簡化計算，方便使用硬體實現，Ken Perlin 在 2002 年對他的方法進行了改進，改進的方法稱為 Simplex 噪聲。Simplex 噪聲使用 6t515t410t3 作為插值函式，杜絕了導數中的線性部分。另外，Simplex 噪聲演算法有效地降低了插值次數。 如上文，二維經典 Perlin 噪聲將二維空間用正方形填充，用四個頂點進行 3 次插值，而 Simplex 噪聲將二維空間用等邊三角形填充，使用三個頂點進行插值。三維經典 Perlin 噪聲將三維空間用立方體進行填充，使用 8 個頂點進行 7 次插值，三維 Simplex 噪聲使用正四面體填充空間，用 4 個頂點進行插值。對於更高維（N 維）的情況，經典 Perlin 噪聲將空間用超立方體填充，頂點數目是 2N，而 Simplex 噪聲使用高維正三角形（稱為 Simplex）進行填充，頂點數目為 N1。Simplex 噪聲插值次數隨維數增長線性增長。 對於二維的情況，使用正三角形填充空間使得直接判斷某點落在哪個正三角形中，計算該三角形的頂點位置變得複雜。在實現上通常透過座標變換將正三角形對映成直角三角形。使用該方法進行變換可以使用和經典 Perlin 噪聲相同的方法對頂點進行求值。 Simplex 噪聲和經典 Perlin 噪聲的應用 Perlin 噪聲可以用來模擬自然界中的噪聲現象。由於它的連續性，如果將二維噪聲中的一個軸作為時間軸，得到的就是一個連續變化的一維函式。同樣的也可以得到連續變化的二維影像。該噪聲可以用來模擬人體的隨機運動，螞蟻行進的線路等。另外，還可以透過計算分形和模擬雲朵，火焰等非常複雜的紋理。。 Perlin 噪聲對各個點的計算是相互獨立的，因此非常適合使用圖形處理器進行計算。OpenGL 在 GLSL 中定義了一維至四維的噪聲函式 noise1、noise2、noise3、noise4，在該規範中噪聲的性質與上述 Perlin 提出的性質相同。在 Mesa 3D 實現中，這一組函式是使用 Simplex 演算法實現的。在硬體的實現中，噪聲的生成可以達到即時效果。 分形噪聲 分形噪聲是上述 Perlin 1985 年的文章中提出的將符合上文所述三條件的噪聲透過計算分形和構造更復雜效果的演算法。 分形噪聲可以用來模擬自然界的自相似過程，包括海岸線，地形，海浪等。分形噪聲的原理是利用 Perlin 噪聲頻率受限的特性，透過不斷疊加更高頻率的 Perlin 噪聲達到自相似的效果。 一維分形噪聲 在一維的情況下，設噪聲函式為 noise x，則透過 noise 2x noise 4x 等就可以構造更高頻率的噪聲。 下圖左邊是一維 Perlin 噪聲頻率頻率在不斷倍增，振幅不斷倍減的情況，右圖是左邊這些函式求和的影像。 FilePerlinNoise1D1x32xpng6 條頻率倍增的一維 Perlin 噪聲 FilePerlinNoise1DFacalSumpng 一維 Perlin 噪聲分形和右邊的影像是自相似的，將它放大會得到和原圖相似的效果。 從數學上描述分形噪聲，則是： sum_t frac text Noise2i text point2i 分形噪聲有時也被稱作 1f 噪聲。 二維分形噪聲 對於二維的情況，可以使用類似的方法進行分形和運算，產生的效果類似於雲層，如下圖所示。 FilePerlinNoise2D1xpng 二維 Simplex 噪聲原函式 FilePerlinNoise2D1x2xpng 二維 Simplex 噪聲疊加 2 倍頻 FilePerlinNoise2D1x2x4xpng 二維 Simplex 噪聲疊加到 4 倍頻 FilePerlinNoise2D1x2x4x8x16x32x64x128xpng 二維 Simplex 噪聲疊加到 128 倍頻 對分形和函式進行一些小修改可以模擬各種複雜效果。 描述 結果 Noise 2i pointright2i Noise 2i pointright2i 同上，將三維分形噪聲中的一個軸作為時間軸，可以構造連續動態的噪聲效果。 參考文獻 外部連結 An image synthesizer Ken Perlin 在 1985 年研究畫素渲染器時提出了噪聲的性質 Noise Hardware Ken Perlin 在 2002 年研究用硬體發生噪聲時改進了原有的噪聲生成演算法，新演算法稱為 Simplex 噪聲 Simplex noise demystified 對 Simplex noise 進行詳細的介紹 Implementing Improved Perlin Noise Ken Perlin 為 NVIDIA GPU Gems 第一版撰寫了一篇關於 Perlin 噪聲的短文 Implementing Improved Perlin Noise NVIDIA GPU Gems 第二版中給出的使用 Cg 生成 Perlin 噪聲的程式 Perlin Noise 關於一維 Perlin 噪聲和分形噪聲的簡單介紹 Ken Perlin 的主頁 Category 計算機圖形學 Category 二維計算機圖形學