キューブ環境サーフェスの作成 (Direct3D 9)
キューブ環境マップ テクスチャーを作成するには、IDirect3DDevice9::CreateCubeTexture メソッドを呼び出します。キューブ環境マップ テクスチャーは矩形でなければならず、その大きさは 2 の累乗です。
次のコード例は、C++ アプリケーションで単純なキューブ環境マップを作成する方法を示しています。
// Init m_d3dDevice to point to an IDirect3DDevice9 interface LPDIRECT3DCUBETEXTURE9 m_pCubeMap; m_d3dDevice->CreateCubeTexture(256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R8G8B8, D3DPOOL_DEFAULT, &m_pCubeMap);
キューブ環境マップ面へのアクセス
IDirect3DCubeTexture9::GetCubeMapSurface メソッドを使ってキューブ環境マップの面から面に移動できます。
次のコード例は、IDirect3DCubeTexture9::GetCubeMapSurface を使って、正方向の y 面 (面 2) に使用するキューブ マップ サーフェスを取得します。
// Init m_pCubeMap to point to an IDirect3DCubeTexture9 interface LPDIRECT3DSURFACE9 pFace2; m_pCubeMap->GetCubeMapSurface(D3DCUBEMAP_FACE_POSITIVE_Y, 0, &pFace2);
IDirect3DCubeTexture9::GetCubeMapSurface が受け取る第 1 パラメーターは、このメソッドで取得する必要があるアタッチされたサーフェスを記述する D3DCUBEMAP_FACES 列挙値です。第 2 パラメーターは、取得するミップマップ化キューブ テクスチャーのレベルを Direct3D に指示します。第 3 パラメーターは、返されるキューブ テクスチャー サーフェスを表す IDirect3DSurface9 インターフェイスのアドレスです。この場合、このキューブ マップはミップマップ化されていないので、0 が使われます。
注
このメソッドを呼び出した後は、IDirect3DSurface9 インターフェイスの内部リファレンス カウントが増えます。このサーフェスの使用後は、必ずこの IDirect3DSurface9 インターフェイスに対して IUnknown メソッドを呼び出す必要があります。呼び出さないと、メモリー リークが発生します。
キューブ環境マップへのレンダリング
キューブ マップの各面へは、その他のテクスチャーやサーフェス オブジェクトと同じように画像をコピーすることができます。この面へのレンダリングを行う前に実行する最も大切なことは、カメラを正しく配置し、その面に対して正しい方向を向くようにトランスフォーム行列を設定することです。正しい方向とは、前方 (+z)、後方 (-z)、左 (-x)、右 (+x)、上方 (+y)、または下方 (-y) です。
次の C++ コード例は、レンダリングする面に応じてビュー行列を用意して設定します。
// Init pCubeMap to point to an IDirect3DCubeTexture9 interface // Init d3dDevice to point to an IDirect3DDevice9 interface void RenderFaces() { // Save transformation matrices of the device D3DXMATRIX matProjSave, matViewSave; d3dDevice->GetTransform(D3DTS_VIEW, &matViewSave ; d3dDevice->GetTransform(D3DTS_PROJECTION, &matProjSave); // Store the current back buffer and z-buffer LPDIRECT3DSURFACE9 pBackBuffer, pZBuffer; d3dDevice->GetRenderTarget(&pBackBuffer); d3dDevice->GetDepthStencilSurface(&pZBuffer);
キューブ環境マップの各面は 90°の視野を表すことを思い出してください。アプリケーションで特殊効果などのために視野の角度を変更しない限り、この角度に応じて射影行列を設定するよう注意が必要です。
次のコード例は、最も一般的に使う射影行列を作成および設定します。
// Use 90-degree field of view in the projection D3DMATRIX matProj; D3DXMatrixPerspectiveFovLH(matProj, D3DX_PI/2, 1.0f, 0.5f, 1000.0f); d3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); // Loop through the six faces of the cube map for(DWORD i=0; i<6; i++) { // Standard view that will be overridden below D3DVECTOR vEnvEyePt = D3DVECTOR(0.0f, 0.0f, 0.0f); D3DVECTOR vLookatPt, vUpVec; switch(i) { case D3DCUBEMAP_FACE_POSITIVE_X: vLookatPt = D3DVECTOR(1.0f, 0.0f, 0.0f); vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f); break; case D3DCUBEMAP_FACE_NEGATIVE_X: vLookatPt = D3DVECTOR(-1.0f, 0.0f, 0.0f); vUpVec = D3DVECTOR( 0.0f, 1.0f, 0.0f); break; case D3DCUBEMAP_FACE_POSITIVE_Y: vLookatPt = D3DVECTOR(0.0f, 1.0f, 0.0f); vUpVec = D3DVECTOR(0.0f, 0.0f,-1.0f); break; case D3DCUBEMAP_FACE_NEGATIVE_Y: vLookatPt = D3DVECTOR(0.0f,-1.0f, 0.0f); vUpVec = D3DVECTOR(0.0f, 0.0f, 1.0f); break; case D3DCUBEMAP_FACE_POSITIVE_Z: vLookatPt = D3DVECTOR( 0.0f, 0.0f, 1.0f); vUpVec = D3DVECTOR( 0.0f, 1.0f, 0.0f); break; case D3DCUBEMAP_FACE_NEGATIVE_Z: vLookatPt = D3DVECTOR(0.0f, 0.0f,-1.0f); vUpVec = D3DVECTOR(0.0f, 1.0f, 0.0f); break; } D3DMATRIX matView; D3DXMatrixLookAtLH(matView, vEnvEyePt, vLookatPt, vUpVec); d3dDevice->SetTransform(D3DTS_VIEW, &matView);
カメラを正しく配置し、射影行列を設定すると、シーンをレンダリングできます。シーンの各オブジェクトは、通常どおりに配置します。次のコード例では、処理全体がわかるように、このタスクの概略を示します。
// Get pointer to surface in order to render to it LPDIRECT3DSURFACE9 pFace; pCubeMap->GetCubeMapSurface((D3DCUBEMAP_FACES)i, 0, &pFace); d3dDevice->SetRenderTarget (pFace , pZBuffer); SAFE_RELEASE(pFace); d3dDevice->BeginScene(); // Render scene here ... d3dDevice->EndScene(); } // Change the render target back to the main back buffer. d3dDevice->SetRenderTarget(pBackBuffer, pZBuffer); SAFE_RELEASE(pBackBuffer); SAFE_RELEASE(pZBuffer); // Restore the original transformation matrices d3dDevice->SetTransform(D3DTS_VIEW, &matViewSave); d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjSave); }
IDirect3DDevice9::SetRenderTarget メソッドの呼び出しに注意してください。キューブ マップ面にレンダリングするときは、その面をカレント レンダー ターゲット サーフェスとして割り当てる必要があります。深度バッファーを使うアプリケーションでは、そのレンダー ターゲットに明示的に深度バッファーを作成したり、既存の深度バッファーをレンダー ターゲット サーフェスに再割り当てたりすることができます。上のコード例では、後者の方法を使っています。