とあるネタを作る際に、オブジェクトを追従させるようなカメラの動きが必要になりました。
そしてトラックボール的な機能も加えたかったので、(この辺りの学習をサボッていた
私にとって)これらの機能の実装は結構時間がかかってしまいました。。
理解が正しいかどうか不安ですが、忘れないように簡単なメモを残そうと思います。
トラッキング機能の基本仕様
レンダリング時のプログラムフロー
以下のようなフローにしました。
- オブジェクトの現在位置をカメラの基本位置に設定
※ 基本位置とは、一定距離離す前のカメラの位置です。 - オブジェクトの現在位置をカメラの注視点に設定
- カメラの位置を、オブジェクトから一定の距離だけ離す。
※ 予め決めておいた距離と方向ベクトルから移動分のベクトルを計算し、
カメラの基本位置に加算します。距離を変更できるようにするので、
移動ベクトルの計算はこのタイミングで行います。 - 求まったカメラ位置と注視点を利用し、視点座標系の変換を行う
- オブジェクトの描画
これを実装すると以下のような動きになります。
トラックボール機能
次に、マウスドラッグでグリグリと回転できるようにトラックボール機能を追加します。
トラックボール機能は、
- 画面上のマウス位置の変化から、視点座標系のX軸、Y軸に対するクォータニオンを計算
※ 画面に表示されているものはカメラからみたもの(視点座標系)なので、画面上のマウス位置の変化が
視点座標系のX軸、Y軸に対する回転となります。 - 計算したクォータニオンを合成
※ 合成することにより、視点座標系内での任意軸回転を表すクォータニオンとなります。 - 合成したクォータニオンから、そのクォータニオンが表現する回転軸及び回転する角度を求める
- 求めた回転軸及び回転する角度から回転行列を生成し、それを掛ける
という手順を踏むことで実現できます。
カメラとオブジェクトが動かない場合、基本となるX軸とY軸は固定(視点座標系のX軸とY軸が、
ワールド座標系のX軸(1.0, 0.0, 0.0)とY軸(0.0, 1.0, 0.0)に一致するような場合)でよいので、
そんなに難しくありません。
openFrameworksのサンプル"quaternionArcballExample"などを見ると非常にシンプルです。
ただ、今回のようにカメラとオブジェクトが動く(視点座標系が変わる)ような場合は少し工夫が必要です。
まず考えなければならないことは、視点座標系です。
現状では、画面上のマウス位置の変化に対応する視点座標系のX軸、Y軸が分かりません。
そこで視点座標系を求めます。
まずはZ軸からです。
Z軸はカメラが向いている方向、つまりカメラ位置と注視点を結ぶベクトルです。
Z軸 = カメラ位置 - 注視点です。
※ 正規化が必要です。
次にX軸です。
X軸は、ワールド座標系のY軸と先ほど求めたZ軸(が作る平面)に対して垂直となるベクトルです。
X軸 = (0.0, 1.0, 0.0) × Z軸です。
※ 正規化が必要です。
最後にY軸です。
Y軸は、先ほど求めたZ軸とX軸(が作る平面)に対して垂直となるベクトルです。
X軸と同様に、Z軸とX軸の外積がY軸になります。
Y軸 = Z軸 × X軸です。
※ 正規化が必要です。
※ 図は適当なイメージです。X軸、Z軸がマイナス方向になってたりします。
レンダリング時のプログラムフロー
最後に、上記の視点座標計算を組み込んだフローをまとめます。
- オブジェクトの現在位置をカメラの基本位置に設定
- オブジェクトの現在位置をカメラの注視点に設定
- 1,2で設定したカメラの基本位置と注視点に、前フレームで更新したマウスドラッグによる回転(トラックボール機能)を適用
※ カメラ位置にマウスドラッグによる回転を加えるのは、当然ながら視点座標系への変換(lookAt())より
前に行う必要があります。 - カメラの位置を、オブジェクトから一定の距離だけ離す
※ カメラ位置は、マウスドラッグによる回転が考慮されたものになっています。 - 求まったカメラ位置と注視点を利用し、視点座標系の変換を行う
- オブジェクトの描画
※ 描画するオブジェクトに対しても、マウスドラッグによる回転を適用します。 - 次のフレームに備えてて、視点座標系の座標軸を更新
![mouse.gif](https://qiita-image-store.s3.amazonaws.com/0/42772/22851859-1a10-289d-0fa8-09f981b0457f.gif)
サンプルとして作成したソースはGithubにアップしています。 プログラムのベースはopenFrameworksのorientationExampleです。 [trackerSample](https://github.com/tkt182/trackerSample)