Shader 魔法的学习之路 #3 - 让图形动起来

作者:mnikn
2022-06-17
4 3 0

之前的日志:

我们之前的教程都是静态图,但是 shader 的一大魅力就是让图形能够按照规律动起来,我们这次尝试实现一个日落的效果吧。

太阳

老规矩我们先画个圆作为太阳:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;
    uv -= 0.5;
    uv.x *= iResolution.x / iResolution.y;

    float radius = 0.2;
    float blur = 0.01;
    vec3 suncol = vec3(1.0, 0.9, 0.3);

    vec3 col = vec3(0.0);

    float d = smoothstep(radius, radius - blur, length(uv));
    col = mix(col, suncol, d);

    // Output to screen
    fragColor = vec4(col,1.0);
}

image-20220609162453159

背景

然后我们加上背景,这里我们使用了 mod 函数来生成分割矩形 ,用 uv.y 对 0.2 取余能够保证值按规律落在 [0,0.2),然后再加上 step 函数针对过半的值映射到 0 和 1,结果就是分割矩形。注意背景需要在圆之前画,否则会覆盖圆。

vec3 bgcol = vec3(0.65, 0.4, 0.1);
float rect = step(mod(uv.y, 0.2), 0.1);
col = mix(col, bgcol * 1.2, rect);
col = mix(col, bgcol, 1.0 - rect);
// ...画圆的代码

image-20220609163317448

移动

接下来我们要让太阳从左边向右边以圆弧形式先升起后落下,我们使用了一个内置变量 iTime,这个变量的值是当前运行时间,会不断叠加,我们把 iTime 传到 sincos 中就能按照规律得到 [0,1] 区间的值。然后我们定义了 center 圆心,它会随着时间做圆周运动,由于圆心不再是零点了,我们就改用 distance 来计算圆。

uv.y += 0.5;
vec2 center = vec2(sin(iTime * speed) / 0.9, cos(iTime * speed) / 2.0);
float d = smoothstep(radius, radius - blur, length(distance(center, uv)));
col = mix(col, suncol, d);

a1

补充细节

现在基本的样子有了,不过有点粗糙,我们再完善一点点细节,例如太阳移到正中央会逐渐变大,同时颜色也有相应的渐变。

float t = abs(sin(iTime*0.8));
radius -= t * 0.05;
blur += t * 0.01;
suncol -= t * 0.4;
bgcol *= cos(iTime*0.8) * 0.9;

a2

完整代码在:https://www.shadertoy.com/view/NsGcD1