ようやく立方体以外のウィンドウ表示を透明化することができるようになった。スワップチェーンをターゲットにして描画し、スワップチェーンのサーフェースのポインタを取得、デバイスコンテキストを取得、レイヤードウィンドウを更新というやり方でできた。実際の動きを動画にしてみた。
ポイントとしては2つ。1つめはスワップチェーンを初期化するときにGDI互換サーフェースとなるようにパラメータをセットする。ピクセルフォーマットは「DXGI_FORMAT_B8G8R8A8_UNORM_SRGB」に、DXGI_SWAP_CHAIN_DESCのFlagsメンバはDXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLEをセットする。
// 表示モード
DXGI_MODE_DESC desired_desc = {} , actual_desc = {};
// 各色8ビットで符号化なし正規化数
desired_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
desired_desc.Height = client_height_;// 高さ
desired_desc.Width = client_width_;// 幅
desired_desc.Scaling = DXGI_MODE_SCALING_CENTERED;// スケーリングなし
// リフレッシュレートを60Hzを要求する
desired_desc.RefreshRate.Numerator = 60000;
desired_desc.RefreshRate.Denominator = 1000;
// 近いモードを検索
output_->FindClosestMatchingMode(&desired_desc,&actual_desc,d3d_device_);
// スワップチェーンの作成
{
DXGI_SWAP_CHAIN_DESC desc = {};
desc.BufferDesc = actual_desc;
desc.SampleDesc.Count = 1;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = 1;
// desc.SampleDesc = msaa;
desc.OutputWindow = hwnd_;
//desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
desc.Windowed = TRUE;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
THROW_IFERR(dxgi_factory_->CreateSwapChain(d3d_device_,&desc,&swap_chain_));
}
2つめは描画時。サーフェースへのポインタを取得しレイヤードウィンドウに描画後に再度OMSetRenderTargetを行うということ。これはヘルプに書いてあった。
template <typename ProcType>
void base_win32_window<ProcType>::render()
{
static float t = 0.0f;
static DWORD time_start = 0;
if(init_)
{
float color[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
// 描画ターゲットのクリア
d3d_context_->ClearRenderTargetView(view_,color);
// 深度バッファのクリア
d3d_context_->ClearDepthStencilView( depth_view_, D3D11_CLEAR_DEPTH, 1.0f, 0 );
DWORD time_count = GetTickCount();
if( time_start == 0 )
time_start = time_count;
t = ( time_count - time_start ) / 1000.0f;
// Y軸で回転させる
mat_world_ = XMMatrixRotationY( t );
// 色の変更
mesh_color_.x = ( sinf( t * 1.0f ) + 1.0f ) * 0.5f;
mesh_color_.y = ( cosf( t * 3.0f ) + 1.0f ) * 0.5f;
mesh_color_.z = ( sinf( t * 5.0f ) + 1.0f ) * 0.5f;
// 定数更新
cb_changes_every_frame cb;
cb.mWorld = XMMatrixTranspose( mat_world_ );
cb.vLightColor = mesh_color_;
d3d_context_->UpdateSubresource( cb_changes_every_frame_, 0, NULL, &cb, 0, 0 );
// 立方体の描画
d3d_context_->VSSetShader( v_shader_, NULL, 0 );
d3d_context_->VSSetConstantBuffers( 0, 1, &cb_never_changes_.GetInterfacePtr() );
d3d_context_->VSSetConstantBuffers( 1, 1, &cb_change_on_resize_.GetInterfacePtr() );
d3d_context_->VSSetConstantBuffers( 2, 1, &cb_changes_every_frame_.GetInterfacePtr() );
d3d_context_->PSSetShader( p_shader_, NULL, 0 );
d3d_context_->PSSetConstantBuffers( 2, 1, &cb_changes_every_frame_.GetInterfacePtr() );
d3d_context_->PSSetShaderResources( 0, 1, &shader_res_view_.GetInterfacePtr() );
d3d_context_->PSSetSamplers( 0, 1, &sampler_state_.GetInterfacePtr() );
d3d_context_->DrawIndexed( 36, 0, 0 );
// 表示
swap_chain_->Present(1,0);
// 画面に転送
IDXGISurface1Ptr surface;
THROW_IF_ERR(swap_chain_->GetBuffer(0, __uuidof(IDXGISurface1), (void**) &surface));
HDC sdc;
THROW_IF_ERR(surface->GetDC( FALSE, &sdc ));
get_dc ddc(hwnd_);
RECT rc;
GetWindowRect(hwnd_,&rc);
POINT wnd_pos = {rc.left,rc.top};
SIZE wnd_size = {client_width_,client_height_};
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 128; // 不透明度(レイヤードウィンドウ全体のアルファ値)
blend.AlphaFormat = AC_SRC_ALPHA;
// デバイスコンテキストにおけるレイヤの位置
POINT po;
po.x = po.y = 0;
UpdateLayeredWindow(hwnd_, ddc.get(), &wnd_pos, &wnd_size, sdc, &po, RGB(255,0,0), &blend, ULW_ALPHA | ULW_COLORKEY);
surface->ReleaseDC( NULL);
surface.Release();
// OMステージに登録する
d3d_context_->OMSetRenderTargets( 1, &view_.GetInterfacePtr(), depth_view_ );
}
}
透明度を指定すると立方体を半透明にすることもできる。
とりあえずこれで動いているが、おかしな所はあるかもしれない。