学习一下 GL(一)

359 阅读4分钟

前言

阅读 The Book of Shaders 的全过程,以及非常主观的一些总结。

Shader 着色器

并行运算,像一系列像素点同时着色。

GLSL

像 C 语言一样的着色语言

Hello World

image.png

#ifdef GL_ES 
precision mediump float;
#endif

uniform float u_time;

void main() {
  gl_FragColor = vec4(0.0,0.4,0.6,1.0);
  // gl_FragColor = vec4(0,1,1,0); 错误,不能自动转化类型

}
  1. 宏,定义了 GL_ES 才执行包裹着的precision mediump float 代表设定中精度。
  2. 精度越高质量越高运行开销越大。
  3. gl_FragColor 代表颜色,相当于全局变量。
  4. 填浮点,因为并不能保证有自动类型转换。

Uniforms

统一只读的输入值

比如有

#ifdef GL_ES 
precision mediump float; 
#endif 

uniform vec2 u_resolution; // 画布尺寸(宽,高) 
uniform vec2 u_mouse; // 鼠标位置(在屏幕上哪个像素) 
uniform float u_time; // 时间(加载后的秒数)

这样就可以做一个随着时间变化的颜色了。

#ifdef GL_ES
precision mediump float;
#endif

uniform float u_time;

void main() {
  gl_FragColor = vec4(abs(sin(u_time)),0.0,0.0,1.0);
}

image.png

gl_FragCoord

用来处理画布上每一个像素点的颜色。

比方说希望越靠左边颜色越红反之越黑。

image.png

再比方说希望越靠上面越蓝否则越白。

image.png

组合起来是这样的。

image.png

可以发现每次都要vec2 st = gl_FragCoord.xy / u_resolution,这是为什么?

因为要获取规范化值,说人话就是把具体数值转化为比例值

u_resolution代表宽高,gl_FragCoord.xy代表像素点的位置。两者每一维各自相除之后就转化为了比例。

算法绘图

一次函数

什么叫多看一眼就会爆炸,乍一看没看懂。。 image.png 但是只是因为没见过smoothstep是什么东西,所以才看不懂。在这里,+ 可以当作是两个着色器重叠(不一定对,但最好先理解)。可以大胆猜pct * vec3(0.0, 1.0, 0.0)是用来画绿线的,所以首先关注这部分。

简单来说,看代码。

float smoothstep(float t1, float t2, float x) {
    x = clamp((x - t1) / (t2 - t1), 0.0, 1.0);
    
    return x * x * (3 - 2x);
}

其中 clamp 代表提供两个最值一小一大,然后检测第三个数,输出的数为这个数字夹在里面的值(小于最小则最小,大于最大则最大,其余在之内)。

最终smoothstep获取的值为:x 越靠 t1 (<= t1)则越接近 0(最小为 0),越靠 t2 (>= t2)则越接近 1(最大为 1)。

具体讲解推荐 Shader实验室: smoothstep函数 - 知乎 (zhihu.com)

所以上图中的 plot 函数获得的东西的理解如下:

  • 为什么检测值要传入的是abs(st.y - st.x),首先可以想到他在y = x的曲线上越接近,那这个值就越小,结果就是越来越接近 0,再看smoothstep(0.01, 0.0, t),可以看到它越接近t2,也就是 smoothstep(...) 获取的值越接近 1,因此pct * vec3(0.0, 1.0, 0.0)越来越能显现绿色。
  • 然后我们再看看这个abs(st.y - st.x)越来越大,也就是离y = x的曲线越来越远的情况。这时候x远远超过了0.01,但他最大还是只能为0.01,因此放他属于越来越接近或者已经等于t1,因此经过smoothstep处理就越来越接近0,因此别的地方就画不出绿线了(因为0 * vec3(...) = vec3(0))。
  • 在这里我们还可以尝试调大调小这个t1的值观察它的变化,相信能够得到更好的理解。

总感觉有点说复杂了。。不知大伙还能不能理解,总的来说绿线就是这么画出来的。

顺便说一下这个float y = st.x,就代表 y 随 st.x,然后因为color就是从左往右越来越白,至于为什么还要乘上这个(1 - pct),你可以去掉这个绿线试试看显示了什么东西,理解了自然明白了。(答案是让这个渐变背景不会影响到绿线上)

高次幂函数

当你好像理解了上面所说的之后,看到这个你又懵了。。 image.png

我们再尝试梳理一下。

看第一项,f(x) = smoothstep(pct - 0.02, pct, st.y),在 y 越来越大的时候,代表越来越接近 甚至超过t2,这个时候f(x)基本上是 1。在示例代码中plot(st, y)代表你的 st.y 越接近 y 则plot就越基本是1。因此假设只保留这一项,那么显现出来的图形是这样的:

image.png

这就是 y 超过了 st.y 之后都染上绿色了。

那么再看这个公式的第二部分smoothstep(pct, pct + 2, st.y)

image.png

原理是一样的,只不过做了相差,就是将所有 st.y 大于 pct + 2 的部分全部的 1 抹掉,做减法嘛(第一项是 st.y 大于pct 的部分 全设为 1 了)。

image.png

这里面我为什么pct * vec3(1.0, -1.0, 0.0),我为什么要在 G 值上设为 -1 ,可以思考一下。

大概就是这么个过程,想讲明白发现很费劲。。

step 函数

尝试改变 step 中第一个参数。如注释所述,在step的第二个参数小于第一个参数(阈值)时为0.0,否则为1.0,与smoothstep的区别在于它是离散的,smoothstep是平滑连续的。

image.png

image.png

写一个波形图,可以随时间移动的

image.png

再写一个波纹图

image.png