見出し画像

Babylon.js v4.2.0 Practiceめも⑥

その⑤からのつづきです。 物理演算で衝突判定をしつつ、操作対象3Dモデルを「forward」「left」「right」「backward」ボタンで前進、左回転、右回転、後退させるときに、その動作にアニメーションを対応させてみました。

物理演算用の物理エンジンに、それぞれOimo.js、Cannon.js、Ammo.jsを使用したコードを比較のために3種類作成してみました。

見た目の操作対象3Dモデルとは別にbox(立方体)の3Dオブジェクトを作って、それを実際の操作と物理演算の対象としています。 見た目の操作対象3Dモデルをそのboxの範囲内にだいたい収まるようにして、boxで物理演算の計算したあと、そのboxの座標や回転を見た目の3Dモデルに反映するようにしています。

3種類の物理エンジンについては、Oimo.jsは操作対象がSphere(球)に衝突時にめりこんでしまう、Cannon.jsは衝突の反動で操作対象が倒れてしまうことがある(x、y軸の衝突の反動を消す設定していないので本来の挙動ではありますが)、Ammo.jsはそのどちらでも安定?している(めりこまない&倒れない)、といった感じでした。

なので、とりあえず今後の作業はAmmo.jsバージョンのコードで引き続き行っていこうかと考えています。 

今回いろいろと初めての実装をしたので、それらについて自分用の備忘録としてメモを残しておこうと思いましたが、長くなりそうなので、それらは後回しにして下記の3コードのリンク貼り付けの後につらつらと書き連ねています。


コードその① 物理エンジンがOimo.jsのもの

Babylon.js v4.2.0 Practice#50 Babylon.js and Physics Engine Test01 with Oimo.js

画像1


コードその② 物理エンジンがCannon.jsのもの

Babylon.js v4.2.0 Practice#51 Babylon.js and Physics Engine Test02 with Cannon.js

画像2


コードその③ 物理エンジンがAmmo.jsのもの

Babylon.js v4.2.0 Practice#52 Babylon.js and Physics Engine Test03 with Ammo.js

画像3


まず上記の3コードの物理エンジンの使い分けでは、以下のようなコードの記述で物理エンジンの使い分けを行っています。

コードその① 物理エンジンがOimo.jsのもの
html部分

<script src="https://cdnjs.cloudflare.com/ajax/libs/oimo/1.0.9/oimo.min.js"></script>

javascript部分

scene.enablePhysics(new BABYLON.Vector3(0,-9.81, 0), new BABYLON.OimoJSPlugin());


コードその② 物理エンジンがCannon.jsのもの

html部分

<script src="https://cdn.jsdelivr.net/npm/cannon@0.6.2/build/cannon.min.js"></script>

javascript部分

scene.enablePhysics(); 


上記のような引数なしのscene.enablePhysics(); は自動で

scene.enablePhysics(new BABYLON.Vector3(0,-9.81, 0), new BABYLON.CannonJSPlugin());

と同じ意味となっている? Babylon.jsではCannon.jsが物理エンジンのデフォルト的なものとなっているのでしょうか?


コードその③ 物理エンジンがAmmo.jsのもの

html部分

<script src="https://cdn.jsdelivr.net/npm/ammo-node@1.0.0/ammo.min.js"></script>

javascript部分

scene.enablePhysics(new BABYLON.Vector3(0, -9.81, 0), new BABYLON.AmmoJSPlugin());


物理エンジンの使い分けは以上のように行っています。


newScene.executeWhenReady

次に一番苦労したのが以下の

「newScene.executeWhenReady(function () {   ~   });」

の部分です。 

BABYLON.SceneLoader.ImportMesh関数で、glTFファイルが完全に読み込まれてから処理を始めるnewScene.executeWhenReadyの中に諸々の処理を書いておかないと、(glTFファイルの読み込み処理の完了後に行われるせいか?)設定や生成の処理が間に合わなかったオブジェクトが存在しないと指摘されてエラーとなってしまい、その解決までにけっこうハマりました。 

自分の作業時にはboxがundefinedとかいわれて、どこが問題なんじゃ~、全然わからん~、としばらく悶えてましたw。 

とりあえずなんでもかんでも入れられるだけnewScene.executeWhenReady関数の中に詰め込んでなんとか動くようできました。

作業にあたり以下のサイトを参考にさせていただきました。

