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