ShaderJoy —— 方方圆圆?圆圆方方?【GLSL】

1,063 阅读1分钟

这是我参与8月更文挑战的第16天,活动详情查看: 8月更文挑战

效果图

2233.gif

算法简介

首先,是常规操作,将 uv 坐标换算到 [-0.5, 0.5] 之间

vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;

uv 可视化后的效果 image.png

下一步,就是如何绘制圆

float circle = length(uv) - 0.23;  

圆的函数示意图

image.png

实际效果图为

image.png

以及如何绘制矩形

 float rect =  max(abs(uv.x), abs(uv.y)) - 0.1; 

矩形的函数示意图

image.png

实际效果为

image.png

下一步,我们需要设计一个缓动函数,来对圆和矩形进行平滑切换

float w = -sin(t + sin(t + sin(t))) * 0.5 + 0.5;

其函数示意图为

image.png

则 w 的值域就在 [0., 1.] 之间随着时间而变化了(t 是伴随时间变化的量)

采用 mix 函数来插值

float f = mix(circle, rect, w);

动态的效果如下

2233.gif

最后,为了显示为线条形状,我们使用 smoothstep 函数来(平滑地)截取出我们想要的一段数值

f = smoothstep(0.0, -0.01, f) - smoothstep(-0.01, -0.02, f);

上式的减号左侧示意图为

image.png

上式的减号右侧示意图为

image.png

合并起来以后就截取出了其中一段(太大、太小都被抑制)

image.png

至此我们就得到了如文章开头的效果

完整代码与注释

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

    float circle = length(uv) - 0.23;               ///< 圆的绘制
    float rect =  max(abs(uv.x), abs(uv.y)) - 0.1;  ///< 矩形的绘制

    /// @note 插值比例,0: circle, 1: rect
    float w = -sin(t + sin(t + sin(t))) * 0.5 + 0.5;
    /// @note 缓动插值
    float f = mix(circle, rect, w);

    f = smoothstep(0.0, -0.01, f) - smoothstep(-0.01, -0.02, f);
    vec3 col = vec3(f);
    fragColor = vec4(col, 1.0);
}