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 的知识,我们下次再见 ~

相关推荐
诸神黄昏EX1 小时前
Android 分区相关介绍
android
大白要努力!2 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee2 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood2 小时前
Perfetto学习大全
android·性能优化·perfetto
旭日猎鹰3 小时前
Flutter踩坑记录(三)-- 更改入口执行文件
flutter
旭日猎鹰3 小时前
Flutter踩坑记录(一)debug运行生成的项目,不能手动点击运行
flutter
️ 邪神3 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
webmote3 小时前
做一个FabricJS.cc的中文文档网站——面向markdown编程
canvas·fabric·使用手册·中文·fabricjs
Dnelic-5 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen7 小时前
MTK Android12 user版本MtkLogger
android·framework