Direct3Dの射影変換行列。

多くのDirect3Dプログラマは、射影変換には↓の関数を使っているんじゃなかろうか。


D3DXMatrixPerspectiveFovLH(
D3DXMATRIX* pOut,
float fovY, // Y方向の視野角
float aspect, // 画面のアスペクト比
float zn, // ビューボリュームの近平面までの距離
float zf // ビューボリュームの遠平面までの距離
);
(左手座標系の)透視投影変換行列を作る関数。
zn,zfは、ニアクリップ・ファークリップなんて言ったりもしますな。
コレの良い所は、視野角指定で射影変換行列を作れるので、
ズームイン・アウトが視野角調整でカンタンに出来る事。
ほとんどの場合はこの関数で事足りるかなと思う。


なんだけど、敢えて違うのを使ってみる。


D3DXMatrixPerspectiveLH(
D3DXMATRIX* pOut,
float w, // ビューボリュームの横幅
float h, // ビューボリュームの縦幅
float zn, // ビューボリュームの近平面までの距離
float zf // ビューボリュームの遠平面までの距離
);
特に使う必要が無かったので見ぬ振りをしていたこの関数。
こちらも同じ透視投影変換行列を作るモノなんだけど、
自分はかなり罠にハマってしまい・・・。


と言うのも、FovLHを使う際はほとんどのケースで


D3DXMatrixPerspectiveFovLH(&mProj,
D3DXToRadian(θ),
SCREEN_W/SCREEN_H,
zn, zf);
という風に、画面サイズを直接使ってアスペクト比を指定してたせいで、
Fovなしの方にも当然

D3DXMatrixPerspectiveLH(&mProj,
SCREEN_W,
SCREEN_H,
zn, zf);
こうするもんだと思い込んでいて・・・('A`)
やってみればわかるけど・・・被写体がすっごい小さく写る。


wとhに指定するのは、「ビューボリュームの近平面の」横幅縦幅。
ビューボリュームってなんよ、と思って調べてみたら、
透視投影する範囲にあたる「射影空間」の事で。
引数に指定するのは、それの近平面のサイズの事だったんですねえ。
そりゃーSCREEN_W/Hの、640とか480とかみたいな値を指定していれば
被写体も小さくなるわと。
要は視野角がとんでもなく広い状態になってたんですな。
こんなんで3、4時間近くも悩んでしまったorz
無学っておそろしい。


でまぁ、正しくは以下の通り。


float nearH = zn * tan(fovY/2.0f) * 2.0f;
// 近平面の縦幅 = zn * tan(Y方向の視野角/2) * 2
float nearW = nearH * SCREEN_W/SCREEN_H;
// 近平面の横幅 = 近平面の縦幅 * アスペクト比
D3DXMatrixPerspectiveLH(&mProj,
nearW,
nearH,
zn, zf);
近平面の縦幅の計算式がなんでそうなるかは、ちょっと図を書けばわかります。
カンタンな三角比。


さて、なんでわざわざこっちの関数を使おうと思ったのか。
というのは、そもそもこの関数が、↓の関数と同じ引数で、
↓の関数で射影をした時に、表示が上手く行かず、なんでだ?となったからでして。


D3DXMatrixOrthoLH(
D3DXMATRIX* pOut,
float w, // ビューボリュームの横幅
float h, // ビューボリュームの縦幅
float zn, // ビューボリュームの近平面までの距離
float zf // ビューボリュームの遠平面までの距離
);
何かというと、「正射影(平行投影)」変換行列を作る関数。
透視投影とは違って奥行き(つまりz座標)情報を無視した感じに射影するやり方。
奥にあるポリゴンでも、小さく描かれません。
むしろ透視投影の時よりも俄然大きい感じに写ります。
そう、その奥にあっても小さく描かれないという機能を使いたかったんです!


どう使いたかったのかは、また次回の記事で。
普段正射影するプログラマはあまり居ないと思うので、
一度やってみると面白いかも。