如何根据一定的策越生成图案。
1.网格策略
使用先放大网格再使用fract的技巧生成网格。
#ifdef GL_ES
precision mediump float; // 为GL_ES环境设定中等精度浮点数
#endif
uniform vec2 u_resolution; // 全局变量,用于存储屏幕的分辨率
uniform float u_time; // 全局变量,存储从程序开始运行到现在的时间
// 定义一个圆形函数,输入为一个二维向量(屏幕的一个点)和一个半径,输出一个浮点数,表示该点是否在半径为_radius的圆内
float circle(in vec2 _st, in float _radius){
vec2 l = _st-vec2(0.5); // 将屏幕坐标转换为以屏幕中心为原点的坐标
return 1.-smoothstep(_radius-(_radius*0.01),
_radius+(_radius*0.01),
dot(l,l)*4.0); // 计算该点到原点的距离是否在半径范围内,是的话返回1,否则返回0
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution; // 将片元的坐标转换为以屏幕左下角为原点的坐标,范围是[0,1]
vec3 color = vec3(0.0); // 初始化颜色为黑色
st *= 3.0; // 将屏幕的坐标范围放大3倍,变为[0,3]
st = fract(st); // 计算坐标的小数部分,从而将坐标范围变为[0,1],但每1/3部分为一个循环
// 现在我们有9个范围从0-1的空间
color = vec3(st,0.0); // 计算颜色,颜色的红绿分量由坐标决定,蓝色分量为0
// color = vec3(circle(st,0.5)); // 或者你也可以将颜色设定为圆形函数的输出,圆形的半径为0.5
gl_FragColor = vec4(color,1.0); // 将计算得到的颜色赋给片元,颜色的alpha通道设定为1
}
结果为。
(图1)
若是采用circle结果为。
(图2)
当然如果修改第20行的参数 st *= vec2(4,4);
(图3)
2.图案变换
有了前面的基础,在上面图1的矩形网格基础上修改代码。
// 设置浮点数运算的精度
#ifdef GL_ES
precision mediump float;
#endif
// Uniform变量声明
uniform vec2 u_resolution;
uniform float u_time;
// 定义PI的值
#define PI 3.14159265358979323846
// 将一个2D点绕原点旋转的函数
vec2 rotate2D(vec2 _st, float _angle) {
// 将点平移到原点
_st -= 0.5;
// 应用旋转矩阵
_st = mat2(cos(_angle), -sin(_angle),
sin(_angle), cos(_angle)) * _st;
// 将点平移到原来的位置
_st += 0.5;
return _st;
}
// 在空间中进行瓦片化的函数
vec2 tile(vec2 _st, float _zoom) {
// 缩放点的位置
_st *= _zoom;
// 返回缩放后点的小数部分
return fract(_st);
}
// 绘制带有平滑边缘的方形的函数
float box(vec2 _st, vec2 _size, float _smoothEdges) {
// 将大小转换为范围在0到1之间的值
_size = vec2(0.5) - _size * 0.5;
// 计算用于平滑边缘的抗锯齿区域
vec2 aa = vec2(_smoothEdges * 0.5);
// 计算点在水平和垂直方向上的插值因子
vec2 uv = smoothstep(_size, _size + aa, _st);
// 在水平和垂直方向上应用插值因子
uv *= smoothstep(_size, _size + aa, vec2(1.0) - _st);
// 返回水平和垂直插值因子的乘积作为最终值
return uv.x * uv.y;
}
void main(void) {
// 归一化屏幕坐标
vec2 st = gl_FragCoord.xy / u_resolution.xy;
// 初始化颜色
vec3 color = vec3(0.0);
// 将空间划分为4个瓦片
st = tile(st, 4.0);
// 使用矩阵将空间旋转45度
// st = rotate2D(st, PI * 0.25);
// 绘制方形
color = vec3(box(st, vec2(0.7), 0.01));
// color = vec3(st, 0.0);
// 输出最终颜色
gl_FragColor = vec4(color, 1.0);
}
结果是这样的。
(图4)
(图5)
3.偏移图案
有了上面的基础下面对图案进行偏移。
(图6)
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
// 瓦片化函数,用于创建砖块效果
vec2 brickTile(vec2 _st, float _zoom){
_st *= _zoom;
// 在这里进行偏移
// 使用 step 函数来判断是否需要在 x 方向上进行偏移
// step(a, b) 在 b 处返回 0,否则返回 1
// mod(_st.y, 2.0) 取 _st.y 对 2.0 的模
// 如果 _st.y 对 2.0 的模小于 1.0,step 的结果为 1,进行偏移
// 如果 _st.y 对 2.0 的模大于等于 1.0,step 的结果为 0,不进行偏移
_st.x += step(1., mod(_st.y, 2.0)) * 0.5;
// 返回经过瓦片化后的点的小数部分
return fract(_st);
}
// 绘制带有平滑边缘的方形的函数
float box(vec2 _st, vec2 _size){
// 将大小转换为范围在0到1之间的值
_size = vec2(0.5) - _size * 0.5;
// 使用非常小的偏移量避免除以零
vec2 uv = smoothstep(_size, _size + vec2(1e-4), _st);
// 在水平和垂直方向上应用插值因子
uv *= smoothstep(_size, _size + vec2(1e-4), vec2(1.0) - _st);
// 返回水平和垂直插值因子的乘积作为最终值
return uv.x * uv.y;
}
void main(void){
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec3 color = vec3(0.0);
// 现代度量砖块尺寸为 215mm x 102.5mm x 65mm
// 取消下面的注释以应用砖块尺寸的缩放
st /= vec2(2.15, 0.65) / 1.5;
// 应用砖块瓦片化
st = brickTile(st, 5.0); // 将坐标进行砖块瓦片化,缩放因子为 5.0
// 绘制方形
// color = vec3(box(st, vec2(0.9)));
// 取消下面的注释以查看空间坐标
color = vec3(st, 0.0);
gl_FragColor = vec4(color, 1.0);
}
效果如下。
(图7)
(图8)
加入动画向左偏移 稍加需改
// 瓦片化函数,用于创建砖块效果
vec2 brickTile(vec2 _st, float _zoom){
_st *= _zoom;
// 计算偏移量,偏移行的偏移距离随时间变化
float yOffset = step(1., mod(_st.y, 2.0)) * (u_time * 0.1); // 这里的 0.1 是用于调整偏移量的因子
_st.x += yOffset;
// 返回经过瓦片化后的点的小数部分
return fract(_st);
}
奇数行向左移动偶数行向右移动 floor取整 mod取模 step分解函数小于为0大于等于为1
// 瓦片化函数,用于创建砖块效果
vec2 brickTile(vec2 _st, float _zoom){
_st *= _zoom;
// 计算偏移量,奇数行向左移动,偶数行向右移动,移动距离随时间变化
float yOffset = (mod(floor(_st.y), 2.0) - 0.5) * (u_time * 0.1);
_st.x += yOffset;
// 返回经过瓦片化后的点的小数部分
return fract(_st);
}
4.瓷砖技巧
有了前面的网格砖块设计,现在对每个网格变换一分为四生成瓷砖效果。利用rotateTilePattern函数。
#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.14159265358979323846
uniform vec2 u_resolution;
uniform float u_time;
// 二维旋转函数,根据给定的角度对点进行旋转
vec2 rotate2D(vec2 _st, float _angle) {
_st -= 0.5;
_st = mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle)) * _st;
_st += 0.5;
return _st;
}
// 瓦片函数,将坐标进行瓦片化,缩放因子为 _zoom
vec2 tile(vec2 _st, float _zoom) {
_st *= _zoom;
return fract(_st);
}
// 旋转瓦片模式函数,根据位置对每个瓦片进行旋转
vec2 rotateTilePattern(vec2 _st) {
// 将坐标系统放大为2x2
_st *= 2.0;
// 根据位置给每个单元格分配索引号
float index = 0.0;
index += step(1.0, mod(_st.x, 2.0));
index += step(1.0, mod(_st.y, 2.0)) * 2.0;
// |
// 2 | 3
// |
//--------------
// |
// 0 | 1
// |
// 将每个单元格的值限制在0.0到1.0之间
_st = fract(_st);
// 根据索引号旋转每个单元格
if (index == 1.0) {
// 旋转单元格1 90度
_st = rotate2D(_st, PI * 0.5);
} else if (index == 2.0) {
// 旋转单元格2 -90度
_st = rotate2D(_st, PI * -0.5);
} else if (index == 3.0) {
// 旋转单元格3 180度
_st = rotate2D(_st, PI);
}
return _st;
}
void main(void) {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
st = tile(st, 3.0); // 对坐标进行瓦片化,缩放因子为3.0
st = rotateTilePattern(st); // 根据位置旋转每个单元格
// 创建更有趣的组合效果
// st = tile(st, 2.0);
// st = rotate2D(st, -PI * u_time * 0.25);
// st = rotateTilePattern(st * 2.0);
// st = rotate2D(st, PI * u_time * 0.25);
// step(st.x, st.y) 生成了一个黑白三角形
// 你可以根据需要使用任何设计
gl_FragColor = vec4(vec3(step(st.x, st.y)), 1.0);
}
结果为。
(图9)