Pick mesh in the Scene

OBJ and BABYLON 3D Export


3Dオブジェクト間の座標と回転のコピペ

次に苦労した点は、操作&物理演算の対象となるboxの位置座標と回転を、このnoteの最初のほうにも書いたように、見た目の3Dモデルへコピーする部分でした。 

位置座標は以下のコードでわりと簡単にboxからコピペすることができました。

mesh.position.x = box.position.x;
mesh.position.y = box.position.y-1;
mesh.position.z = box.position.z;

y座標の-1は座標の高さを、見た目用の3Dモデルと、物理演算用のboxとで揃えるための計算用です。

回転情報のほうは

mesh.rotationQuaternion = box.rotationQuaternion;

または

box.rotationQuaternion.toEulerAnglesToRef(box.rotation)
mesh.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(box.rotation.y, box.rotation.x, box.rotation.z);

といったコードでboxから操作対象3Dモデルへコピペすることができました。

以下のサイトやサンプルコードを参考にさせていただきました。

Copy position and rotation from one object to another (Physics)

Euler Angle and Quaternion issue

サンプルコードその1

サンプルコードその2

これらのサイトやサンプルコードにあったものをとりあえず、コピペしてみて思うとおり動くか動かないかだけ試し続けて、なんとか位置座標と回転のコピペできるようになりましたw。 いつものようにクォータニオンが何であるかはロクに理解せずとりあえず動くようにしたものですw。


GUIボタン

最後にBabylon.jsのGUI機能によるボタンに設定についてです。 結果から言うと、レスポンシブなボタンとゆ~やつを目指したが失敗した、ですw。

スマホ対応としてボタンやそのボタン上の文字を画面サイズにあわせて変化させようとしていろいろ試してみた結果、結局スマホで実行してみたら文字がつぶれてしまいましたよ、的なw。

う~ん、ムズい。。。

後で使うかも的に残していた、サンプルコードからテキトーにずっと使いまわしているボタンのほうがスマホでもちゃんと表示されたという。。。

で、失敗はしましたが、いちおう画面にあわせた可変的なサイズを目指したボタン設定のコードを残しておきます。 以下のようになります。

左ボタン「left」

leftButton.paddingLeft = "20%";
//leftButton.width = "20%";
leftButton.paddingRight = "60%";
leftButton.paddingTop = "40%";
//leftButton.height = "20%";
leftButton.paddingBottom = "40%";

前進ボタン「forward」

forwardButton.paddingLeft = "40%";
//forwardButton.width = "20%";
forwardButton.paddingRight = "40%";
forwardButton.paddingTop = "20%";
//forwardButton.height = "20%";
forwardButton.paddingBottom = "60%";

後退ボタン「backward」

backwardButton.paddingLeft = "40%";
//backwardButton.width = "20%";
backwardButton.paddingRight = "40%";
backwardButton.paddingTop = "60%";
//backwardButton.height = "20%";
backwardButton.paddingBottom = "20%";

左ボタン「right」

rightButton.paddingLeft = "60%";
//rightButton.width = "20%";
rightButton.paddingRight = "20%";
rightButton.paddingTop = "40%";
//rightButton.height = "20%";
rightButton.paddingBottom = "40%";

ボタンの設定で「//」によるコメントアウト表示にされているものは、ボタンのwidthとheightは本当はpaddingLeft、paddingRight、paddingTop、paddingBottom、等に挟まれることによって設定されているものだけれど、意味的にはwidthやheightをそのようなパーセンテージで設定しているのと同じだよ、という説明のつもりでコメントアウトしているものです。

そして、文字のサイズも上記のボタンをまとめるパネルの設定で

UiPanel.fontSize = "4%";

とパーセンテージで設定しました。

ですが、最初に説明したように、結局パーセンテージ設定にしたせいで、PCからスマホの表示にしてみると横幅が縮められすぎて、文字をボタン上に表示するには幅が足りなくなってしまいました。 けっこう設定頑張ったのに。。。 _| ̄|○

今後のコーディングの糧としていきたいと思います、たぶんw。

まぁでも、3Dモデルを物理演算させながらアニメーションも切り替える、という当初の目的は達せられたからそれなりにはいいのかな。


参考まとめ
Babylon.js v4.2.0 CodePen投稿コードまとめ

この記事が気に入ったらサポートをしてみませんか?