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