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 相关的文章,谢谢观看~

相关推荐
老码沉思录13 分钟前
Android开发实战班 -网络编程 - Retrofit 网络请求 + OkHttp 使用详解
android·网络·retrofit
前期后期23 分钟前
Android 工厂设计模式的使用:咖啡机,可以做拿铁,可以做美式等等。
android·java·设计模式
LinXunFeng25 分钟前
Flutter - 子部件任意位置观察滚动数据
前端·flutter·开源
guoruijun_2012_46 小时前
hyperf 配置步骤
android
500了6 小时前
Android和Java的发布/订阅事件总线EventBus
android·java·开发语言
诸神黄昏EX6 小时前
Android 常用命令和工具解析之Trace相关
android
leluckys6 小时前
flutter 专题十二 Flutter Fair逻辑动态化架构设计与实现
flutter
sunly_7 小时前
Flutter:AnimatedIcon图标动画,自定义Icon通过延时Interval,实现交错式动画
flutter
嘟嘟叽7 小时前
初学 flutter 问题记录
flutter
__WanG7 小时前
Flutter将应用打包发布到App Store
前端·flutter·ios