Perlin Noise變種及無縫紋理生成

2021-09-23 01:51:21 字數 4664 閱讀 9756

一、perlin noise變種

通過前面幾篇文章,我們已經成功實現了1d,2d,3d,4d perlin 雜訊,perlin雜訊實現不是很複雜,但是我們也應該注意到,隨著維度的增多,實現的複雜度也在大幅度增加,包括permutation表的檢索和插值都會變得越來越難以控制,而且效能瓶頸表現得也是越來越明顯。當然,我們平時很少用到超過4d以上的perlin雜訊,事情還不沒有想象的那麼困難。在ken perlin的**中,他實現了幾種對雜訊變形應用,我們一併學習之。

(一)turbulence脈流

在分形疊加的過程中,如果我們不是直接取雜訊值,而是取雜訊的絕對值,這時就會因為在0值變化處出現不連續性,形成一些尖銳細紋狀條紋,在影象上表現出來就像毛細血管一樣。脈流的實現就是對各octive取絕對值,生成的圖形如下。 

(二)方向脈流(oriented turbulence)

方向脈流是利用下面公式對脈流進行乙個方向應用。 

sin(x+|noise(p)|+12|noise(2p)|+14|noise(4p)|+...)

sin(x+|noise(p)|+12|noise(2p)|+14|noise(4p)|+...)

sin(y+|noise(p)|+12|noise(2p)|+14|noise(4p)|+...)

sin(y+|noise(p)|+12|noise(2p)|+14|noise(4p)|+...)

方向脈流是在之前turbulence公式的基礎上使用了乙個關於x分量、y分量的正弦函式,這個公式可以讓脈流在表面沿著x方向,y方向形成乙個條紋狀的結構。其生成的圖形如下: 

通過對x,y系統的控制,我們可以生成不同寬幅的條紋。

二、無縫紋理生成

在利用雜訊生成紋理時,我們往往希望生成的紋理是無縫的(tileable,seamless),這樣我們就可以生成連續的地形、雲朵,而不會在邊界處出現跳躍,在大範圍應用時,這種無縫紋理會非常有用。

(一)、利用perlin noise內在週期性生成無縫紋理

在生成perlin雜訊時,我們首先初始化了一張permutation表,目的是利用這張表來索引梯度值,雖然經過多次計算,但對於給點的輸入,會產生乙個固定的輸出,又因為這張表裡只有256個元素,所以當輸入值大於256時,肯定會出現重複,這也是perlin雜訊生成時的內在週期性,為什麼平時我們看起來生成的紋理沒有重複,一方面是因為我們頻率不夠高,另一方面是因為perlin雜訊生成時不僅能處理整數,也能處理小數,這大大平抑了短週期帶來的影響。但如果我們把頻率調高,還是能看出來重複,下面是我輸入了0到1000,我們可以看到週期出現了。 

既然perlin雜訊生成是帶有內在週期性的,那我們就可以利用他來生成我們想要的無縫紋理,原理就是控制對permutation表取值來現實不同週期的調整,我們利用乙個tilerepeat引數對輸入的值進行模除,將其值週期化,同時,我們將對permutation表索引加1的操作也調整到tilerepeat週期內(因為涉及到模除,所以tilerepeat只能取正整數)。關鍵**如下:

if (tilerepeat > 0)

----------------------------------------

public int increase(int num)

通過對輸入值和索引值增量的處理,我們就可以利用tilerepeat來控制週期了,期生成的影象如下: 

至此我們已經能夠根據我們的要求生成無縫的紋理,現在生成的紋理會無縫的鋪滿整個可用的平面,跟畫布大小沒有關係,這有時不是我們想要的,我們可能就只需要單重複紋理,而自己來處理平鋪問題,那這時我們就需要進行周密的計算來確定畫布的大小以確保紋理正好滿週期的畫在畫布上。例如:如果我們取tilerepeat=5,frequency=0.01,如果我們想要獲得乙個整週期紋理,那麼畫布width=500,同理,如果想要獲得兩個整週期紋理,那麼畫布width=1000,以此類推,高度也同樣處理。下面是生成的2x2和1x1紋理,這樣我們就可以隨心所欲的應用生成的紋理了。 

(二)、採用高維紋理生成低維無縫紋理

另一種生成無縫紋理的方法是採取高維生成低維的辦法,先來看張圖: 

在這張2d圖中,如果我們沿著紅色圓環取樣,那麼可以得到1d的無縫紋理,因為圓的週期性保證了取樣後資料的連續性,同樣,對於2d紋理,我們可以使用高階雜訊來圍繞其中乙個軸或者兩個軸來取樣。

1、x軸可平鋪無縫紋理

我們以x軸可平鋪的無疑紋理生成為例,如下圖所示: 

我們用立方體表示3d perlin雜訊,我們在其內部畫乙個圓柱體如綠線所示,然後我們用紅色框沿箭頭向下切開圓柱體的一邊,向左右兩面展開圓柱體的表面,將得到右側所示的長方形(即我們需要的2d紋理),可以想象得到,長方形左右兩條邊是可以沿綠色箭頭方向旋轉重合到一起(它們都來自前面的切口),由此保證了左右兩邊是可以無縫對接到一起的。基於這個基礎,我們就可以得到在x軸向上無縫的紋理。對其進行資料建模後**如下:

float x1 = 20, x2 = 10f;

float y1 = 20, y2 = 10f;

