[程式] 超新手 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