はじめに
こんにちは!
引き続いて座標変換の話をします。今回は射影トランスフォーム行列の中を覗いていきます。
前回の関連記事
・DirectXとOpenGLのビュートランスフォーム行列の違い
・3DCGの座標系の紹介
・DirectXとOpenGLの回転行列、回転軸、回転方向
トランスフォーム行列の意味
DirectXとOpenGLのヘルパー関数
これまでと同様、行列作成用の関数が用意されています。
DirectX
matrix *D3DXMatrixPerspectiveFovLH( matrix *pOut, float fovy, float Aspect, float zn, float zf );
左手座標系のパースペクティブ射影行列を作成
matrix *D3DXMatrixPerspectiveFovRH( matrix *pOut, float fovy, float Aspect, float zn, float zf );
右手座標系のパースペクティブ射影行列を作成
OpenGL
void gluPerspective( double fovy, double aspect, double zNear, double zFar);
右手座標系のパースペクティブ射影行列を作成
ヘルパー関数を使用したときに作成される行列
DirectXは、マイクロソフトのページの行列。OpenGLは、OpenGLプログラミングメモの「gluPerspectiveを置き換える」の行列が元となります。関数の解説にある行列がDirectXとOpenGLとだいぶ違うため、DirectXのD3DXMatrixPerspectiveFovLH
をベースにして、ゲーム3D数学と完全ホワイトボックスなパースペクティブ射影変換行列を参考にしつつ、式変形したものを示します。
引数は次の通り
fovY 視体積の上下方向の視野角(0度から180度)
Aspect 近平面、遠平面のアスペクト比(Width / Height)
Far カメラから遠平面までの距離(ファークリッピング平面)
Near カメラから近平面までの距離(ニアークリッピング平面)
一度これらを次のようにまとめます。
zoomYの逆関数、Aspectの求め方を補足で書きました。
上記の変数を使用して、DirectXとOpenGLの各行列を書くと次のようになります。
右手系と左手系による行列の違い
D3DXMatrixPerspectiveFovLH
とD3DXMatrixPerspectiveFovRH
を比較すると分かりやすいのですが、行列の3行目の正負が反転しています。また、D3DXMatrixPerspectiveFovRH
と同じ右手系のOpenGLのgluPerspective
の3行目の正負が等しいです。正負の反転により、掛け算の最終結果のZ値の値を反転させているようです。
これまで右手座標系の計算では手前をZ値のプラスとして考えていましたが、この反転の計算により、奥をプラスに変換させます。つまり左手座標系へ変換させているわけです。
行列の式の意味を考える
一度、このプロジェクショントランスフォーム行列の式を実際に使用した場合を少し考えてみましょう。行列は、ベクトルに掛け算して使用します。
掛け算した結果は、クリッピング座標系・クリップ座標系と呼ばれます。そして、この座標系から、w値で割ったものが正規化デバイス座標系と呼ばれます。
上記の式からx値とy値については、簡単に何をしているのか想像がつくようになります。AとBはzoomXとzoomYですので、アスペクト比に関わる値を掛けて縦と横幅を調整することに繋がっています。z値に関しては、上記の式変形ではまだ分かりにくいので、さらに値を代入して数式を変形していきましょう。今回は、分かりやすくD3DXMatrixPerspectiveFovLH
の値を代入しました。
このようにすると、zの値が、NearからFarまでの値をとると、0~1の結果になることが分かるかと思います。さらにイメージしやすくなるように、1と10の値を代入してみましょう。
これをグラフに書くと次のようになります。
xが1から10をとると、f(x)が0から1までをとることが分かります。
射影行列を位置ベクトルに掛け算した結果のz値の値を、0未満と1以上の場合を表示させないと作ることで、NearからFarまでにある座標のデータを表示させるという作りが可能となります。なお空間のNearからFarまでを切り出すため、クリッピング座標系と呼ばれていると思われます。
ところで、数式から分かるように Near = Far と設定してしまうと、0割り算エラーが発生してしまいます。ある程度値を持ったうえで、 Far > Near となるような値を設定する必要があります。
DirectXとOpenGLの式の違いの理由
右手系の行列を作成するD3DXMatrixPerspectiveFovRH
と、右手系のOpenGLのgluPerspective
との式が微妙に異なることにお気づきでしょうか。本来同一になるはずなのに、Near と Far が関係するZ値の計算部分が少し違います。なぜ、このようになっているのでしょうか。先ほどと同じようにグラフを作ってみましょう。
さらに、NearとFarの値を適当に決めてグラフを描きます。
なんと、OpenGLでは、xが1から10をとると、f(x)が-1から1までをとります。ということで、OpenGLの射影変換後のz値は正負をとるという特徴があるようです。DirectXではz値が0から1なので、この違いが行列に現れていたようです。
おわりに
今回は、座標系の変換の中で難易度が高いプロジェクショントランスフォーム行列をとりあげました。
右手座標系だったものはこの変換により左手座標系になることが分かりました。
DirectXの右手座標系のD3DXMatrixPerspectiveFovRH
と、OpenGLの右手座標系のgluPerspective
は基本的に同じですが、DirectXのZ値は0~1までに正規化されるのに対して、OpenGLのZ値は-1~1までに正規化されるため、微妙に行列が違っているということが分かりました。
よくわからない式もグラフをかくと、分かりやすくてよいですね。
以上。おつかれさまでした!
コメント