日別アーカイブ: 2007年8月17日

Direct3D 10 ウィンドウのリサイズ (ResizeBuffers)

Direct3D 10 では Window のリサイズが比較的簡単にできます。
もちろん何もしない状態でも、DirectX9 と同じようにサイズの異なる
FrontBuffer に対して BackBuffer を拡縮 Copy します。
よってそのままでもウィンドウのリサイズが可能です。
Direct3D 10 の場合、さらに BackBuffer のサイズも容易に追従
させることができます。

サイズの変更は IDXGISwapChain の ResizeBuffer() です。
SwapChain が作成した Buffer のリサイズは行いますが、Buffer を
参照しているオブジェクトがあると同時には解決できません。
それらのオブジェクトはあらかじめ Release() しておく必要があります。

通常は BackBuffer から ID3D10RenderTargetView を作りますので、
RenderTargetView は先に開放しておきます。

また OMSetRenderTarget() で同時に DepthStencilView を登録する
場合、RenderTargetView とサイズが異なると受け付けてくれません。
結局 DepthStencilView も作り直す必要があります。

まずは Release()

ID3D10RenderTargetView*	iRTV= NULL;
iDevice->OMSetRenderTarget( 1, &iRTV, NULL );	// NULL, NULL の設定
iRenderTargetView->Release();
iDepthStencilView->Release();

次にリサイズ。サイズに 0, 0 を渡すと、Window の ClientRect
にあわせてくれます。(ここでは WindowMode のみ対象にしています)

iSwapChain->ResizeBuffers( 2,
	0, 0,	// ClientRect を参照する
	SwapChainDesc.BufferDesc.Format,	// Format は DESC から
	0 );

必要なバッファを作り直します。この手順は最初の初期化時と全く
同じなので、共通化しておいたほうが良いです。
BackBuffer と DepthStencil の作成

// back buffer
ID3D10Texture2D*	iBackBuffer= NULL;
iSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ),
		reinterpret_cast( &iBackBuffer ) );
iDevice->CreateRenderTargetView(
			iBackBuffer, NULL, &iRenderTargetView );
iBackBuffer->Release();

// depth stencil buffer
ID3D10Texture2D*	iTexture= NULL;
D3D10_TEXTURE2D_DESC	tex2ddesc= {
	width, height, 1, 1,	// width, height, mip, array
	DXGI_FORMAT_D24_UNORM_S8_UINT,	// format
	{	1,	0,	},	// sample
	D3D10_USAGE_DEFAULT,
	D3D10_BIND_DEPTH_STENCIL,
	0,	// cpu flags
	0	// misc flags
};
iDevice->CreateTexture2D( &tex2ddesc, NULL, &iTexture );

D3D10_DEPTH_STENCIL_VIEW_DESC	vdesc= {
	DXGI_FORMAT_D24_UNORM_S8_UINT,
	D3D10_DSV_DIMENSION_TEXTURE2D
};
iDevice->CreateDepthStencilView(
		iTexture, &vdesc, &iDepthStencilView );
iTexture->Release();

g_iDevice->OMSetRenderTargets( 1,
	&g_iRenderTargetView, g_iDepthStencilView );

忘れてはならないのが Viewport の設定です。
またここでは書いていませんが、ProjectionMatrix も再計算が必要です。

// viewport
D3D10_VIEWPORT	viewport= {
	0, 0, width, height, 0.0f, 1.0f
};
iDevice->RSSetViewports( 1, &viewport );

WM_SIZE でサイズが変わったことを検知したら、これらの処理を
呼び出します。アイコン化最小化などもきちんと区別しておかないと、
サイズ (0, 0) に対してリサイズが発生してしまうので注意。

またリサイズによって VRAM が足りなくなり、速度が極端に低下する
可能性も考えられます。場合によっては、極端な速度低下を検出したら
元のサイズに戻す処理も入れた方が良いのかもしれません。