OpenGL Shader-缓动函数

516 阅读3分钟

「这是我参与2022首次更文挑战的第21天,活动详情查看:2022首次更文挑战

缩放效果

纹理中心缩放实现原理是调整纹理顶点坐标和纹理坐标的关系。调整后的顶点坐标是以(0.5,0.5)为中心点,然后根据缩放系数计算缩放大小。amplitude缩放系数越接近1缩放大小就越小。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    //中心点
    vec2 anchorPoint = vec2(0.5, 0.5);
    float amplitude = 1.5;
    vec2 textCoords = vec2(anchorPoint.x + (uv.x - anchorPoint.x) / amplitude, anchorPoint.y + (uv.y - anchorPoint.y) / amplitude);
    gl_FragColor = texture(iChannel2, textCoords);
}

缩放动画

具备缩放能力后再增加iTime参数来缩放具备动画效果。

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    // 缩放时间周期
    float duration = 3.;
    //缩放中心点
    vec2 anchorPoint = vec2(0.5, 0.5);
    //根据当前时间进度计算缩放幅度
    float time = mod(iTime, duration);
    float amplitude = 1.0 + time;
    //转化纹理坐标变化
    vec2 textCoords = vec2(anchorPoint.x + (uv.x - anchorPoint.x) / amplitude, anchorPoint.y + (uv.y - anchorPoint.y) / amplitude);
    gl_FragColor = texture(iChannel2, textCoords);
}

2290ccea81b024f6c2e8439698396216.gif

缓动函数

在实际使用动画的过程中经常会去实现不同速度的动画效果。像是线性动画会显得效果比较平淡,可以通过改变动画执行速率让动画效果更加灵动具有弹性自然,可以提高动画效果的高级感。

例如下图所示是比较常用的缓动动画曲线表,通过不同算法函数来实现动画速率不同表现形式。 image.png 下面选取几个类别来实现缩放运用缓动函数后的动画效果。首先使用线性函数举个例子,t表示当前时间,b表示初始值,c是变化量,d是持续时间,将之前动画例子中time替换为缓动函数即可,线性函数动画效果与上述动画效果是一致的。

//t: current time(当前时间);
//b: beginning value(初始值);
//c: change in value(变化量);
//d: duration(持续时间)。
float linear(float t, float b, float c, float d) { 
    return c*t/d + b; 
}
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;

    // 缩放时间周期
    float duration = 3.;
    //缩放中心点
    vec2 anchorPoint = vec2(0.5, 0.5);
    //根据当前时间进度计算缩放幅度
    float time = mod(iTime, duration);
    // 
    float amplitude = 1.0 + linear(time, 0., 1.5,duration);

    //转化纹理坐标变化
    vec2 textCoords = vec2(anchorPoint.x + (uv.x - anchorPoint.x) / amplitude, anchorPoint.y + (uv.y - anchorPoint.y) / amplitude);
    gl_FragColor = texture(iChannel2, textCoords);

}

Quad

  • easeInQuad:开始慢,后来快
  • easeOutQuad:开始快,后来慢
  • easeInQuad:开始快,后来快,中间过渡慢 image.png
float easeInQuad(float t, float b, float c, float d) {
    return c * (t /= d) * t + b;
}

float easeOutQuad(float t, float b, float c, float d) {
    return -c * (t/= d) * (t-2.) + b;
}

 float easeInOutQuad(float t, float b, float c, float d) {
    return (t /= d / 2.) < 1. ? c / 2. * t * t + b : -c / 2. * ((--t) * (t-2.) - 1.) + b;
}

easeInQuadeaseOutQuadeaseInOutQuad
2dd1b15b773038afbd1d5e7b823e92d3.gifb507e73e44a050ca12a58b066a427bee.gifVideo_20220204_010520_933.gif

Back

  • easeInBack:开始慢,后来快,中间会有一段低于起始值
  • easeOutBack:开始快,后来慢,中间会有一段高于最终值
  • easeInOutBack:开始快,后来快,中间过渡慢,其中中间会有低于起始值,高于最终值的情况 image.png
float easeInBack(float t, float b, float c, float d) {
    float s = 1.70158;
    return c * (t /= d) * t * ((s + 1.) * t - s) + b;
}
float easeOutBack(float t, float b, float c, float d) {
    float s = 1.70158;
    return c * ((t = t/d - 1.) * t * ((s + 1.) * t + s) + 1.) + b;
}
float easeInOutBack(float t, float b, float c, float d) {
    float s = 1.70158; 
    if ((t /= d / 2.) < 1.) return c / 2. * (t * t * (((s *= (1.525)) + 1.) * t - s)) + b;
    return c / 2.*((t -= 2.) * t * (((s *= (1.525)) + 1.) * t + s) + 2.) + b;
}
easeInBackeaseOutBackeaseInOutBack
ce7304d106ff94ef185006fe6384ecab.gif90bdb078ccc5f094bf4262271d1cca40.gifa044e4971b30641f6dc01624c8f9975d.gif

Bounce

  • easeInBounce:开始一段跳跃式,最后一个跃进
  • easeOutBounce:开始一个跃进,最后一段跳跃式
  • easeInOutBounce:开始一段跳跃式,最后一段跳跃式,中间是一个跃进 image.png
float easeOutBounce(float t, float b, float c, float d) {
    if ((t /= d) < (1. / 2.75)) {
        return c * (7.5625 * t * t) + b;
    } else if (t < (2. / 2.75)) {
        return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
    } else if (t < (2.5 / 2.75)) {
        return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
    } else {
        return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
    }
}

float easeInBounce(float t, float b, float c, float d) {
    return c - easeOutBounce(d-t, 0. ,c, d) + b;
}

float easeInOutBounce(float t, float b, float c, float d) {
    if (t < d / 2.) {
        return easeInBounce(t * 2., 0., c, d) * .5 + b;
    } else {
        return easeOutBounce(t * 2. - d, 0., c, d) * .5 + c * .5 + b;
    }
}
easeInBounceeaseOutBounceeaseInOutBounce
Video_20220204_011338_846.gifabe19bd56b0336cc6d405919aeb64ba9.gifVideo_20220204_011349_70.gif

总结

除了BounceQuad缓动函数之外还有其他例如SineCubic等其他动画效果不一一例举,在glsl没有内置方法因此需要开发者自行实现。

参考