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

作者: meowyih (meowyih)   2021-09-27 13:54:55
上一篇,
我們一個 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
下一篇會繼續練習這篇提到的內建運算的函式,
先畫出一條平行的雷射光,
然後頭尾縮短變成一個光點,
再來加入時間參數變成一道射過螢幕的光箭,
最後讓彈道變曲線,
變成流星般的效果。
作者: CarpeDiemAL (CarpeDiemAL)   2021-09-28 15:53:00
推!
作者: oopFoo (3d)   2021-09-28 19:57:00
if是效能的問題,warp/wavefront最好是走同一個if。你畫圓圈剛好大部分warp/wavefront會在同一邊所以ok。當然能避免if是最好,尤其在fragment shader
作者: leonardo0917   2021-09-29 12:35:00
推推
作者: erowii (保保)   2021-10-02 19:53:00
推!原來是這樣!
作者: tv1239 (路過的)   2021-10-30 04:27:00
推 解答了很多工作上碰到的疑惑 <(_ _)>

Links booklink

Contact Us: admin [ a t ] ucptt.com