Babylon.js に標準機能でイージングのための機能があるか確認して軽く触ってみた

これまで主に 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
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/10b3ed5c-bf31-b45d-cf75-0b3926db5c8f.png)

●Advanced Animation Methods | Babylon.js Documentation
　https://doc.babylonjs.com/features/featuresDeepDive/animation/advanced_animations

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/7c919a77-3b3e-d021-277c-4fd9880d0e56.png)

### プレイグラウンドのサンプル
さらに見ていくと、プレイグラウンドのサンプルもありました。

●PGDemo | Babylon.js Playground
　https://playground.babylonjs.com/#8ZNVGR

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9272b9de-7c0d-1f28-574e-1ce94059973b.png)

3つのオブジェクトがあり、1つはイージングを適用していない動きで、残り2つは異なるイージングが適用されているもののようですた。
コードの内容は、以下のとおりです。

```javascript
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つずつ見ていきます。

まずは片方のイージングに関する処理を見てみます。
イージングの始点・終点の位置を決める部分は、以下が該当しそうです（フレーム数と場所が設定されているようです）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3171a44b-9bfa-03b6-4271-edd7a121276e.png)

また、Babylon.js で用意された複数のイージングの種類の中の 1つを指定して、それを適用する部分は以下が関連しそうです（※ 細かく見ると、他の部分も関連しそうですが）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2929f475-4925-f942-e046-6346e4344d68.png)

上記で 1つ目のイージングの処理に関連した部分を見ていったので、残ったもう片方も見ていきます。
関連しそうな部分は、以下のようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/59eee078-06fc-53ef-e2e9-8e20e7b0eafd.png)

上記の　2つのイージングでは、ドキュメントで掲載されているものの中でいうと、以下の赤矢印で示した 2つが利用されていたようでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2b21c82b-d7b4-0c20-cbc1-cd2dd128642c.png)

なお、2つあるうちの `BezierCurveEase(0.32, -0.73, 0.69, 1.59)` と、引数が指定されているほうについては、それがどんな意味になっているかは公式ドキュメントを見ると分かりやすそうでした。
具体的には以下の部分で、アニメーションにおけるイージングを使った変化の様子が、視覚的に分かりやすく理解できそうでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c6b43ac3-9be9-0a6a-118c-ec14a70a13a4.png)

#### 変更を加えてみる
上記のサンプルにほんの少しだけ変更を加えて、イージングを使った処理の挙動を変化させてみます。

具体的には、イージングの種類を別のものに変えてみます。行うことは、上記で 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