Flutter & GLSL#8 | 乘法与矩形

张风捷特烈 Flutter & GLSL 系列文章:

案例代码开源地址 【skeleton】


1. 回首 step 函数

step 是 GLSL 中内置的函数,其逻辑非常简单:比较两个数的大小,前者 < 后者时返回 0, 否则返回 1

c 复制代码
float step(float a, float b) {
    return a < b ? 0 : 1;
}

先来看一下下面的着色器 step(0.1,coo.x); 返回的值,当 x < 0.1 时为 0 。使用返回值作为 rgb 三个颜色的通道,fragColor 也就是 (0,0,0,1) ,于是 x < 0.1 的区域显示出黑色。 同理 [0.1,1] 区域显示 (1,1,1,1) 白色:

c 复制代码
---->[shaders/rect/r01_rect_step_1.frag]----
#version 460 core
#include <flutter/runtime_effect.glsl>
precision mediump float;

out vec4 fragColor;
uniform vec2 uSize;

void main() {
    vec2 coo = FlutterFragCoord() / uSize;
    float ret = step(0.1,coo.x);
    vec3 color = vec3(ret);
    fragColor = vec4(color,1.0);
}

2. 初探矩形形状

同理,如果将结果取 step(0.1,coo.y),在纵坐标小于 0.1 的区域内将会展示黑色:

现在问题来了,如果想要将横竖两个条纹同时存在,该怎么办呢? 仔细思考一下,图中的黑色等价于结果的数值 0 , 白色等价于结果的数值 1。也可以将其视为 true/false :

0 和 1 的乘法具有 的性质, 即:

0 * 0 = 0 : 两个黑色结果叠加,输出 0 黑色。 (true|true) = true
0 * 1 = 0 : 黑色和白色结果叠加,输出 0 黑色。 (true|false) = true
1 * 1 = 1 : 白色和白色结果叠加,输出 1 白色。 (false|false) = false

所以,只要将两个结果相乘,就可以合并两个黑色内容。黑色内容之外的白色区域就可以视为一个 矩形:

c 复制代码
---->[shaders/rect/r01_rect_step_2.frag]----
#version 460 core
#include <flutter/runtime_effect.glsl>
precision mediump float;

out vec4 fragColor;
uniform vec2 uSize;

void main() {
    vec2 coo = FlutterFragCoord() / uSize;
    float ret1 = step(0.1, coo.x);
    float ret2 = step(0.1, coo.y);
    vec3 color = vec3(ret1 * ret2);
    fragColor = vec4(color, 1.0);
}

同理,叠加右侧和下方的黑色区域,就可以得到 左上角坐标 (0.1,0,1);边长是 0.8 的正方形,如下所示:

右侧黑色条纹,可以通过 step(0.1, 1 - coo.x) 得到,也就是 0.1 < 1 - coo.x 时, 即 coo.x < 0.9,结果为 0 展示白色,下方同理。将四个数乘起来,就可以得到最终结果:

c 复制代码
---->[shaders/rect/r01_rect_step_3.frag]----
#version 460 core
#include <flutter/runtime_effect.glsl>
precision mediump float;

out vec4 fragColor;
uniform vec2 uSize;

void main() {
    vec2 coo = FlutterFragCoord() / uSize;
    float left = step(0.1, coo.x);
    float top = step(0.1, coo.y);
    float right = step(0.1, 1 - coo.x);
    float bottom = step(0.1, 1 - coo.y);
    vec3 color = vec3(right * top * left * bottom);
    fragColor = vec4(color, 1.0);
}

3. 矩形形状的封装

现在问题来了,如何呈现一个 指定坐标指定宽高 的矩形呢?比如下面由四个矩形构成的图案:

这里的核心是根据坐标和尺寸确定右下角坐标 br ,从图形关系上不难分析出

vec2 br = vec2(pos.x + size.x, pos.y + size.y);

定义横坐标来说, coo.x < br.x 展示白色,值为 0 。即 right = step(coo.x, br.x) ; 底部同理,所以可以封装为如下的方法:

