Babylon.jsはWebVRコンテンツを作る仕組みが色々と揃っていますが、コントローラでオブジェクトを移動させる機能は入っていません。
そこで、Babylon.jsのメソッドを利用して作りました。今回は作り方を紹介します。
- 1. Babylon.jsにはコントローラのrayが当たったことを検出するメソッドがある
- 2. コントローラの動きに同期させるには、オブジェクトを親子関係にする
- 3. ボタンの押しっぱなしはonTriggerStateChangedObservableメソッドを利用する
- 4. 動作確認する
- 5. 残課題
- 6. おわりに
1. Babylon.jsにはコントローラのrayが当たったことを検出するメソッドがある
Babylon.jsでVRのコントローラを表示させ、インタラクションを有効にすると、このように白い線が出ます。
var VRHelper = scene.createDefaultVRExperience(); // Babylon.jsでVR機能を使うときの宣言 VRHelper.enableInteractions();//インタラクション有効
この白い線はUnityでいうraycastです。rayが当たったことを検出するメソッドonNewMeshSelectedを使うと、rayが当たったオブジェクトの情報を取得できます。
そこで、たとえばこのように書いておくと、rayが当たったとき、rayが離れたときでそれぞれselectedMeshに値を入れることができます。
var selectedMesh; VRHelper.onNewMeshSelected.add(function(mesh) { selectedMesh = mesh; }); VRHelper.onSelectedMeshUnselected.add(function() { selectedMesh=null; });
2. コントローラの動きに同期させるには、オブジェクトを親子関係にする
Unityでは、以下のようなコードで親子関係を作ることができます。
childObject.transform.parent = parentObject.transform;
Unityの場合、childとparentは同じワールド座標系で配置されたままです。したがって今回やりたいことが実現できます。
Babylon.jsでもparentがあり、以下のように書くことで親子関係を実現できます。
childObject.parent = parentObject
しかし、仕様上childObjectがparentObjectのローカル座標系で表示されてしまいます。そのため、親子関係にはなるのですが、childObjectが予想しないところにワープしてしまいます。
Making mesh P a parent of mesh C changes the frame of reference for mesh C to the local axes of mesh P.
引用元:Use a Parent - Babylon.js Documentation
これを避けるため、コントローラ側から子としたいオブジェクトを指定して、座標変換が起きないようにします。
webVRController.mesh.addChild(selectedMesh);
3. ボタンの押しっぱなしはonTriggerStateChangedObservableメソッドを利用する
前回の下記記事の2.3に書いた内容を元にします。
Babylon.jsでOculus Questコントローラの入力を取る方法 - CrossRoad
ただし、このときは単押しを取得する方法でした。今回は押しっぱなしを使いたいので、以下のstateObject.valueの値で比較します。
webVRController.onTriggerStateChangedObservable.add((stateObject)=>{ //途中省略 if(stateObject.value > 0.01){ //途中省略
4. 動作確認する
Oculus Questのブラウザから以下のURLにアクセスし、HMDアイコンを選択すると確認できます。ソースコードもみられます。
補足:Playgroundという仕組みを使っています。Playgroundについては別の記事で解説予定です。
以下は実行例の動画です。
www.youtube.com
5. 残課題
5.1 両手で使用することもできるが、しばらくすると固まってしまう
以下のif文をコメントアウトすると、両手のコントローラでオブジェクトを移動させることができます。
if(webVRController.hand=="left"){ }
しかし、何度か実行していると、以下のエラーが出て固まります。
maximum call stack size exceeded
どうもこの辺りが参考になりそうな可能性が高いですが、時間なくて追えていません。
【今日のバグ取り】 JavaScript でコールスタックが溢れていたのをどうにかした話 - 無駄と文化
わかったら追記します。
6. おわりに
過去の記事と合わせて、キー入力、テレポート移動、今回のオブジェクト移動など、WebVRでの基本的な動きがだいぶわかってきました。そろそろBabylon.jsを使ったゲームなど、もう少しアプリのようなものを試してみる予定です。
また、この機能をtwitterで紹介したところ、Babylon.jsのコミッターの方に声をかけていただきました。
Hey this is cool. Do you want to contribute it back to the framework?
— David Catuhe (@deltakosh) 2019年7月14日
近いうちにBabylon.jsのドキュメントにプルリクエストを投げる予定ですので、反映されたらそちらもご確認いただければと思います。
2019/7/15追記
マージされました。
Use the WebVR experience helper - Babylon.js Documentation