看板 GameDesign 關於我們 聯絡資訊
上一篇, 我們一個 function 做了一個直徑為 2 的黑色白底漸層圓, 現在想改成黑色實心圓。 上一篇的 code https://i.imgur.com/334yGHD.jpg
執行結果 https://i.imgur.com/pfzXpxl.png
用 if 來寫實心圓 警告! 不要這樣寫! 直覺上, 我們可以簡單的用 if-statement 寫, 像這樣。 code https://i.imgur.com/DdqvAGY.jpg
雖然上面的程式是可以動的, 但沒人會這樣寫, Shader 是控制顯卡的語言, 顯卡的特性除了大量的平行運算外, 另一點是它非常不擅長處理判斷式。 用了 if-else 或其他類似的任何語法 (ex: a = (a>b)? c:d), 都會大幅的拖累效能, 所以在 Shader 中是看不到 if-else 的。 不用判斷式的前題下, Shader 有提供幾個數學運算的函式, 可以組合起來代替 if-else。 常用的內建函式 step(edge, val) - (val>=edge? 1.0: 0.0) clamp(val, min, max) - 回傳 val,但最大不超過 max, 最小不低於 min floor(val) - 取最接近但不超過 val 的整數 ceil(val) - 取最接近且超過 val 的整數 mod(x,y) - x/y 的餘數 fract(val) - 取得小數值 sin cos smoothstep(edge0, edge1, val) - 類似 step,但在 edge0 和 edge1 之間時, 會平滑的回傳 (0,1) 之間的值。 sign(val) - 判斷 val 的正負值,正值回傳1.0,反之-1.0。 mix(val1, val2, weight) - 照權重將 val1 val2 混合回傳。 abs(x) - if x<0 return x*-1.0 用 step 產生 mask 畫實心圓 在不使用 if 的前提下, 我們可以用 step (大於某數為1,小於某數為0), 來產生一個 mask。 code https://i.imgur.com/kLPMFPY.jpg
這樣就可以不用 if-else 畫出實心黑色圓了。 image https://i.imgur.com/DgxbCgk.png
下一篇會繼續練習這篇提到的內建運算的函式, 先畫出一條平行的雷射光, 然後頭尾縮短變成一個光點, 再來加入時間參數變成一道射過螢幕的光箭, 最後讓彈道變曲線, 變成流星般的效果。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 61.228.97.156 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1632722097.A.474.html ※ 編輯: meowyih (61.228.97.156 臺灣), 09/27/2021 14:20:38 ※ 編輯: meowyih (61.228.97.156 臺灣), 09/27/2021 14:52:11
CarpeDiemAL: 推! 09/28 15:53
oopFoo: if是效能的問題,warp/wavefront最好是走同一個if。你畫 09/28 19:57
oopFoo: 圓圈剛好大部分warp/wavefront會在同一邊所以ok。 09/28 19:58
oopFoo: 當然能避免if是最好,尤其在fragment shader 09/28 20:27
leonardo0917: 推推 09/29 12:35
erowii: 推!原來是這樣! 10/02 19:53
tv1239: 推 解答了很多工作上碰到的疑惑 <(_ _)> 10/30 04:27