scss 复制代码
---->[shaders/rect/r01_rect_step_4.frag]----
#version 460 core
#include <flutter/runtime_effect.glsl>
precision mediump float;

out vec4 fragColor;
uniform vec2 uSize;

float rect(vec2 coo, vec2 pos, vec2 size) {
    float left = step(pos.x, coo.x);
    float top = step(pos.y, coo.y);
    vec2 br = vec2(pos.x + size.x, pos.y + size.y);
    float right = step(coo.x, br.x);
    float bottom = step(coo.y, br.y);
    return right * top * left * bottom;
}

void main() {
    vec2 coo = FlutterFragCoord() / uSize;
    float rect1 = rect(coo, vec2(0.2, 0.25), vec2(0.6, 0.1));
    float rect2 = rect(coo, vec2(0.2, 0.45), vec2(0.25, 0.1));
    float rect4 = rect(coo, vec2(0.55, 0.45), vec2(0.25, 0.1));
    float rect3 = rect(coo, vec2(0.2, 0.65), vec2(0.6, 0.1));
    vec3 color = vec3(rect1 + rect2 + rect3 + rect4);
    fragColor = vec4(color, 1.0);
}

4. 高维向量的 step 函数

step 函数不仅仅作用于数字,也可以作用于高维的向量。其作用是对两个值在各个分量上做 step 处理:

c 复制代码
float left = step(pos.x, coo.x);
float top = step(pos.y, coo.y);
vec2 lt = vec2(left,top);

等价于:
vec2 lt = step(pos, coo);

所以可以将 rect 方法的代码简化为:

c 复制代码
float rect(vec2 coo, vec2 pos, vec2 size) {
    vec2 br_pos = vec2(pos.x + size.x, pos.y + size.y);
    vec2 lt = step(pos, coo);
    vec2 br = step(coo, br_pos);
    return lt.x * lt.y * br.x * br.y;
}

最后,将白色区域作用于贴图纹理,就可以在白色区域内展示图像。下面将黑色区域设置为透明度 0.2 ,白色区域显示原图像:

c 复制代码
---->[shaders/rect/r01_rect_step_5.frag]----
#version 460 core
#include <flutter/runtime_effect.glsl>
precision mediump float;

out vec4 fragColor;
uniform vec2 uSize;
uniform sampler2D uTexture;

float rect(vec2 coo, vec2 pos, vec2 size) {
    vec2 br_pos = vec2(pos.x + size.x, pos.y + size.y);
    vec2 lt = step(pos, coo);
    vec2 br = step(coo, br_pos);
    return lt.x * lt.y * br.x * br.y;
}

void main() {
    vec2 coo = FlutterFragCoord() / uSize;
    float rect1 = rect(coo, vec2(0.2, 0.25), vec2(0.6, 0.1));
    float rect2 = rect(coo, vec2(0.2, 0.45), vec2(0.25, 0.1));
    float rect4 = rect(coo, vec2(0.55, 0.45), vec2(0.25, 0.1));
    float rect3 = rect(coo, vec2(0.2, 0.65), vec2(0.6, 0.1));
    float ret = rect1 + rect2 + rect3 + rect4;

    vec4 color = texture(uTexture, coo);
    fragColor = color * max(0.2, ret);
}

本文主要分析了 GLSL 中矩形形状的展现方式。了解通过乘法可以实现 01 组合的 关系。那本文就到这里,后期还会带来更多 GLSL 相关的文章,谢谢观看~

相关推荐
幻雨様2 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端4 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.5 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton5 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw9 小时前
安卓图片性能优化技巧
android
风往哪边走10 小时前
自定义底部筛选弹框
android
江上清风山间明月10 小时前
Flutter AlwaysScrollableScrollPhysics详解
flutter·滚动·scrollable·scrollphysics
Yyyy48210 小时前
MyCAT基础概念
android
Android轮子哥11 小时前
尝试解决 Android 适配最后一公里
android
普罗米拉稀11 小时前
Flutter 复用艺术:Mixin 与 Abstract 的架构哲学与线性化解密
flutter·ios·面试