Swampdog part4 -カメラ回転-
3Dモデルの一側面しか観察できないのでは意味がありません。
あらゆる位置、角度、距離から矯めつ眇めつ観察できるようにします。
カメラを動かせばいいと考えていましたが、動かすのは物体でもいいのかと思い至りどちらを動かすか検討。
何か変わるところがあるでしょうか。
パッと思いついたのはそこそこ容量の大きい3Dモデルを動かすのは処理が重くなるかも?
あと、後に骨、筋肉、血管、神経などの複数の3Dモデルを切り替えるようにしたくて、その時自分が見ていた部分を固定してほしい。
つまり骨のある部分に着目して観察していて、筋肉に切り替えた時視界に同じ場所が写っていると比較がしやすいという要望がある。
物体の方を動かしたら複数のモデルを同期させて動かす必要が出て来ますね。
ということで当初の予定通りカメラを動かすことにします。
さて操作方法ですが、スマホVRアプリとするならばスクリーンをタッチして操作することはできません。
外部コントローラで操作することになります。Oculusみたいな感じですね。
調べてみるとPS3のコントローラをケーブルで繋げばAndroidを操作することができるみたいです。
参考: Android端末にPS3コントローラを繋いでゲームアプリを楽しもう!
Amazonのこちらの商品で接続できそうです。
参考: OAproda OTGケーブルホスト機能USBホスト変換アダプター ブラックMicroBオス-Aメス(Amazon)
Bluetooth接続できれば一番いいですが、難しそうなので優先度低めで対応。
参考: How to connect the Dualshock 3 to Android via Bluetooth
調べるとroot化とか出てくるのですが、なるべく穏便な方法で進めたいですね。
調査、方針立て
以下の記事を参考に実装します。
参考: 【Unity】スワイプとピンチでカメラをグリグリ動かせるライブラリを作った
機能とボタンの対応は以下を仮として想定します。
スマブラの鑑賞モードなんかを思い出しながら。。。
3Dモデルの中心を原点にするとします。
カメラは基本的に原点を中心とする球の表面上を動きます(回転、ズーム)。
これは三次元極座標で表現します。
この位置を起点として、移動により球表面上から逸脱します。
操作はこんなもんでしょうか。
- 移動(基準点からの位置x, y): 十字キー
- 回転(角度パラメータθ, φ): 左スティック
- ズーム(球の半径r): 右スティック前後
- リセット: △ボタン
- 終了: ×ボタン
回転、ズームでP点が変位し、移動によりさらにP点を原点としたxy座標面での移動が起こるという感じです。
とりあえずは、PCのキーボードでカメラ機能を実装、確認しておきます。
最終的に条件分岐をコントローラのボタンなりHololensでの操作に置き換えれば良いでしょう。
まずはまんま以下のサイト通りに実装します。これで回転とズームが実現できるはずです(ピンチによるズームは実機で検証する必要あり)。
ここで、TargetObjectは3Dモデルです。
参考: 【Unity】スワイプとピンチでカメラをグリグリ動かせるライブラリを作った
スワイプによるカメラの回転が想定と違いました。
3Dモデルが縦長なので中心がずれてたのが原因でした。
修正しました。
横にスワイプした時は良いのですが、縦にスワイプした時の挙動が想定と異なります。
ここら辺で極座標を用いてカメラを動かした方がすんなり行くのかなと思いました。
いくつかのサイトを練り歩いて情報収集します。
参考: 極座標(球面座標)のインスペクタを作ると VR音ゲー作るときに死ぬほど便利だった
ObservationCameraスクリプトではスワイプによりObservationCameraのRotationが変化するようです。
少しずつゴールが見えてきました。
カメラ回転
これまでに確認した先人のソースを参考に新しく作ってみます。
オブジェクトは以下の3つ。
- 原点: Origin
- (0, 0, 0)で固定。
- スクリプト: なし
- 基準点: ReferencePoint
- θ, φ, rの変化を担う。
- スクリプト: ReferencePoint
- カメラ: Camera
- x, yの変化を担う。
- スクリプト: Camera
注意点として上で引用した三次元極座標とy軸、z軸が入れ替わっている点です。
左右にスワイプした時はφ、上下にスワイプした時はθが変化します。
これに応じて基準点の位置が変わります。
さらに、向きは常に原点を向いているようにしなければいけません。
よって、スワイプではReferencePointのPositionとRotationを適切に動かします。
// スワイプによる基準点の移動 if (isMouseDown) { // マウスグリグリ動かすことでここが変化する Vector3 mousePos = Input.mousePosition; Vector3 distanceMousePos = (mousePos - baseMousePos); // スワイプの距離が極座標のθ,φに相当する float swipeX = distanceMousePos.x * swipeMoveSpeedX; float swipeY = distanceMousePos.y * swipeMoveSpeedY; theta += swipeY; phai += swipeX; // θ,φの変位を直交座標の変位に変換する float newX = r * Mathf.Sin(theta) * Mathf.Cos(phai); float newY = r * Mathf.Cos(theta); float newZ = r * Mathf.Sin(theta) * Mathf.Sin(phai); if (theta > 0 && theta < 180 * Mathf.Deg2Rad) { this.transform.position = new Vector3 (newX, newY, newZ); // 原点にむけてRotationを修正 transform.LookAt(new Vector3 (0, 0, 0)); } baseMousePos = mousePos; }
かなり手こずってしまいました。
終わってみれば実にシンプルなコードとなりましたが、そもそも極座標の復習からはじめ、
なぜか偏微分、全微分したり、調べているうちにヤコビアンとかラプラシアンとかこれまでスルーしてきたものをなぜか勉強し直すという紆余曲折を経ました。
数学大事。
次回
そんなこんなで数学のお勉強で躓いてしまったので、今回はカメラの回転のみの実装となりました。
次回はカメラの移動、ズームを実装します。
今回よりは簡単に行くかなと思います。
それが終わったら、DUALSHOCK3に対応、VR化です。
ちょっとずつ形になってきていて面白いです。
余談だけどWordPressにソース貼り付けるとタブが消えるのはなんでだろう。