ゲームフレームワーク的なものを作る。(6)〜スプライト描画〜
今回はDirect3D側で用意されているID3DXSpriteインターフェイスを使って、画像ファイルからテクスチャを生成し、画像の描画を行います。
スプライト描画オブジェクトの生成
Graphicsクラスにスプライト描画オブジェクト生成メソッドを追加します。前述のデバイスやフォントと同様、std::shared_ptr
typedef std::shared_ptr< ID3DXSprite > SpritePtr; class Graphics { /*略*/ public: /** * スプライト描画オブジェクトの生成 */ SpritePtr CreateSprite(); };
/** * スプライト描画オブジェクトの生成 * * @return スプライト描画オブジェクトを指すスマートポインタ */ SpritePtr Graphics::CreateSprite() { ID3DXSprite* sprite = nullptr; HRESULT hr = D3DXCreateSprite( device.get(), &sprite ); if( FAILED( hr ) )throw std::runtime_error( "D3DXCreateSprite" ); return SpritePtr( sprite, com_deleter() ); }
テクスチャの生成
スプライト描画オブジェクト同様、Graphicsクラスにテクスチャ生成メソッドを追加します。
typedef std::shared_ptr< ID3DXSprite > SpritePtr; class Graphics { /*略*/ public: /** * 画像ファイルからテクスチャを生成 */ TexturePtr CreateTexture( const std::string& filename );
/** * 画像ファイルからテクスチャを生成 * * @param filename ファイル名 * @return 生成したテクスチャを指すスマートポインタ */ TexturePtr Graphics::CreateTexture( const std::string& filename ) { IDirect3DTexture9* texture = nullptr; HRESULT hr = D3DXCreateTextureFromFile( device.get(), filename.c_str(), &texture ); if( FAILED( hr ) )throw std::runtime_error( "D3DXCreateTextureFromFile[" + filename + "]" ); return TexturePtr( texture, com_deleter() ); }
使い方
まずはGameクラスのメンバに持たせて、ID3DXSpriteインターフェイスの機能を直接使ってみましょう。
/** * Gameクラス */ class Game { /*略*/ private: Graphics graphics; SpritePtr sprite; TexturePtr texture; };
Game::Game( const WindowWeakPtr& window ) : graphics( window ) , sprite( graphics.CreateSprite() ) , texture( graphics.CreateTexture( "image\\bg.bmp" ) ) //画像ファイル名を指定 { /*略*/ }
Beginメソッド〜Endメソッド内でDrawメソッドを呼び出すことで、複数のスプライトを描画することができます。(レンダーステートを変更しない描画物は、1度のBegin〜Endで一気に描画した方が効率が良い)
void Game::Run() { //シーンの実行 ; //バックバッファをクリアし、シーンのレンダリングを開始する //レンダリング終了後、画面を更新する graphics.Clear(); if( graphics.BeginScene() ) { //シーンの描画 ; //Begin〜End内で描画処理を記述 sprite->Begin( 0 ); { RECT rect = { 0, 0, 720, 480 }; //描画元画像の矩形を指定 D3DXVECTOR3 pos( 0.0f, 0.0f, 0.0f ); //描画先座標を指定 sprite->Draw( texture.get(), &rect, nullptr, &pos, 0xffffffff ); } //以下同様にDrawメソッドを呼び出す。 { /*略*/ } sprite->End(); sprite->Begin( 0 ); /*略*/ sprite->End(); graphics.EndScene(); } graphics.Update(); }
行列(スケーリング、回転、平行移動)を利用する。
ID3DXSpriteインターフェイスには、いわゆるアフィン変換(スケーリング、回転、平行移動など)を行うためのSetTransformメソッドが用意されています。
行列の設定には
- D3DXMATRIXクラス
- D3DXMatrixScaling
- D3DXMatrixRotationX/Y/Z/YawPitchRoll/Axis
- D3DXMatrixTranslation
- D3DXMatrixMultiply
- D3DXMatrixIdentity
などを使用します。
行列を使用する際、Drawメソッドには描画座標指定せず、矩形と回転の中心座標のみ指定した方が使いやすいです。
sprite->Begin( D3DXSPRITE_ALPHABLEND ); { RECT rect = { 0, 0, 128, 128 }; //描画元画像の矩形を指定 D3DXVECTOR3 center( 64.0f, 64.0f, 0.0f ); //矩形の左上を基準とした回転の中心座標を指定 D3DXMATRIX mat, m; D3DXMatrixIdentity( &mat ); D3DXMatrixScaling( &m, 1.0f, 1.0f, 1.0f ); D3DXMatrixMultiply( &mat, &mat, &m ); D3DXMatrixRotationZ( &m, D3DXToRadian( 30.0f ) ); D3DXMatrixMultiply( &mat, &mat, &m ); D3DXMatrixTranslation( &m, 360.0f, 240.0f, 0.0f ); D3DXMatrixMultiply( &mat, &mat, &m ); sprite->SetTransform( &mat ); sprite->Draw( texture2.get(), &rect, ¢er, nullptr, 0xffffffff ); } sprite->End();
DDSファイルを使用する。
上記の例ではαチャンネル付き画像としてDDSファイルを使用しています。αチャンネル付き画像はPhotoshop、GIMPなどのソフトやDirectXSDK付属のTextureToolで作成可能です。
作り方はgoogle先生に聞いてください。「DDSファイル」
行列スタック(ID3DXMatrixStackインターフェイス)を使用する。
関節などの階層構造を持つオブジェクトの描画には、行列スタックを使うと便利です。Direct3Dには行列スタックを扱うためのID3DXMatrixStackインターフェイスが用意されています。
typedef std::shared_ptr< ID3DXMatrixStack > MatrixStackPtr; class Graphics { /*略*/ public: /** * 行列スタックオブジェクトの生成 */ MatrixStackPtr CreateMatrixStack(); };
/** * 行列スタックオブジェクトの生成 * * @return 行列スタックオブジェクトを指すスマートポインタ */ MatrixStackPtr Graphics::CreateMatrixStack() { ID3DXMatrixStack* matrix_stack = nullptr; HRESULT hr = D3DXCreateMatrixStack( 0, &matrix_stack ); if( FAILED( hr ) )throw std::runtime_error( "D3DXCreateMatrixStack" ); return MatrixStackPtr( matrix_stack, com_deleter() ); }
一例として、マウス座標で回転するオブジェクト(はちゅねミク)のまわりを自転しながら公転するオブジェクト(ネギ)を描画してみます。
class Game { /*略*/ private: Graphics graphics; ///< 描画機能 SpritePtr sprite; ///< MatrixStackPtr matrix_stack; ///< TexturePtr texture; TexturePtr texture2; float rotate; };
Game::Game( const WindowWeakPtr& window ) : window( window ) , graphics( window ) , sprite( graphics.CreateSprite() ) , matrix_stack( graphics.CreateMatrixStack() ) , texture( graphics.CreateTexture( "image\\bg.bmp" ) ) //画像ファイル名を指定 , texture2( graphics.CreateTexture( "image\\miku.dds" ) ) //画像ファイル名を指定 , rotate( 0.0f ) { /*略*/ }
rotate += D3DXToRadian( 1.0f ); //ミクの描画 // マウス位置に描画 matrix_stack->LoadIdentity(); { RECT rect = { 0, 0, 128, 128 }; D3DXVECTOR3 center( 64.0f, 64.0f, 0.0f ); matrix_stack->TranslateLocal( mouse_pos.x, mouse_pos.y, 0.0f ); matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); //自転角 matrix_stack->ScaleLocal( 1.0f, 1.0f, 1.0f ); //ネギの描画 // ミクを中心に自転しながら公転する matrix_stack->Push(); { RECT rect = { 128, 0, 256, 128 }; D3DXVECTOR3 center( 64.0f, 64.0f, 0.0f ); matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); //公転角 matrix_stack->TranslateLocal( 100.0f, 0.0f, 0.0f ); //公転半径 matrix_stack->RotateYawPitchRollLocal( 0.0f, 0.0f, rotate ); //自転角 matrix_stack->ScaleLocal( 1.0f, 1.0f, 1.0f ); sprite->SetTransform( matrix_stack->GetTop() ); sprite->Draw( texture2.get(), &rect, ¢er, nullptr, 0xffffffff ); } matrix_stack->Pop(); sprite->SetTransform( matrix_stack->GetTop() ); sprite->Draw( texture2.get(), &rect, ¢er, nullptr, 0xffffffff ); }
download
- framework07.zip
- VC++2010 ExpressEdition、DirectX SDK(February 2010)で動作確認
- 「はちゅねミク」の画像は、三次元CG@七葉(http://nanoha.kirara.st/3dcg/)からお借りしたモデルを使用しています。
今回はDirectXの機能を直接利用してスプライト描画を行いましたが、DirectXに依存したプログラムは出来るだけ書きたくないので、前回作成したRectクラス、Colorクラスの利用、また今後の3D描画のためのベクトルクラス、行列クラスの作成なども行っていきたいと思います。