噪音 - Perlin Noise
轉載自:http://www.cnblogs.com/babyrender/archive/2008/10/27/BabyRender.html
說起perlin noise, 最初也就是在課上大概了解了一下, 知道是個生成仿真貼圖的東西. 學的時候沒怎么細想, 只是知道這個東西很快. 生成3d貼圖很方便. 不過最近在做sampling的時候, 發(fā)現(xiàn)我的算法有個很大的內(nèi)存問題, 在超過3d的空間里sampling需要太大的內(nèi)存. 結果我敬愛的victor一語敲醒夢中人(抬抬一臺一臺臺). "2d或者3d如果可行的話, 去做noise吧" ... 于是就去找了perlin從85年開始的文章一篇篇看了過來...(說實話, 真正的perlin noise 其實是在89年, 85年那篇個人認為更大的突破在于提出了shading language的思想...) 嗯.. 發(fā)現(xiàn)noise還是很有意思的 ... 而且最近在siggraph和eurographics都很火的樣子...恩, 好吧, 不廢話了, 大家亂起來~~~~
perocedural texture?
說起texture, 一般來說分成2種. 一種是在物體表面直接貼圖片的. 優(yōu)點很明顯, 就是真實感非常的強, 能精確的表達想要的效果(比如墻上的畫啊, 酒瓶上的標簽之類的). 不過缺點也很明顯. 就是內(nèi)存需要量太大, 尤其是做3d貼圖的時候. 一個128*128*128的單色貼圖至少需要2^21個BYTE. ?而實際上, 很多我們需要的貼圖都不是需要跟某張圖一一對應的. 舉個例子, 比如我們想在一個平面上貼一張國際象棋棋盤的紋理. 我們沒必要讓這張紋理和某張國際象棋棋盤的圖片一模一樣, 而只是需要平面"看起來"覆蓋了一張棋盤的紋理就好了. 比如下面這張圖, 我們完全可以用幾行代碼加幾個mod運算就可以生成. 這種方法被人稱作procedural texture. 簡單來說就是一個時間(運算)換空間(內(nèi)存)的換算.
理論上說, 所有的texture都可以用procedural texture來模擬. 但事實上, 很多東西是很難模擬的, 比如說某人的照片, 這個恐怕很難找到一個合理的算法來生成. 但自然界的很多物體, 或者現(xiàn)象都是在混亂的基礎上規(guī)律出現(xiàn)的. 比如說樹的年輪, 我們可以說是很多個不規(guī)則的同心圓. 比如說水面, 我們可以說是很多個不同的sin函數(shù)的和, 等等. 而這些現(xiàn)象, 如果找到一個合理的函數(shù), 在加上一些"合理的"隨機值的話, 完全可以被模擬. 而perlin noise的目的就是來模擬這種現(xiàn)象.
coherent noise?
procedural texture的目的(其實是所有貼圖的目的)是在給定一個坐標值的時候, 能返回一個相應的顏色值. 在2d空間里, 就相當于一個這樣的函數(shù)
Color Texture(float x, float y);
?如果在這個函數(shù)里, 對于每一個x和y返回的顏色都是無關的, 比如, 只是返回一個隨機的顏色值. 那我們就得到了一個非常雜亂的圖像.:
顯然, 這種圖片還里現(xiàn)實中的物體表面相差很遠. 原因就是我們沒有考慮到 : 自然界中, 物體的表面都是相對平滑的, 物體表面距離很近的2個點, 顏色會比較相似, 而距離很遠的2個點, 顏色相對沒有任何關系. ? 這種相對關聯(lián)的關系怎么表現(xiàn)呢? 一種流行的做法就是, 規(guī)定好一些關鍵點. 然后把這些關鍵點的顏色固定. 之后"平滑"的插入這些關鍵點之間的點.?
?? ??
2d的圖片可以表象的更好一點:
?? ?
雖然我們依舊不能說右邊這張貼圖是個什么物體的表面, 但起碼看起來要比左邊那張看起來"自然"多了.左邊那張只是些點的雜亂無章的排列, 叫做噪音(一般叫做白色噪音), 而右邊那張被平滑過的, 就算做關聯(lián)噪音coherent noise.
multi-octaves??
如果你拿到很多個這種"平滑"過的噪音再把它們加起來的話, 呵呵, 會有很有意思的現(xiàn)象發(fā)生的. 比如下面這個1d的例子.?
??
其中每一個噪音的頻率都是之前一個的2倍. 而每一個噪音的振幅都是之前一個的一半. 他們的和是這個樣子的:
?
我們可以看到, 這個"和噪音" 像極了一個1d的山峰, 恩, 我要說,還真看起來蠻像那么回事的,其中, 頻率比較低的噪音表現(xiàn)出了山峰的大概輪廓, 頻率比較高的噪音表現(xiàn)了相對比較雜亂的細節(jié). 恩.其實很多游戲里的山都是這么生成的. 而這個現(xiàn)象, 其實應用到了很多方面. 像fourier transform, wavelet transform之類的轉換.在noise這個領域, 相加之前的每個噪音函數(shù)叫做octave, 這種把很多個頻率是之前一個一般的octave加起來的技術叫做multi octaves. 應用這種技術, 可以仿真很多真實的紋理, perlin在他的網(wǎng)頁里給出了一張圖片. 實際上, 因為這張圖片太經(jīng)典了, 基本上, 只要是介紹perlin noise 的網(wǎng)頁都會給出, 為了遵守行業(yè)潛規(guī)則, 我也不得不把它加上.
?
?perlin noise?
就像前面我說的, 生成perlin noise , 要分3步走:
?
- 固定一部分點的顏色
?
?
?
- ?"平滑"這些固定點中間的顏色
?
- 用上面的方法生成幾個不同頻率的平滑噪音, 然后相加,.
?
為了保證生成噪音的頻率, 一般是通過改變固定點的數(shù)量. 固定點多的, 噪音自然相對比較雜亂(因為2個點之間的間隔比較小, 整體上來看, 平滑的程度自然不高), 也就是說, 噪音的頻率比較高. 相對的, 固定點少的, 噪音的頻率就比較低. 基于這個原因, 對于每個噪音, 我們固定4倍于之前噪音的點就可以保證頻率是之前噪音的2倍(2d環(huán)境下).
說到現(xiàn)在, 你可能覺得perlin noise也不過如此. 也不算什么太革新的東西. 但實際上, 我們還有一個很大的問題沒有解決, 就是那個"平滑". 怎么平滑? 用什么函數(shù)來平滑? 線性的? polynomial的? gaussian的? 復雜的函數(shù)肯定會帶來更好的結果, 但運算時間呢? 要知道, cpu或者gpu可不能浪費大把的時間來處理一個小小的texture, 還有大把更重要的工作要做.?
于是乎, perlin noise 的核心思想出現(xiàn)了. 叫做gradient noise . (其實在很多文獻里, 人們把perlin noise 叫做gradient noise).?
gradient noise?
首先要說的是, ? 固定一部分點的顏色值, 然后"平滑"這些顏色絕對是一個笨辦法(其實叫做value noise. 可能在其他方面有他的應用. 但在texture方面絕對不可行.).因為為了到達很好的連續(xù)度 要用到很高階的過濾函數(shù). 恩, 換種說法. 為了達到很好的連續(xù)度, 用于"平滑"的函數(shù)要很復雜才行. perlin在89年提出了一種更有效的"平滑"方法. 就是給每個固定點固定一個gradient(中文不知道該怎么說, 應該是叫坡度吧.), 然后在中間的點"平滑"這些坡度. 這樣, 哪怕是使用線性函數(shù), 也能保證達到C1的平滑度(具體定義比較麻煩, 其實C1是指兩條曲線在接觸點的微分值相等, 簡單的說, 就是Cn中n越大, 連續(xù)度越好, 一般C2在人眼看來就已經(jīng)很平滑了. 具體定義還是參看相關文獻). 于是乎, 對于生成perlin noise 的那三步, 現(xiàn)在變成了:?
- 固定一部分點的gradient
?
?
?
- ?"平滑"這些固定點中間的gradient
?
- 用上面的方法生成幾個不同頻率的平滑噪音, 然后相加,.
?
而對于"平滑"函數(shù), perlin用了一個hermite曲線 : w(t)=3t2 - 2t3 ?(hermite嘛... 反正就是一個曲線啦....) .因為這個曲線保證了w(0)=0, w(1)=1. (換句話說, 保證了能在固定點取固定值, 而在非固定點取一個平滑的值.) 而且保證了w'(0) = 0和w'(1)=0, 也就是說保證了C2的連續(xù)度. (在02年, perlin推薦了一個更高階的曲線, 保證了w''=0, 能夠保證更好的連續(xù)度). 下面這張圖是w曲線的1d表示
結束了? 還沒有... 還有個內(nèi)存上的小問題...
. 如果說我們的最終texture只是由一些低頻的噪音生成的. 那么當用戶把鏡頭拉的離物體很近的時候, 會像普通貼圖一樣產(chǎn)生一塊一塊的現(xiàn)象(回憶一下 Doom 撞墻的時候). 所以高頻率的噪音絕對是有必要的. 而為了儲存固定點的gradient, 要建立一個數(shù)組才行. 而當噪音的頻率非常高的時候, 由于需要的固定點會很多, 這個數(shù)組也會非常的大. 為了降低內(nèi)存的使用, perlin使用了1個256個元素的哈希表. 也就是說, 預先找出合理的, 足夠隨機的256個gradient, 存在一個表里. 然后每次需要某個固定點的gradient值的時候, 通過這個這個點的坐標, 偽隨機的在表里選出一個值. 對于3d的情況, 如果我們想要坐標(i,j,k)的gradient g(i,j,k),而P里預存儲了256個gradient, 那么:
g(i,?j,?k) =?P[ (?i?+?P[ (j?+?P[k]) mod 256 ] ) mod 256 ]
?這樣, 在生成perlin noise的時候, 內(nèi)存的使用限定在了1個256大小的哈希表. 在02年, perlin進一步縮小了這個哈希表的大小到16.?
想想還有什么要說的...
作為對比, 下面第2張圖使用了perlin noise 來達到"舊"的效果,是不是看起來更真實了?
?
perlin noise 的應用那是相當?shù)膹V泛. texture, terrain, bump map, 云動畫, 煙霧(ray marching)... 可以用在幾乎所有那些"雜亂而有規(guī)律"的現(xiàn)象上.?
????
尤其是對材質的模擬, 可以說是出神入化. 原因就是perlin noise 快, 簡單, 而且只占用很少的內(nèi)存. 當然, 他的缺點也一樣明顯. 就是他的fourier spectrum不夠band limited. 由于要闡述到fourier domain里的東西, 和其他類型的noise , 像 blue noise 的定義, 有機會再寫吧. 值得一提的是, 這兩年有不少人在研究完善perlin noise 和開發(fā)其他具有blue noise性質的其他技術. 比較成功的有wavelet noise (siggraph 2005) 和anisotropic noise(siggraph 2008). 有興趣的朋友歡迎一起討論.
轉載于:https://www.cnblogs.com/zengqh/archive/2012/10/17/2727421.html
總結
以上是生活随笔為你收集整理的噪音 - Perlin Noise的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: QQ空间及邮箱验证码登录的校验方式及自动
- 下一篇: 5款新颖的ReSharper插件