Platform SDK: DirectX |
ほかのすべてのトランスフォームと同様、一連のトランスフォーム行列を、個々の効果をすべて含む単一の行列に連結することでワールド トランスフォームを作成する。簡単な例では、あるモデルがワールド原点にあり、そのローカル座標軸がワールド空間と同じ方向に定義されている場合、ワールド行列は単位行列である。さらに一般的には、ワールド行列はワールド空間への平行移動を組み合わせたものであり、必要に応じてモデルを 1 回または何度も回転することができる。
次の例は、C++ で記述された架空の 3D モデル クラスに関するものである。ここでは、D3dutil.cpp および D3dmath.cpp ファイル (DirectX SDK に付属) のヘルパー関数を使用して、モデルを方向付ける回転を 3 回行い、さらにワールド空間での位置座標を基準にそのモデルを再配置する平行移動を行うワールド行列を作成する。
/* * この例では、 * 以下の変数が有効で、初期化されているとする。 * * m_vPos 変数は、このモデルのワールド座標での位置座標を格納する * D3DVECTOR である。 * * m_fPitch、m_fYaw、および m_fRoll 変数は、 * 傾斜角、偏揺れ角、および回転角 (ラジアン) で表すモデルの方向を格納する * D3DVALUE である。 */ D3DMATRIX C3DModel::MakeWorldMatrix(void) { D3DMATRIX matWorld, // 作成するワールド行列。 matTemp, // 回転用の一時行列。 matRot; // 最終的な回転行列 (matWorld に適用する)。 // 行列連結に関する "左から右" ルールを使用して、 // 回転を適用する前に // 平行移動をオブジェクトのワールド位置座標に適用する。 D3DUtil_SetTranslateMatrix(matWorld, m_vPos); D3DUtil_SetIdentityMatrix(matRot); // // 次に、方向付け変数を // ワールド行列に適用する。 // if(m_fPitch || m_fYaw || m_fRoll) { // 回転行列を作成して結合する。 D3DUtil_SetRotateXMatrix(matTemp, m_fPitch); // 傾斜 D3DMath_MatrixMultiply(matRot,matRot,matTemp); D3DUtil_SetRotateYMatrix(matTemp, m_fYaw); // 偏揺れ D3DMath_MatrixMultiply(matRot,matRot,matTemp); D3DUtil_SetRotateZMatrix(matTemp, m_fRoll); // 回転 D3DMath_MatrixMultiply(matRot,matRot,matTemp); // 回転行列を適用してワールド行列を完成する。 D3DMath_MatrixMultiply(matWorld, matRot, matWorld); } return (matWorld); }
ワールド トランスフォーム行列が準備できたら、この行列を設定するために IDirect3DDevice7::SetTransform メソッドを呼び出して、第 1 パラメータに D3DTRANSFORMSTATE_WORLD フラグを指定する。詳細については、「トランスフォームの設定」を参照すること。
次の例は、架空の 3D モデル クラスに関するものである。ここでは、DirectX7 クラスの関数を使用して、モデルを方向付ける回転を 3 回行い、さらにワールド空間での位置座標を基準にそのモデルを再配置する平行移動を行うワールド行列を作成する。
' ' この例では、 ' 以下の変数が有効で、初期化されているとする。 ' ' g_dx 変数には、DirectX7 オブジェクトへの有効な参照が格納される。 ' ' m_vPos 変数は、このモデルのワールド座標における位置座標を格納する ' D3DVECTOR である。 ' ' m_fPitch、m_fYaw、および m_fRoll は、 ' 傾斜角、偏揺れ角、および回転角 (ラジアン) で表すモデルの方向を格納する ' Single 型の変数である。 ' Public Function MakeWorldMatrix() As D3DMATRIX Dim matWorld As D3DMATRIX ' 結果として返すワールド行列。 Dim matTemp As D3DMATRIX ' 各回転を格納するための一時行列。 Dim matRot As D3DMATRIX ' 回転を表す一時行列。 ' matWorld を修正して平行移動行列を作成する。 Call g_dx.IdentityMatrix(matWorld) matWorld.rc41 = m_vPos.x matWorld.rc42 = m_vPos.y matWorld.rc43 = m_vPos.z Call g_dx.IdentityMatrix(matRot) ' 回転行列を設定する。 ' ' 行列連結の "左から右" ルールを使用して、 ' 回転を適用する前に ' 平行移動をオブジェクトのワールド位置座標に適用する。 ' ' 回転行列を作成して結合する。 If (m_sPitch <> 0) Or (m_sYaw <> 0) Or (m_sRoll <> 0) Then ' 最初にX軸回転、 Call g_dx.RotateXMatrix(matTemp, m_sPitch) Call g_dx.MatrixMultiply(matRot, matRot, matTemp) ' 次にY軸回転、 Call g_dx.RotateYMatrix(matTemp, m_sYaw) Call g_dx.MatrixMultiply(matRot, matRot, matTemp) ' 最後にZ軸回転。 Call g_dx.RotateZMatrix(matTemp, m_sRoll) Call g_dx.MatrixMultiply(matRot, matRot, matTemp) ' matWorld に既に存在する平行移動行列に回転行列を適用して、 ' ワールド行列を完成する。 Call g_dx.MatrixMultiply(matWorld, matRot, matWorld) End If MakeWorldMatrix = matWorld End Function
ワールド トランスフォーム行列が準備できたら、この行列を設定するために Direct3DDevice7::SetTransform メソッドを呼び出して、第 1 パラメータに D3DTRANSFORMSTATE_WORLD フラグを指定する。詳細については、「トランスフォームの設定」を参照すること。
パフォーマンスの最適化 Direct3D では、設定されたワールド行列およびビュー行列を使用して、いくつかの内部データ構造を構築する。新しいワールド行列またはビュー行列を設定するたびに、関係する内部構造が再計算される。これらの行列をフレームごとに数千回も設定するなど頻繁に設定すると、多大な計算負荷が発生する。必要な計算を最小限に抑えるには、ワールド行列として設定する "ワールドビュー" 行列にワールド行列およびビュー行列を連結し、次にビュー行列を単位行列に設定する。ワールド行列およびビュー行列の各キャッシュ コピーは保持しておくこと。必要に応じてワールド行列を修正、連結、およびリセットできる (Direct3D のサンプルでは、簡潔であることを優先して、この最適化はほとんど用いていない)。