ShaderToy入门

1,330 阅读3分钟

源码:github.com/buglas/shad…

前言

Shader Toy 就是着色玩具的意思。

在Shader Toy的官网里,大家可以找到许许多多的炫酷案例。

shadertoy 存在的意义,除了好玩、好看,还可以成为许多实战、创新项目的算法支撑和灵感来源。

1-Shader Toy 牛刀小试

我们可以在vscode 里安装一个Shader Toy,然后建立glsl 文件,用来书写shader 代码。

image-20220821203551594

1.建立一个项目文件夹,然后在其中建立一个01-fragColor.glsl 文件

image-20220821204051412

2.绘制一片蓝色。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  fragColor = vec4(0, 0, 1, 1);
}
  • mainImage() :主函数。
  • fragColor :输出变量,用于设置canvas 画布中每个片元的颜色。

3.右击页面,在提示面板中选择Shader Toy:Show GLSL Preview

image-20220708000307505

这样便可以在Shader Toy的显示窗口中看见一张蓝色的画布。

image-20220708000551619

4.我们基于fragCoord 还可以绘制一片线性渐变背景。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 coord = fragCoord / iResolution.xy;
  fragColor = vec4(coord, 1, 1);
}

效果如下:

shadertoy

  • fragCoord: 输入变量,当前片元的像素位置,其对应的坐标系就是canvas画布坐标系:

image-20220822094845457

​ w、h 代表canvas画布的宽高。

  • iResolution: canvas画布的宽高尺寸

到现在我们已经知道了Shader Toy 的正确解锁方式,接下来我们再画个圆形练练手。

2-绘制圆形

一般而言,我们在使用shader toy 绘图的时候,不会用canvas画布坐标系,而是使用一种原点在canvas画布中心,宽高为2 的裁剪坐标系:

image-20220822100807306

接下来咱们就构建一个这样的坐标系,然后绘制圆形。

1.建立裁剪坐标系。

vec2 ClipCoord(in vec2 fragCoord) {
  return 2. * (fragCoord / iResolution.xy - 0.5);
}

2.在mainImage()方法中,将fragCoord转换为裁剪坐标。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 uv = ClipCoord(fragCoord);
  fragColor = vec4(uv, 1, 1);
}

现在右下方都变成了蓝色:

02

3.以uv的长度为rgb色值,可以绘制一个径向渐变。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 coord = ClipCoord(fragCoord);
  float coordlen = length(coord);
  fragColor = vec4(vec3(coordlen), 1);
}

03

4.以uv的长度为判断依据,还可以绘制一个实色填充的圆。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 coord = ClipCoord(fragCoord);
  float coordlen = length(coord);
  vec3 rgb = vec3(coordlen > 0.1 ? 1 : 0);
  fragColor = vec4(rgb, 1);
}

image-20220822115849568

上面的图形是一个椭圆,这是因为canvas画布的宽高并不相同,所以圆形被拉伸了。

5.基于canvas画布中的最小边,构建一个不会让图形发生拉伸的坐标系,在此我暂且称之为投影坐标系了。

vec2 ProjectionCoord(in vec2 fragCoord) {
  return 2. * (fragCoord - 0.5 * iResolution.xy) / min(iResolution.x, iResolution.y);
}

这个投影坐标系跟svg中viewBox 有点类似。

无论canvas画布的尺寸如何,在其内部都会基于其最小的边显示一个正方形。

如下图所示:

image-20220822151049878

image-20220822151208947

6.在投影坐标系中画圆。

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
  vec2 coord = ProjectionCoord(fragCoord);
  float coordlen = length(coord);
  vec3 rgb = vec3(coordlen > 0.1 ? 1 : 0);
  fragColor = vec4(rgb, 1);
}

效果如下:

image-20220822151438635

关于图像周边的锯齿我们后面会说。

现在我们已经知道了如何构建坐标系。接下我们再说一下如何把坐标系显示出来,以方便我们更好的绘图。

参考链接:space.bilibili.com/10707223/ch…