欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案

程序员文章站 2022-07-14 21:04:55
...

前言

本节是算法绘图的最后一节,介绍了是如何通过简单图形,有规律地重复排布生成图案。
《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案
然后在本节的最后,运用本节于前几节的技巧可大概画出这样的图形。
《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案

正文

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

// -------- 缩放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);
}

《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案
另外,这个示例后有个练习
// -------- Chapter_2_5_Task3.4.glsl -------- //
《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案

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

《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案

// -------- Chapter_2_5_Task4.6.glsl -------- //
最后是太极图案的练习(有时间可以让代码更规范些)

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.1415926

// -------- 常用图形函数 -------- //
mat2 rotate2d(float angle) {
    return mat2(cos(angle), -sin(angle),
                sin(angle), cos(angle));
}

mat2 scale(vec2 scale){
    return mat2(scale.x, 0.0,
                0.0, scale.y);
}

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

float semicircle(vec2 st, vec2 pos, float radius) {
    vec2 l = st - pos;
    float pct = 1.0 - smoothstep(0.95 * radius * radius, 1.05 * radius * radius, dot(l,l));
    
    pct *= step(0.0, l.y);
    return pct;
}

float square(vec2 st, vec2 size, vec2 pos) {
    size = 0.5 - 0.5 * size;
    vec2 uv = smoothstep(size, size + vec2(1e-4), st - pos);
    uv *= smoothstep(size, size + vec2(1e-4), vec2(1.0) - st + pos);
    return uv.x * uv.y;
}

// 太极
float EightElemrnt(vec2 uv, vec2 pos, float n) {
    float pct = 0.0;
    vec2 st = uv - pos;
    pct = square(st, vec2(0.5, 0.08), vec2(0.0, 0.15));
    pct += square(st, vec2(0.5, 0.08), vec2(0.0));
    pct += square(st, vec2(0.5, 0.08), vec2(0.0, -0.15));

    pct -= (step(0.1,n) * step(n,1.0) + step(3.1,n) * step(n,4.1) + step(4.1,n) * step(n,5.) + step(6.1,n) * step(n,7.)) * square(st, vec2(0.1, 0.08), vec2(0.0,0.15)); // 1,4,5,7 
    pct -= (step(1.1,n) * step(n,2.1) + step(3.1,n) * step(n,4.1) + step(5.1,n) * step(n,6.) + step(6.1,n) * step(n,7.)) * square(st, vec2(0.1, 0.08), vec2(0.0));      // 2,4,6,7
    pct -= (step(2.1,n) * step(n,3.1) + step(4.1,n) * step(n,5.1) + step(5.1,n) * step(n,6.) + step(6.1,n) * step(n,7.)) * square(st, vec2(0.1, 0.08), vec2(0.0,-0.15)); // 3,5,6,7

    return pct;
}


void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;

    uv = 2.0 * uv - 1.0;
    // uv *= rotate2d(0.5 * iTime);
    float pct = 0.0;
    // -------- 太极 -------- //
    vec2 st = uv * rotate2d(0.6 * iTime);
    pct = semicircle(st * rotate2d(-PI / 2.0), vec2(0.0),0.5);
    pct *= 1.0 - semicircle(st * rotate2d(-PI / 2.0), vec2(-0.25, 0.0), 0.25);
    pct += semicircle(st * rotate2d(PI / 2.0), vec2(-0.25, 0.0), 0.25);
    
    pct += circle(st, vec2(0.0, -0.25), 0.08);
    pct -= circle(st, vec2(0.0, 0.25), 0.08);


    // -------- 八卦 -------- //
    pct += EightElemrnt(uv * 2.0, vec2(-0.5, -2.),  2.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 0.25), vec2(-0.5, -2.),  3.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 0.5), vec2(-0.5, -2.),  0.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 0.75), vec2(-0.5, -2.),  1.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI), vec2(-0.5, -2.),  5.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 1.25), vec2(-0.5, -2.),  4.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 1.5), vec2(-0.5, -2.),  7.0);
    pct += EightElemrnt(uv * 2.0 * rotate2d(PI * 1.75), vec2(-0.5, -2.),  6.0);
    
    vec3 color = vec3(pct);

    gl_FragColor = vec4(color, 1.0);
}

《The Book of Shader》笔记 - Chapter 2.5 Patterns 图案

相关标签: shader glsl