Note
列ベクトル方式で説明
このページでは、 単純な形からglFrustnumの行列を合成していこうと思う。
ビュー座標(まだ右手系)で、z=dの平面を投影面とすると 投影面の向こう(z<d)にある点p(x, y, z)は、点p’(x’, y’, d)に投影される。 このとき、三角形の相似を利用してx, yの投影平面上の位置を計算できる。
これは元の座標をdでスケーリングしてからzでわることで実現できる。 z, wにも同じ計算を適用して
ここで、w値に除算する値をいれておけばいいじゃないということになり
これを正規化(w値が1になるように割り算する。遠近除算)すると
となり具合がいい。
これを行列で得たい。
wにz/dが入るようにするには
とできる。
ここで簡単のためdを-1に決め打ちすることにする。
これで座標{x, y, z, 1}に乗算してから正規化すると遠近感(遠くが小さくなる)がつくようになった。
今の行列だと正規化するとZが一律-1になり奥行きが失われてしまう。 ここで(x, y, near)を変換するとzが-1になるように(x, y, far)を変換するとzが+1になるようにする。 Z軸のみの問題なので関係部分A(スケール), B(移動)とおいておく。
2式を解いて
次にBを求める
Aを代入
A、Bをnearとfarの式で置き換えることができた。
ここまでで適用してから正規化すると遠近感がついてZが-1~+1になる行列ができた。 Zの+方向を反転している(遠い方が+)ためこの行列を適用した座標は左手系になるがあまり気にすることもない?
(移動は省略) x, yともに[-1, +1]におさまるようにスケーリングする。 実際にはz=nearの地点で[-near, +near]になるようにスケーリングする。 要するに、z=nearのときにx=2near(right-left)とy=2near(top-bottom)となるようにスケーリング行列を追加するだけ。
ここで注意を要するのは、near値と(right-left)値の大きさの関係で左右の視野角、near値と(top-bottom)値の大きさの関係で上下の視野角を指定することになること。これがわかりにくいために[[gluPerspective:http:gluperspective.html]]関数がある。 fovyとnear値によりtop-bottomの大きさを計算し、さらにaspect値からright-leftの大きさを得るのがgluPerspective関数。
ここで最後の関門。 glFrustumの定義と比べると第3行第4列の符号が合わない。 何故かというと引数のnear, farは視点からの距離をあらわしていて 視点座標では負の値になるところを正の値をとっているからです。 そこでnear=-near’、far=-far’と置き換えます。
これでright+left=0かつtop+bottom=0の時限定だけど、glFrustumの式になった。 左右と上下が非対称の場合は、x, yのスケーリング時に移動要素が加わることになる。
http://angra.blog31.fc2.com/blog-entry-114.html
今回のはこちらに書いてあるもの(DirectX仕様の行優先)を ベースにOpenGL風味(列優先)に解読したものであります。