LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

Shader入门教程(图文)

admin
2024年4月1日 9:39 本文热度 684

自从接触了shader之后我便深深得爱上了它,因为它独特的编程思考方式冲击着我这十几年的惯性认知。在向各位大佬学习的过程中,每学到一个新的技巧,我都不禁感叹:“实在是妙!”。本文将整理一些个人常用的shader技巧/方法,只包含片元着色器相关内容。由于本人尚属初学,所以内容会比较基础。

简单几何图形

区间(带通)


两个阶梯函数叠加构成的带通函数,用数字信号处理的角度去思考貌似是个不错的选择

1.  float Band(float v, float start, float end) {

2.      float up = step(start, v);

3.      float down = 1.0 - step(end, v);

4.      return up * down;

5.  }

矩形


x, y两个方向的带通函数叠加

1.  float Rect(vec2 uv, float l, float b, float r, float t) {

2.      float x = Band(uv.x, l, r);

3.      float y = Band(uv.y, b, t);

4.      return x * y;

5.  }

圆形


圆形比较容易出现锯齿,所以用 smoothstep 做平滑处理。
由于 distance() 依赖 sqrt() 开根号,在一些老硬件上会比较耗时,实际使用时可以考虑转换为和r平方进行比较的公式。

1.  float Circle(vec2 uv, vec2 o, float r, float blur) {

2.      return smoothstep(r, r-blur, distance(uv, o));

3.  }

混合叠加

上述几何图形函数的输出值是0或1的float(经过 smoothstep() 可能会出现中间值,不过此处可以不考虑)。
0或1的float值可以利用加、减、乘来模拟位运算。比如上述区间、矩形几何图形都是通过乘法叠加。

加减法例子:ET脸


画一个大圆当脸,减去两个小圆当眼睛

1.  float ETFace(vec2 uv, vec2 o) {

2.      float c = Circle(uv, vec2(.0, .0), 0.5, 0.01);

3.      c -= Circle(uv, vec2(-.2, -.2), 0.2, 0.01);

4.      c -= Circle(uv, vec2(.2, -.2), 0.2, 0.01);

5.      return c;

6.  }

坐标空间处理

Cocos Creator以 左上角 为坐标原点,范围(0, 1)。
shadertoy, GlslEditor中均以 左下角 为坐标原点,范围(0, 1),接下来所有代码将使用这个坐标系。

在绘制某些对称图形时可能需要将原点调整到屏幕中心,即将(0, 1)区间映射到(-0.5, 0.5)。
根据不同场景也可以将(0, 1)区间映射到(-1, 1),哪个处理起来方便用哪个。

1.  // (0, 1)区间映射到(-1, 1)

2.  uv = uv * 2.0 - 1.0;

也可以用下面的方法从任意区间映射到任意区间

1.  float Remap01(float a, float b, float t) {

2.      return (t-a) / (b-a);

3.  }

4.   

5.   

6.  float Remap(float a, float b, float c, float d, float t) {

7.      return Remap01(a, b, t) * (d-c) + c;

8.  }

长宽适配

不知道这个功能的简称是什么,暂且这么称呼吧。
其作用是在分辨率长宽不等的情况下将坐标空间映射为等边,映射后原先较长的一边其自变量区间会被放大

1.  void main() {

2.      vec2 uv = gl_FragCoord.xy/u_resolution.xy;

3.      uv = uv * 2.0 - 1.0;            // 位移到以中间为原点

4.      uv.x *= u_resolution.x/u_resolution.y;    // x的自变量区间拉长

5.      

6.      float mask = Rect(uv, -0.5, -0.5, 0.5, 0.5);

7.      vec3 color = vec3(mask);

8.      gl_FragColor = vec4(color,1.0);

9.  }

计算角度


atan() 计算角度,图中将(-PI, PI)区间映射到(0, 1)区间,并且将值对应的灰度输出。
atan() 计算比较耗时,实际项目中慎用。

1.  #define PI 3.141592653589793

2.   

3.   

4.  void main() {

5.      vec2 uv = gl_FragCoord.xy/u_resolution.xy;

6.      uv = uv * 2.0 - 1.0;

7.      uv.x *= u_resolution.x/u_resolution.y;

8.      

9.      float angle = atan(uv.y, uv.x);

10.    angle = Remap(-PI, PI, 0., 1.0, angle);

11.    vec3 color = vec3(angle);

12.    gl_FragColor = vec4(color,1.0);

13.}

旋转


uv乘以旋转矩阵

1.  #define PI 3.141592653589793

2.   

3.   

4.  mat2 Rotate2d(float angle){

5.      return mat2(cos(angle), -sin(angle),

6.             sin(angle), cos(angle));

7.  }

8.   

9.   

10.void main() {

11.    vec2 uv = gl_FragCoord.xy/u_resolution.xy;

12.    uv = uv * 2.0 - 1.0;

13.    uv.x *= u_resolution.x/u_resolution.y;

14.   

15.    uv = Rotate2d(PI / 6.) * uv;

16.    float mask = Rect(uv, -0.5, -0.5, 0.5, 0.5);

17.    vec3 color = vec3(mask);

18.    gl_FragColor = vec4(color,1.0);

19.}

网格化


将屏幕分割成5x5个网格,每个格子里画一个圆。
原理是将uv拉伸5倍后取小数部分,这样处理后uv会变成每个网格内的局部坐标,这个技巧被广泛使用。

1.  void main() {

2.      // ...

3.      uv = fract(uv * 5.);

4.      float mask = Circle(uv, vec2(0.5), 0.5, 0.01);

5.      // ...

6.  }

噪音(随机化hash)


获取噪音的方法很多很灵活,输入一般是和uv相关的变量,输出(0, 1)范围的1维或2维值。
只要让人肉眼难分辨出模式,就是一个好用的噪音函数。
噪音的用途非常广泛,可以利用噪音降低图片的人工痕迹,后面会单独整理一篇文章。

1.  float Noise1(vec2 p) {

2.      return fract(sin(

3.          dot(p, vec2(12.9898,78.233))

4.      ) * 43758.5453123);

5.  }

6.   

7.   

8.  float Noise2(vec2 p) {

9.      p = frac(p * vec2(123.34, 345.45));

10.    p += dot(p, p + 34.345);

11.    return frac(p.x * p.y);

12.}

常用链接

  • shadertoy
    可以找到很多大神级shader作品
    http://shadertoy.com/

  • 《The Book Of Shaders》
    很棒的入门书籍,可惜还没更新完
    https://thebookofshaders.com/

  • 我的博客
    将《The Book Of Shaders》里的GlslEditor嵌入博客用于平时练习
    https://caogtaa.github.io/shader/2020/07/16/shader-playground/


该文章在 2024/4/1 12:46:01 编辑过
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved