《The Book of Shader》笔记 :第五节 - Pattern 图案

前言

本节是算法绘图的最后一节,介绍了是如何运用简单图形,有规律地重复排布生成图案。
在这里插入图片描述
在本节的最后,综合使用本章的技巧可大概画出这样的图形。
在这里插入图片描述

正文

贴示例之前,先总结下本节中出现频率较多的几个函数。

// -------- 缩放uv坐标系(本节的练习中基本都需要使用该函数) -------- //
vec2 tile(vec2 st, float zoom){
    // 通过先给st 乘上一个倍数,将屏幕中的坐标范围增大,再调用fract 达到复制出重复区域的效果
    st *= zoom;
    return fract(st);
}

// -------- 画圆 -------- //
float circle(vec2 st, float radius){
    vec2 l = st - vec2(0.5);
    return 1.0 - smoothstep(0.99 * radius, radius * 1.01, dot(l,l)*4.0);
}
// -------- 画方 -------- //
float box (vec2 st, vec2 size, float smoothEdge) {
    size = vec2(0.5) - size * 0.5;
    vec2 aa = vec2(smoothEdge * 0.5);
    vec2 uv = smoothstep(size, size + aa, st);
    uv *= smoothstep(size, size + aa, vec2(1.0) - st);
    return uv.x * uv.y;
}
// -------- 旋转二维图形 -------- //
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;
}

// -------- Chapter_2_5_Main 0 -------- //
首先是前言中介绍的图案。
在这里插入图片描述

#ifdef GL_ES
precision mediump float; 
#endif

vec2 tile(vec2 st, float zoom){
    // 通过先给st 乘上一个zoom,再调用fract 达到复制出好几个[0,1]范围的效果
    st *= zoom;
    return fract(st);
}

float circle (vec2 st, float radius) {
    vec2 pos = vec2(0.5) - st;
    radius *= 0.75;
    return 1.-smoothstep(radius * 0.95, radius * 1.05, dot(pos, pos) * 3.14);
}

float circlePattern(vec2 st, float radius) {
    // 用加法的方式,画四个小圆
    return circle(st+vec2(0.,-.5), radius)+
            circle(st+vec2(0.,.5), radius)+
            circle(st+vec2(-.5,0.), radius)+
            circle(st+vec2(.5,0.), radius);
}

void main() {
    vec2 st = gl_FragCoord.xy / iResolution.xy;
    st.x *= iResolution.x / iResolution.y;
    vec3 color = vec3(0.0);
    

    // ******** 画出第一个图层 ******** //
    vec2 grid1 = tile(st, 8.0);
    grid1 = tile(st + vec2(cos(iTime),sin(iTime))*0.01,7.);   // 让图案运动起来, vec2(cos(iTime),sin(iTime))*a 这个公式让图片沿圆形轨迹运动,参数a表示周期运动的频率
    color += mix(vec3(0.075,0.114,0.329),vec3(0.973,0.843,0.675),circlePattern(grid1,0.23)-circlePattern(grid1,0.01));
    /*给图形上色
        circlePattern(grid1,0.23)-circlePattern(grid1,0.01) 减法的方式画出同心圆
    */
    // ******** 画出第二个图层,叠在第一个图层之上 ******** //
    vec2 grid2 = tile(st, 3.0);
    grid2 = tile(st + vec2(cos(iTime),sin(iTime))*0.02 ,3.);
    color = mix(color, vec3(0.761,0.247,0.102), circlePattern(grid2,0.2)) - circlePattern(grid2,0.05),
    
    gl_FragColor = vec4(color, 1.0);
}

二. 砖墙图案
// -------- Chapter_2_5_Main 3.glsl -------- //

#ifdef GL_ES
precision mediump float;
#endif

vec2 brickTile(vec2 st, float zoom) {
    st *= zoom;
    // 借助mod取余函数达到奇偶行图形错开的效果
    st.x += step(1.0, mod(st.y, 2.0)) * 0.5;
    return fract(st);
}

float box(vec2 st, vec2 size) {
    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() {
    vec2 st = gl_FragCoord.xy / iResolution.xy;
    st.x *= iResolution.x/ iResolution.y;
    vec3 color = vec3(0.0);


    // Apply the brick tiling
    st = brickTile(st, 5.0);

    color = vec3(box(st, vec2(0.9)));
    // Uncomment to see the
    gl_FragColor = vec4(color, 1.0);
}

在这里插入图片描述
再来个六边形(轻喷,感觉还是得网上参考下大神们怎么写的。)

const float PI = 3.1415926;

mat2 rot2(float angle) {
    return mat2(cos(angle), -sin(angle), sin(angle), cos(angle));
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    float sqrt3 = sqrt(3.0);
    
    float pct = 0.0;
    vec3 color = vec3(pct);
    uv.y *= sqrt3 / 2.0;
    uv *= 10.0;
    vec2 i = floor(uv);
    vec2 f = fract(uv);
    f.x = (1.0 - f.x) * mod(i.x, 2.0) + f.x * mod(i.x + 1.0, 2.0); 
    float width = 0.05;

    
    // -------- Line -------- //
    f.x += 0.141;
    pct = step(0.5 - width, f.y) * step(f.y, 0.5 + width) * step(f.x, 0.5);
    pct += step(f.y, width) * step((3.+sqrt(3.))/ 6., f.x);
    pct += step(1.0 - f.y, width) * step((3.+sqrt(3.))/ 6., f.x);
    f = rot2(-2.0 * PI / 3.0) * (f - vec2(0.5)) + vec2(0.5);
    pct += step(0.5 - width, f.y) * step(f.y, 0.5 + width) * step(f.x, 0.5);
    f = rot2(-2.0 * PI / 3.0) * (f - vec2(0.5)) + vec2(0.5);
    pct += step(0.5 - width, f.y) * step(f.y, 0.5 + width) * step(f.x, 0.5);    
    
    color = vec3(pct);
    gl_FragColor = vec4(color, 1.0);
}

在这里插入图片描述

另外,这个示例后有个练习
// -------- Chapter_2_5_Task3.4.glsl -------- //
在这里插入图片描述

#ifdef GL_ES
precision mediump float;
#endif

float circle(vec2 st, float radius){
    vec2 l = st - vec2(0.5);
    return 1.0 - smoothstep(0.99 * radius, radius * 1.01, dot(l,l)*4.0);
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    
    vec3 color = vec3(0.0);
    uv *= 10.0;
   // 将放大后的坐标系分为整数与小数部分,分别提取出来
    vec2 ipos = floor(uv);
    vec2 fpos = fract(uv);

    // 在fract 中加偏移量才能移动,在fract外面加偏移量会出现奇怪的现象
    uv = fract(uv + (mod(ipos.x, 2.0) + mod(ipos.x, 2.0) - 1.0) * vec2(0.0, iTime * step(mod(iTime - 1.0, 2.0), 1.0)));
    uv = fract(uv + (mod(ipos.y, 2.0) + mod(ipos.y, 2.0) - 1.0) * vec2(iTime * step(mod(iTime, 2.0), 1.0), 0.0));

    color = vec3(1.0 - circle(uv, 0.5));

    gl_FragColor = vec4(color, 1.0);
}

// -------- Chapter_2_5_Main 4.glsl -------- //
Truchet 瓷砖示例。对前一个示例中使用到的区分奇偶行的技巧,做进一步应用。

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265358979323846

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);
}

vec2 rotateTilePattern(vec2 st) {
    st *= 2.0;
    // Give each cell an index number
    // according to its position
    float index = 0.0;
    index += step(1.0, mod(st.x, 2.0));
    index += step(1.0, mod(st.y, 2.0)) * 2.0;
    // Make each cell between 0.0 - 1.0
    st = fract(st);
    // Rotate each cell according to the index
    if (index == 1.0) {
        // Rotate cell 1 by 90 degrees
        st = rotate2D(st, PI * 0.5);
    } else if (index == 2.0) {
        st = rotate2D(st,PI*-0.5);
    } else if (index == 3.0) {
        st = rotate2D(st,PI);
    }
    return st;
}

void main(void) {
    vec2 st = gl_FragCoord.xy / iResolution.xy;
    st.x *= iResolution.x / iResolution.y;
    st = tile(st, 3.0);
    st = rotateTilePattern(st);

    // Make more interesting combinations
    st = tile(st,2.0);
    //st = rotate2D(st,-PI*iTime*0.25);
    //st = rotateTilePattern(st*2.);
    st = rotate2D(st,PI*iTime*0.25);
    gl_FragColor = vec4(vec3(step(st.x, st.y)), 1.0);
}

在这里插入图片描述

// -------- Chapter_2_5_Task4.6.glsl -------- //
最后是太极图案的一个小练习。
在这里插入图片描述
代码链接:
https://www.shadertoy.com/view/Ws3BRf

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值