前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter & GLSL#8 | 乘法与矩形

Flutter & GLSL#8 | 乘法与矩形

作者头像
张风捷特烈
发布2024-03-19 08:31:54
720
发布2024-03-19 08:31:54
举报

案例代码开源地址 【skeleton】

1. 回首 step 函数

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

代码语言:javascript
复制
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) 白色:

代码语言:javascript
复制
---->[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

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

代码语言:javascript
复制
---->[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 展示白色,下方同理。将四个数乘起来,就可以得到最终结果:

代码语言:javascript
复制
---->[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) ; 底部同理,所以可以封装为如下的方法:

代码语言:javascript
复制
---->[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 处理:

代码语言:javascript
复制
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 方法的代码简化为:

代码语言:javascript
复制
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 ,白色区域显示原图像:

代码语言:javascript
复制
---->[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 相关的文章,谢谢观看~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 回首 step 函数
  • 2. 初探矩形形状
  • 3. 矩形形状的封装
  • 4. 高维向量的 step 函数
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档