見出し画像

Three.js r110とAmmo.jsを併用して物理演算してみるテスト

 タイトルにあるようにThree.js r110とAmmo.jsを使用した、3D上での物理演算をためしてみました。

 Ammo.jsは20200314時点のものを使用しました。Ammo.jsはバージョンの見方やすでにCDNに登録されたものの使い方がよくわからなかったので、いつものgithackのCDN経由で使用した上で、使いはじめた日付をテキトーに記録するだけの方針で作業しています。

 まずAmmo.jsでの作業に先だって、物理演算ライブラリの概要を知るために以下のサイトを参考にさせていただきました。

WebGLと3D物理演算ライブラリの組み合わせを試してみる

2019年の3D物理演算ライブラリ状況

 そこから、物理演算ライブラリで更新がまだ続いていそうなものはAmmo.jsとOimo.jsの2つであることを知って、そのうちOimo.jsでの作業は途中で挫折したので、最後に残ったAmmo.jsでの作業をすることにしました。 

 今回の作業の最終目標は物理演算での障害物への当たり判定とモンハン的なカメラ機能をできるだけ実装することでした。具体的なイメージとしては、Unityで以前作成したここにあるようなものをいくらかでもThree.jsとAmmo.jsで実現することでした。

 結果としては、なんとかまぁ、それっぽい物理演算機能とカメラ機能ができたかも、といったところです。。。 Unityで作ったものからは相当割り引いたものです。。。 (ちなみに今回の一連の作業で一番思ったのは、Unityのもろもろの機能は、すごい&すばらしいです。。。)

 そのような少しビミョーな感じになりますが、今回の最終成果物は以下になります。
Three.js r110でカメラ視点移動ボタン追加テスト

画像1

 仕様としては、「camLeftRot」「camRightRot」「camHeight」「camDist」「camReset」ボタンでカメラ視点操作、「forward」「backward」「leftRot」「rightRot」ボタンで操作用の青い箱を操作、となります。 黄色い床からはずれると赤い球、青い箱ともに永遠に落下していきます。 

 「camReset」ボタンでカメラの視点が想定したようにリセットできない、操作用の青い箱で赤い玉を押し続けると(物理設定が微妙なのか?)箱が浮いてしまう、等のビミョーな感じですがこれ以上は自分には改善できそうになかったのでそこで作業打ち切りとしました。

 最終成果物からしてそんなビミョーな感じですが、最終成果物にたどりつくまでの過程のコードへのリンクを貼り付けてみます。 自分でAmmo.jsについて後でいろいろと見返す用のメモ的機能も多分に含めて、コードを作成した時系列&説明付きで貼り付けてみます。 

 初期の作業は以下の2サイトを参考にしながらの、かなーりゆっくーりとした作業進捗となりました。


【忙しい人向け】JavaScriptで3D物理エンジン動かしてみる (three.js + ammo.js)
日本語で丁寧に最初からAmmo.jsの基礎について説明されています。 コードはそのままのコピペでは実際には動かないようです。 コードの内容自体はボール(Sphere)が落ちてきて地面(Box)で止まるまでのものです。 なのでキーボード、マウス等の操作によるインタラクティブな機能までは解説されていないです。


Intro to JavaScript 3D Physics using Ammo.js and Three.js
Moving Objects In JavaScript 3D Physics using Ammo.js and Three.js
英語によるサイトです。 こちらのサイトはコードをコピペしたら実際にコードを動かすことができました。 インタラクティブな機能についても↑↓←→やWSADといったキーボードからの操作でボール(Sphere)や箱(Box)を操作できるところまで解説されています。 KinematicやDyanamic、StaticといったAmmo.jsのRigidBody(剛体)の種類や機能についての解説も。


まず自分がThree.js & Ammo.jsの機能を使って実装したものは
Three.js r110とAmmo.js(20200314時点)の実験その1
になります。

画像2

 上記の①②サイトのほぼ写経作業でした。。。 Three.js & Ammo.jsのBox(立方体)を地面に見立てて作成して、そこに同じようにThree.js & Ammo.jsのSphere(球体)を赤い球として載せているだけのコードです。 いちおうAmmo.jsで物理演算のための設定もしていますが、何も動かないです。。。

