アットウィキロゴ
ノート > Direct3D 入門 > BMP画像を表示する

BMP画像をスプライトにテクスチャとして貼りつけて表示する方法を説明します。

サンプルプログラム

Subversionリポジトリ内、下記の場所にVisual Studio のプロジェクトがあります
trunk/directx/ShowXFile_base20100511

やること

  • BMP画像をスプライトに貼りつけて3D空間上で表示する

用語

ジオメトリ
「頂点」「線」「平面」(ポリゴン)という3D空間上の幾何学図形
テクスチャ
3次元コンピュータグラフィックスで、物体の表面の質感を表現するために貼り付ける画像のこと
スプライト
キャラクターなどを表す画面上の2Dイメージ。Direct3Dでは、4頂点から成る4角形ジオメトリにテクスチャを張り付けたものとして扱う。

解説

<< stdafx.h >>

インクルードファイルについて

ポリゴンの表示では
//DirectX ヘッダー ファイル
#include <d3d9.h>
のように、d3d9.h をインクルードしていましたが、
//DirectX ヘッダー ファイル
#include <d3dx9.h>
今回は d3dx9.h をインクルードします。

<< ShowXFile_test20100510.cpp >>

定義とグローバル宣言

// シンボル定義及びマクロ
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define SPRITE_WIDTH 200
#define SPRITE_HEIGHT 246
ウィンドウサイズは800x600、スプライトの画像は200x246だと指定している。

#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
Direct3D のインスタンスをメモリから開放するためのマクロ。

PDIRECT3D9 pD3d = NULL;                       //Direct3Dへアクセスするためのポインタ
LPDIRECT3DDEVICE9 pDevice = NULL;          //ビデオカードへアクセスするためのポインタ
pD3d は「Direct3オブジェクト」、pDevice は「Direct3Dデバイス・オブジェクト」。
Direct3Dのプログラムではこの2つが必須。

LPDIRECT3DTEXTURE9 pTexture;
LPD3DXSPRITE pSprite;
テクスチャ・オブジェクト(pTexture)、スプライト・オブジェクト(pSprite)を宣言している。

InitD3d 関数

プロトタイプ宣言部
HRESULT InitD3d(HWND);      //DirectXの初期化

  • Direct3D 関係のオブジェクトを作って、初期化する関数。
  • はじめに一度だけ InitInstance() から実行される。(147行目あたり)
if(FAILED (InitD3d(hWnd)))
{
  return FALSE;
}

Direct3D を使うには、なによりもDirect3D オブジェクトを作らなければならない。
// 「Direct3D」オブジェクトの作成
if( NULL == ( pD3d = Direct3DCreate9( D3D_SDK_VERSION ) ) )
{
  MessageBox(0,TEXT("Direct3Dの作成に失敗しました"),TEXT(""),MB_OK);
  return E_FAIL;
}
  • Direct3DCreate9 関数により Direct3D オブジェクトが作られる
    • このように生成を手助けする外部関数を「ヘルパー関数」と呼んだりする
  • Direct3D で使うその他のオブジェクトはすべてここで作成した Direct3D オブジェクトから作られる

次は、Direct3D デバイス・オブジェクトの作成(169~200行目あたり)

  • Direct3D デバイス・オブジェクトとは、簡単にいえば、「ディスプレイ」「モニタ」「ビデオ・カード」のオブジェクトのこと
  • 「IDirect3D9::CreateDevice メソッド」で作成する
    • 「IDirect3D9」はDirect3D オブジェクト、「CreateDevice」はそのメソッド

  • if文が何重にもネストしているのは、様々なビデオ・カードの環境に対応するため
    • 使い回せばなんとかなる部分なので、詳細については割愛

※FAILED() と SUCCEEDED() マクロ
  • それぞれ括弧内の処理が失敗(FAILED)、成功(SUCCEEDED)したときに真を返すマクロ

//「テクスチャオブジェクト」の作成
if(FAILED(D3DXCreateTextureFromFileEx(pDevice,TEXT("Sprite.bmp"),SPRITE_WIDTH,SPRITE_HEIGHT,0,0,	D3DFMT_UNKNOWN,
										D3DPOOL_DEFAULT,D3DX_FILTER_NONE,D3DX_DEFAULT,
							            0xff000000,NULL,NULL,&pTexture)))
{
	MessageBox(0,TEXT("テクスチャの作成に失敗しました"),TEXT(""),MB_OK);
	return E_FAIL;
}
D3DXCreateTextureFromFileEx関数を使ってテクスチャオブジェクトを作成する。
成功すると、pTexture が作成されたテクスチャオブジェクトを指すことになる。

