[程式] 超新手 shader language 教學文 (四)

作者: meowyih (meowyih)   2021-09-29 20:09:18
有看完前三篇的新手,
是不是想說:
"我學 shader,
是想畫出浩克大戰索爾的3D動畫,
怎麼學了半天只畫了一個雷射光?!
我阿嬤教得都比你快啦!"
雖然我保證看完這篇,
你還是畫不出來復仇者聯盟的浩克,
但是要畫出守護者羅夏的臉(Rorschach in Watchmen)
應該沒問題的唷! (笑)
寫程式,
一定知道亂數(random)是甚麼。
寫 shader,
也一定會聽過雜訊/噪音(noise)這個詞。
這二個有甚麼不同?
這是亂數
https://i.imgur.com/sgywCet.png
這是雜訊
https://i.imgur.com/vPWjuzI.png
... huh? XD
讓我們先做一個簡單的亂數函式吧
亂數
下面函式的功用,
是輸入一個值 float x,
然後輸出個零到一間的亂數。
演算法是把 sin(x)
把第7位以後的小數點
當作小數點的第1位,
像這樣
sin(x) = 0.4235238812
return 0.8812
https://i.imgur.com/4j6bxXw.jpg
畫圖是用 uv.x 取得亂數 random 後,
在 uv.x 的 x 軸畫一條長度為 random 的直線。
https://i.imgur.com/sgywCet.png
雜訊
而雜訊是比較平滑的亂數,
意思是當輸入的亂數種子是連續的數字的時候,
(ex: 前一個例子 uv.x 就是個從 0 連續到 1 的數字)
希望得到的是 "稍微" 有點規律的結果。
做法請看程式說明,
程式是取二個相鄰的亂數,
然後用二者間的小數值作內插。
(讀程式比較好懂)
https://i.imgur.com/LlUU92K.jpg
用和前面完全一樣的方法,
畫出的結果是
https://i.imgur.com/vPWjuzI.png
一維的雜訊用處不大,
但是這是二維亂數和二維雜訊的基礎。
接著看二維的亂數和雜訊。
二維雜訊
二維雜訊指的是這樣的雜訊函式
float noise2d( vec2 x );
而三維 (float noise3d( vec3 x ))
、四維 (float noise4d( vec4 x ))、
以至於更高維度的差別,
也都只是輸入的是幾維的陣列而已。
下面是個簡單的二維亂數和二維雜訊的寫法。
https://i.imgur.com/6OHGMbH.jpg
亂數的產生跟一維的差不多,
如果看不懂 dot (內插) 是甚麼,
請去LINE國中老師道歉!
開玩笑的,
程式有簡單的說明,
再想不起來,
試試看 a.b = |a| |b| cos(O) 有沒有印象。
雜訊也跟一維的差不多,
差別是本來是一維是二個點間的內插,
二維變成四個點 (也就是平面上正方形頂點)。
因為接下來程式開始不是幾行就能寫完的了,
我也沒辦法每個演算法都重寫一次了,
讓我偷懶用剪貼的,
抱歉。
我們把每個 uv 的點的亂數畫出來
亂數code
https://i.imgur.com/ZoroeHF.jpg
亂數畫面
https://i.imgur.com/optWAiL.png
然後把每個 uv 的雜訊畫出來
雜訊code
https://i.imgur.com/gEUAQcC.jpg
雜訊畫面
https://i.imgur.com/4JZmYjb.png
比較一下畫面,
亂數就真的是平均分配的 0~1 的隨機數字,
雜訊每個值都跟相鄰的值有關係,
所以?
當要畫一面有髒汙的牆壁時,
要用到的是雜訊。
要畫沙地上的隨機散佈的閃光時,
要用到的是亂數。
多維雜訊的常見運用
前面我們只是單純的把某個 uv 當種子,
然後在 uv 位置上畫出數值,
實際上的運用是可以很多元的。
1. 把某一個維度當作時間變成動畫效果。
我們還是運用前面那個 2D 雜訊的函式,
配合下面這個簡單的程式,
程式有一行是畫亂數動畫用,
一行可以畫雜訊動畫,
一次執行一行就好。
https://i.imgur.com/RgA34yV.jpg
Visualized 2D random numer
https://www.youtube.com/watch?v=oSNcR1Z-_NQ
Visualized 2D Noise
https://www.youtube.com/watch?v=Z87XGQxGUPg
如果覺得畫面頓頓的,
那是錄影和youtube的技術問題,
在 ShaderToy 上雜訊跑起來風騷的勒 (誤)。
同樣的邏輯,
我們把三維的雜訊畫成 3D 模組,
大概就是一堆不規則的 3D 霧氣。
但如果把其中一維當時間,
就可以畫出2D變形蟲般的平面動畫。
所以我們為什麼要四維的雜訊?
我們可以把其中一維當時間,
可以做成一陀會蠕動變形的史萊姆,
就不用辛苦建立模組了~
2. 把回傳結果當作高度
在一個 3D 世界的水平平面上,
我們對每一個點做3維雜訊,
然後把回傳的值當作高度,
形成的就是一堆的高山群。
自動產生地形在實務上,
最簡單的方法是用 vertex shader 做,
我也不知道這系列會不會寫到 vertex shader,
希望會囉。
上面二種外當然還有很多很多,
像是把雜音回傳做成顏色就是一個例子。
常用到的雜訊演算法
下面幾個是在各種遊戲引擎裡,
常會看到的雜訊演算法,
我不熟歷史,
所以如果有錯得請見諒。
Perlin Noise (1983)
1983 年 Perlin 發表的雜訊演算法,
有專利不能亂用,
使用類似上面提到的亂數內插法,
應該有支援到四維以上的雜訊。
Simplex Noise (2001)
Perlin 把自己的演算法改善後的東西,
最明顯的差別是,
本來用正方形/正方體的頂點做內插的做法,
改成三角形/三角錐的頂點內插,
想像一下就知道有效能很大的改進。
因為是同一個人做的,
所以還是常被叫 Perlin Noise,
一樣有專利! 不能亂用~
(Unity 好像有 Perlin 名字的 API,
不知道是不是付錢給他了?)
Open Simplex Noise (2004)
Kurt Spencer 在 GitHub 上分享的演算法,
可以用在各種 Project 上,
不用怕被告~
世界會進步就是有這種無私的大大 T_T
令人敬佩。
Open Simplex Noise 其實還是 Simplex Noise,
但不管是為了效能,
還是為了避開專利,
有改了不少地方,
GitHub 上是 Java 寫的,
現在當然各種語言的版本都有了。
不管是哪種,
使用上基本上都是:
float noise( vec2 x );
float noise( vec3 x );
float noise( vec4 x );
引擎裡用雜訊的各種參數
遊戲引擎中,
雜訊演算的參數,
大抵上都是設定要取樣到多細,
請參考下面 1D 雜訊的code (前面用過的)
https://i.imgur.com/LlUU92K.jpg
在第 23 行的地方,
寫了 uv.x * 100,
為什麼要 *100?
因為要 zoom-out,
為什麼要 zoom-out?
因為我們找 "相鄰" 的二個亂數值 (第12行)
是用 1 當間隔的,
間隔越小,
雜訊越細致,
間隔越大,
雜訊越粗曠,
請自己改這個值試試就懂了,
如果不乘100,
就只是個有點平滑的上坡而已。
不管是幾維的雜訊,
間隔的大小都直接影響到雜訊的 "外型"。
所以實際上在使用時,
引擎或 API 都會讓使用者調整的。
羅夏的臉
跟著我這樣做!
使用三維雜訊,
把其中一維當作時間,
另外二個當 uv,
先畫圖再做鏡像,
需要的話用 round 讓黑白分明點,
看,就是這麼簡單!
https://i.imgur.com/zGHwpAb.png
......
好啦,
我知道我開頭有說要寫,
但時間不夠,
讓我過幾天找時間再寫。
抱歉啦~
作者: dklassic (DK)   2021-09-29 20:24:00
XD 辛苦了看反應熱烈你得再多寫五篇了吧(?
作者: oopFoo (3d)   2021-09-29 21:08:00
讚!產生地形是用Fragment Shader沒錯。
作者: coolrobin (泳圈)   2021-09-29 22:08:00
30天鐵人邦 (X
作者: louisalflame (louisalflame)   2021-09-30 01:57:00
加油 對萌新幫助頗多
作者: OSDim (I'm So Sorry)   2021-09-30 02:08:00
這系列超優文==
作者: nicetw20xx (哇愛台灣)   2021-09-30 08:36:00
系列文對沒碰過的我滿有趣的
作者: wangm4a1 (水兵)   2021-09-30 09:04:00
作者: CarpeDiemAL (CarpeDiemAL)   2021-09-30 09:46:00
推推~~~
作者: iLeyaSin365 (伊雷雅鑫)   2021-09-30 18:36:00
我想問:都聽說技美必備會學shader(應該就是你寫的程式碼吧?),但問題是引擎不都能畫雷射光(用調的)嗎?,3dsmax ,substance的材質也是那麼如何把寫shader的知識跟那些連起來?
作者: oopFoo (3d)   2021-09-30 20:32:00
https://reurl.cc/WX1zr7 Substance Shader API,有範例但有限制在API 的 砂盒裡。原理跟這裡是一樣的
作者: LayerZ (無法如願)   2021-10-01 13:27:00
@iLey 寫這東西你要想的是,畫面上每個點在畫的時候要怎麼搞,這幾篇都是從最最最基礎入門,而不是在告你做雷射我把我入門的東西也分享一下好了,雖然可能不適合新手..
作者: johnny94 (32767)   2021-10-03 01:06:00
跪求當成連載來寫,好好看
作者: aegis123321 (PE)   2021-10-04 18:50:00
等等perlin noise 1983有專利!? 剛剛餵狗只看到2001的才有?
作者: scott20144 (DaYo)   2021-10-22 07:39:00
優文

Links booklink

Contact Us: admin [ a t ] ucptt.com