手賤去點了圖形學裏面的噪聲課程,而後一個週末就交代在這上面了,仍是有些雲裏霧裏。html
噪聲就是給定一個輸入變量,生成一個值在0~1範圍內的僞隨機變量的函數。在圖形學中通常是輸入一個座標獲得一個範圍在0~1之間的變量,在利用各類顏色計算獲得一些比較酷炫的效果,像火焰、雲彩、地形等。下面就是perlin噪聲生成個灰度圖。算法
沒啥意思是吧,那麼看下面這個:函數
如今說說最有名的噪聲算法:perlin噪聲又稱柏林噪聲,噪聲鼻祖。柏林噪聲是基於網格的,假想了一堆格網,每一個格子由四個頂點組成(三維場景就是立方體,每一個立方體由8個頂點組成);post
圖1:小藍點表明輸入值在單元正方形裏的空間座標,其餘4個點則是單元正方形的各頂點ui
每一個頂點有一個僞隨機向量(就是一個向量,由一個僞隨機函數生成的,僞隨機函數能夠隨便找一個,perlin老爺子也是隨便找了一個)。this
圖2:各頂點上的梯度向量隨機選取結果url
同時這四個頂點距離落在格網中的點,能夠獲得四個距離向量。spa
圖3:各個距離向量.net
將圖2獲得的梯度向量與圖3的距離向量作點乘,因爲都是單位向量點乘積在0-1之間。同時這個點最終的值由四個點乘積根據權重關係作差值獲得。code
這個差值函數使用緩和曲線(ease curves)來計算它們的權重和。在原始的Perlin噪聲實現中,緩和曲線是s(t)=3t2−2t3s(t)=3t2−2t3,在2002年的論文6中,Perlin改進爲s(t)=6t5−15t4+10t3s(t)=6t5−15t4+10t3。(原文來自這篇文章)
好了如今來看看第一個效果是怎麼作出來的(至於第二個麼,咳咳,等我徹底看明白會寫出來的)
這個效果是來自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 ); }
最後仍是列一下大神們的文章: