透過表示

この章で使用するプログラムおよび画像ファイル

今までのプログラムでは、ビットマップ画像をそのままポリゴンに貼り付けて描画しているため、キャラクタとは関係ない部分まで転送してしまう。しかし、DirectX Graphicsでは描画を行う際に不要な部分を透明にすることができる。この処理を透過処理(スプライト)と呼ぶ。
ここでは、透過処理の手順を紹介する。

スプライト処理の考え方

2Dゲームでは通常、キャラクタは透過表示され、キャラクタ以外の部分は透明になるよう描画処理が行われている。

上図のようにポリゴン1(背景画像)の上にポリゴン2(キャラクタ画像)を配置した場合、指定した透過色の部分(上図では黄色)が透明になる。

透過処理を行えるようプログラムを修正する

透過処理を行うには、描画の設定を宣言しなければならない。次のようにプログラムを修正する。

1.透過処理の宣言

透明処理を行うための宣言を行う。この処理はDirectXの初期化処理後に行えばいいが、ウィンドウ復帰時に再実行しなければならないため、関数化する。この関数はInitDX8()関数の下に作成するといいだろう。プロトタイプ宣言も行うこと。

//-----------------------------------------------------------------------------
// 関数名 : InitRender()
// 機能概要: 描画の設定など
//-----------------------------------------------------------------------------
void InitRender(void)
{
    // アルファ・ブレンディングを行う
    gl_lpD3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    // 透過処理を行う
    gl_lpD3ddev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
}

2.InitRenderの実行

作成した関数を実行し、透過処理が行えるようにする。この関数はDirectXの初期化をした後に実行する。

//-------------------------------------------------------------------------------------------------
//      メイン関数(エントリーポイント)プログラムはここから始まる
//-------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
{
    MSG msg;		// メッセージ構造体変数
    HRESULT hr;

    //表示するウィンドウの定義、登録、表示
    if ( !InitApp(hThisInst, nWinMode) )	// InitApp関数を呼び出し、
        return (FALSE);						// 正常に終了すれば次にメッセージループへ

    // DirectX8の初期化
    hr = InitDX8();
    if ( FAILED(hr) ) return (FALSE);

    // 描画の設定
    InitRender();

    // ゲームループ
    while ( TRUE ) {
    // メッセージがあるかどうか
        if ( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) ) {
            // メッセージを取得し、WM_QUITかどうか
            if ( !GetMessage(&msg, NULL, 0, 0) ) break;
            TranslateMessage(&msg);  //キーボード利用を可能にする
            DispatchMessage(&msg);  //制御をWindowsに戻す
        } else if ( g_appActive ) {
            // ゲームメイン処理
            if ( FAILED( UpdateFrame() ) ) break;
            Sleep(1);
        } else {
            WaitMessage();
        }
    }

    // DirectX8オブジェクトの削除
    ReleaseD3D();

    return msg.wParam;
}

※以上の修正を行い、エラーが出ないことを確認する。

テクスチャに透明色を指定して描画する

現在のプログラムは、白で塗りつぶされた背景に、飛行機のキャラクタ(同じ画像だが、別のテクスチャとして用意)を2つ描画している。しかし、ビットマップ画像は青いキャンバスの上にキャラクタが描かれているため、飛行機の周りに青い部分が残ってしまっている。この青い部分を透明にすることにより、キャラクタだけが描画されるようにしたい。
今回は動作確認のため、1つ目のキャラクタはそのまま描画し、2つ目のキャラクタは透明処理を行って描画するようプログラムを修正する。

透明色を指定してテクスチャを生成

ビットマップファイルを読み込んでテクスチャを作成するが、このときに透明色を指定できる。今回は2つ目のキャラクタ用のテクスチャに透明色を指定して作成する。

//-----------------------------------------------------------------------------
// 関数名 : CreateStartTexture()
// 機能概要: スタート画面用テクスチャの作成・再生成
//-----------------------------------------------------------------------------
void CreateStartTexture(void)
{
    HRESULT hr;
    char buff[80];

    // キャラクタ1
    hr = D3DXCreateTextureFromFile(gl_lpD3ddev, gl_szCharFileName, &gl_Texture1);
    if ( FAILED(hr) ) {
        wsprintf(buff, "%s をテクスチャ1として読み込めませんでした", gl_szCharFileName);
        MessageBox(hWnd, buff, "ERROR", MB_OK);
        return;
    }
    // キャラクタ2
    hr = D3DXCreateTextureFromFileEx(
        gl_lpD3ddev,
        gl_szCharFileName,              // ファイル名
        0,
        0,
        0,
        0,
        D3DFMT_A1R5G5B5,                // 色抜きを可能に
        D3DPOOL_MANAGED,
        D3DX_FILTER_LINEAR,
        D3DX_FILTER_LINEAR,
        D3DCOLOR_ARGB(255, 0, 0, 255),  // 青色を透過色とする
        NULL,
        NULL,
        &gl_Texture2                    // テクスチャ名
    );
    if ( FAILED(hr) ) {
        wsprintf(buff, "%s をテクスチャ2として読み込めませんでした", gl_szCharFileName);
        MessageBox(hWnd, buff, "ERROR", MB_OK);
        return;
    }

}

《POINT》

  1. 透明色を指定する場合、D3DXCreateTextureFromFile関数ではなくD3DXCreateTextureFromFileEX関数を使用する。
  2. D3DXCreateTextureFromFileEX関数の第11引数で、D3DCOLOR_ARGB関数により透過色を指定する。

※上記修正を行い、2つ目のキャラクタの背景が透明になっていることを確認する。

ウィンドウの復帰に対応させる

今までの修正により、2つ目のキャラクタの背景を透明にすることができた。しかし、今の状態ではウィンドウを切り替えた後復帰させると、2つ目のキャラクタの背景が透明ではなくなってしまう。これは、ウィンドウ復帰時、ディスプレイ・モードは再設定されたが、描画の設定が失われてしまったことが原因である。
 これを修正するには、復帰処理でInitRender()関数を実行させればよい。プログラムを次のように修正する。

//-----------------------------------------------------------------------------
// 関数名 : ResetWindow()
// 機能概要: ウィンドウの再設定
//-----------------------------------------------------------------------------
void ResetWindow(void)
{
    if ( gl_lpD3ddev ) {
        // ディスプレイ・パラメータの値を使ってウィンドウをリセットする
        gl_lpD3ddev->Reset(&gl_d3dpp);
        // 描画の設定
        InitRender();
    }
}

※上記修正を行い、ウィンドウが復帰しても透明色が有効になっていることを確認する。



NEXT(半透明表示)