DirectX11始めました

■はじめに

Windows7 SP1やVisualStudio2010 SP1が出ている現在において、未だにDirectX11を扱うプログラムコードを作ったことがありませんでした。2011年4月と”11″繋がりで、ちょっとDirectX11を始めてみました。

いつものことですが、画面をクリアするまでの最小限サンプルをまずは作ってみようと思います。

昨年夏にDirectX10の記事も同じように書いたので、
DirectX10とDirectX11でどんなふうに変わったかも気付く範囲で書いてみます。

■プログラムの流れ

手順としては以下のように実装をしていきます。

  1. スワップチェインとD3D11デバイスのセットアップ
  2. バックバッファを描画対象とするための設定
  3. バックバッファに対するデプス・ステンシルの準備
  4. 準備したデータを描画対象に設定
  5. メッセージループ
    1. バックバッファのクリア
    2. 表示バッファの更新

■D3D11デバイスの作成

まずDXGIでスワップチェインの準備を行います。
DXGIはD3D11よりも低位に位置し、グラフィックスハードウェアの情報を扱うレイヤーになります。
スワップチェインはこのレイヤーに属します。
また、画面の解像度等を取得したいとき、フルスクリーン表示にしたいときにもDXGIにお世話になります。

[cpp]
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof(sd) );
sd.BufferCount = 1;
sd.BufferDesc.Width = 640;
sd.BufferDesc.Height = 480;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWindow;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
[/cpp]

このDXGIの設定についてはDirectX10のDXGIの設定をほぼ変わっていないようです。

続いて、機能レベルの設定です。
DirectX11では多くの環境で動作させることが出来るように設計されているので、
プログラムがハードウェアのサポート範囲をどこまでにするかを決めるために必要です。
ここでは以下のようにして、範囲を絞ってみました。

[cpp]
// 要求する順番に並べる.
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3,
};
UINT nLevelCount = sizeof( featureLevels ) / sizeof( featureLevels[0] );
[/cpp]

*デバイスの作成

スワップチェインの設定と、機能レベルの設定を引数に設定して、
DirectX11のデバイスを作成します。
他の項目も色々とありますが、多くの場合はこのようなコードになると思います。

[cpp]
D3D_FEATURE_LEVEL supportLevel; // デバイス生成時に選択された機能レベル.
ID3D11Device* pd3dDevice = 0;
IDXGISwapChain* pSwapChain = 0;
ID3D11DeviceContext* pImmediateContext = 0;
// デバイスの作成.
HRESULT hr = D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
0,
featureLevels,
nLevelCount,
D3D11_SDK_VERSION,
&sd,
&pSwapChain,
&pd3dDevice,
&supportLevel,
&pImmediateContext );
[/cpp]

DirectX11からデバイス以外にも必要になるDirectXのオブジェクトがあります。
それは、上記のコードでいう pImmediateContext です。
どちらかというと、従来の環境でのデバイスはこのpImmediateContextが担当する感じです。

また、supportLevelの値を確認することで生成されたデバイスおよびコンテキストがどの機能レベルなのかを知ることが出来ます。

■バックバッファの準備 -カラーバッファ設定-

DirectX11ではDirectX9と違い、バックバッファのカラーバッファの設定を自分でおこなう必要があります。
デバイス生成状態ではバックバッファは1つ存在します。
これを描画先とするために、ビュー(RenderTargetView)を作成します。

このビューを作成するまでのコードは以下のようになります。
この部分はDirectX10のときと全く同じです。

[cpp]
ID3D11Texture2D* pBackBuffer = 0;
ID3D11RenderTargetView* pRenderTargetView = 0;
hr = pSwapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer );
if( FAILED(hr) )
{
OutputDebugStringA( “GetBufferで失敗.\n” );
}
hr = pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &pRenderTargetView );
if( FAILED(hr) )
{
OutputDebugStringA( “CreateRenderTargetView [Backbuffer] failed.\n” );
}
if( pBackBuffer )
{ // バックバッファはもう使わないので解放.
pBackBuffer->Release();
pBackBuffer = 0;
}
[/cpp]

■バックバッファの準備 -デプスステンシル設定-

カラー用はスワップチェインで用意されたバックバッファでしたが、
デプスやステンシルのバッファは自分で作成する必要があります。

  1. デプス&ステンシルのテクスチャを用意
  2. そのテクスチャをバックバッファとして扱えるようにビューを作成

このような手順で行います。

[cpp]
// バックバッファ用にデプス・ステンシルの準備
D3D11_TEXTURE2D_DESC descDepth;
ZeroMemory( &descDepth, sizeof(descDepth) );
descDepth.Width = 640; descDepth.Height = 480;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
descDepth.SampleDesc.Count = 1; descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;

ID3D11Texture2D* pDepthStencil = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );

D3D11_DEPTH_STENCIL_VIEW_DESC descDepthStencilView;
ZeroMemory( &descDepthStencilView, sizeof(descDepthStencilView) );
descDepthStencilView.Format = descDepth.Format;
descDepthStencilView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDepthStencilView.Texture2D.MipSlice = 0;
ID3D11DepthStencilView* pDepthStencilView = 0;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, &descDepthStencilView, &pDepthStencilView );
if( pDepthStencil )
{
pDepthStencil->Release();
pDepthStencil = 0;
}
[/cpp]

ビューを作成したら、テクスチャのインターフェースは解放しておきます。

■描画先設定

今まで準備したバッファを描画対象として、デバイスに設定します。
デバイスに設定するのですが、pImmediateContext、すなわち、ID3D11DeviceContextインターフェースに対して設定します。

このID3D11DeviceContextに対して設定する部分が D3D10と違いますね。

[cpp]
// 作成した各ビューを描画ターゲットに設定.
pImmediateContext->OMSetRenderTargets( 1, &pRenderTargetView, pDepthStencilView );
// ビューポート設定
D3D11_VIEWPORT vp;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = 640;
vp.Height = 480;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
pImmediateContext->RSSetViewports( 1, &vp );
[/cpp]

■画面のクリア

クリア処理は、デバイスに対して行うという感じではなく、
コンテキストに対して、クリアするビューを設定して行う、という感じになっています。

[cpp]
// 画面のクリア
float clearColor[4] = { 0.0f, 0.0f, 0.25f, 0.0f };
pImmediateContext->ClearRenderTargetView( pRenderTargetView, clearColor );
pImmediateContext->ClearDepthStencilView(
pDepthStencilView,
D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,
1.0f, 0 );
pSwapChain->Present( 0, 0 );
[/cpp]

■後始末

[cpp]
if( pImmediateContext )
{ // デバイスのステートを初期状態に戻す。
pImmediateContext->ClearState();
}
if( pRenderTargetView ) { pRenderTargetView->Release(); pRenderTargetView = 0; }
if( pDepthStencilView ) { pDepthStencilView->Release(); pDepthStencilView = 0; }
if( pImmediateContext ) { pImmediateContext->Release(); pImmediateContext = 0; }
if( pd3dDevice ) { pd3dDevice->Release(); pd3dDevice = 0; }
if( pSwapChain ) { pSwapChain->Release(); pSwapChain = 0; }
[/cpp]

■感想

DirectX10をやっていれば、そこまで大きく変わった感じはしないですね。
今までデバイスに指示していたのがデバイスコンテキストへ指示と変えたくらいです。

■今回のソースコード

HelloDX11 ダウンロード

DirectXプログラミング
すらりんをフォローする
すらりん日記

コメント

タイトルとURLをコピーしました