Microsoft Visual Studio .NET 2003 Microsoft DirectX 9.0 SDK (December 2004) |
■動的テクスチャー | Prev Top Next | 関連ページ:なし |
今回は、動的テクスチャーをやります。久しぶりにシェーダー以外のことをやります。 さて動的テクスチャーですが、このテクスチャー自体は書き込み可能なテクスチャーだということ以外特別なことはありません。 しかし、使い方によっては面白いことができます。今回はその例を紹介します。
静止画ではよくわからないのですが、ロゴの周辺を青いパーティクルが周回しています。
この移動するパーティクルの進行方向を動的テクスチャーで制御します。
実際に動いているところを見たい方は自作のゲーム「GrowWing」のタイトル画面を参照してください。
同じことやってますんで。
さて動的テクスチャーには次の画像を使用します。
ロゴの周辺をグレー色で囲ってます。この色(0x9b9b9b)がパーティクルが移動する道筋となります。そして右上の「K」の文字の上側を拡大すると
となっています。暗いグレー(0x646464)がパーティクルの次の移動方向となり、白(0xffffff)がパーティクルの現在の位置となります。
パーティクルは白いピクセル位置にレンダリングします。
そして3色のピクセルをリアルタイムに更新することにより、パーティクルを移動させます。
ではソースを見ていきます。
---Main.cpp---
LPDIRECT3DDEVICE9 m_pd3dDevice = NULL; D3DPRESENT_PARAMETERS m_d3dParameters; //動的テクスチャーの宣言。 LPDIRECT3DTEXTURE9 m_pDynamicTexture = NULL; //画像ファイルの情報を格納する構造体。 D3DXIMAGE_INFO m_SrcInfo; int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmpLine*/, INT /*nCmdShow*/) { HRESULT hr; D3DCAPS9 caps; //**************************************************************** //ここでウィンドウクラスの登録処理を行う。 //**************************************************************** //**************************************************************** //ここでウィンドウの作成処理 //**************************************************************** //**************************************************************** //ここでDirect3Dの初期化を行う。 //**************************************************************** //**************************************************************** //ここで2Dロゴオブジェクトのロード //**************************************************************** //**************************************************************** //動的テクスチャーのロード //**************************************************************** //ハードウェアが動的テクスチャーをサポートするか調査する D3DCAPS9 caps; m_pd3dDevice->GetDeviceCaps( &caps ); if( caps.Caps2 & D3DCAPS2_DYNAMICTEXTURES ) { D3DXCreateTextureFromFileEx( m_pd3dDevice, // IDirect3DDevice9 インターフェイスへのポインタ。 _T("res\\02.bmp"), // ロードするファイル名。 D3DX_DEFAULT, // 幅。ファイルからディメンジョンが取得され、2の累乗に切り上げられる。 D3DX_DEFAULT, // 高さ。ファイルからディメンジョンが取得され、2の累乗に切り上げられる。 1, // ミップマップレベル。ミップマップを作成しない。 D3DUSAGE_DYNAMIC, // 動的テクスチャーを指定する。 D3DFMT_A8R8G8B8, // 32ビットフォーマット。 D3DPOOL_DEFAULT, // 動的テクスチャーを使用する場合は、D3DPOOL_DEFAULTを指定する。 D3DX_FILTER_NONE, // スケーリングもフィルタリングも行わない。 D3DX_FILTER_NONE, // スケーリングもフィルタリングも行わない。 0, // カラー キーを無効にする。 &m_SrcInfo, // 画像ファイルの情報を取得する。D3DXIMAGE_INFO型。 NULL, // 256色パレット。使用しない。 &m_pDynamicTexture // 作成されたテクスチャオブジェクト。 ); } //**************************************************************** //ここでメッセージループ処理を行う。 //**************************************************************** } //動的テクスチャーを参照し、パーティクルのレンダリング位置を取得し、レンダリング位置を更新する void ParticleNextFrame( LPDIRECT3DTEXTURE9 pDynamicTexture, D3DXVECTOR2* pNowPos ) { if( pDynamicTexture == NULL ) return ; D3DLOCKED_RECT rc; //ロックされた矩形領域。 DWORD x = 0, y = 0; LPDWORD pTextureBits = NULL; LPDWORD pNextMoveBits = NULL; LPDWORD pCanMoveBits = NULL; const DWORD NOW_PIXEL = 0xFFFFFFFF; //現在のピクセルカラー const DWORD NEXT_PIXEL = 0xFF646464; //次に移動すべきピクセルカラー const DWORD MOVE_PIXEL = 0xFF9B9B9B; //移動できるピクセルカラー // const DWORD NO_PIXEL = 0x00000000; //移動できないピクセルカラー pNowPos->x = -1.0f; pNowPos->y = -1.0f; //動的テクスチャーをロックし、アクセスできるようにする。 HRESULT hr = pDynamicTexture->LockRect( 0, &rc, NULL, 0 ); //動的テクスチャーメモリの先頭アドレスを取得。D3DFMT_A8R8G8B8を指定したので1ピクセルは32ビット。したがってDWORD型を使用する。 pTextureBits = (LPDWORD)rc.pBits; //**************************************************************** //動的テクスチャーを1ピクセルごとに参照し、パーティクルの現在の位置を探す //**************************************************************** for( y=0; y < m_SrcInfo.Height; y++ ) { for( x=0; x < m_SrcInfo.Width; x++ ) { if( *pTextureBits == NOW_PIXEL ) { //パーティクルをレンダリングする位置を返す pNowPos->x = (float)x; pNowPos->y = (float)y; goto NEXT1; } pTextureBits++; } } NEXT1: //**************************************************************** //現在の位置から上下左右を調べ移動先ピクセルを探す //**************************************************************** //左側に移動先ピクセルがあるか if( x > 0 ) { pNextMoveBits = pTextureBits - 1; if( *pNextMoveBits == NEXT_PIXEL ) { x--; goto NEXT2; } } //右側に移動先ピクセルがあるか if( x < m_SrcInfo.Width - 1 ) { pNextMoveBits = pTextureBits + 1; if( *pNextMoveBits == NEXT_PIXEL ) { x++; goto NEXT2; } } //上側に移動先ピクセルがあるか if( y > 0 ) { pNextMoveBits = pTextureBits - m_SrcInfo.Width; if( *pNextMoveBits == NEXT_PIXEL ) { y--; goto NEXT2; } } //下側に移動先ピクセルがあるか if( y < m_SrcInfo.Height - 1 ) { pNextMoveBits = pTextureBits + m_SrcInfo.Width; if( *pNextMoveBits == NEXT_PIXEL ) { y++; goto NEXT2; } } NEXT2: //**************************************************************** //パーティクルの移動先ピクセルを基準に上下左右を調べパーティクルが移動可能なピクセルを探す //**************************************************************** //左側に移動できるピクセルがあるか if( x > 0 ) { pCanMoveBits = pNextMoveBits - 1; if( *pCanMoveBits == MOVE_PIXEL ) goto NEXT3; } //右側に移動できるピクセルがあるか if( x < m_SrcInfo.Width - 1 ) { pCanMoveBits = pNextMoveBits + 1; if( *pCanMoveBits == MOVE_PIXEL ) goto NEXT3; } //上側に移動できるピクセルがあるか if( y > 0 ) { pCanMoveBits = pNextMoveBits - m_SrcInfo.Width; if( *pCanMoveBits == MOVE_PIXEL ) goto NEXT3; } //下側に移動できるピクセルがあるか if( y < m_SrcInfo.Height - 1 ) { pCanMoveBits = pNextMoveBits + m_SrcInfo.Width; if( *pCanMoveBits == MOVE_PIXEL ) goto NEXT3; } NEXT3: //現在の位置を移動できるピクセルカラーで更新 *pTextureBits = MOVE_PIXEL; //移動先のピクセルを現在のピクセルカラーで更新 *pNextMoveBits = NOW_PIXEL; //移動可能なピクセルを移動先で更新 *pCanMoveBits = NEXT_PIXEL; //ロックを解除する hr = pDynamicTexture->UnlockRect( 0 ); } //メッセージループからコールされる関数 BOOL MainLoop() { m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0L ); m_pd3dDevice->BeginScene(); D3DXMATRIX matProj, matView, matWorld; //射影座標変換 D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4.0f, 4.0f / 3.0f, 11.0f, 220.0f ); m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj ); //ビュー座標変換 D3DXMatrixIdentity( &matView ); m_pd3dDevice->SetTransform( D3DTS_VIEW, &matView ); //ワールド座標変換 D3DXMatrixTranslation( &matWorld, 0.0f, 0.0f, 200.0f ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); //**************************************************************** // 2Dロゴをレンダリング //**************************************************************** D3DXVECTOR2 Pixel; ParticleNextFrame( m_pDynamicTexture, &Pixel ); if( Pixel.x > -1.0f && Pixel.y > -1.0f ) { //動的テクスチャーから取得した座標は 0.0f 〜 テクスチャーの解像度 となるので中心位置に移動させる。 //なおテクスチャーの解像度は X = 256.0f, Y = 64.0f。 D3DXMatrixTranslation( &matWorld, Pixel.x - 128.0f, -( Pixel.y - 32.0f ), 200.0f ); m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld ); //**************************************************************** // パーティクルをレンダリング //**************************************************************** } m_pd3dDevice->EndScene(); m_pd3dDevice->Present( NULL, NULL, NULL, NULL ); return TRUE; }
以上です。
ParticleNextFrame()関数内でパーティクルのレンダリング位置を取得し、さらに動的テクスチャーの更新を行います。
さて動的テクスチャーですが、今回紹介した方法以外にもさまざまなテクニックに使用できると思います。ただしひとつ問題があります。デバイスロスト後の復帰処理でせっかく更新した テクスチャーの内容が初期化されてしまいます。どうすればいいんだろ。