DirectX12使用時にウィンドウを透過させる

# はじめに

DirectX12を使っているときにウィンドウの背景を透過させようとしたのですが，
情報が少なすぎて苦しんだので記録を残します．

筆者はプログラミング初心者なので，間違ったことを言うかもしれません．
間違いがあれば指摘していただけると幸いです．

# 問題
なぜか[SetLayeredWindowAttributes](https://docs.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-setlayeredwindowattributes)では透過させられず，
[UpdateLayeredWindow](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-updatelayeredwindow)は**レイヤード ウィンドウを定義するサーフェスの DC へのハンドル**というものが分からなかったので試すことが出来ませんでした...

[ID3D12GraphicsCommandList::ClearRenderTargetView](https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12graphicscommandlist-clearrendertargetview)でアルファ値を0に設定したものを併用してもダメでした．

# 解決法

[DirectComposition](https://docs.microsoft.com/ja-jp/windows/win32/directcomp/directcomposition-portal)を使用することで解決できました．
これを使用することで，諸々の描画結果を全て合成したものを描画できるようになるようです．

以下が関係ありそうな部分の疑似コード?です．

~~~main.cpp
// スワップチェインの初期化
ComPtr<IDXGISwapChain3> m_swapChain;

DXGI_SWAP_CHAIN_DESC1 desc = {};
desc.Width = m_windowWidth;
desc.Height = m_windowHeight;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Stereo = false;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 2;
desc.Scaling = DXGI_SCALING_STRETCH;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

ComPtr<IDXGISwapChain1> tmpSwapChain;

auto hr = m_dxgiFactory->CreateSwapChainForComposition(
		m_commandQueue.Get(),
		&desc,
		nullptr,
		tmpSwapChain.GetAddressOf()
	);

if (FAILED(hr))
{
    return false;
}

hr = tmpSwapChain.As(&m_swapChain);

if (FAILED(hr))
{
    return false;
}
~~~
~~~main.cpp
// 以下をインクルード
#include<dcomp.h>
#pragma comment(lib, "dcomp")

// DirectCompositionの初期化
ComPtr<IDCompositionDevice> m_dcompDevice;
ComPtr<IDCompositionTarget> m_dcompTarget;
ComPtr<IDCompositionVisual> m_dcompVisual;

auto hr = DCompositionCreateDevice(nullptr,
        IID_PPV_ARGS(&m_dcompDevice));

if (FAILED(hr))
{
    return false;
}

hr = m_dcompDevice->CreateTargetForHwnd(
    m_hwnd,
    true,
    &m_dcompTarget
);
if (FAILED(hr))
{
    return false;
}

hr = m_dcompDevice->CreateVisual(&m_dcompVisual);

if (FAILED(hr))
{
    return false;
}

hr = m_dcompVisual->SetContent(m_swapChain.Get());

if (FAILED(hr))
{
    return false;
}

hr = m_dcompTarget->SetRoot(m_dcompVisual.Get());

if (FAILED(hr))
{
    return false;
}

hr = m_dcompDevice->Commit();

if (FAILED(hr))
{
    return false;
}
~~~

:::note warn
レンダーターゲット生成については平時と特に変わりませんが，
 **D3D12_RENDER_TARGET_VIEW_DESC** を使用する場合は **フォーマット** を
 **スワップチェインのものと揃える** ことを忘れないでください．
:::

~~~main.cpp
// PSOの初期化
// ここでもフォーマットに気を付けてください
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = {};

D3D12_RENDER_TARGET_BLEND_DESC renderTargetBlendDesc = {};
renderTargetBlendDesc.BlendEnable = TRUE;
renderTargetBlendDesc.LogicOpEnable = FALSE;
renderTargetBlendDesc.SrcBlend = D3D12_BLEND_ONE;
renderTargetBlendDesc.DestBlend = D3D12_BLEND_ZERO;
renderTargetBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
renderTargetBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
renderTargetBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
renderTargetBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_MIN;
renderTargetBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
renderTargetBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;

desc.BlendState.RenderTarget[0].BlendEnable = TRUE;
desc.BlendState.AlphaToCoverageEnable = TRUE;
desc.BlendState.IndependentBlendEnable = FALSE;
desc.BlendState.RenderTarget[0] = renderTargetBlendDesc;

desc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;

// 以下省略
~~~

これで，レンダーターゲットのクリア時に
~~~main.cpp
const float clearColor[4] = {};
~~~
を渡すと...
![スクリーンショット (427).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546193/59324651-db35-ae16-dfe1-b5de6983a9de.png)

無事透過させることができました！！！！

# あとがき
拙い文章だったかもしれませんが，ここまでお読みいただきありがとうございました．
次回はボーンアニメーションの予定です．

それでは良きDirectX12ライフを．アデュー

P.S.　現在，結果をhrに代入するかSUCCEEDED/FAILEDに直接入れるか滅茶苦茶迷っています．

### 参考資料
https://github.com/PJayB/DirectCompositionDirectX12Sample
https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2014/june/windows-with-c-high-performance-window-layering-using-the-windows-composition-engine