《The Book of Shader》笔记 : 第三节 - Shader绘制简单图形

前言

本节示例代码中介绍了如何画出一个矩形,圆形。以及利用极坐标的思想进一步画出如下形状。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结果看着挺有意思(花点时间理解下代码更有意思,让人不禁回想起被高中数学支配的时光。)

在这里插入图片描述
文末彩蛋。

正文

// ------------ Chapter_2_3_Main 1.glsl ------------ //

#ifdef GL_ES
precision mediump float;
#endif

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec3 color = vec3(0.0);

    // bottom - left
    vec2 bl = step(vec2(0.1), uv);
    float pct = bl.x * bl.y;

    // top - right 
    vec2 tr = step(vec2(0.1), (1.0 - uv));
    pct *= tr.x * tr.y;
    
    
    color = vec3(pct);
    gl_FragColor = vec4(color, 1.0);    
}

在这里插入图片描述
结果是一个适应屏幕长宽的矩形。

// ------------ Chapter_2_3_Main 2.glsl ------------ //

#ifdef GL_ES
precision mediump float;
#endif

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

    // 取uv坐标上一点为圆心,pct值向外线性递增
    float pct = 0.0;
    pct = distance(uv, vec2(0.5));
    
    // 给颜色赋值
    vec3 color = vec3(pct);
    gl_FragColor = vec4(color, 1.0);
}

在这里插入图片描述
第二部分介绍了,利用length 函数 (或distance函数)求uv坐标到圆心距离的方式来画圆。

// ------------ Chapter_2_3_Main 3.glsl ------------ //

#ifdef GL_ES
precision mediump float;
#endif

float circle(vec2 uv, float radius) {
    vec2 dist = uv - vec2(0.5);
    // return 1. - smoothstep(radius * 0.99, radius * 1.01, dot(dist, dist) * 4.0);
    return 1. - smoothstep(radius * radius * 0.99, radius * radius * 1.01, dot(dist, dist));
    /*
   在书中的基础上稍微修改了下,感觉这样比较符合公式
    
    当length(uv - vec2(0.5)) < radius * 0.99 时, smoothstep = 0 返回值为 1。
    length(uv - vec2(0.5)) 在 [radius * 0.99, radius * 1.01] 之间 做 1 到 0 的线性插值
    length(uv - vec2(0.5)) > radius * 1.01时, smoothstep = 1 返回值为 0
    */
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    
    vec3 color = vec3(circle(uv, 0.5));
    gl_FragColor = vec4(color, 1.0);
}

同样画圆,但采用了向量点乘这种更为高效的运算方式。
相当于由原先比较公式
在这里插入图片描述
转变为比较公式
在这里插入图片描述
两边的值。避免了开方运算
在这里插入图片描述
后面开始要玩点花样了。
// ------------ Chapter_2_3_Main 4.glsl ------------ //

#ifdef GL_ES
precision mediump float;
#endif
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    vec3 color = vec3(0.0);

    float d = 0.0;

    // 将uv 的范围映射到[-1, 1]
    uv = uv * 2.0 - 1.0;  
    
    // Make the distance field
    /******************************************************
        *相当于其他几个象限的形状由第一象限的形状做对称复制得到
        *采用length的方式画了一个以[0.3, 0.3]为圆心的圆
    */
    d = length(abs(uv) - 0.3);    
    //d = length(min(abs(uv) - 0.3, 0.0));  // [1] min 中第一个参数是一个向量,第二个参数 0.0(被自动转为向量?),然后两个向量的min
    //d = length(max(abs(uv) - 0.3, 0.0));  // [2]

    // Visualize the distance field
    gl_FragColor = vec4(vec3(fract(d*10.0)), 1.0);

    // Drawing with the distance field
    // gl_FragColor = vec4(vec3(step(0.3, d)), 1.0);  
     gl_FragColor = vec4(vec3(step(0.3, d) * step(d, 0.4)), 1.0);                       // [3] 仅将d >= 0.3, 小于0.4的部分做保留 
     gl_FragColor = vec4(vec3(smoothstep(0.3, 0.4, d) * smoothstep(0.6, 0.5, d)), 1.0); // [4] 在上一个的基础上给边界做渐变
}
gl_FragColor = vec4(vec3(fract(d*10.0 - iTime)), 1.0);