次に作成したものが
Three.js r110とAmmo.js(20200314時点)の実験その2
になります。

画像3

 今度は黄色い地面に見立てたBoxの上に、Sphereによる赤い球が落下してくるコードです。 これも内容はほぼ①②サイトからの写経です。 まだAmmo.jsの使い方なんとなーくわかった程度です。

その次に作成したコードが
Three.js r110とAmmo.js(20200314時点)の実験その3
になります。

画像4

 これは同じようにBoxの黄色い地面の上にSphereの赤い球が落下してくることに加えて、操作対象となるBoxによる青い箱を設置したものです。「forward」「backward」「left」「right」のボタンで操作対象の青い箱を前後左右に移動できるようにしました。 Ammo.jsの物理演算により、操作対象の青い箱が赤い球にぶつかるとその球を押せるようになっています。

で、次に作成した
Three.js r110とAmmo.js(20200314時点)の実験その4
は、自分の求めていた操作Boxの動きを実現したもの、と思ったら違って、操作できるようになったかわりに物理演算ができなくなってしまったものです。 (上記の「...実験その3」も後で同じ状態だと気づきました。。。)

画像5

 これはAmmo.jsのKinematicという機能を使いつつ、いろいろなパラメータを操作対象の青箱に設定してみたものでした。 これで目標とした青箱の動きを実現しつつ、かつ青箱で赤球は押せるようにはなりましたが、かわりに物理演算がされず重力を受けない状態になってしまってます。 この状態では地面と見立てた黄色いBoxを越えても青箱は落下せず空中を進んでいくような状況になってしまいました。 

 どうやらKinematicという設定をされたものは、操作はできるが物理演算が制限されるようです。 目標とする動きは達成できませんでしたが、そのうちこのKinematicという機能も何かに使えるかも、と思いコードを残しているものです。 

上記のKinematicによる操作用の青い箱の設定をあきらめて作成したのが
Three.js r110とAmmo.js(20200314時点)の実験その5
です。

画像6

 物理計算が適用される普通のAmmo.jsによるBoxを作成して操作用の青い箱としました。 青い箱に対する操作は、Boxの進行方向への力を加えることで実現ということにしています。 物理演算による摩擦の計算のせいなのかなんなのか、青い箱で赤い球を押すとフワフワと青い箱が浮いていってしまいますが、とりあえず。 

Three.js r110とAmmo.js(20200314時点)の実験その6(失敗)
はタイトルのとおり、やろうとしたことに失敗したコードです。 

画像7

 「rot Left」「rot Right」ボタンで操作用の青箱の進行方向を決めてから、「forward」「backward」ボタンで進行方向に沿って前進・後退する動きを実装しようとしましたが、失敗したものです。 「rot Left」「rot Right」ボタンで操作用の箱を回転させて進行方向を決めようとすると、摩擦の設定がなっていないのか永遠に回転し続けますw。

 ちなみに、なんでわざわざ失敗コードを残したのか理由忘れました。。。

Three.js r110とAmmo.js(20200314時点)の実験その7
は「...実験その6(失敗)」で目指したことの実現ができずにあきらめかけて、Ammo.jsに最初から用意されている車3Dモデル用の機能を使ってみようかと浮気し、そのデモをCodePen上で実行してみたものです。 結局これ以上は進めませんでしたが。

画像8


その後、このコード
Three.js r110とAmmo.js(20200314時点)の実験その8
でなんとか「rot Left」「rot Right」ボタンによる青箱の進行方向の変更ができるようになりました。 進行方向の変更時にまた変な摩擦計算が付随しているようにも見えますが、とりあえずOKってことに。

画像9

 この進行方向を変えるためのコードはUnityのために書かれた以下のサイト等を参考にしてなんとか実装することができたものです。

 ここまで気づいて実装するまでめっちゃ苦労しました。。。 クォータニオンとかよくわからんし。。。

 なので今後またそれらの情報が必要になって見返すことになっても、すぐにまた参照できるように、コードにコメントしたものをここでも抜き出してメモとしておきます。 