// 「スプライトオブジェクト」の作成
if(FAILED(D3DXCreateSprite(pDevice,&pSprite)))
{
	MessageBox(0,TEXT("スプライトの作成に失敗しました"),TEXT(""),MB_OK);
	return E_FAIL;
}
D3DXCreateSprite関数を使ってスプライトオブジェクトを作成する。
成功すると、pSprite が作成されたスプライトオブジェクトを指すことになる。

DrawSprite 関数

プロトタイプ宣言部
VOID DrawSprite();			//描画

  • スプライトを表示する関数
  • プログラムの起動中は常に繰り返し実行される

pDevice->Clear( 0, NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB(30,30,30), 1.0f, 0 );
  • なにか描画を行う前には、画面をクリアする
    • 厳密には単色で画面を塗りつぶす

  • ゲームなどでは多くの場合、1秒間に60回の更新を行う。
    • その1回の更新を「1フレーム」と呼んだりする
    • 各フレームの最初にはクリアが実行される

if( SUCCEEDED( pDevice->BeginScene() ) )
  • クリアはしてもしなくても構わないが、「BeginScene メソッド」は実行しておかないと描画処理ができない。
  • あらゆる描画処理の前にはこのメソッドをコールすること

RECT rect={0,0,SPRITE_WIDTH,SPRITE_HEIGHT};
  • RECT 構造体の rect を、BMP画像の大きさ(SPRITE_WIDTH x SPRITE_HEIGHT)で初期化する

D3DXVECTOR3 vec3Center(0,0,0);
D3DXVECTOR3 vec3Position(210,110,0);
  • D3DXVECTOR3 は3次元ベクトルを表す構造体
    • float 型のx, y, z をメンバとして持つ
    • D3DVECTOR3 を継承した派生型で、加減算や乗算を直感的に行えるようオペレーター定義されている
  • vec3Center はスプライトの中心座標
    • 絶対的なスクリーン座標ではなく、そのスプライト内のローカル座標でありウィンドウ上では相対座標
      • 中心を(0,0,0)とすると、スプライトの左上の点を意味する
      • 通常は(スプライトの横幅半分,スプライトの縦幅半分,0)とする
      • スプライトを回転させる際に、軸がずれているように回ってしまうため
  • vec3Position はスプライトの位置(スクリーン座標)として使う
    • ウィンドウ上では絶対座標
    • この座標がスプライトの左上に対応している
      • (0,0,0)とすればウィンドウの左上から描画される
      • (400,300,0)とすれば(ウィンドウが800x600の場合)、ウィンドウの丁度真ん中から描画される

pSprite->Begin(D3DXSPRITE_ALPHABLEND);
  • スプライトの描画前には必ず「ID3DXSprite::Begin メソッド」を実行する
  • ここでの引数の意味は、「アルファ・ブレンド(透過処理)が効くようにする」ということ

pSprite->Draw(pTexture,&rect,&vec3Center,&vec3Position,D3DCOLOR_ARGB(255,255,255,255));
  • 先に作っておいたテクスチャを第1引数として与えることで、スプライトにテクスチャが貼られる
  • 第2引数は、スプライトのサイズを保持した矩形
  • 第3引数は、中心座標
  • 第4引数は、位置の絶対座標
  • 第5引数は、スプライトの透明度と色合い

pSprite->End();
  • スプライト描画の終りには、「ID3DXSprite::End メソッド」を実行する
  • これを実行しないとスプライトが画面に描画されない

pDevice->EndScene();
  • スプライトを含む全ての描画処理の後に実行する

pDevice->Present( NULL, NULL, NULL, NULL );
  • 「IDirect3DDevice9::Present メソッド」は、画面を更新するためのもの
  • なんにしろ、これも実行しないと画面が更新されないため、描画結果が見えない

FreeDx 関数

プロトタイプ宣言部
VOID FreeDx();				//後片付け

  • プログラム内で作ったオブジェクトをメモリから開放する関数
  • プログラムの終了時に1度だけ実行される(82行目あたり)
FreeDx();  //ループから抜けたときに後片付け
  • 開放は『生成した順番とは逆』に行う

メモ

d3dx9.lib と d3dx9d.lib

前の項では d3dx9.lib を使っていて、
この項で参考にしている本では d3dx9.lib を指定しているが、
その違いは Debug 時に使うか(d3dx9d.lib)、Release 時に使うか(d3dx9.lib)の違いみたい。

なので、Visual Studio 上で試している限りでは d3dx9d.lib をインクルードしているままで大丈夫だと思う。


WinAPI メッセージボックスについて

error C2664: 'MessageBoxW' : 2 番目の引数を 'const char [29]' から 'LPCWSTR' に変換できません。(新しい機能 ; ヘルプを参照)
こんなこと言われた場合の解決方法。


資料(引用元だったり)

書籍
Web
最終更新:2010年05月13日 10:00