半透明にしてみる


~きれいなポリゴンは好きですか?~




■今回のファイルは

今回は、さらに、アルファブレンディングを用いて、半透明を実現します。

次のソースを、ダウンロードしてください。

今回も、draw.cpp を書き換えただけです。

■オブジェクト

今回は、2枚のポリゴンを使います。そのために、オブジェクトを2倍、用意しました。

LPDIRECT3DVERTEXBUFFER8 pVB1 = NULL;
LPDIRECT3DVERTEXBUFFER8 pVB2 = NULL;
LPDIRECT3DTEXTURE8      pTexture1 = NULL;
LPDIRECT3DTEXTURE8      pTexture2 = NULL;

また、テクスチャー画像として、桜の絵(sakura.bmp)と、TEST と書いた絵(test.bmp)を用意しました。
下の画像の、下地になって、一部隠れている部分が、sakura.bmp で、黄色くTEST と書かれた画像が test.bmp です。

■初期化

とにかく、2倍2倍です。
それぞれ、色分けしてみました。

HRESULT InitRender(LPDIRECT3DDEVICE8 lpD3DDEV)
{
    CUSTOMVERTEX vertices1[] =
    {
        //     x,      y,    z,  rhw, color
        { 100.0f, 100.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 0.0f,0.0f,},
        { 420.0f, 100.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 1.0f,0.0f,},
        { 100.0f, 340.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 0.0f,1.0f,},
        { 420.0f, 340.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 1.0f,1.0f,},
    };
    CUSTOMVERTEX vertices2[] =
    {
        //     x,      y,    z,  rhw, color
        { 132.0f, 124.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 0.0f,0.0f,},
        { 388.0f, 124.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 1.0f,0.0f,},
        { 132.0f, 316.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 0.0f,1.0f,},
        { 388.0f, 316.0f, 0.5f, 1.0f, D3DCOLOR_RGBA(0xff, 0xff, 0xff, 0x80), 1.0f,1.0f,},
    };
    HRESULT hr;
    
    hr = lpD3DDEV->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX),0,
                    D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVB1);
    if(FAILED(hr)) return E_FAIL;
    hr = lpD3DDEV->CreateVertexBuffer( 4*sizeof(CUSTOMVERTEX),0,
                    D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVB2);
    if(FAILED(hr)) return E_FAIL;

    VOID* pVertices;
    hr = pVB1->Lock( 0, sizeof(vertices1), (BYTE**)&pVertices, 0);
    if(FAILED(hr)) return E_FAIL;
    memcpy( pVertices, vertices1, sizeof(vertices1) );
    pVB1->Unlock();
    
    hr = pVB2->Lock( 0, sizeof(vertices2), (BYTE**)&pVertices, 0);
    if(FAILED(hr)) return E_FAIL;
    memcpy( pVertices, vertices2, sizeof(vertices2) );
    pVB2->Unlock();
    
    D3DXCreateTextureFromFileEx(lpD3DDEV, "sakura.bmp",0,0,0,0,D3DFMT_A8R8G8B8,
                                D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR,
                                0, NULL, NULL, &pTexture1);

    D3DXCreateTextureFromFileEx(lpD3DDEV, "test.bmp",0,0,0,0,D3DFMT_A8R8G8B8,
                                D3DPOOL_MANAGED, D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR,
                                0, NULL, NULL, &pTexture2);

    return S_OK;
}

まさに、コピペの嵐ですね。もっと、きれいにまとめて初期化しましょう。
今回、D3DCOLOR_RGBA の第四引数が 0x80=128 になっています。 この値がアルファ値で、合成する時の割合(濃さ)として用いられます。 255 のだいたい半分の値で、半分の強さで合成されることになります。

■描画

今回は、ここが豊かです。

