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 <flutter/runtime_effect.glsl>
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 <flutter/runtime_effect.glsl>
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 <flutter/runtime_effect.glsl>
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 的知识,我们下次再见 ~