Platform SDK: DirectX |
ここでは、C および C++ でのアプリケーション開発について説明する。Visual Basic については、「Direct3D 直接モード Visual Basic チュートリアル」を参照すること。
シーンはほぼ完成しているが、立方体の頂点を手動で回転、平行移動、およびスケーリングする処理が残っている。まず、D3DTLVERTEX 構造体の配列 g_pvCube に立方体の未トランスフォーム データを格納する。最初の 3 つのパラメータは、スクリーン座標の各頂点の未トランスフォームの位置座標を表している。
g_pvCube[0] = D3DTLVERTEX( D3DVECTOR(-1,-1,-1 ), 0, 0xffffffff, 0, 0, 0 ); g_pvCube[1] = D3DTLVERTEX( D3DVECTOR( 1,-1,-1 ), 0, 0xff00ffff, 0, 0, 0 ); g_pvCube[2] = D3DTLVERTEX( D3DVECTOR(-1, 1,-1 ), 0, 0xffff00ff, 0, 0, 0 ); g_pvCube[3] = D3DTLVERTEX( D3DVECTOR( 1, 1,-1 ), 0, 0xff0000ff, 0, 0, 0 ); g_pvCube[4] = D3DTLVERTEX( D3DVECTOR(-1,-1, 1 ), 0, 0xffffff00, 0, 0, 0 ); g_pvCube[5] = D3DTLVERTEX( D3DVECTOR( 1,-1, 1 ), 0, 0xff00ff00, 0, 0, 0 ); g_pvCube[6] = D3DTLVERTEX( D3DVECTOR(-1, 1, 1 ), 0, 0xffff0000, 0, 0, 0 ); g_pvCube[7] = D3DTLVERTEX( D3DVECTOR( 1, 1, 1 ), 0, 0xff000000, 0, 0, 0 );
次に、プログラマ定義関数 TransformVertices を呼び出して、立方体の 8 つの頂点を手動でトランスフォームする。
TransformVertices( pd3dDevice, g_pvCube, 8 );
ただし、3D トランスフォームを実装する前に、ビューポートの高さと幅を取得する必要がある。この情報は、レンダリング ウィンドウに合わせてトランスフォーム済み頂点をスケーリングするために使用される。
HRESULT TransformVertices( LPDIRECT3DDEVICE7 pd3dDevice, D3DTLVERTEX* pvVertices, DWORD dwNumVertices ) { // ビューポートの幅と高さを取得する。この情報は、レンダリング ウィンドウに合わせて // トランスフォーム済み頂点をスケーリングするのに必要である。 D3DVIEWPORT7 vp; pd3dDevice->GetViewport( &vp ); DWORD dwClipWidth = vp.dwWidth/2; DWORD dwClipHeight = vp.dwHeight/2;
Direct3D は行列を使用してトランスフォームを行う。3D トランスフォームを実行するには、現在の行列セットの値を取得する必要がある。このためには、レンダリング デバイスで IDirect3DDevice7::GetTransform を呼び出す。
D3DMATRIX matWorld, matView, matProj; pd3dDevice->GetTransform( D3DTRANSFORMSTATE_WORLD, &matWorld ); pd3dDevice->GetTransform( D3DTRANSFORMSTATE_VIEW, &matView ); pd3dDevice->GetTransform( D3DTRANSFORMSTATE_PROJECTION, &matProj );
行列連結には行列乗算を使用する。
D3DMATRIX matTemp = matWorld * matView; D3DMATRIX matSet = matTemp * matProj;
上記のコードでは、トランスフォームの連結値が合成行列 matSet, から算出される。連結の際には、処理を行う順序で行列が乗算されていることを確認する。
行列連結の詳細については、「行列連結」を参照すること。
次に、現在の行列セットを使用して各頂点をトランスフォームする。
for( DWORD i=0; i<dwNumVertices; i++ ) { // 未トランスフォームの頂点の位置を取得する。 FLOAT x = pvVertices[i].sx; FLOAT y = pvVertices[i].sy; FLOAT z = pvVertices[i].sz; // 現在の行列セットでトランスフォームする。 FLOAT xp = matSet._11*x + matSet._21*y + matSet._31*z + matSet._41; FLOAT yp = matSet._12*x + matSet._22*y + matSet._32*z + matSet._42; FLOAT zp = matSet._13*x + matSet._23*y + matSet._33*z + matSet._43; FLOAT wp = matSet._14*x + matSet._24*y + matSet._34*z + matSet._44;
最後に、スクリーン座標に合わせて頂点をスケーリングする。次のコードでは、まず各座標が wp 値で除算されて、座標が 3D 空間から 2D デバイス座標に平面化される。その次に、x および y 成分がデバイス座標からスクリーン座標に変換される。
pvVertices[i].sx = ( 1.0f + (xp/wp) ) * dwClipWidth; pvVertices[i].sy = ( 1.0f - (yp/wp) ) * dwClipHeight; pvVertices[i].sz = zp / wp; pvVertices[i].rhw = wp; }
3D トランスフォームの詳細については、「3D トランスフォーム」を参照すること。
注 : ビューポートでデバイス座標がとる範囲は、-1 から +1 の間の値である。また、sz 座標が Z バッファで使用される。
これで立方体の 8 つの頂点をトランスフォームできた。次は、完成したシーンのフレームをレンダリングする。これについては、「ステップ 2.4 : シーンをレンダリングする」で説明する。