たとえば、オブジェクトがX1座標からX2座標に等時間間隔でSステップにわたって移動するEase-OutアニメーションとEase-Inアニメーションを実行しているとします。この動きのX座標を計算する式を提案できる人はいますか?
6 に答える
個人的には、[0;で時間を取得する関数を使用したいと思います。1]そして[0;に値を出力します。1]、結果を任意のタイプ(2Dベクトル、3Dベクトルなど)に適用できるようにします。
解決策1
二次イージングイン/アウトの場合、曲線は次の値に応じて2つの異なる関数に分けられますt
。
t
<= 0.5の場合:f(x) = 2 * x * x
[0; 0.5]のxを使用(グラフ)t
> 0.5の場合:f(x) = 2 * x * (1 - x) + 0.5
xが[0; 0.5]の場合(グラフ)
グラフは次のとおりです。
2番目の関数も[0;0.5]にありますがt
、使用を開始すると> 0.5になるため、0.5減らす必要がありt
ます。
これは、Cでの結果です。
float InOutQuadBlend(float t)
{
if(t <= 0.5f)
return 2.0f * t * t;
t -= 0.5f;
return 2.0f * t * (1.0f - t) + 0.5f;
}
解決策2(ベジェ)
もう1つの興味深いブレンド曲線は、ベジェによって与えられたものです。これには、非常に最適化されるという利点があります(ifがない場合)。これがWolframの曲線です。
そしてここにCコードがあります:
float BezierBlend(float t)
{
return t * t * (3.0f - 2.0f * t);
}
解決策3(パラメトリック関数)
@DannyYaroslavskiによって提案された別の方法は、ここで提案された単純な式です。
それはパラメトリックであり、素晴らしいイン/アウトの加速と減速を取得します。
alpha = 2の場合、次の関数が得られます。
これはCで次のように変換されます:
float ParametricBlend(float t)
{
float sqt = t * t;
return sqt / (2.0f * (sqt - t) + 1.0f);
}
編集1: @DannyYaroslavskiからソリューション3を追加
編集2:ソリューション1のより良い説明
編集3:すべてのソリューションにグラフを追加
二次方程式はどこで簡単になりますか:
t=現在の時刻
b=開始値
c=値の変化
d=期間
function (float time, float startValue, float change, float duration) {
time /= duration / 2;
if (time < 1) {
return change / 2 * time * time + startValue;
}
time--;
return -change / 2 * (time * (time - 2) - 1) + startValue;
};
ソース: http: //gizma.com/easing/
上記のすべてのソリューションには、使用例がありません。
ここで良い解決策を見つけました:
function animate({timing, draw, duration}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
// timeFraction goes from 0 to 1
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
// calculate the current animation state
let progress = timing(timeFraction)
draw(progress); // draw it
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}
使用例:
animate({
duration: 1000,
timing(timeFraction) { // here you can put other functions
return timeFraction;
},
draw(progress) {
elem.style.width = progress * 100 + '%';
}
});
その他の機能:
function quad(timeFraction) {
return Math.pow(timeFraction, 2)
}
詳細はこちら
同じ問題が発生しました。チャートをアニメーション化したかったの(Ease in-out)
です。
ブレインストームは私に2つの方法を与えました:
1)トリゴノメトリック式。最初に、私は書いたy=(sin(x/π*10-π/2)+1)/2
、どのアナログはsin^2((5*x)/π)
float TrygoEase (float x) {
float y=(float)Math.pow(Math.sin(5*x/Math.PI),2);
return y;
}
2)2つの放物線。難しくはありませんでした。私はちょうどで、そしてで使用y=2*x*x
しました[0;0.5]
y=-2(x-1)^2+1
[0.5;1]
float ParabolEase(float x) {
float y=2*x*x;
if(x>0.5f){
x-=1;
y=-2*x*x+1;
}
return y;
}
この方法を使用してx=[0;1]
、何が返されるかについても説明しy=[0;1]
ます。
これで、このグラフを比較できます。
これは、Creakによってリンクされたこの一般的なソリューションに従って、曲率の量を引数として持つバージョンです。
/*
* applyCurve: apply an S-curve to an input value.
* The highest positive curvature will result in a step from 0 to 1,
* the most negative curvature will result in a constant of 0.5.
*
* progress: the input value between 0 and 1,
* curvature: the amount of curvature between -1 and 1.
* Negative values curve the other way, 0 applies no curvature.
*/
double applyCurve(double progress, double curvature) {
assert(progress >= 0.0 && progress <= 1.0);
assert(curvature >= -1.0 && curvature <= 1.0);
if (curvature >= 0.0) {
if (curvature > 0.99999) return progress > 0.5 ? 1.0 : 0.0;
float exp = 1.0 / (1.0 - curvature); // find s-curve exponent
return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
} else {
if (curvature < -0.99999) return 0.5;
float exp = 1.0 + curvature; // find s-curve exponent
return pow(progress, exp) / (pow(progress, exp) + pow(1.0 - progress, exp)); // apply s-curve
}
}
このバージョンでは、イーズインおよびイーズアウト関数(EaseInおよびEaseOut)を使用できます。両方の関数は、0から1の間の時間値パラメーターを取り、0から1の間の緩和された時間値を返す必要があります。
float EaseInOut(float t)
{
if (t <= 0.5f)
{
return EaseIn(t * 2) * 0.5f;
}
else
{
t -= 0.5f;
return (EaseOut(t * 2) * 0.5f) + 0.5f;
}
}