408.マスク処理


マスク処理とは

 画面全体にかかわる効果やエフェクトをポストエフェクトとかアフターエフェクトとか言いますが、その一種で、画面の中を部分的に暗くしたり半透明の色を付けたりする場合があります。
 このような処理をマスキングなんても言います。このサンプルはそのマスク処理です。

 FullSample408ディレクトリのソリューションを開き、リビルド、実行してみましょう。以下の画面が現れます。

 

図0408a

 

 両脇を暗くマスキング処理をしています。Bボタンでマスクが外れます。
 このマスク処理をしているオブジェクトはCharacter.h/cppにあります、MaskSpriteクラスです。
 これはスプライトの一種で、OnCreate()関数では、VertexPositionColorTexture型の頂点で四角形を作成しています。この頂点はX方向は-1.0から1.0、Y方向は-1.0から1.0、Zは0.0にしておきます。
 また、ワールド行列はそのまま(Idebntity)にしておきます。
 そうしたうえで、OnDraw()関数では、以下のように記述します。
void MaskSprite::OnDraw() {
    auto Dev = App::GetApp()->GetDeviceResources();
    auto pID3D11DeviceContext = Dev->GetD3DDeviceContext();
    auto RenderStatePtr = Dev->GetRenderState();
    pID3D11DeviceContext->OMSetBlendState(RenderStatePtr->GetAlphaBlendEx(), nullptr, 0xffffffff);
    pID3D11DeviceContext->OMSetDepthStencilState(RenderStatePtr->GetDepthNone(), 0);
    pID3D11DeviceContext->RSSetState(RenderStatePtr->GetCullNone());
    ID3D11SamplerState* pSampler = nullptr;
    pSampler = RenderStatePtr->GetLinearClamp();
    pID3D11DeviceContext->PSSetSamplers(0, 1, &pSampler);
    //シェーダの設定
    //頂点シェーダ
    pID3D11DeviceContext->VSSetShader(VSPCTSprite::GetPtr()->GetShader(), nullptr, 0);
    //インプットレイアウトの設定
    pID3D11DeviceContext->IASetInputLayout(VSPCTSprite::GetPtr()->GetInputLayout());
    //ピクセルシェーダ
    pID3D11DeviceContext->PSSetShader(PSPCTSprite::GetPtr()->GetShader(), nullptr, 0);
    //個別処理
    SpriteConstants sb;
    //コンスタントバッファの作成
    //行列の取得
    auto PtrTrans = GetComponent<Transform>();
    //行列の定義
    bsm::Mat4x4 World;
    World = PtrTrans->Get2DWorldMatrix();
    //エミッシブ
    sb.Emissive = Col4(0,0,0,1);
    //デフィーズはすべて通す
    sb.Diffuse = Col4(1, 1, 1, 1);
    //行列の設定
    sb.World = World;
    //テクスチャ
    auto shTex = App::GetApp()->GetResource<TextureResource>(m_TextureKey);
    pID3D11DeviceContext->PSSetShaderResources(0, 1, shTex->GetShaderResourceView().GetAddressOf());
    //コンスタントバッファの更新
    pID3D11DeviceContext->UpdateSubresource(CBSprite::GetPtr()->GetBuffer(), 0, nullptr, &sb, 0, 0);
    //コンスタントバッファの設定
    ID3D11Buffer* pConstantBuffer = CBSprite::GetPtr()->GetBuffer();
    //頂点シェーダに渡す
    pID3D11DeviceContext->VSSetConstantBuffers(0, 1, &pConstantBuffer);
    //ピクセルシェーダに渡す
    pID3D11DeviceContext->PSSetConstantBuffers(0, 1, &pConstantBuffer);
    //ストライドとオフセット
    UINT stride = m_SpriteMesh->GetNumStride();
    UINT offset = 0;
    //描画方法のセット
    pID3D11DeviceContext->IASetPrimitiveTopology(m_SpriteMesh->GetPrimitiveTopology());
    //頂点バッファのセット
    pID3D11DeviceContext->IASetVertexBuffers(0, 1, m_SpriteMesh->GetVertexBuffer().GetAddressOf(), &stride, &offset);
    //インデックスバッファのセット
    pID3D11DeviceContext->IASetIndexBuffer(m_SpriteMesh->GetIndexBuffer().Get(), DXGI_FORMAT_R16_UINT, 0);
    //描画
    pID3D11DeviceContext->DrawIndexed(m_SpriteMesh->GetNumIndicis(), 0, 0);
    //後始末
    Dev->InitializeStates();
}
 ここで行っている処理は、描画コンポーネントを使わずに直接デバイスに描画する処理です。
 また、あらかじめ、マスク処理のための半透明のテクスチャを準備しておきます。このサンプルではLenMask.pngというテクスチャを使い、L"LENMASK_TX"というキーワードでアクセスできるようにしています。
 シェーダーはVSPCTSprite(頂点シェーダ)とPSPCTSprite(ピクセルシェーダ)です。

 また、マスクを描画する場合必ず最後に描画する必要があります。そのためには、一番最後にAddGameObjectするわけですが、加えて、OnCreate()
        SetDrawLayer(2);
 としておきます。これは描画レイヤーと言って、描画順番を強制的に後ろにする方法です。描画レイヤーはデフォルトは0 です。大きくすると後で描画になります。ですからこ々の設定ではSetDrawLayer(1);でもよいわけですが、ほかにレイヤーを指定するオブジェクトのためにできるだけ後ろにしています。