在这里插入图片描述
部分的调整:

d = length(min(abs(uv) - 0.3, 0.0));  // [1]

在这里插入图片描述

d = length(max(abs(uv) - 0.3, 0.0));  // [2]

在这里插入图片描述
// ------------ Chapter_2_3_Main 5.glsl ------------ //
这段代码就对应了前言中的几幅图片。

#ifdef GL_ES
precision mediump float;
#endif

void main() {
    vec2 uv = gl_FragCoord.xy/iResolution.xy;
    uv.x *= iResolution.x/ iResolution.y;
    
    vec3 color = vec3(0.0);
    vec2 pos = vec2(0.5) - uv;

    float r = length(pos) * 2.0;
    float a = atan(pos.y, pos.x);
    

    // Make the distance field
    float f = cos(a*3.0);
    // f = abs(cos(a* 3.0));                                 // 六瓣花
    // f = abs(cos(a * 2.5)) * 0.5 + 0.3;                    // 五瓣花
    // f = abs(cos(a * 12.0) * sin(a * 3.0) * 0.8 + 0.1);    // 放射性的花
    // f = smoothstep(-0.5, 1.0, cos(a * 10.0)) * 0.2 + 0.5; // 齿轮

    // Visualize the distance field
    color = vec3(1.0 - smoothstep(f, f + 0.02, r));
    gl_FragColor = vec4(color, 1.0);
}

// ------------ Chapter_2_3_Main 6.glsl ------------ //
利用极坐标的思想画三角型。

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359
#define TWO_PI 6.28318530718

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

    // Remap the space -1.0 to 1.0
    uv = uv * 2.0 - 1.0;
    // Number of sides of your shape
    int N = 3;
    // Angle and radius from the current pixel
    float a = atan(uv.x, uv.y) + PI;
    float r = TWO_PI / float(N);
    // Shaping function that modulate the distance
    d = cos(floor(0.5 + a / r) * r - a) * length(uv);
    color = vec3(1.0 - smoothstep(0.4, 0.41, d));
    gl_FragColor = vec4(color, 1.0);
}

在这里插入图片描述
疯了,没看懂,不过通过修改变量N 可以画出不同的多边形。
在这里插入图片描述
如此一来整合出一个画多边形的函数,以后使用就很方便了。

// -------- Chapter_2_3_Task6.1.glsl -------- //

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359
#define TWO_PI 6.28318530718

float polygon(vec2 uv, vec2 pos, int n) {
    // ******** uv, pos : position; n : Number of sides ******** //
    uv = 2.0 * uv - 1.0 - pos; 

    float a = atan(uv.x, uv.y) + PI;
    float r = TWO_PI / float(n);

    float d = cos(floor(0.5 + a / r) * r - a) * length(uv);
    return 1.0 - smoothstep(0.4, 0.41, d);
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    uv.x *= iResolution.x / iResolution.y;
    vec3 color = vec3(polygon(uv, vec2(0.0), 3 + int(floor(0.5 * iTime))));  
    gl_FragColor = vec4(color, 1.0);
}

在这里插入图片描述
在这里插入图片描述
其中函数中,pos 的定义域目前设为了[-1.0, 1.0]。

同时也可以利用这这个函数在同一张图上画好几个图形

    vec3 color = vec3(polygon(uv, vec2(0.0), 3));
    color += vec3(polygon(uv, vec2(1.0), 3));
    color += vec3(polygon(uv, vec2(0.0, 0.5), 3));

在这里插入图片描述

小结

画图形确实是个需要花点精力研究的课题,本节仅是入了个门。书的作者在最后也留了一个传送门(学习小组?)。
https://patriciogonzalezvivo.github.io/PixelSpiritDeck/
另外,自从看完这节之后莫名的又想给自己挖个坑。。。。。。
在这里插入图片描述
------------------ 分界线 2021/2/23 ----------------
算是填了一个小坑吧。
在这里插入图片描述
https://www.shadertoy.com/view/3ddfWX

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值