void Render(LPDIRECT3DDEVICE8 lpD3DDEV)
{
    lpD3DDEV->SetVertexShader( D3DFVF_CUSTOMVERTEX );
    
    // テクスチャのブレンディング方法を定義する
    lpD3DDEV->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);// 引数の成分を乗算する
    lpD3DDEV->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
    lpD3DDEV->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
    
    // 桜のポリゴンを描く
    lpD3DDEV->SetTexture( 0, pTexture1);
    lpD3DDEV->SetStreamSource( 0, pVB1, sizeof(CUSTOMVERTEX) );
    lpD3DDEV->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2);
    
    // アルファ合成の設定
    lpD3DDEV->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    lpD3DDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    lpD3DDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
    
    // TESTのポリゴンを描く
    lpD3DDEV->SetTexture( 0, pTexture2);
    lpD3DDEV->SetStreamSource( 0, pVB2, sizeof(CUSTOMVERTEX) );
    lpD3DDEV->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2);
    
    // 次のポリゴンが半透明にならないように
    lpD3DDEV->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}

lpD3DDEV->SetVertexShader( D3DFVF_CUSTOMVERTEX );は、前回もやりましたが、ポリゴンの頂点フォーマットを設定します。

lpD3DDEV->SetTextureStageState(....);は、アルファ合成する時に、どのような色を用いるか、指定します。
今回の設定では、テクスチャーの色と、ポリゴン自体の色を掛けた値を使います。 つまり、テクスチャーの画像でも、ポリゴンの色でも、どちらでも色の指定が可能になります。

そのあと、桜の画像を描画します。ここは、前回やったとおりです。

次に、いよいよ半透明の設定です。
lpD3DDEV->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); で、アルファ合成の切り替えをします。 これで、半透明が使えるようになりました。
後の 2 つは、どのように合成するかを設定します。
D3DRS_DESTBLEND は、下地の画像の合成法を設定します。 D3DBLEND_INVSRCALPHA は、上に描くポリゴンのアルファ値の濃さによって、下地の描画を薄くします。 上に描くポリゴンのアルファ値が 0 の時はそのまま描き、255 の時は描きません(黒く描きます)。 これで、透けた先の濃さが調整されます。
D3DRS_SRCBLEND は、上に書く画像の合成法を設定します。 D3DBLEND_SRCALPHA は、描くポリゴンのアルファ値の濃さで描きます。 アルファ値の値が高ければ高いほど、濃く描きます。
これで、透けるような描画ができる設定になりました。
後で、設定を変えた場合に、どのようになるかお見せします。

そして、TEST 画像の描画です。
描画自体は、桜の画像を描画したのと変わりません。 つまり、その前の SetRenderState が、半透明画像の描画の肝になっています。

最後に、この後のポリゴンが半透明で描画されないように、アルファ合成をオフします。

■後片付け

後片付けは、いつものように、使ったものを開放するだけです。

void CleanRender()
{
    RELEASE(pTexture2);
    RELEASE(pTexture1);
    RELEASE(pVB2);
    RELEASE(pVB1);
}

■バリエーション

D3DRS_DESTBLEND や、D3DRS_SRCBLEND を変える事によって、様々な合成を行うことが出来ます。 一例として、下に挙げてみました。

内挿:色ガラスみたいに、後ろが透けて見える表現です。 半透明のポリゴンのアルファ値を変える事によって、濃さを調整できます (0:透明~128:下の画像~255:不透明)。

    lpD3DDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
    lpD3DDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

加算:ポリゴンが光り輝く表現をする時に使います。

    lpD3DDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
    lpD3DDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);

減算もどき(黒く乗算):色を沈ませたい時に使えます。 下の画像では黄色いテクスチャーを張ったために青くなっていますが、白いテクスチャーを張ると、そこが黒くなります。

    lpD3DDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR);
    lpD3DDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);

不透明:アルファ合成の ON/OFF の切り替えをせずに、不透明のポリゴンを表示するのに使います。

    lpD3DDEV->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
    lpD3DDEV->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);




もどる

imagire@gmail.com