ShaderJoy ——旋转的分层齿轮【GLSL】

821 阅读2分钟

效果图

正文

首先,我们将获得一个范围 [-1., 1.] 之间的 uv 坐标,即屏幕中心是 (0., 0.) 点

vec2 uv = (u * 2. - res.xy) / res.xy ;

然后我们据此计算出每个 uv 坐标到中心点的距离(圆的半径)

r = length(uv)

可视化后的效果如下所示【越黑值越小,越白值越大】

接下来我们据此来对圆域进行分层,没错就是我们的老朋友 —— floor 函数

float i = floor(r * N); ///< 圆域分层

其实际函数如下

为了让对比度层次更加具有 “艺术性”,可以给它一个指数函数

floor(pow(128., i / N))

其函数图就变成了这样

可视化后为

那么这个对比度分层的圆域有什么用呢?

其实它是作用于像素的角度

a = atan(uv.y, uv.x);
a *= floor(pow(128., i / N)); ///< 指数分阶

原 atan(uv.y, uv.x) 的函数可视化如下【由于 y 轴是上下相反的,所以函数图和 shader 可视化的效果图也是上下颠倒的】

shader 实际效果图

经过我们之前准备的指数量化的圆域后,其 shader 可视化的效果为

其实,此时将像素角度经过 cos 函数,再配合分阶的半径,我们就可以达成以下锯齿的效果

r +=  (.5 + .5 * cos(a)) / N; ///< 齿轮状
r = floor(N * r) / N; ///< 齿轮状效果后,半径再分阶

通过给它着色来进一步美化,得到如下效果

o = (1. - r) * vec4(3, 2, 1, 1);

最后一步,因为静止的 “齿轮” 还是略显单调,我们可以通过让像素的角度随着时间变化,让 “齿轮” 运动起来

a += 10.*t +     ///< 旋转
123.34 * i; ///< 各层的角度差别

其效果为

稍加修改(两处代码),我们还可以得到如下效果

第一处,像素角度随着时间变化的代码

a += 20.*sin(.5 * t) + 123.34 * i - 100.*r * cos(.5 * t); // (r-0.*i/N)

第二处,着色代码

 o = (1. - r) * vec4(.5, 1, 1.5, 1);

完整的代码

#define N 20.#define res iResolutionvoid mainImage( out vec4 o, vec2 u ){    vec2 uv = (u * 2. - res.xy) / res.xy ;    float t = iTime,          r = length(uv),          a = atan(uv.y, uv.x);    float i = floor(r * N); ///< 圆环分层    a *= floor(pow(128., i / N)); ///< 指数分阶#ifdef EFFECT_0    a += 10.*t +     ///< 旋转         123.34 * i; ///< 角度分阶#else    a += 20.*sin(.5 * t) + 123.34 * i - 100.*r * cos(.5 * t); // (r-0.*i/N)#endif    r +=  (.5 + .5 * cos(a)) / N; ///< 齿轮状    r = floor(N * r) / N;         ///< 齿轮状效果后,半径再分阶#ifdef EFFECT_0    o = (1. - r) * vec4(3, 2, 1, 1); ///< 反向着色#else    o = (1. - r) * vec4(.5, 1, 1.5, 1);#endif}