これまで主に 2D系の描画では、ライブラリを使ったり自前で実装したりというやり方で多用してきて、記事もいくつか書いたことがあった「イージング」の話です。
●「イージング user:youtoy」の検索結果 - Qiita
https://qiita.com/search?q=%E3%82%A4%E3%83%BC%E3%82%B8%E3%83%B3%E3%82%B0%20user%3Ayoutoy&sort=created
ふと、「Babylon.js で使う場合に標準機能であったりするかな?」と気になって手をつけてみました。
Babylon.js でイージング
標準機能でイージング
まず、「Babylon.js easing」といったキーワードで検索をしてみたら、すぐに公式ドキュメントなどに行き当たりました。
●EasingFunction | Babylon.js Documentation
https://doc.babylonjs.com/typedoc/classes/BABYLON.EasingFunction
●Advanced Animation Methods | Babylon.js Documentation
https://doc.babylonjs.com/features/featuresDeepDive/animation/advanced_animations
プレイグラウンドのサンプル
さらに見ていくと、プレイグラウンドのサンプルもありました。
●PGDemo | Babylon.js Playground
https://playground.babylonjs.com/#8ZNVGR
3つのオブジェクトがあり、1つはイージングを適用していない動きで、残り2つは異なるイージングが適用されているもののようですた。
コードの内容は、以下のとおりです。
var createScene = function () {
var scene = new BABYLON.Scene(engine);
var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(0, 100, 100), scene);
var camera = new BABYLON.ArcRotateCamera("Camera", 0, 0.8, 100, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);
// Torus
var torus = BABYLON.Mesh.CreateTorus("torus", 8, 2, 32, scene, false);
torus.position.x = 25;
torus.position.z = 30;
var materialBox = new BABYLON.StandardMaterial("texture1", scene);
materialBox.diffuseColor = new BABYLON.Color3(0, 1, 0);//Green
// -----------------------------------------
// Creation of an easing animation within predefined easing functions
// ------------------------------------------
//Create a Vector3 animation at 30 FPS
var animationTorus = new BABYLON.Animation("torusEasingAnimation", "position", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
// the torus destination position
var nextPos = torus.position.add(new BABYLON.Vector3(-80, 0, 0));
// Animation keys
var keysTorus = [];
keysTorus.push({ frame: 0, value: torus.position });
keysTorus.push({ frame: 120, value: nextPos });
animationTorus.setKeys(keysTorus);
// Adding an easing function
// You can use :
//1. CircleEase()
//2. BackEase(amplitude)
//3. BounceEase(bounces, bounciness)
//4. CubicEase()
//5. ElasticEase(oscillations, springiness)
//6. ExponentialEase(exponent)
//7. PowerEase(power)
//8. QuadraticEase()
//9. QuarticEase()
//10. QuinticEase()
//11. SineEase()
// And if you want a total control, you can use a Bezier Curve animation
//12. BezierCurveEase(x1, y1, x2, y2)
var easingFunction = new BABYLON.CircleEase();
// For each easing function, you can choose beetween EASEIN (default), EASEOUT, EASEINOUT
easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEINOUT);
// Adding easing function to my animation
animationTorus.setEasingFunction(easingFunction);
// Adding animation to my torus animations collection
torus.animations.push(animationTorus);
//Finally, launch animations on torus, from key 0 to key 120 with loop activated
scene.beginAnimation(torus, 0, 120, true);
// ------------------------------------------
// Using Bezier curve to create a custom easing function
// See here to see some samples and values : http://cubic-bezier.com/
// -----------------------------------------
// Torus
var bezierTorus = BABYLON.Mesh.CreateTorus("torus", 8, 2, 32, scene, false);
bezierTorus.position.x = 25;
bezierTorus.position.z = 0;
// Create the animation
var animationBezierTorus = new BABYLON.Animation("animationBezierTorus", "position", 30, BABYLON.Animation.ANIMATIONTYPE_VECTOR3, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
var keysBezierTorus = [];
keysBezierTorus.push({ frame: 0, value: bezierTorus.position });
keysBezierTorus.push({ frame: 120, value: bezierTorus.position.add(new BABYLON.Vector3(-80, 0, 0)) });
animationBezierTorus.setKeys(keysBezierTorus);
var bezierEase = new BABYLON.BezierCurveEase(0.32, -0.73, 0.69, 1.59);
animationBezierTorus.setEasingFunction(bezierEase);
bezierTorus.animations.push(animationBezierTorus);
scene.beginAnimation(bezierTorus, 0, 120, true);
// ------------------------------------------
// Create a simple animation without easing functions
// ------------------------------------------
var torus0 = BABYLON.Mesh.CreateTorus("torus", 8, 2, 32, scene, false);
torus0.position.x = 25;
torus0.position.z = -30;
torus0.material = materialBox;
BABYLON.Animation.CreateAndStartAnimation("anim", torus0, "position", 30, 120,
torus0.position, torus0.position.add(new BABYLON.Vector3(-80, 0, 0)));
return scene;
}
ポイントになりそうな部分を見てみる
イージングを実現する場合の構成としては、始点と終点を決めて、「その始点・終点の間の動きを、線形・非線形な関数でどのようにつなぐか」を設定する感じかと思います。
上記のサンプルでは、イージングを適用したものが 3つのうち 2つあるようだったので、1つずつ見ていきます。
まずは片方のイージングに関する処理を見てみます。
イージングの始点・終点の位置を決める部分は、以下が該当しそうです(フレーム数と場所が設定されているようです)。
また、Babylon.js で用意された複数のイージングの種類の中の 1つを指定して、それを適用する部分は以下が関連しそうです(※ 細かく見ると、他の部分も関連しそうですが)。
上記で 1つ目のイージングの処理に関連した部分を見ていったので、残ったもう片方も見ていきます。
関連しそうな部分は、以下のようです。
上記の 2つのイージングでは、ドキュメントで掲載されているものの中でいうと、以下の赤矢印で示した 2つが利用されていたようでした。
なお、2つあるうちの BezierCurveEase(0.32, -0.73, 0.69, 1.59)
と、引数が指定されているほうについては、それがどんな意味になっているかは公式ドキュメントを見ると分かりやすそうでした。
具体的には以下の部分で、アニメーションにおけるイージングを使った変化の様子が、視覚的に分かりやすく理解できそうでした。
変更を加えてみる
上記のサンプルにほんの少しだけ変更を加えて、イージングを使った処理の挙動を変化させてみます。
具体的には、イージングの種類を別のものに変えてみます。行うことは、上記で CircleEase()・BezierCurveEase() が使われている部分を、別のものにいれかえるだけです。
その際に、引数指定が不要のものを選んで試すのが手軽だと思うので、それに該当しそうなものを適当に選んでみました。具体的には QuadraticEase()・SineEase() です。
それらを、サンプルで使われている CircleEase()・BezierCurveEase() と入れかえてみた結果、アニメーションする物体の動きが変わったことが確認できました。
Babylon.js でのアニメーション
今回の標準機能を使ったイージングは、Babylon.js標準のアニメーションの機能と組み合わせられているようです。
今回用いたイージングを使う場合は、そもそも Babylon.js でのアニメーションを標準機能で扱う、という話もセットで見ておくと良さそうでした(※今回の記事では、その部分は割愛)。
●Animation | Babylon.js Documentation
https://doc.babylonjs.com/typedoc/classes/BABYLON.Animation
●Designing Animations | Babylon.js Documentation
https://doc.babylonjs.com/features/featuresDeepDive/animation/animation_design
●3-06: キャラクターのアニメーション (Character Animation)
https://zenn.dev/chomado/books/babylonjs-tutorial-ja/viewer/3-06
●Babylon.jsでアニメーション作成
https://zenn.dev/ricky/articles/c8c79e52bbd11d