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 小时前
MySQL 8.0安装(压缩包方式)
android·mysql·adb
梓仁沐白3 小时前
Android清单文件
android
董可伦5 小时前
Dinky 安装部署并配置提交 Flink Yarn 任务
android·adb·flink
每次的天空6 小时前
Android学习总结之Glide自定义三级缓存(面试篇)
android·学习·glide
恋猫de小郭6 小时前
如何查看项目是否支持最新 Android 16K Page Size 一文汇总
android·开发语言·javascript·kotlin
明似水7 小时前
2025年Flutter初级工程师技能要求
flutter
flying robot8 小时前
小结:Android系统架构
android·系统架构
xiaogai_gai8 小时前
有效的聚水潭数据集成到MySQL案例
android·数据库·mysql
鹅鹅鹅呢9 小时前
mysql 登录报错:ERROR 1045(28000):Access denied for user ‘root‘@‘localhost‘ (using password Yes)
android·数据库·mysql
在人间负债^9 小时前
假装自己是个小白 ---- 重新认识MySQL
android·数据库·mysql