perlin噪聲
手賤去點了圖形學裡面的噪聲課程,然後一個週末就交代在這上面了,還是有些雲裡霧裡。
噪聲就是給定一個輸入變數,生成一個值在0~1範圍內的偽隨機變數的函式。在圖形學中一般是輸入一個座標得到一個範圍在0~1之間的變數,在利用各種顏色計算得到一些比較酷炫的效果,像火焰、雲彩、地形等。下面就是perlin噪聲生成個灰度圖。
沒啥意思是吧,那麼看下面這個:
現在說說最有名的噪聲演算法:perlin噪聲又稱柏林噪聲,噪聲鼻祖。柏林噪聲是基於網格的,假想了一堆格網,每個格子由四個頂點組成(三維場景就是立方體,每個立方體由8個頂點組成);
Line"/> 圖1:小藍點代表輸入值在單元正方形裡的空間座標,其他4個點則是單元正方形的各頂點
每個頂點有一個偽隨機向量(就是一個向量,由一個偽隨機函式生成的,偽隨機函式可以隨便找一個,perlin老爺子也是隨便找了一個)。
圖2:各頂點上的梯度向量隨機選取結果
同時這四個頂點距離落在格網中的點,可以得到四個距離向量。
圖3:各個距離向量
將圖2得到的梯度向量與圖3的距離向量做點乘,由於都是單位向量點乘積在0-1之間。同時這個點最終的值由四個點乘積根據權重關係做差值得到。
這個差值函式使用緩和曲線(ease curves)來計算它們的權重和。在原始的Perlin噪聲實現中,緩和曲線是s(t)=3t2−2t3s(t)=3t2−2t3,在2002年的論文6中,Perlin改進為s(t)=6t5−15t4+10t3s(t)=6t5−15t4+10t3。(原文來自 ofollow,noindex">這篇文章 )
好了現在來看看第一個效果是怎麼做出來的(至於第二個麼,咳咳,等我完全看明白會寫出來的)
這個效果是來自 ShaderToy 中的。
// 生成一個偽隨機向量,這個函式是找的一個偽隨機函式,可以用其他的偽隨機函式代替 vec2 hash( vec2 x )// replace this by something better { const vec2 k = vec2( 0.3183099, 0.3678794 ); x = x*k + k.yx; // fract的作用是取小數,那麼小數在0~1之間;乘以2再加-1,最終返回座標範圍在-1~1之間 return -1.0 + 2.0*fract( 16.0 * k*fract( x.x*x.y*(x.x+x.y)) ); } float noise( in vec2 p ) { vec2 i = floor( p ); // 取一個格子 vec2 f = fract( p ); // 獲取在格子內的位置 vec2 u = f*f*(3.0-2.0*f); // 根據權重的平滑函式 return mix( mix( dot( hash( i + vec2(0.0,0.0) ), f - vec2(0.0,0.0) ), dot( hash( i + vec2(1.0,0.0) ), f - vec2(1.0,0.0) ), u.x), // 將水平方向得到的兩個點乘積根據水平方向的權重做差值 mix( dot( hash( i + vec2(0.0,1.0) ), f - vec2(0.0,1.0) ), dot( hash( i + vec2(1.0,1.0) ), f - vec2(1.0,1.0) ), u.x), u.y);// 在豎直方向上對兩個值按權重進行差值 } // ----------------------------------------------- void mainImage( out vec4 fragColor, in vec2 fragCoord ) { vec2 p = fragCoord.xy / iResolution.xy; // 畫素位置除以解析度,座標範圍在0~1之間 vec2 uv = p*vec2(iResolution.x/iResolution.y,1.0); // 這時u.x範圍在0~寬高比之間,u.y在0~1之間 float f = 0.0; // left: noise if( p.x<0.6 )// 左邊部分簡單的生成單噪聲 { f = noise( 32.0*uv ); // 32作為一個引數音箱噪音頻率 } // right: fractal noise (4 octaves) else// 右邊部分使用四個倍頻在模擬效果 { uv *= 8.0; mat2 m = mat2( 1.6,1.2, -1.2,1.6 ); f= 0.5000*noise( uv ); uv = m*uv; f += 0.2500*noise( uv ); uv = m*uv; f += 0.1250*noise( uv ); uv = m*uv; f += 0.0625*noise( uv ); uv = m*uv; } f = 0.5 + 0.5*f; f *= smoothstep( 0.0, 0.005, abs(p.x-0.6) );// 生成中間那條黑線,smoothstep的作用看這裡,https://blog.csdn.net/libing_zeng/article/details/68924521 fragColor = vec4( f * iTime, f, f, 1.0 ); }
最後還是列一下大神們的文章: