Flutter & GLSL 系列文章:

事例代码开源地址 【skeleton】

Flutter & GLSL - 陆 | 滑润过渡 smoothstep


1. 去除锯齿

在上一篇中,我们经过 step 函数经过 像素与原点的间隔 操控输出的色彩,从而到达如下右图展现白色圆形区域。但仔细观察不难发现圆的四周十分锯齿十分显着,所以视觉上很不漂亮。本篇将介绍一下 smoothstep 函数让值能够滑润过渡。

有锯齿 滑润过渡
Flutter & GLSL - 陆 | 滑润过渡 smoothstep
Flutter & GLSL - 陆 | 滑润过渡 smoothstep

内置函数 smoothstep(e0,e1,v) :
v < e0 时, 返回 0;
v > e1 时, 返回 1;
v 在 [e0,e1] 之间 时,经过曲线函数在 0~1 间过渡插值

这样的话,经过圆形区域操控纹理采样,就能够得到边际光滑的图片,如下右图:

有锯齿 滑润过渡
Flutter & GLSL - 陆 | 滑润过渡 smoothstep
Flutter & GLSL - 陆 | 滑润过渡 smoothstep

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 的过渡突变,也便是两个虚线间 由白到黑 的突变过渡。

Flutter & GLSL - 陆 | 滑润过渡 smoothstep

#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 的作用:

Flutter & GLSL - 陆 | 滑润过渡 smoothstep

#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
Flutter & GLSL - 陆 | 滑润过渡 smoothstep
Flutter & GLSL - 陆 | 滑润过渡 smoothstep

这样就完成了图片边际模糊突变的小特效:

#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) 函数进行滑润过渡:

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 - 陆 | 滑润过渡 smoothstep

那本文就到这儿,后边还会带来更多 Flutter & GLSL 的知识,我们下次再见 ~