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

相关推荐
奔跑吧 android36 分钟前
【android bluetooth 案例分析 03】【PTS 测试 】【PBAP/PCE/SGSIT/SERR/BV-01-C】
android·pts·aosp·pbap·sgsit
難釋懷3 小时前
Android开发-Application
android
0wioiw04 小时前
Flutter基础()
flutter
seven27295 小时前
Android 适配之——targetSdkVersion 30升级到31-34需要注意些什么?
android·版本设置31-34·targetsdk
androidwork7 小时前
Kotlin Android单元测试MockK指南
android·kotlin
麻辣璐璐7 小时前
Kotlin并发请求的一些知识记录
android·kotlin
东风西巷7 小时前
MobiPDF:安卓设备上的专业PDF阅读与编辑工具
android·智能手机·pdf·软件需求
肥肥呀呀呀7 小时前
flutter 视频通话flutter_webrtc
flutter
難釋懷9 小时前
Android开发-在应用之间共享数据
android·jvm·oracle
明似水9 小时前
2025年Flutter项目管理技能要求
flutter