theme: cyanosis
Flutter & GLSL 系列文章:
- 《Flutter & GLSL - 壹 | Shader 让绘制无限强大》
- 《Flutter & GLSL - 贰 | 从坐标到颜色》
- 《Flutter & GLSL - 叁 | 变量传参》
- 《Flutter & GLSL - 肆 | 从条纹到马赛克》
- 《Flutter & GLSL - 伍 | 图形区域控制》
- 《Flutter & GLSL - 陆 | 平滑过渡 smoothstep》
案例代码开源地址 【skeleton】
1. 去除锯齿
在上一篇中,我们通过 step 函数通过 像素与原点的距离 控制输出的颜色,从而达到如下右图展示白色圆形区域。但仔细观察不难发现圆的四周非常锯齿非常明显,所以视觉上很不美观。本篇将介绍一下 smoothstep 函数让值可以平滑过渡。
| 有锯齿 | 平滑过渡 | | --- | --- | | |
|
内置函数 smoothstep(e0,e1,v) :
v < e0
时, 返回 0;v > e1
时, 返回 1;v 在 [e0,e1] 之间
时,通过曲线函数在 0~1 间过渡插值
这样的话,通过圆形区域控制纹理采样,就可以得到边缘光滑的图片,如下右图:
| 有锯齿 | 平滑过渡 | | --- | --- | ||
|
smoothstep 方法可以让结果在 [e0,e1] 区间内逐渐变化,而不是像 step 非 0 即 1 的突然转变。下面的 circle 函数中,len 表示像素坐标距离,区间是 [r, r + 0.1]
:
- 当 len 小于 r : smoothstep(r, r + 0.1, len) = 0 ;
1-0 = 1
,表示白色(如下内虚线区域)。 - 当 len 大于 r : smoothstep(r, r + 0.1, len) = 1 ;
1-1 = 0
,表示黑色(如下外虚线外部)。 - 当 在 [e0,e1] 之间 : smoothstep(r, r + 0.1, len) 会从 0~1 过渡插值,
1 - 结果
就是从1~0
的过渡渐变,也就是两个虚线间 由白到黑 的渐变过渡。
```c
version 460 core
include
precision mediump float;
out vec4 fragColor; uniform vec2 uSize;
float circle(vec2 coo, float r) { float len = length(coo); return 1 - smoothstep(r, r + 0.1, len); }
void main() { vec2 coo = FlutterFragCoord() / uSize; coo = coo * 2 - 1; float ret = circle(coo, 0.5); fragColor = vec4(ret, ret, ret, 1); } ```
2. 通过交互来控制过渡区域大小
前面介绍过 Flutter 向着色器中传参,如下所示,定义 uThreshold
变量控制渐变区域的大小。通过 Slider 的拖拽事件改变 uThreshold 的值,从而更直观地展示 smoothstep 的作用:
```c
version 460 core
include
precision mediump float; uniform float uThreshold; uniform vec2 uSize; out vec4 fragColor;
float circle(vec2 coo, float r) { float len = length(coo); return 1 - smoothstep(r, r + uThreshold, len); }
void main() { vec2 coo = FlutterFragCoord() / uSize; coo = coo * 2 - 1; float ret = circle(coo, 0.5); fragColor = vec4(ret, ret, ret, 1); } ```
3. 图片纹理和平滑过渡的结合
上节介绍过通过圆形区域来采样图片的颜色,这里也是类似。通过 color*ret
就可以达到想要的效果。因为:
- 黑色时
ret = 0
,任何颜色乘 0 后透明度都会变成 0 ,效果是不显示。 - 白色时
ret = 1
,任何颜色乘 1 不变,效果是原样显示。 - 在中间的过渡区域内,即颜色的各个分量减少一定的百分比
| uThreshold = 0.2 | uThreshold = 0.3 | | --- | --- | | |
|
这样就完成了图片边缘模糊渐变的小特效:
```c
version 460 core
include
precision mediump float; uniform vec2 uSize; uniform float uThreshold; uniform sampler2D uTexture; out vec4 fragColor;
float circle(vec2 coo, float r) { float len = length(coo); return 1 - smoothstep(r, r + uThreshold, len); }
void main() { vec2 coo = FlutterFragCoord() / uSize; coo = coo * 2 - 1; float ret = circle(coo, 0.5); vec2 picCoo = (coo + 1) / 2; vec4 color = texture(uTexture, picCoo);
fragColor = color*ret;
} ```
本文主要介绍 smoothstep 的使用,让某段区域可以平滑过渡,从而在视觉上消除锯齿或者其他过渡不和谐的转变。虽然 smoothstep 很强大,但是本质上是非常简单的。在 e0 ~ e1 直接通过 x * x * (3 - 2 * x)
函数进行平滑过渡:
c float smoothstep(float e0, float e1, float x) { x = clamp((x - e0) / (e1 - e0), 0.0, 1.0); return x * x * (3 - 2 * x); }
也就是说过渡区域内输入的值,将被以如下的曲线转化输出:比如上面第一个案例区域在 [0.5,0.6],过渡时符合蓝框区域的曲线:
那本文就到这里,后面还会带来更多 Flutter & GLSL 的知识,我们下次再见 ~