ジオメトリパイプライン

2010.5.6 8:25 PM

ジオメトリパイプラインの超私的メモ。毎度の超私的メモでスミマセン。
このサイトの記事を参考にさせていただきました。ありがとうございました。

ジオメトリパイプラインとは3Dオブジェクトを画面に描画するための座標変換のこと。

変換の流れは以下。

1 . ローカル座標で3Dオブジェクトを組み立てる。
2 . ワールド座標変換
3 . ビュー座標変換(またはカメラ座標変換ともいう)
4 . プロジェクション座標変換(または射影変換ともいう)
5 . スクリーン座標変換(またはビューポート座標変換ともいう)

1 . ローカル座標で3Dオブジェクトを組み立てる。
まず、ローカル座標で3Dオブジェクトを組み立てる。
2 . ワールド座標変換
ワールド変換行列でローカル座標からワールド座標に変換する。
平行移動行列、回転行列、スケーリング行列を使う。
※平行移動行列は演算順序によって、結果が変わるので、以下の順序で演算を行う。

求めたい行列 = スケーリング行列 * 回転行列 * 平行移動行列

※ちなみにアフィン変換とは、変換によっても図形の形が変わらない変換のことをいう。

3 . ビュー座標変換(カメラ座標変換)
カメラの位置を定義することによって、物体をワールド座標からカメラの位置・方向を表す座標系への変換を行う。
カメラの位置を定義するには、視点(カメラ)の位置ベクトル、注視点の位置ベクトル、およびカメラの上方向を表すベクトルの3つのベクトルによって定義される。

ビュー座標変換の手順としては、まずカメラの座標を定義された位置から原点まで移動する。
そして、その負の移動座標を全てのオブジェクトに適用する。

カメラを移動したら、軸の調整をする。カメラの軸は以下のようにして求める。

At = 注視点の位置ベクトル
Eye = 視点(カメラ)の位置ベクトル
Up = カメラの上方向を表すベクトル

//z軸にカメラをあわせる。視線方向の単位ベクトルを求める。
zaxis = normal(At – Eye)

//x軸にカメラを合わせる。カメラの向いてる方向とカメラの上方向の法線がx軸となる。 
xaxis = normal(cross(Up, zaxis)) 

//y軸にカメラを合わせる。カメラの向いてる方向とx軸の方向の法線がy軸となる。
yaxis = cross(zaxis, xaxis)

軸を求めたら、それに合わせて全てのオブジェクトを回転させる。
以上をふまえるとビュー座標変換行列は以下になる。

ビュー座標変換行列 = [
 xaxis.x  yaxis.x  zaxis.x  0
 xaxis.y  yaxis.y  zaxis.y  0
 xaxis.z  yaxis.z  zaxis.z  0
 -dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  1
]

※normal(a) = aの単位ベクトルを求める
※cross(a,b) = aとbの外積を求める
※dot(a,b) = aとbの内積を求める

4 . プロジェクション座標変換(射影変換)
3Dの情報であるビュー座標を、投影により2Dの座標に変換する。
それと、カメラの設定(主にズームなどの機能)をする。

プロジェクション座標変換行列には二通りある。平行投影と透視投影。
平行投影は視点の手前にあるものと視点の奥にあるものの大きさが同じ。
透視投影は実際にカメラで覗いてるように物体が視点に近いと大きくなり、遠いと小さくなる。

平行投影に関しては今回はスルーして、透視投影について。

まず視錘台を定義する。
定義する要素は、近クリップ平面、遠クリップ平面、アスペクト比、視野角。
近平面と遠平面の間が実際に画面に表示される部分。つまり視錘台とは見える領域を表す。
視野角はカメラの角度。ズームインやズームアウトといったことができる。
アスペクト比は横と縦の比率を決める。

視野角に関して。
視野角が広いほど奥行き感が増加する。またズームアウトする感じになり、周りの映る範囲が広がる。
カメラを回転させるとパースがきき過ぎて歪んでいる感じがする。
逆に視野角が狭いほど奥行き感が減少する。
ズームインする感じになり周りの映る範囲が狭くなる。
45 ~ 60度くらいが3Dゲームではよく使われているらしい。

先にも書いたが、視錘台の外にあるオブジェクトは見えない。つまり描画処理を行う必要はない。
そこでオブジェクトを内包する単純な形状(球など)を考え、それが視錘台の内部にあるかを判定し、
内部に無ければ描画処理を行わないようにする。これを視野カリングとか視錘台カリングと呼ぶ。

プロジェクション変換行列を適用した結果は、
X座標が-1.0 から1.0、
Y座標が-1.0 から1.0、
Z軸が0.0 から 1.0の間の値になる。
ちなみに、近クリップ平面がz=0、遠クリップ平面がz=1。

んで、プロジェクション変換行列を生成する計算式。

θ = Y方向の視野角
a = アスペクト比
n = 近クリップ平面までの距離
f = 遠クリップ平面までの距離

sy = cot(θ/2)
sx = sy / a
sz = f / (f-n)

プロジェクション変換行列 = [
 sx, 0, 0, 0,
 0, sy, 0, 0,
 0, 0, sz, 0,
 0, 0, -sz*n, 0
]

となる。
んー、むずい。

5 . スクリーン座標変換(ビューポート座標変換)
スクリーン座標は左上隅を原点とし、Flashの場合なら、右方向を+X、下方向を+Yとする。

w = スクリーンの横幅/2
h = スクリーンの縦幅/2

スクリーン座標行列 = [
 1, 0, 0, 0,
 0, 1, 0, 0,
 0, 0, 1, 0,
 w, h, 0, 1
]

※Flashで実装する場合はわざわざスクリーン座標変換するよりも、3D空間を内包したDisplayObjectをまるっとステージの中央に配置した方が処理的に軽いかも。

ちょっと間違ってるところありそうだけど以上。

タグ: , ,

Leave a Reply