モデルビュー行列からカメラのパラメータを計算する.
modelview matrix は model に作用する matrix も含んでいるので,シーンがスケール,移動,回転されていたりするとその効果が含まれている.これをmatrixの情報のみを使って分離する方法はない.そこで,ここではシーンに対するtransformation matrix は Identity matrix, つまり全てはカメラの効果としてカメラのパラメータを抽出する.もし,シーンに対する効果が分離されているようなレンダラと OpenGL レンダラを併用する場合には,この transformationmatrix を undo する必要がある.modelview matrix は以下のような成分になっている.この成分の詳しいことに関しては私の以前の blog(http://shitohichiumaya.blogspot.de/2011/01/what-matrix-glulookat-generates-1.html)を参照のこと.
\begin{eqnarray*}
\left[
\begin{array}{cccc}
x_x & y_x & z_x & 0 \\
x_y & y_y & z_y & 0 \\
x_z & y_z & z_z & 0 \\
-(\vec{x} \cdot \vec{e}) &
-(\vec{y} \cdot \vec{e}) &
-(\vec{z} \cdot \vec{e}) & 1 \\
\end{array}
\right]
\end{eqnarray*}
4行を \(a,b,c\)で置きかえるとこの行列は以下のように書ける.
\begin{eqnarray*}
\left[
\begin{array}{cccc}
x_x & y_x & z_x & 0 \\
x_y & y_y & z_y & 0 \\
x_z & y_z & z_z & 0 \\
a & b & c & 1 \\
\end{array}
\right]
\end{eqnarray*}
この行列には既にカメラの basis があるので,問題は視点の位置である.これは4行の1-3列だけを取り出して行列表示する.(ここでは行列とベクトルをカラムベクトル表示 \(\vec{x}, \vec{y}, \vec{z}, \vec{e}\)している.)
\begin{eqnarray*}
\left[
\begin{array}{ccc}
& & \\
\vec{x} & \vec{y} & \vec{z}\\
& & \\
\end{array}
\right]
\left[
\begin{array}{c}
\\
\vec{e} \\
\\
\end{array}
\right]
& = &
\left[
\begin{array}{c}
a \\
b \\
c \\
\end{array}
\right]
\end{eqnarray*}
であるから,
\begin{eqnarray*}
\left[
\begin{array}{c}
\\
\vec{e} \\
\\
\end{array}
\right]
& = &
\left[
\begin{array}{ccc}
& & \\
\vec{x} & \vec{y} & \vec{z}\\
& & \\
\end{array}
\right]^{-1}
\left[
\begin{array}{c}
a \\
b \\
c \\
\end{array}
\right]
\end{eqnarray*}
が視点の位置となる.従ってプログラムの実装例は以下のようになる(C++).
/// get camera parameters from /// the OpenGL modelview matrix /// /// \param[out] eyepos eye position /// \param[out] viewdir viewing directio /// \param[out] updir up direction vector void gl_get_camera_parameters_from_modelview_matrix( Vector3d & eyepos, Vector3d & viewdir, Vector3d & updir) { GLdouble mat[16]; glGetDoublev(GL_MODELVIEW_MATRIX, mat); Vector3d xdir(0.0, 0.0, 0.0); Vector3d ydir(0.0, 0.0, 0.0); Vector3d zdir(0.0, 0.0, 0.0); xdir[0] = mat[0]; ydir[0] = mat[1]; zdir[0] = mat[2]; xdir[1] = mat[4]; ydir[1] = mat[5]; zdir[1] = mat[6]; xdir[2] = mat[8]; ydir[2] = mat[9]; zdir[2] = mat[10]; // This is a, b, c components. Vector3d bvec(-mat[12], -mat[13], -mat[14]); Matrix33d basis_mat(xdir[0], xdir[1], xdir[2], ydir[0], ydir[1], ydir[2], zdir[0], zdir[1], zdir[2]); // This matrix should not be singular. // invert() gives matrix inverse. basis_mat.invert(); eyepos = basis_mat * bvec; viewdir = -zdir; updir = ydir; } ここでも簡単のためにエラーチェックをしていないが,個人的にはいくつかのassertion はしておきたい.
Comments
Post a Comment