■以下Unityのものについてですが、ベクトルとクォータニオンによる進行の速度と方向をもつベクトルの計算の参考とさせていただきました
オブジェクトの回転角度から単位方向ベクトルを求める

UnityのベクトルとQuaternionによる回転について

■Three.jsのベクトルとクォータニオンの計算方法については以下を参考にさせていただきました
Three.js Doc > Object3D > getWorldQuaternion

Three.js Doc > Vector3 > applyQuaternion

コード的には

// 操作用3Dオブジェクト操作時の計算・設定
function moveOp3DObject()

という関数内で目的とした処理を行っています。

20221025追記

あとで見返すと、「moveOp3DObject」のコメント付き処理コードも置いておくと参照時に便利そうだったので貼り付けてみます。

// 操作用3Dオブジェクト操作時の計算・設定
function moveOp3DObject(){

   let scalingFactor = 10;

   let moveX =  0;
   let moveY =  0; 
   let moveZ =  opMoveDirection.back - opMoveDirection.forward;

   let rotX =  0;
   let rotY =  opMoveDirection.left - opMoveDirection.right;
   let rotZ =  0;

   ammoTmpRot.setValue( rotX, rotY, rotZ );

   let physicsBody = opObject.userData.physicsBody;

   // setAngularVelocity() で回転速度を設定
   // setAngularVelocity() はこの処理を常に実行して、指定されない場合も0を設定しなおさないと回転が止まらなくなる? Ammo.jsの仕様?
   physicsBody.setAngularVelocity( ammoTmpRot );

   // setLinearVelocity() を実行中は updatePhysics() の処理が遅くなるのでここでの処理実行の判定が必要?
   if( moveZ == 0 ) return;

   // Three.jsの機能でクォータニオンとベクトルの計算
   // 操作対象3Dオブジェクトの進行方向をクォータニオンとして取得
   opObject.getWorldQuaternion( tmpQuat ); 
   // 進行速度をベクトルとして設定
   tmpVel.set( moveX, moveY, moveZ ); 
   // 「 進行速度のベクトル 」に「 進行方向のクォータニオン 」を掛け合わせて進行方向速度をベクトルとして取得
   tmpVel.applyQuaternion( tmpQuat );

   // Three.jsのベクトルからAmmo.jsのベクトルへ
   ammoTmpVel.setValue( tmpVel.x, tmpVel.y, tmpVel.z );
   // 進行方向速度ベクトルをスケールする
   ammoTmpVel.op_mul( scalingFactor );

   // setLinearVelocity() で進行速度を設定
   // setLinearVelocity() は0を指定しなおさなくても進行が止まる? Ammo.jsの仕様?
   physicsBody.setLinearVelocity( ammoTmpVel );

}


最後に、このnoteの最初のほうにもリンクを貼り付けた最終成果物
Three.js r110でカメラ視点移動ボタン追加テスト
では操作用青箱の周りをカメラが回転する機能を追加しました。

画像10

 回転するカメラの機能を PerspectiveCamera で作成するにあたっては、以下のサイトを参考にさせていただきました。
ics.media > TThree.jsのカメラ

ics.media > Three.jsのカメラの制御

 いつもほぼそのままコピペしただけのようなコードを考えずに書いているから、応用して「camReset」ボタンで操作用青箱の真後ろにカメラがくるようなコードが書けないのかな、やはり。。。

 おまけに、少し以前作成した以下の自分のコードも参考にしました。 まぁカメラ回転部分の処理についてはだいたい同じコード内容ですけれども。
Three.js r87(WebGL使用)とCreateJSでインターフェース実験2

前回コードよりカメラ視点移動ボタンとサウンドON/OFFボタンを追加してみました


Ammo.jsの扱いムズいっす。。。

■参考サイト

本家サイト
kripken/ammo.js

Three.jsとAmmo.jsで作業を始める前の自分への動機付け&目標的なものとなったサイト
Web上でちょっと本気の3Dアクションゲームを作る



参考まとめ
Three.js r110 CodePen投稿コードまとめ


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