0

所以我一直在研究Perlin和Simplex噪聲是如何工作的,雖然我得到了常規Perlin噪聲的核心原理,但我對於置換和漸變表的工作原理有點困惑。Perlin和Simplex Noise的排列和漸變表如何在實踐中工作?

從我的理解來看,它們提供比種子隨機數生成器更好的性能,因爲它們是預先計算的值的表格,它們爲快速訪問提供了很好的索引。

我不完全知道的是他們是如何工作的。我見過的洗牌值的陣列,像這樣實現從0-255置換表:

permutation[] = { 151,160,137,91,90,15, 
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 
}; 

但我不確定這個是什麼的practial目的。我想知道的是:

  • 如何使用與網格點相關的置換表?
  • 如何生成漸變表?
  • 如何使用梯度表的排列表中的值?置換值是否與梯度表中的索引相對應?

回答

1

我一直在使用libnoise和perlin噪聲代碼進行一段時間的分離,以便我能夠理解它是如何工作的。我討厭使用我不明白的代碼:)

如果你不使用Unity,可能會幫助你,但你也許能夠相應地轉換代碼。這對我幫助很大。

有各種其他網站提示和技巧。谷歌libnoise,程序等應該告訴你一些例子,你可以看看。

基本上,雖然噪聲與整數陣列結合使用的梯度是0,0,0附近的點,但有一些額外的點可以將其填充到設定的數字。使用整數數目的組合拾取基於在x,y,z座標(0和1表示的點的每一側)例如使得您有:

// Separate the integer element 
int ix0 = int(point.x); 
int iy0 = int(point.y); 
int iz0 = int(point.z); 

// Grab the fractional parts for use later 
float tx0 = point.x - ix0; 
float ty0 = point.y - iy0; 
float tz0 = point.z - iz0; 
float tx1 = tx0 - 1f; 
float ty1 = ty0 - 1f; 
float tz1 = tz0 - 1f; 

// Make sure that it is a value compatible with the integer array 
ix0 &= hashMask; 
iy0 &= hashMask; 
iz0 &= hashMask; 

// Get the other side of the point 
int ix1 = ix0 + 1; 
int iy1 = iy0 + 1; 
int iz1 = iz0 + 1; 

// Grab the integers found at the location in the array 
int h0 = hash[ix0]; 
int h1 = hash[ix1]; 
int h00 = hash[h0 + iy0]; 
int h10 = hash[h1 + iy0]; 
int h01 = hash[h0 + iy1]; 
int h11 = hash[h1 + iy1]; 

// Gradient array 
private static Vector3[] gradients3D = { 
    new Vector3(1f, 1f, 0f), 
    new Vector3(-1f, 1f, 0f), 
    new Vector3(1f,-1f, 0f), 
    new Vector3(-1f,-1f, 0f), 
    new Vector3(1f, 0f, 1f), 
    new Vector3(-1f, 0f, 1f), 
    new Vector3(1f, 0f,-1f), 
    new Vector3(-1f, 0f,-1f), 
    new Vector3(0f, 1f, 1f), 
    new Vector3(0f,-1f, 1f), 
    new Vector3(0f, 1f,-1f), 
    new Vector3(0f,-1f,-1f), 

    new Vector3(1f, 1f, 0f), 
    new Vector3(-1f, 1f, 0f), 
    new Vector3(0f,-1f, 1f), 
    new Vector3(0f,-1f,-1f) 
}; 

private const int gradientsMask3D = 15; 

// Grab the gradient value at the requested point 
Vector3 g000 = gradients3D[hash[h00 + iz0] & gradientsMask3D]; 
Vector3 g100 = gradients3D[hash[h10 + iz0] & gradientsMask3D]; 
Vector3 g010 = gradients3D[hash[h01 + iz0] & gradientsMask3D]; 
Vector3 g110 = gradients3D[hash[h11 + iz0] & gradientsMask3D]; 
Vector3 g001 = gradients3D[hash[h00 + iz1] & gradientsMask3D]; 
Vector3 g101 = gradients3D[hash[h10 + iz1] & gradientsMask3D]; 
Vector3 g011 = gradients3D[hash[h01 + iz1] & gradientsMask3D]; 
Vector3 g111 = gradients3D[hash[h11 + iz1] & gradientsMask3D]; 

// Calculate the dot product using the vector and respective fractions 
float v000 = Dot(g000, tx0, ty0, tz0); 
float v100 = Dot(g100, tx1, ty0, tz0); 
float v010 = Dot(g010, tx0, ty1, tz0); 
float v110 = Dot(g110, tx1, ty1, tz0); 
float v001 = Dot(g001, tx0, ty0, tz1); 
float v101 = Dot(g101, tx1, ty0, tz1); 
float v011 = Dot(g011, tx0, ty1, tz1); 
float v111 = Dot(g111, tx1, ty1, tz1); 

// Interpolate between 2 dot results using the fractional numbers 
l0 = Lerp(v000, v100, tx); 
l1 = Lerp(v010, v110, tx); 
l2 = Lerp(l0,l1,ty); 

l3 = Lerp(v001, v101, tx); 
l4 = Lerp(v011, v111, tx); 
l5 = Lerp(l3,l4,ty); 

l6 = Lerp(l2,l5,tz); 

這導致在一個單一的數字,表示空間中單個唯一點的代表使用相同的整數和梯度數組。只需更改種子並重新整理整數數組和梯度數組,將生成一個不同的數字,以便爲項目帶來唯一性,但使用相同的代碼來生成它。

爲什麼整數數組是重複的總數爲512個元素的數字集合,這樣查找並不會意外超過上面代碼中添加的+1值可能導致的0-255限制。 (1D x0 - x1),正方形(2D x0,y0 - x1,y1)和立方體(3D x0,y0,z0 - x1,y1,z1),您將希望看到什麼代碼在做,而且大部分代碼將非常相似。

我試着製作我自己的代碼版本,但儘管做了幾次嘗試,我現在可以理解爲什麼每個人的噪音代碼都如此相似。實際上只有perlin的一種方式,同樣的單工噪音也能起作用。

所以我現在的目標是將這個功能應用到着色器等效代碼中,以幫助我至少理解perlin噪聲和着色器編程的來龍去脈。這是一個學習曲線,但它同時很有趣。

很希望,這已經回答了你所有的問題。如果你想知道原因和肯·培林的改善培林碼退房的wherefores如下:

http://http.developer.nvidia.com/GPUGems/gpugems_ch05.html - 視覺魔方

相關問題