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

相关推荐
大耳猫3 小时前
主动测量View的宽高
android·ui
帅次6 小时前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
枯骨成佛6 小时前
Android中Crash Debug技巧
android
sunly_9 小时前
Flutter:父组件,向子组件传值,子组件向二级页面传值
flutter
kim565912 小时前
android studio 更改gradle版本方法(备忘)
android·ide·gradle·android studio
咸芝麻鱼12 小时前
Android Studio | 最新版本配置要求高,JDK运行环境不适配,导致无法启动App
android·ide·android studio
无所谓จุ๊บ12 小时前
Android Studio使用c++编写
android·c++
csucoderlee12 小时前
Android Studio的新界面New UI,怎么切换回老界面
android·ui·android studio
kim565912 小时前
各版本android studio下载地址
android·ide·android studio
饮啦冰美式12 小时前
Android Studio 将项目打包成apk文件
android·ide·android studio