前回は、Blenderを使ってキャラクターに複数のアニメーションを割り当ててBabylon.js sandboxで再生する手順を紹介しました。
今回は、このキャラクタの3DCGモデルを使ってBabylon.js Editorで操作できるシーンを作る手順を紹介します。
環境
・Babylon.js Editor v4.2.0
- 1. Babylon.js Editorについて
- 2. Babylon.js Editorにglbファイルをインポートする
- 3. Babylon.js EditorのPreviewの中にglbをドラッグする
- 4. glbに入っているアニメーションが再生できるか確認する
- 5. キャラクタモデルにスクリプトを割り当てて制御を作る
- 6. おわりに
1. Babylon.js Editorについて
以前から何度か紹介していますが、UnityのようにGUIベースでオブジェクトの配置を調整したり、オブジェクトにスクリプトをアタッチすることができます。
Electronという技術で作られており、Webアプリがexe、app形式でまとまっています。
このサイトの右上にある"Download"からダウンロードして使います。
基本的な使い方などはこの辺りを参照ください。
TypeScriptで記述することと独特の記法のため、Babylon.jsを知っている人でも少し慣れが必要です。
Babylon.js Editorでは、作成する一連のプロジェクトのことをworkspaceと呼びます。Babylon.js Editorを開くと、既存のworkspaceを読み込むか (Open an existing project)、新規にworkspaceを作るか (Create a new workspace) を選択する画面になります。Emptyを選ぶと何もない状態、それ以外を選ぶと簡単なシーン付きのworkspaceが生成されます。 今回はThird Person Shooterのテンプレートを選んで新規作成しました。
なお、生成するときにフォルダを選ぶ必要がありますが、この処理の中で新しくフォルダを作る機能は入っていないので、あらかじめExplorer (Windows) またはFinder (Mac) 上で空フォルダを作る必要があります。
2. Babylon.js Editorにglbファイルをインポートする
以下の画像に書いた順番で操作します。
[3] の付近で右クリックすると、このフォルダ構成の中で新しくフォルダを作ることができます。フォルダを作成しなくてもインポートはできますが、glbファイルをインポートしてCG空間のViewに表示させると大量のマテリアルやテクスチャが一気にフォルダに生成されます。そのため、新しくフォルダを作ってその中でインポートするのがおすすめです。
3. Babylon.js EditorのPreviewの中にglbをドラッグする
ドラッグすると、Asset Browserの中にマテリアルとテクスチャが展開されます。Graph View (UnityでのHierarchy View) の中にroot というものが増えて、Previewの中でキャラクターが表示されれば成功です。
この時点で何も見えない場合、キャラクタのscalingが小さすぎる可能性があります。rootを選択してから右側のInspectorでscalingのx, y, zの値をそれぞれ1から20くらいに変更するとみえるようになります。
4. glbに入っているアニメーションが再生できるか確認する
特に実施しなくても良いのですが、Asset Browserに展開されたglbファイルをダブルクリックすると、タブ状態でもう1つのウインドウでMesh Viewerが開きます。
Mesh Viewerの中にはInspectorがあり、アニメーション付きメッシュの場合はAnimation Groupが表示されます。
ここから再生させたいアニメーションを選んでPlayボタンを押せば、アニメーション再生を確認できます。
5. キャラクタモデルにスクリプトを割り当てて制御を作る
5.1 スクリプトの作成
以下の手順で、Asset Browserのsrc/sceneの中にスクリプトを作ります。
このsceneはUnityでのsceneと同じと思って大丈夫です。この画像では私が検証用にscene1, scene2を増やしていますが、初期状態ではsceneフォルダのみが表示されます。
このフォルダの中に作ることは必須ではないですが、後で解説するように別のスクリプトの内容を参照したいとき (UnityでのGetComponent) 、階層構造を正しく表示する必要があります。今後テンプレートプロジェクトから動きを参考にするときにコピペで済ませられるよう、このフォルダの中に作っておくのが安心です。
Add > TypeScript File を選択するとファイル名称を入力する欄が出ます。まずはscene全体の情報を使えるようにするため、SceneManagerと入力してenterキーを押します。すると、SceneManager.tsがsrc/scene以下に生成されます。
(SceneManager.tsと入力しても、SceneManager.ts.tsとはなりませんでした)
このSceneManager.tsをダブルクリックすると、ご自身が使っているPCでインストールされたエディタが開きます。
(私の場合はVisual Studio Codeです)
開くと最初はこのように表示されます。 gist.github.com
普段使うBabylon.jsの書き方と少し異なっており、起動時に一度だけ呼びたい処理をonStart()に、フレームごとに動いてほしい処理をonUpdate()に記述します。これはUnityと少し似ています。
また、Babylon.jsでPlaygroundを使っている場合、このようにBABYLONをつけてメソッドを使います。
Babylon.js Editorではそれらをimport構文で呼び出すことになっています。上の例では最初にこのような宣言が必要です。
importへの追加は後からでもできるので、コードを書きながら都度追加がおすすめです。
SceneManager.tsについて、Babylon.jsで使っているsceneという変数を他のスクリプトでも使えるようにするため、このように書きます。
次に、先ほどと同じ手順で新しくスクリプトを作って、character.tsとします。これを開いたらこのように記述します。
以降、いくつか補足します。
5.2 他のスクリプトで書かれた変数を呼ぶ
冒頭に書いてある
import SceneManager from "./SceneManager";
により、SceneManager.tsの情報を取得しています。これはcharacter.tsとSceneManager.tsが同じ階層に位置している場合の書き方です。
public _scene:SceneManager;
これにより、SceneManager.tsで宣言したsceneの情報を使うことができます。
5.3 AnimationGroupの再生
考え方はこちらに書かれています。
doc.babylonjs.com
今回はBabylon.js Editorなので、書き方を少し変えます。ドキュメントに書いてある"scene.getAnimationGroupByName()"を使うために先ほどの_sceneを使います。
onStart()の中で上のようにanimIdleStartを呼ぶことで、開始時にIdle状態のアニメーションがループ再生されます。
5.4 キー入力に応じて処理を実行する
"@onKeyboardEvent([84], KeyboardEventTypes.KEYDOWN)"を関数の冒頭に付けます。番号はJavaScriptで使われるキーコード番号です。
例
_moveStraight()を呼び、その中で"this.translate(new Vector3(0,0,1),0.2);"を入れることで、走るアニメーション+移動を実現しています。
また、_mmaKick()を呼ぶことでキックアニメーションが実現できるようにしています。
5.5 キックアニメーションでそばにある物体を吹き飛ばす
Babylon.jsでは物体に力を与える方法が提供されています。
https://playground.babylonjs.com/#RHBQY9#12
https://playground.babylonjs.com/#UZHINX%E3%80%80%E3%80%80
2つめで使われているphysicsHelper.applyRadialExplosionImpulseなどはちょうど良さそうなのですが、なぜか動きませんでした。ただ、これは私の書き方に問題があるかもしれずまたどこかで調べてみます。
今回は、目の前にボールを表示して非表示にし、ボールを猛スピードで飛ばすことで吹き飛ばす処理を作りました。
" @fromChildren("Ball")" では、rootの子オブジェクトとして配置されている"Ball" (Sphereメッシュ) を呼び出しています。
_impluseShot()関数の中では、characterの目の前にBallを表示させ ("ballInstance.position.copyFrom" )、"ballInstance.applyImpulse"でcharacterの目の前からボールをとばします。
成功するとこのようになります。
ただし、今時点ではキックアニメーションの瞬間にsphereが飛んでブロックに衝突してしまっているため、やや不自然です。特定のフレームのときに_impluseShot()を呼べればと思ったのですが、該当する関数を見つけられていません。
この辺りは今後対策を考えてみます。
2022/6/27 追記
特定フレームで関数を呼ぶ方法を書きました
6. おわりに
次回は、このキャラクタにカメラを割り当ててTPS (Third Person Shooter) 的な視点で移動できるようにする方法を書く予定です。