■はじめに
今はもうDirectX11が出て使われ始めていますが、
今更DirectX10の勉強を始めてみました。
今回初ということで、画面のクリアをするプログラムを作ってみました。
これをベースにしていろいろと機能を触ってみようかと思います。
■DXGIのセットアップ
DXGIとはスワップチェインとか管理しているレイヤーになります。
ハードウェアデバイス列挙やフルスクリーンへの切り替えなど担当してくれます。
まずはこの初期化を行います。
初期化すると、スワップチェインとD3D10デバイスが取得できます。
やり方は以下の通りです。
[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;
// インターフェース
ID3D10Device* pDevice = 0;
IDXGISwapChain* pSwapChain = 0;
DWORD dwCreateFlags = 0;
HRESULT hr;
hr = D3D10CreateDeviceAndSwapChain(
NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL,
dwCreateFlags, D3D10_SDK_VERSION, &sd,
&pSwapChain, &pDevice );
[/cpp]
初期化に必要なパラメータを構造体に詰めて、D3D10CreateDeviceAndSwapChainを呼び出します。
D3D9の頃と比べるとこの部分は楽になったような気がします。
■バックバッファの取得とメインとなるカラーバッファの取得
デバイス生成するとバックバッファが1つ付いてきます。
これを通常の描画先とするために、ビュー(RenderTargetView)を取得します。
その取得している部分は以下のようになります。
[cpp]
ID3D10Texture2D* pBackBuffer = 0;
ID3D10RenderTargetView* pRenderTargetView = 0;
hr = pSwapChain->GetBuffer(
0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer );
hr = pDevice->CreateRenderTargetView(
pBackBuffer, NULL, &pRenderTargetView );
pBackBuffer->Release();
pBackBuffer = 0;
[/cpp]
バックバッファは2次元テクスチャの扱いで、
この中身にアクセスするためのビューと作成しています。
普段のクリアで使うのは、ビューを用いて行うので、
作成が終わったらpBackBufferは使わないため解放しています。
■デプスバッファとステンシルバッファ
カラーのバッファについては標準で付いてきたのですが、
デプスは自分で作らないといけないようです。
デプスとステンシルについては扱い的に2Dテクスチャとなっているようで
まずはこれの作成から開始します。
このテクスチャを作った後はバックバッファと同じようにビューを作成します。
[cpp]
// デプスとステンシル
ID3D10Texture2D* pDepthStencil = 0;
ID3D10DepthStencilView* pDepthStencilView = 0;
D3D10_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 = D3D10_USAGE_DEFAULT;
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL;
hr = pDevice->CreateTexture2D(
&descDepth, NULL, &pDepthStencil );
D3D10_DEPTH_STENCIL_VIEW_DESC descDepthView;
ZeroMemory( &descDepthView, sizeof(descDepthView) );
descDepthView.Format = descDepth.Format;
descDepthView.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;
descDepthView.Texture2D.MipSlice = 0;
pDevice->CreateDepthStencilView(
pDepthStencil, &descDepthView, &pDepthStencilView );
[/cpp]
■ビューポートの設定と標準の描画先の設定
若干構造体が変わっていますがD3D9のころと中身は変わりません。
ここで先ほど作成した2つのビューをデバイスに設定しておきます。
[cpp]
D3D10_VIEWPORT vp;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = 640;
vp.Height = 480;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
pDevice->RSSetViewports( 1, &vp );
pDevice->OMSetRenderTargets(1, &pRenderTargetView, pDepthStencilView );
[/cpp]
■画面のクリア処理
クリア処理は、デバイスに対して行うという感じではなく、
デバイスに対して、クリアするビューを設定して行う、という感じになっています。
[cpp]
// クリア処理
float clearColor[4] = { 0.5f, 0.0f, 0.0f, 0.0f };
pDevice->ClearRenderTargetView(
pRenderTargetView, clearColor );
pDevice->ClearDepthStencilView(
pDepthStencilView,
D3D10_CLEAR_DEPTH |D3D10_CLEAR_STENCIL, 1.0f, 0 );
pSwapChain->Present( 0, 0 );
[/cpp]
メインのループでこの記述をすれば画面のクリアが行われ、
今回赤い色が表示されます。
■後始末
今まで取得した&作成したインターフェースに対して、
Releaseを呼び出していきます。
pRenderTargetView->Release(); pDepthStencilView->Release(); pDepthStencil->Release(); pSwapChain->Release(); pDevice->Release();
■感想
画面のクリアまでならば、D3D9の頃と比べて遙かに楽でした。
若干概念が変わっている部分については最初こそ戸惑いましたが、
そういうものだと理解してしまえば引っかかるような場所でもありません。
ビューとは、バイナリデータを解釈するものである、と自分は理解しました。
このバイナリデータというものがテクスチャであり、リソース群を示します。
よって、解釈対象であるビューに対してクリアなどの操作指示を行うのだと。
この2段構えな感じがD3D10の特徴なのかもしれないと思います。
そしてこのせいでD3D9ほど素直な感じがしないのだとも感じます。
■ソースコード
適当に書いた初回D3D10のソースコードです。
自動生成されるコードに今まで説明した部分付け加えて、
そして、描画ループがまわるようにした程度の簡単なものです。
何かの役に立つかな・・・