2D Tiling3_Hexagonal 六边形平面镶嵌

以下的图案都是基于Hexagonal Tiling创作出的一些艺术图形,怎么样,非常动人吧,只用了大概不到200行的代码。

www.shadertoy.com/view/WtSfWK

www.shadertoy.com/view/4td3zj

六边形SDF

两个向量的 d o t dot dot用来表示一个向量在另外一个向量上的投影大小,同时点积的正负号可以表示两个向量的方向。

glsl 复制代码
    float d = dot(uv, vec2(1.));
    if (d < 0.25 + sin(iTime*3.0) * 0.25) {
        col.bg = vec2(0.8);
    } else {
        col = vec3(0.0);
    }

下图中的白线表示vec2(1.0)向量的方向,也是 y = x 的函数图像, 可以看出颜色块都是垂直与白线的。

这个时候我们在加上 abs 就可以获得一个正方形了。

同样的原理如果我们花一个六边形的斜线,只需要找到下图的 u ⃗ \vec{u} u 向量即可。 从图中不难得出向量 u ⃗ = ( c o s ( 60 ° ) , s i n ( 60 ° ) ) \vec{u} = (cos(60\degree), sin(60\degree)) u =(cos(60°),sin(60°)) 修改点积函数

glsl 复制代码
    float d = dot(uv, vec2(cos(0.3 * PI), sin(0.3 * PI)));

可以得到菱形 要的到六边形就非常简单点,只需要在x轴垂直方向切一刀,

ini 复制代码
        d = max(d, uv.x);

这里面的 d 到底是什么呢? 其实是沿着六边形边的垂直方向距离 零点的长度,所以其实我们略微修改,就可以变成一个距离边的距离场函数

glsl 复制代码
float SdfHexgon(vec2 p, float r) {
    p = abs(p);
    float d = dot(p, vec2(cos(0.3 * PI), sin(0.3 * PI))); 
    d = max(d, p.x);
    return d - r; 
}

col += step(SdfHexgon(uv, 0.24), 0.0); 

于是有

六边形镶嵌

上一节,理解如何画出一个六边形,并推倒了SDF, 但是为了做镶嵌,我们需要将六边形铺满整个屏幕,这也是为什么不直接用sdf的方式, 这里我们将采用 坐标系偏移的思路 画出六边形的镶嵌,里面最核心的 两个坐标系分界方法 就是 上节的画菱形的方法。

为了能够让六边形铺满整个平面,需要以下图的方式镶嵌

在前面很多文章中有提过制作grid的方法,

ini 复制代码
    vec2 gv = fract(uv) - .5;
    vec2 gv2 = fract(uv - .5) - .5;

假设我们在grid基础上,在做一个offset(.5)的grid 会产生如下的两个grid.

这个时候我们对两个坐标做一个比较判断

scss 复制代码
    if (length(gv) < length(gv2)) {
        col += vec3(.5);
    }

就得到了正方形

不过六边形有一个特点,就是他的高度和宽度是不一样的,高度与宽度比为 2 / 3 2/\sqrt{3} 2/3 . 也就是说如果我们吧六边形放到正方形中会导致高溢出或者宽度不够, 如下图所示

而为了解决溢出的问题,我们的grid不能是一个正方形了,grid应该是一个被拉长的长方形 就像下图

grid出不同长高非常简单,就是将fract 函数改为本来的 mod函数

ini 复制代码
    vec2 r = vec2(1., sqrt(3.));
    vec2 h = r * .5;
    vec2 a = mod(uv, r) - h;
    vec2 b=  mod(uv - h, r) - h; 

于是有余下的两个偏移grid

将分割与颜色补充就可以看到六边形镶嵌了

glsl 复制代码
    vec2 gv = length(a) < length(b) ? a : b;
    col.rg = gv;

属性

ID

一样的,对于这些grid类型, 我们都需要获得tile相关的坐标,以便后续的艺术创作。坐标非常简单,在 fract做的正方形grid里面,我们通过 floor获得坐标, 在这里其实一样

ini 复制代码
vec2 id = uv - gv;


// 这里抽象了一个HexCoords的函数,返回坐标与id
col.rb =  (HexCoords(uv).zw + vec2(4.0)) / vec2(8.0);

可以得到图案

Distance

目前返回都是坐标,如果我们能够返回距离六边形边缘的distance, 那么会有更多好的艺术效果可以实现。 这里就用到了我们第一节讲到的方法。

ini 复制代码
    gv.y = SdfHexgon(gv, 0.5);

    col.x =  abs(HexCoords(uv).y);

角度

ini 复制代码
    gv.x = atan(gv.x, gv.y);
    col.x =  HexCoords(uv).x/ PI;

引用

相关推荐
小小小小宇13 分钟前
LLM 长期记忆构建
前端
lichenyang45325 分钟前
从 Express 老项目到 NestJS + Docker:一次车辆管理系统的渐进式重构
前端
Momo__2 小时前
VueUse createReusableTemplate —— 单文件组件内的模板复用神器
前端·vue.js
程序员小富2 小时前
我开源了一个开发者专属的智能 JSON 工具,得到了媳妇高度认可
前端·vue.js·后端
小小小小宇2 小时前
程序员如何给 LLM 装工具以及看懂推理过程
前端
写代码的皮筏艇2 小时前
React中的forwardRef
前端·react.js·面试
槑有老呆2 小时前
花三个月工资请了个 AI 程序员,结果它连青岛啤酒股价都查不了
前端
风骏时光牛马2 小时前
Verilog开发常见问题汇总解析
前端
子兮曰2 小时前
AI Coding Method Map:一张图看懂 AI 编程的完整链路
前端·人工智能·后端