Direct2D Effectの利用
下記記事にて、ID2D1DeviceContextを利用して楕円を描画するところまで実装しました。
Direct2D導入(ID2D1DeviceContext) - 何でもプログラミング
今回はID2D1DeviceContextで利用できるようになったEffectを実装してみたいと思います。
上記記事で描画した楕円画像に、赤と青を入れ替えるEffectを適用してみます。

記事中に特に説明のない関数は、上記記事を参照してみてください。
Effect作成
既存のEffectを利用して、赤と青を入れ替えるEffectを作成します。
#include <initguid.h> #include <d2d1_1.h> #pragma comment(lib, "d2d1.lib") ComPtr<ID2D1Effect> CreateEffect(ID2D1DeviceContext* context) { ComPtr<ID2D1Effect> effect; AssertHR(context->CreateEffect(CLSID_D2D1ColorMatrix, &effect)); D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0); AssertHR(effect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix)); return effect; }
OffscreenBufferの作成
Effectの入力としてBackBufferは利用できないため、一時描画先としてOffscreenBufferを作成します。
ComPtr<ID2D1Bitmap1> CreateTargetBitmap(ID2D1DeviceContext* context, D2D1_SIZE_U size)
{
auto prop = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)
);
ComPtr<ID2D1Bitmap1> bitmap;
AssertHR(context->CreateBitmap(size, nullptr, size.width * 4, prop, &bitmap));
return bitmap;
}
アプリケーションコード
まずOffscreenBufferに楕円を描画し、次にEffectを適用した結果をBackBufferに描画しています。
サイズが変更された場合は、BackBuffer、OffscreenBuffer共に作り直しています。(BackBufferを解放しておかないと、ResizeBuffersで例外が発生します。)
ComPtr<ID2D1DeviceContext> g_context;
ComPtr<IDXGISwapChain1> g_swapChain;
ComPtr<ID2D1Bitmap1> g_backBuffer;
ComPtr<ID2D1Bitmap1> g_offscreenBuffer;
ComPtr<ID2D1Effect> g_effect;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
{
g_context->BeginDraw();
g_context->SetTarget(g_offscreenBuffer.Get());
g_context->Clear(D2D1::ColorF(D2D1::ColorF::LightYellow));
// 楕円描画
D2D1_SIZE_F size = g_context->GetSize();
float rx = size.width / 2;
float ry = size.height / 2;
D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(rx, ry), rx, ry);
ComPtr<ID2D1SolidColorBrush> brush;
AssertHR(g_context->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Orange), &brush));
g_context->FillEllipse(ellipse, brush.Get());
// Effect適用(赤青いれかえ)
g_context->SetTarget(g_backBuffer.Get());
g_effect->SetInput(0, g_offscreenBuffer.Get());
g_context->DrawImage(g_effect.Get());
g_effect->SetInput(0, nullptr);
AssertHR(g_context->EndDraw());
g_context->SetTarget(nullptr);
DXGI_PRESENT_PARAMETERS params = { 0 };
AssertHR(g_swapChain->Present1(1, 0, ¶ms));
}
return 0;
case WM_SIZE:
g_backBuffer = nullptr;
AssertHR(g_swapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0)); // サイズ0で、自動でWindowのサイズが設定される
g_backBuffer = CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get());
g_offscreenBuffer = CreateTargetBitmap(g_context.Get(), g_backBuffer->GetPixelSize());
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
int main() { HWND hwnd = CreateHWND(WndProc); auto dxgiDevice = CreateDXGIDevice(); g_context = CreateD2DContext(dxgiDevice.Get()); g_swapChain = CreateSwapChain(dxgiDevice.Get(), hwnd); g_backBuffer = CreateBackBufferBitmap(g_context.Get(), g_swapChain.Get()); g_offscreenBuffer = CreateTargetBitmap(g_context.Get(), g_backBuffer->GetPixelSize()); g_effect = CreateEffect(g_context.Get()); Run(hwnd); return 0; }