Platform SDK: DirectX |
この SDK 付属の D3dutil.cpp ソース ファイルの D3DUtil_SetViewMatrix ヘルパー関数は、この関数に渡されるカメラ位置座標と注視点に基づいてビュー行列を作成する。この関数は、Magnitude、CrossProduct、および DotProduct D3D_OVERLOADS ヘルパー関数を使用する。
HRESULT D3DUtil_SetViewMatrix( D3DMATRIX& mat, D3DVECTOR& vFrom, D3DVECTOR& vAt, D3DVECTOR& vWorldUp ) { // 奥行きを示す Z 軸の基底ベクトルを取得する。これは、 // 注視点に対する視点とは異なる。 D3DVECTOR vView = vAt - vFrom; FLOAT fLength = Magnitude( vView ); if( fLength < 1e-6f ) return E_INVALIDARG; // z 軸の基底ベクトルを正規化する。 vView /= fLength; // 内積を取得して、上方向ベクトルに対する、Z 軸の基底ベクトルの // 射影を計算する。この射影は y 軸の基底ベクトルである。 FLOAT fDotProduct = DotProduct( vWorldUp, vView ); D3DVECTOR vUp = vWorldUp - fDotProduct * vView; // 不正な上方向ベクトルを入力したために // ベクトルがゼロに近くなった場合は、ベクトルをデフォルト値にする。 if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) { vUp = D3DVECTOR( 0.0f, 1.0f, 0.0f ) - vView.y * vView; // ベクトルがなおゼロに近ければ、別の軸を利用する。 if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) { vUp = D3DVECTOR( 0.0f, 0.0f, 1.0f ) - vView.z * vView; if( 1e-6f > ( fLength = Magnitude( vUp ) ) ) return E_INVALIDARG; } } // y 軸の基底ベクトルを正規化する。 vUp /= fLength; // x 軸の基底ベクトルは、y 軸および z 軸の基底ベクトルの // 外積として簡単に求められる。 D3DVECTOR vRight = CrossProduct( vUp, vView ); // 行列の作成を開始する。先頭の 3 行には、 // ビューを注視点で回転するための基底ベクトルを格納する。 D3DUtil_SetIdentityMatrix( mat ); mat._11 = vRight.x; mat._12 = vUp.x; mat._13 = vView.x; mat._21 = vRight.y; mat._22 = vUp.y; mat._23 = vView.y; mat._31 = vRight.z; mat._32 = vUp.z; mat._33 = vView.z; // 移動値を実行する (回転はまだ視点にある)。 mat._41 = - DotProduct( vFrom, vRight ); mat._42 = - DotProduct( vFrom, vUp ); mat._43 = - DotProduct( vFrom, vView ); return S_OK; }
ワールド トランスフォームの場合と同様、IDirect3DDevice7::SetTransform メソッドを呼び出してビュー トランスフォームを設定し、第 1 パラメータに D3DTRANSFORMSTATE_VIEW フラグを指定する。詳細については、「トランスフォームの設定」を参照すること。
Visual Basic アプリケーションでは、DirectX7.ViewMatrix メソッドを使用して、カメラ位置座標、注視点、"上方向" ベクトル (通常は 0,1,0)、およびラジアン単位で指定する回転値に基づいてビュー行列を作成する。
次の Visual Basic コードは、ViewMatrix メソッドの使用方法を示す。
' この例では、g_dx 変数にグローバル DirectX7 オブジェクトへの ' 有効な参照が格納されているとする。 Dim matView As D3DMATRIX Dim vFrom As D3DVECTOR, _ vTo As D3DVECTOR, _ vUp As D3DVECTOR vFrom.x = 0:vFrom.y = 0:vFrom.z = -15 vTo.x = 0:vTo.y = 0:vTo.z = 0 vUp.x = 0:vUp.y = 1:vUp.z = 0 ' 行列を初期化して単位行列にする。 g_dx.IdentityMatrix matView ' 0,0,-15 にあるカメラでビュー行列を作成する。 ' これは、ワールド原点を指し、vFrom->vTo ベクトルを中心とした回転を行わない。 Call g_dx.ViewMatrix(matView, vFrom, vTo, vUp, 0)
ワールド トランスフォームの場合と同様、Direct3DDevice7::SetTransform メソッドを呼び出してビュー トランスフォームを設定し、第 1 パラメータに D3DTRANSFORMSTATE_VIEW フラグを指定する。詳細については、「トランスフォームの設定」を参照すること。
パフォーマンスの最適化 Direct3D では、設定されたワールド行列およびビュー行列を使用して、いくつかの内部データ構造を構築する。新しいワールド行列またはビュー行列を設定するたびに、関係する内部構造が再計算される。これらの行列をフレームごとに 2 万回も設定するなど頻繁に設定すると、多大な計算負荷が発生する。必要な計算を最小限に抑えるには、ワールド行列として設定する "ワールドビュー" 行列にワールド行列およびビュー行列を連結し、次にビュー行列を単位行列に設定する。ワールド行列およびビュー行列の各キャッシュ コピーは保持しておくこと。必要に応じてワールド行列を修正、連結、およびリセットできる (Direct3D のサンプルでは、簡潔であることを優先して、この最適化はほとんど用いていない)。