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

看板GameDesign (遊戲設計)作者 (meowyih)時間3年前 (2021/09/29 20:09), 3年前編輯推噓13(1308)
留言21則, 12人參與, 3年前最新討論串1/1
有看完前三篇的新手, 是不是想說: "我學 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
...... 好啦, 我知道我開頭有說要寫, 但時間不夠, 讓我過幾天找時間再寫。 抱歉啦~ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 61.228.98.231 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1632917360.A.40C.html

09/29 20:24, 3年前 , 1F
XD 辛苦了
09/29 20:24, 1F

09/29 20:24, 3年前 , 2F
看反應熱烈你得再多寫五篇了吧(?
09/29 20:24, 2F
反正我只是個寫不出好遊戲的老頭, 既然有人看, 我就為了台灣的遊戲界寫個幾篇吧! (T_T) 也許哪個不世天才 看了這幾篇就橫空出世, 自己寫了個3A大作也不一定 XDDD 真的有這種天才的話別忘了遊戲後面的 special thanks 提到我一下謝謝 m(_ _)m

09/29 21:08, 3年前 , 3F
讚!產生地形是用Fragment Shader沒錯。
09/29 21:08, 3F
※ 編輯: meowyih (61.228.98.231 臺灣), 09/29/2021 21:33:26

09/29 22:08, 3年前 , 4F
30天鐵人邦 (X
09/29 22:08, 4F

09/30 01:57, 3年前 , 5F
加油 對萌新幫助頗多
09/30 01:57, 5F

09/30 02:08, 3年前 , 6F
這系列超優文==
09/30 02:08, 6F

09/30 08:36, 3年前 , 7F
系列文對沒碰過的我滿有趣的
09/30 08:36, 7F

09/30 09:04, 3年前 , 8F
09/30 09:04, 8F

09/30 09:46, 3年前 , 9F
推推~~~
09/30 09:46, 9F

09/30 18:36, 3年前 , 10F
我想問:都聽說技美必備會學shader(應該就是你寫的
09/30 18:36, 10F

09/30 18:36, 3年前 , 11F
程式碼吧?),但問題是引擎不都能畫雷射光(用調的)
09/30 18:36, 11F

09/30 18:36, 3年前 , 12F
嗎?,3dsmax ,substance的材質也是那麼如何把寫sh
09/30 18:36, 12F

09/30 18:36, 3年前 , 13F
ader的知識跟那些連起來?
09/30 18:36, 13F
雷射光那篇的目的並不是要教怎麼話雷射光, 那篇只是要熟悉數學函式, 像是 abs/step/sin 等等。 從第一篇到現在這篇, 其實都只是在講數學理論, 沒有任何實務的應用。 因為實務的應用跟開發要怎麼做, 和使用哪種軟體和引擎有關, 不管是 Unreal/Unity/Godot/Blender 或其他的人物模組軟體,服裝模組軟體...etc. 每個軟體都有差異, 我沒打算寫那部分的教學, 因為我也不是任何一種軟體的專家 XD shader 的中文翻譯叫 "著色器", 顧名思義它可以用來製作和修改材質, 而像 substance 或 3dsmax 之類的軟體, 它們為了讓使用者在沒學過相關知識的前題下也能使用, 軟體裡面已經有了很多很多的材質, 而且可以用視覺化的方法套用在3d模組上。 換句話說, 就是他們已經寫好一堆 shader 給設計者用了。 像是你指定某個物件要套用某個材質, 這裡面 shader 相關的應用在背後。 雖然他們也有自訂 shader 的功能, 不過定義上算高級功能? 在這種前提下, 非軟體相關的藝術工作者, 其實沒有學 shader 的必要, 就算有, 頂多學學 "把某個材質和另一個材質相加" 之類的操作就夠了, 對寫成程式的人來說, 這句話也許代表了相乘,相加,相減...etc. 但不知道這些, 使用預設的材質也能做出很驚人的效果了。 所以你說美術工作者是不是要學 shader, 我覺得知道點當科普看看就好, 就像大廚也不用真的知道醬油是怎麼做的吧? XD 知道點大概, 哪天遇到做不出來的材質時, 再去研究? ※ 編輯: meowyih (61.228.98.231 臺灣), 09/30/2021 19:08:58 ※ 編輯: meowyih (61.228.98.231 臺灣), 09/30/2021 19:11:54 ※ 編輯: meowyih (61.228.98.231 臺灣), 09/30/2021 19:12:58

09/30 20:32, 3年前 , 14F
https://reurl.cc/WX1zr7 Substance Shader API,有範例
09/30 20:32, 14F

09/30 20:36, 3年前 , 15F
但有限制在API 的 砂盒裡。原理跟這裡是一樣的
09/30 20:36, 15F

10/01 13:27, 3年前 , 16F
@iLey 寫這東西你要想的是,畫面上每個點在畫的時候要怎麼
10/01 13:27, 16F

10/01 13:28, 3年前 , 17F
搞,這幾篇都是從最最最基礎入門,而不是在告你做雷射
10/01 13:28, 17F

10/01 13:30, 3年前 , 18F
我把我入門的東西也分享一下好了,雖然可能不適合新手..
10/01 13:30, 18F

10/03 01:06, 3年前 , 19F
跪求當成連載來寫,好好看
10/03 01:06, 19F

10/04 18:50, 3年前 , 20F
等等perlin noise 1983有專利!? 剛剛餵狗只看到200
10/04 18:50, 20F

10/04 18:50, 3年前 , 21F
1的才有?
10/04 18:50, 21F
文章代碼(AID): #1XL5TmGC (GameDesign)
文章代碼(AID): #1XL5TmGC (GameDesign)