※iOS13の判定についてはこちらの記事に書きました↓
iOS13+でジャイロ許可、やっぱりDeviceOrientationControlsを使いたい
(2019年10月8日)
Three.jsでスマートフォンなどジャイロセンサー搭載のデバイス向けVR体感型のブラウザゲームを作りたい。そんなとき便利なのがDeviceOrientationControls。スマホの向きに合わせてThree.jsのカメラをぐりぐりと動かしてくれる。
しかしコイツ(DeviceOrientationControls)がかなりの曲者。
ジャイロセンサーによる方向の制御が強すぎてカメラを好き勝手にコントロールできないのだ。
最初の記事で挫折したのもそのせい。
半端な理解で、先人のツールに頼ったことの顛末であるが、今回の記事でリベンジできた。
最近VRばんえい競馬ゲームを作成したことで、どうしてもDeviceOrientationControlsの向きを制御する必要があった。正規の方法もあるのだろうが、深く調べる前に“ウマイ”解決策を思いついたので記録に残す。
- 本当に解決策を探してる人のために先に答え
- DeviceOrientationControlsで方向を取得するだけのカメラとキャンパスに描画するカメラを分けたらOKでした。
今回作ったもの
※開始したときと左上にある「リセット」ボタンを押したとき、必ず馬のいる方向にカメラを向けるという単純に見えて、なかなか(DeviceOrientationControlsのときに限り)難しかったプログラム。
例によって、ジャイロセンサー搭載のデバイスには「DeviceOrientationControls」。PCなどそうでない端末には「OrbitControls」という変わり映えしない構成。
今回のテーマは前者。
ジャイロセンサー搭載のデバイスには「DeviceOrientationControls」の部分。スマホの向きによって動かせるカメラになるが、ゲームである以上“ゲームの開始時”、または“ゲームのリセット時”に必ず一定の方向を向かせる必要があった。
前回の記事「使えるパノラマビューア」では一定の方向を向かせるため、カメラでなく映す対象の方を動かした。しかしパノラマビューアのような単純なものならともかく、ぐりぐりと移動が必要なゲームの場合、対象の向きを動かすのは無理がある。
やはりカメラの向き、アングルを動かす方がシンプルで楽なのだ。
工夫したのはこの部分
//スマホなどジャイロセンサーが有効なときはカメラを2台使う if(isGyro){ //通常カメラ camera=new THREE.PerspectiveCamera(opt.camera.fov,cv._w/cv._h,opt.camera.near,opt.camera.far); camera.position.set(0,0,0.01); camera.lookAt(new THREE.Vector3(0,0,0)); //ジャイロセンサーによる角度を取得する目的だけのカメラ camera_doc=new THREE.PerspectiveCamera(opt.camera.fov,cv._w/cv._h,opt.camera.near,opt.camera.far); camera_doc.position.set(0,0,0.01); camera_doc.lookAt(new THREE.Vector3(0,0,0)); controls=new THREE.DeviceOrientationControls(camera_doc); controls.connect();
実際に描画するカメラ「camera」とDeviceOrientationControlsの方向を取得するためだけのカメラ「camera_doc」を用意。
そして開始時やリセット時にDeviceOrientationControlsが当てられた「camera_doc」の方向(※ジャイロセンサーによるアングル)を保存しておく↓
controls.update(); camera_defx=camera_doc.rotation.x; camera_defy=camera_doc.rotation.y; camera_defz=camera_doc.rotation.z;
runAnimateの中で先ほど保存しておいた方向と現在の「camera_doc」の方向の差分を計算し描画用カメラである「camera」に反映する↓
if(isGyro){ var camera_nowx=camera_doc.rotation.x; var camera_nowy=camera_doc.rotation.y; var camera_nowz=camera_doc.rotation.z; //Y方向のみ制御する場合 camera.rotation.x=camera_nowx; camera.rotation.y=(camera_defy-camera_nowy)*-1; camera.rotation.z=camera_nowz; //全方向参照する場合 //camera.rotation.x=(camera_defx-camera_nowx)*-1; //camera.rotation.y=(camera_defy-camera_nowy)*-1; //camera.rotation.z=(camera_defz-camera_nowz)*-1; }
ただカメラのX方向、Z方向まで制御しようとするとDeviceOrientationControlsのせいでやはり真上/真下を向いた際に挙動がおかしくなる。
Y方向だけ制御できれば十分だと思うのだがいかがだろうか。
※寝ながらVRゲームをするのはやめましょう。
まとめ
繰り返しになってしまうが、スマホVRゲームの基本構造としてジャイロセンサー搭載のデバイスには「DeviceOrientationControls」で、PCなどそうでない端末には「OrbitControls」を使用する。
そして「DeviceOrientationControls」の場合はさらにカメラを2台構成にしてカメラのアングルを制御してみてはいかがか、という提案である。
使用したパノラマ画像は十勝川、十勝大橋付近。
先の台風災害前に撮影した、哀しくも懐かしい自然あふれる河川風景。
【PR】 Amazonで「Three.js」を探す!