float dx = x2 - x1;

float dy = y2 - y1;

double s = x / (float)width;

double t = y / (float)height ;

float nx = (float)(x1 + math.cos(s * 2 * math.pi) * dx / (2 * math.pi));

float ny = (float)(x1 + math.sin(s * 2 * math.pi) * dx / (2 * math.pi));

float nz = (float)t * 16;

return (float)p3d.perlin(nx, ny, nz);

我們解釋一下**,x1,y1定義了取樣圓的圓心座標, dx / (2 * math.pi) 定義了取樣圓的半徑,s,t定義的是取樣步進值,width,height 為畫布寬和高,s * 2 * math.pi保證了可以精確得到乙個完整的週期,nx,ny就是取樣圓的x,y座標值,正弦、余弦值的週期性也保證了紋理的週期性。需要說明的是在計算nx,ny值的時候,x1,y1,x2,y2的值的選取是可以任意的,但需要保證最後得到nx,ny值為正值(負值晶格座標沒有定義),t * 16是為了使最後生成的影象在y軸上不被拉伸變形。計算後的nx,ny,nz就是3d perlin雜訊的座標,通過上面的**可以生成在x軸上可平鋪的無縫紋理。 

2、xy雙軸可平鋪無縫紋理

實現雙軸可平鋪的2d紋理需要用到4d雜訊,這比x軸可平鋪在概念上來說更難理解一些,更由於高階空間無法視覺化,但只要明白,用兩個正交的圓柱在4d空間中去取樣得到的就是2d無縫紋理,圓柱的週期性和兩個圓柱的正交性保證了得到的x,y值也是正交的。理解起來很難,但在**上來看卻幾乎是一樣的。

float x1 = 1f, x2 = 7f;

float y1 = 1f, y2 = 7f;

float dx = x2 - x1;

float dy = y2 - y1; 

double s = x / (float)width;

double t = y / (float)height;

float f = 0.511165f ;

float nx = (float)(x1 + math.cos(s * 2 * math.pi)  * dx / (2 * math.pi)) * f;

float ny = (float)(y1 + math.cos(t * 2 * math.pi)  * dy / (2 * math.pi)) * f;

float nz = (float)(x1 + math.sin(s * 2 * math.pi)  * dx / (2 * math.pi)) * f;

float nw = (float)(y1 + math.sin(t * 2 * math.pi)  * dy / (2 * math.pi)) * f;

return (float)p4d.perlin(nx, ny, nz, nw);

與x軸可平鋪一樣,x1,y1定義了取樣圓的圓心座標, dx / (2 * math.pi) 定義了取樣圓的半徑,s,t定義的是取樣步進值,width,height 為畫布寬和高,s * 2 * math.pi保證了可以精確得到乙個完整的週期,nx,ny就是取樣圓的x,y座標值,正弦、余弦值的週期性也保證了紋理的週期性,f 是乙個調節因子,可以調整雜訊產生的頻率。需要說明的是在計算nx,ny值的時候,x1,y1,x2,y2的值的選取是可以任意的,但需要保證最後得到nx,ny值為正值(負值晶格座標沒有定義),上面的**其實是在nx,nz和ny,nw面上分別定義了乙個圓柱。計算後的nx,ny,nz,nw就是4d perlin雜訊的座標,通過上面的**可以生成在x軸、y軸上均可平鋪的無縫紋理。 

三、小結

在本節中,我們一是實現了perlin 脈流,二是通過兩種方面實現了無縫的可平鋪2d紋理,第一種方法主要是利用 了perlin雜訊生成時本身的週期性,第二種方法則進行了高階取樣生成低階無縫紋理。相比較,第一種方法的實時效能更好,但需要計算好生成的紋理的寬高,第二種方法可以精確生成指定高寬的無縫紋理,但第二種方法因為要進行高階取樣,所以效率上會有所損失。本節我們只關注了2d無縫紋理,對於更高的3d無縫紋理處理方式是一樣的,但3d無縫紋理操作上還是要複雜得多,特別是如果選用第二種方法的話需要先生成6d雜訊。注:本文採用的第一種方式,有人說會影響octives時的使用,這個讀者可以驗證,在使用第二種方法生成2d xy雙軸可平鋪無縫紋理時,我們發現,輸入的nx,ny,nz,nw值域必須要在乙個晶格內,這也是我們加了f這個頻率調節因子的最初原因,初步分析,最大的可能是我們在perlin4d實現時梯度值與距離值的點乘操作不匹配,稍晚點我們會認真思考這個問題。

Bert及變種簡述

老大哥模型,模型的兩個目標mlm和nsp,採用靜態masking 模型預訓練之前已經確定了masking的位置 bert模型的精簡版本,引數更少,訓練更快,主要有以下改動 矩陣分解。詞向量v到encoder全連線m進行分解,bert中參數量 v m,albert v h m h v m h,h可以比...

0 1揹包問題及變種

0 1揹包問題 有n件物品和乙個容量為v的揹包。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。這個問題的特點是 每種物品只有一件,可以選擇放或者不放。演算法基本思想 利用動態規劃思想 子問題為 f i v 表示前i件物品恰放入乙個...

PHP資料結構 2 氣泡排序及變種

經典氣泡排序 function bubble sort array return array 線性表的刪除 陣列中 function delete array element array,i array pop array return array str array 3,5,2,57,43,64,...