Flutter & GLSL - 陆 | 平滑过渡 smoothstep

Flutter & GLSL 系列文章:

案例代码开源地址 【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 的知识,我们下次再见 ~

相关推荐
西瓜本瓜@2 小时前
在Android中如何使用Protobuf上传协议
android·java·开发语言·git·学习·android-studio
似霰6 小时前
安卓adb shell串口基础指令
android·adb
fatiaozhang95278 小时前
中兴云电脑W102D_晶晨S905X2_2+16G_mt7661无线_安卓9.0_线刷固件包
android·adb·电视盒子·魔百盒刷机·魔百盒固件
CYRUS_STUDIO9 小时前
Android APP 热修复原理
android·app·hotfix
鸿蒙布道师9 小时前
鸿蒙NEXT开发通知工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
鸿蒙布道师9 小时前
鸿蒙NEXT开发网络相关工具类(ArkTs)
android·ios·华为·harmonyos·arkts·鸿蒙系统·huawei
大耳猫10 小时前
【解决】Android Gradle Sync 报错 Could not read workspace metadata
android·gradle·android studio
ta叫我小白10 小时前
实现 Android 图片信息获取和 EXIF 坐标解析
android·exif·经纬度
bst@微胖子10 小时前
Flutter之路由和导航
flutter
dpxiaolong11 小时前
RK3588平台用v4l工具调试USB摄像头实践(亮度,饱和度,对比度,色相等)
android·windows