Microsoft Visual Studio .NET 2003 Microsoft DirectX 9.0 SDK (December 2004) |
■キューブマップ | Prev Top Next |
今回は、キューブマップを使用した映りこみ処理を行います。
キューブマップは6つの面をもつサーフェイスです。それぞれの面が立方体のそれぞれの面に対応します。 カメラを6方向に向けて背景をレンダリングし、その結果をキューブマップの対応する面に格納します。 作成されたキューブマップをテクスチャーとして使用し、オブジェクトをレンダリングすると背景がオブジェクトに映りこんだ感じに表示されます。
---Main.cpp---
//LPDIRECT3DDEVICE9 m_pd3dDevice; //D3DPRESENT_PARAMETERS m_d3dParameters; LPDIRECT3DTEXTURE9 m_pMeshTexture; //雪だるまのテクスチャー LPDIRECT3DCUBETEXTURE9 m_pCubeTexture; //キューブマップテクスチャー LPDIRECT3DSURFACE9 m_pZBuffer; //Zマップサーフェイス int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmpLine*/, INT /*nCmdShow*/) { //**************************************************************** //ここでウィンドウクラスの登録処理を行う。 //**************************************************************** //**************************************************************** //ウィンドウの作成処理 //**************************************************************** //**************************************************************** //ここでDirect3Dの初期化を行う。 //**************************************************************** //**************************************************************** //空と地面と雪だるまオブジェクトをロードする //**************************************************************** //雪だるまのテクスチャーの初期化 D3DXCreateTextureFromFileEx( m_pd3dDevice, "Tex.bmp", //ファイル名 D3DX_DEFAULT, //幅 D3DX_DEFAULT, //高さ 1, //ミップマップレベル 0, //テクスチャーの使用目的 D3DFMT_UNKNOWN, //フォーマット D3DPOOL_MANAGED, //メモリ管理方法 D3DX_DEFAULT, //フィルタリング方法 D3DX_DEFAULT, //フィルタリング方法 0x0, //カラーキー NULL, //ファイルの情報を格納する構造体 NULL, //256色パレットを示す構造体 &m_pMeshTexture ); //IDirect3DTexture9 インターフェイス //**************************************************************** //キューブマップを作成する //**************************************************************** D3DCAPS9 Caps; m_pd3dDevice->GetDeviceCaps(&Caps); //キューブマップをハードウェアがサポートしているか調査する //2の累乗のサイズでない、キューブマップを作成するときはD3DPTEXTURECAPS_CUBEMAP_POW2もチェックする //ミップマップ化キューブテクスチャーを作成するときはD3DPTEXTURECAPS_MIPCUBEMAPもチェックする if( (Caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) ) { D3DXCreateCubeTexture( m_pd3dDevice, 128, //キューブマップは湾曲サーフェイスに適用されるため、解像度は小さくてよい 1, //今回はミップマップを無効にする D3DUSAGE_RENDERTARGET, //キューブマップにレンダリングを行うため、レンダリングターゲットを指定する D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, //レンダリングターゲットを指定するのでD3DPOOL_DEFAULTを指定する。したがってリストア処理時には自分で開放と初期化を行うこと &m_pCubeTexture ); //キューブマップレンダリング時に使用するZバッファサーフェイスを作成する m_pd3dDevice->CreateDepthStencilSurface( 128, 128, D3DFMT_D16, m_d3dParameters.MultiSampleType, m_d3dParameters.MultiSampleQuality, TRUE, &m_pZBuffer, NULL ); } //**************************************************************** //ここでメッセージループ処理を行う。 //**************************************************************** } BOOL MainLoop() { //**************************************************************** //シーンのクリア //**************************************************************** m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0x0, 1.0f, 0L ); m_pd3dDevice->BeginScene(); //**************************************************************** //背景のレンダリング //**************************************************************** //拡大フィルター m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); //縮小フィルター m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); //各種行列変換 D3DXMATRIX matProj, matView, matWorld; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 4.0f, 4.0f / 3.0f, 0.1f, 500.0f ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); D3DXMatrixIdentity( &matView ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); D3DXMatrixIdentity( &matWorld ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); //ここで空と地面のオブジェクトをレンダリングする //**************************************************************** //キューブマップの作成 //**************************************************************** //雪だるまの位置ベクトル D3DXVECTOR3 Pos = D3DXVECTOR3( 0.0f, 0.0f, 10.0f ); //現在のビューと射影座標変換マトリックスを保存する D3DXMATRIX matViewSave, matProjSave; m_pd3dDevice->GetTransform( D3DTS_VIEW, &matViewSave ); m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProjSave ); //現在のバックバッファとZバッファを保存する LPDIRECT3DSURFACE9 OldBackBuffer, OldZBuffer; m_pd3dDevice->GetRenderTarget( 0, &OldBackBuffer ); m_pd3dDevice->GetDepthStencilSurface( &OldZBuffer ); //射影では 90°の視野を使うことに注意する。 D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI / 2, 1.0f, 0.1f, 1000.0f ); m_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); //Zバッファサーフェイスを切り替える m_pd3dDevice->SetDepthStencilSurface( m_pZBuffer ); //ビューポートを切り替える D3DVIEWPORT9 OldViewport, Viewport; m_pd3dDevice->GetViewport( &OldViewport ); Viewport.Height = 128; Viewport.Width = 128; Viewport.MaxZ = 1.0f; Viewport.MinZ = 0.0f; Viewport.X = 0; Viewport.Y = 0; m_pd3dDevice->SetViewport( &Viewport ); // キューブ マップの 6 つの面をそれぞれにレンダリングする //視線ベクトル D3DXVECTOR3 vLookatPt, LookAt; //カレント ワールドの上方、一般には [0, 1, 0] を定義する D3DXVECTOR3 vUpVec; for( int i=0; i < 6; i++ ) { switch( i ) { case D3DCUBEMAP_FACE_POSITIVE_X: vLookatPt = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ); vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_X: vLookatPt = D3DXVECTOR3( -1.0f, 0.0f, 0.0f ); vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_POSITIVE_Y: vLookatPt = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); vUpVec = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_Y: vLookatPt = D3DXVECTOR3( 0.0f, -1.0f, 0.0f ); vUpVec = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ); break; case D3DCUBEMAP_FACE_POSITIVE_Z: vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ); vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; case D3DCUBEMAP_FACE_NEGATIVE_Z: vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, -1.0f ); vUpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ); break; } //オブジェクトの位置ベクトルから視線ベクトルを計算する LookAt = Pos + vLookatPt; D3DXMatrixLookAtLH( &matView, &Pos, &LookAt, &vUpVec); //ビューマトリックスを設定する m_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); // サーフェイスをレンダリングするために、そのポインタを取得する LPDIRECT3DSURFACE9 pFace; m_pCubeTexture->GetCubeMapSurface( i, 0, &pFace ); m_pd3dDevice->SetRenderTarget( 0, pFace ); SafeRelease( pFace ); //Zバッファのみクリアする m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0L ); //ここで空と地面のオブジェクトをレンダリングする } //レンダーターゲットをメインのバックバッファに戻す m_pd3dDevice->SetRenderTarget( 0, OldBackBuffer ); //ZバッファをメインのZバッファに戻す m_pd3dDevice->SetDepthStencilSurface( OldZBuffer ); SafeRelease( OldBackBuffer ); SafeRelease( OldZBuffer ); //元の座標変換行列に戻す m_pd3dDevice->SetTransform( D3DTS_VIEW, &matViewSave ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProjSave ); //元のビューポートに戻す m_pd3dDevice->SetViewport( &OldViewport ); //**************************************************************** //キューブマップを使用して雪だるまをレンダリング //**************************************************************** //キューブマップをステージ0に設定する //3Dのテクスチャ座標を使うように設定 m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT3 ); //3Dのテクスチャーを含むように設定 m_pd3dDevice->SetFVF( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0) ); //テクスチャ座標がキューブ マップ用の反射ベクトルとして自動生成する m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR ); //雪だるまのテクスチャーをステージ1に設定するのでステージ1のテクスチャーフィルターをLinearに設定する m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR ); m_pd3dDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); //雪だるまの頂点カラーとステージ0のテクスチャーを乗算合成する m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); //ステージ0の結果とステージ1のテクスチャーを乗算合成する m_pd3dDevice->SetTextureStageState( 1, D3DTSS_TEXCOORDINDEX, 0 ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE ); m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_CURRENT ); //ほとんどの場合アプリケーションでは頂点法線の自動正規化を有効にする必要がある //このレンダー ステートを有効にしていない場合、環境マップの外観が期待とは大きく異なる m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE ); //各頂点の反射ベクトルの計算方法の指定 //射影座標変換マトリックスに正射影を指定している場合はFALSEにする必要がある。 //通常パースペクティブを使用するのでこれの設定を変更する必要はない。 m_pd3dDevice->SetRenderState( D3DRS_LOCALVIEWER, TRUE ); //**************************************************************** //ここで雪だるまのライトとマテリアルと設定する //**************************************************************** //ステージ0にキューブマップテクスチャーをセットする m_pd3dDevice->SetTexture( 0, m_pCubeTexture ); //ステージ1に雪だるまのテクスチャーをセットする m_pd3dDevice->SetTexture( 1, m_pMeshTexture ); //**************************************************************** //ここで雪だるまをレンダリングする //**************************************************************** //ステージ0の設定を2Dテクスチャーに戻す m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 ); m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_PASSTHRU ); //頂点法線の自動正規化を無効にする m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS, FALSE ); //ステージ1のテクスチャーを無効にする m_pd3dDevice->SetTexture( 1, NULL ); m_pd3dDevice->EndScene(); m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); return TRUE; }
こんな感じで表示されました。空と地面が映りこんでいるのが確認できるかと思います。 さらに、キューブマップと雪だるまのテクスチャーを合成しています。 腹に書いてある字が雪だるまのテクスチャーです。
今回は、キューブマップにリアルタイムレンダリングする方法を紹介しましたが、このほかにあらかじめ作成されているキューブマップを画像ファイルとしてロードする方法もあります。 この方法のほうが、毎フレームごとにキューブマップを作成する必要がない分負荷は低いですが、アニメーションができないため使用箇所は限定されると思います。