DirectXというとポリゴンをふんだんに使った3Dプログラミングや動画再生など
どちらかというとマルチメディア処理を行うためのものと言う印象が強いかと思います。
当然その認識は間違っておらずDirectXライブラリを使用することで処理のハードウェアの支援や
プログラムの簡素化など非常に役に立つライブラリです。
そんなDirectXですが当然マルチメディアというからには3Dだけではなく2D処理も得意で
2D画像の表示や回転・移動などの処理を行う際にも絶大な威力を発揮します。
今回はDirectXを使用して2D画像の扱い方を説明します。
まず、DirectXでのスプライトとはどんなものかを説明します。
ビルボードという概念があります。
このビルボードとは3D空間上に存在する表裏のある板なんですが
この板は見ている人に対して常に正面を向くという特徴を持っています。
つまりカメラをどの場所に移動してその板を見ても常にカメラを正面にして向きを変える板です。
こういう特徴を持った板をビルボードと呼び、さらにDirectXではスプライトと呼んでいます。
当然ポリゴンを作成してカメラとの位置を計算して自分のほうに向きを変更するなどの処理を実装して
自分でビルボードを作成することもできるのですが
DirectXのスプライトはこの辺の処理を上手に隠蔽してくれているのです。
ここではそのスプライトの使い方を解説していきます。
プログラムの流れは次の通り。ポリゴンなどを使った普通のDirectX、3Dプログラミングと同じですね。
処理と主に使うAPIを並べておきます。
- Direct3Dのデバイスを初期化する
Direct3DCreate9()
IDirect3D9::GetAdapterDisplayMode()
IDirect3D9::CreateDevice()
IDirect3DSurface9::GetDesc()
- スプライトを作成する
D3DXCreateSprite()
D3DXCreateTextureFromFile()
IDirect3DTexture9::GetSurfaceLevel()
- 作成したスプライトを表示用に変換する
D3DXMatrixIdentity()
D3DXMatrixScaling()
D3DXMatrixRotationZ()
D3DXMatrixTranslation()
- 描画する
IDirect3DDevice9::Clear()
IDirect3DDevice9::BeginScene()
ID3DXSprite::Begin()
ID3DXSprite::Draw()
ID3DXSprite::SetTransform()
ID3DXSprite::End()
IDirect3DDevice9::EndScene()
IDirect3DDevice9::Present()
- 後処理
IDirect3DTexture9::Release()
ID3DXSprite::Release()
IDirect3DDevice9::Release()
IDirect3D9::Release()
上の流れに沿ってそれぞれコードを見ていきましょう。
細かいパラメータはハードコーディングしてありますがひとまず後回しにしときましょう。
HWND hWnd; HRESULT hr; D3DPRESENT_PARAMETERS d3dpp; D3DDISPLAYMODE dmode; UINT nAdapter; D3DDEVTYPE dwDeviceType; // デバイスの種類 DWORD dwBehaviorFlags; // デバイスの動作モード D3DSWAPEFFECT dwSwapEffect; // パラメータの設定 dwDeviceType = D3DDEVTYPE_HAL; nAdapter = D3DADAPTER_DEFAULT; dwBehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING; dwSwapEffect = D3DSWAPEFFECT_DISCARD; // D3Dオブジェクトの作成 pD3D = ::Direct3DCreate9(D3D_SDK_VERSION); // 現在のディスプレイモードを取得 ::ZeroMemory(&d3dpp, sizeof(d3dpp)); hr = pD3D->GetAdapterDisplayMode(nAdapter, &dmode); if (FAILED(hr)) return hr; // パラメータの設定 d3dpp.Windowed = TRUE; // ウィンドウモードで表示 d3dpp.SwapEffect = dwSwapEffect; d3dpp.BackBufferFormat = dmode.Format; d3dpp.BackBufferCount = 2; // トリプルバッファリング d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; // 16Bit Zバッファ作成 // IDirect3DDevice9オブジェクトの作成 hr = pD3D->CreateDevice(nAdapter, dwDeviceType, hWnd, dwBehaviorFlags, &d3dpp, &pd3dDevice); if (FAILED(hr)) return hr; return S_OK;
スプライトとテクスチャの作成を行います。
ここでは画像ファイルからデータを読み込みテクスチャを作成します。
HRESULT hr = S_FALSE; UINT uLevel = 0; IDirect3DSurface9* pSurface = NULL; LPCTSTR lpszFilename = _T("texture.png"); // スプライト情報の生成 if (SUCCEEDED(hr)) hr = ::D3DXCreateSprite(pd3dDevice, &pSprite); if (SUCCEEDED(hr)) hr = ::D3DXCreateTextureFromFile(pd3dDevice, lpszFilename, &pTexture); if (SUCCEEDED(hr)) hr = pTexture->GetSurfaceLevel(uLevel, &pSurface); // サーフェイス取得 if (SUCCEEDED(hr)) hr = pSurface->GetDesc(&sSurfaceInfo); if (pSurface != NULL) pSurface->Release(); pSurface = NULL;
ここでは描画するウィンドウ上にどのようにスプライトを変換するかを記述します。
具体的には移動、回転、拡大縮小などの処理を記述することになります。
ここでは読み込んだ画像をウィンドウ全体に表示することにします。
RECT rc; FLOAT x, y; // 変換行列初期化 ::D3DXMatrixIdentity(&mat); // ウィンドウサイズにスプライトの大きさをあわせる ::GetWindowRect(hWnd, &rc); x = (FLOAT)(rc.right - rc.left) / sSurfaceInfo.Width; y = (FLOAT)(rc.bottom - rc.top) / sSurfaceInfo.Height; // 拡縮させる ::D3DXMatrixScaling(&mat, x, y, 0.0f);
作成・変換したスプライトをウィンドウに表示します。
WM_PAINTメッセージやOnOaint()イベントハンドラで呼ぶか
ゲームなどだとループを作成して固定FPSで描画ルーチンを呼ぶことになります。
// パラメータの設定 D3DXVECTOR3 vCenter = D3DXVECTOR3(0.0f,0.0f,0.0f); D3DCOLOR clrAlpha = D3DCOLOR_RGBA(0xff,0xff,0xff,0xff); D3DCOLOR clrBgColor = D3DCOLOR_RGBA(0xff,0xff,0xff,0xff); // クリア pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clrBackgroundColor, 1.0f, 0); // 描画開始 if (SUCCEEDED(pd3dDevice->BeginScene())) { // スプライトを描画 pSprite->Begin(D3DXSPRITE_ALPHABLEND); pSprite->Draw( pTexture, // LPDIRECT3DTEXTURE9 pTexture NULL, // CONST RECT *pSrcRect &vCenter, // CONST D3DXVECTOR3 *pCenter NULL, // CONST D3DXVECTOR3 *pPosition clrAlpha // D3DCOLOR Color ); pSprite->SetTransform(&mat); pSprite->End(); // シーン描画の終了 pd3dDevice->EndScene(); } // バッファを表示 pd3dDevice->Present(NULL, NULL, NULL, NULL);
アプリが終了したときはそれぞれ破棄します。
ま、お決まりですね。
// スプライトの破棄 if (pTexture != NULL) pTexture->Release(); pTexture = NULL; if (pSprite != NULL) pSprite->Release(); pSprite = NULL; // IDirect3DDevice9オブジェクトの解放 if (pd3dDevice != NULL) pd3dDevice->Release(); pd3dDevice = NULL; // IDirect3D9オブジェクトの解放 if (pD3D != NULL) pD3D->Release(); pD3D = NULL;
このあたりをうまくまとめればウィンドウにスプライトが表示されます。
上のコードではパラメータに直接ハードコーディングでパラメータ値を記述しています。
一つづつ説明するとかなり膨大な量になるのでリンクをご覧ください。
- 今回のソースコード
- DXSprite.ZIP (VS8プロジェクト)
- 各説明
- ・ Direct3D C/C++ リファレンス
- ・ IDirect3D9::GetAdapterDisplayMode メソッド
- ・ IDirect3D9::CreateDevice メソッド
- ・ IDirect3D9::CreateDevice メソッド
- ・ IDirect3DDevice9::Clear メソッド
- ・ IDirect3DDevice9::Clear メソッド
- ・ Direct3D エクステンション (D3DX) C/C++ リファレンス
- ・ ID3DXSprite::Begin メソッド
- ・ ID3DXSprite::Draw メソッド
