Direct3D 10 ss00 サンプルの解説 (1)

以前掲載した D3D10 のサンプルプログラム ss00 を少々解説します。
ss00.cpp 以外にライブラリやら DXUT も使わず、できるだけ
Direct3D 10 の API だけで済むようコードを減らしていったものです。
それでも初期化は思ったより長い関数になりました。
Direct3D 10 シェーダー4.0サンプルプログラム

あらためてゼロから書いてみると結構手間がかかりますね。
それでも DirectX3~6 あたりまでと比べると、シェーダーが必須になった
だけで、初期化自体は簡単になっているはずです。

ソースはこちらからどうぞ
HYPERでんち

動作には Vista + DirectX10 対応 GPU が必要です。

ss00.cpp

●初期化 InitDevice()

InitDevice() は初期化を行います。

Direct3D10 で最初に必要なインターフェースは次の2つです。

ID3D10Device
IDXGISwapChain

この2つは名称が異なるものの、D3D10CreateDeviceAndSwapChain()
関数一発で簡単に作ることができます。
D3D10CreateDeviceAndSwapChain()

DirectX9 以前のように、Device の前に IDirect3D を作る必要がなくなりました。
IDirect3D が行っていた Display 周りの選択や制御が DXGI に移行した形と
なっています。

D3DX10CreateDeviceAndSwapChain() 作成時に与えるパラメータは、
Direct3D9 の D3DPRESENT_PARAMETERS とほとんど同じです。
D3DPRESENT_PARAMETERS
ここは Direct3D9 のコードを基にしていても比較的容易に対応できる
部分でしょう。

フレームバッファのサイズ、リフレッシュレート、フレームバッファのフォーマット、
フロントバッファへ反映させるときのエフェクトやタイミング、フルスクリーン
かどうか、などを与えています。

DXGI_SWAP_CHAIN_DESC swapdesc= {
 {
  width, height, // フレームバッファサイズ
  { 60, 1, }, // リフレッシュレート
  DXGI_FORMAT_R8G8B8A8_UNORM, // フォーマット
  DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED,
  DXGI_MODE_SCALING_UNSPECIFIED,
 },
 { 1, 0, }, // sample
 DXGI_USAGE_RENDER_TARGET_OUTPUT,
 1,
 hwnd, // Window ハンドル
 winmode, // WindowMode か FullScreen か
 DXGI_SWAP_EFFECT_DISCARD,
 0
};

D3D10CreateDeviceAndSwapChain(
 NULL,
 D3D10_DRIVER_TYPE_HARDWARE,
 NULL,
 D3D10_CREATE_DEVICE_DEBUG,
 D3D10_SDK_VERSION,
 &swapdesc,
 &g_iSwapChain, // IDXGISwapChain
 &g_iDevice // ID3D10Device
);

ID3D10Device と IDXGISwapChain ができたら View を作ります。
この View は Direct3D10 になって登場した新しい概念です。
メモリ上のテクスチャ空間に対して、実際にどのような手段で Shader が
アクセスするのか決定します。
リソースの自由度が上がった分、具体的にどのような使い方をするのか
ひと手間必要になったわけですね。

IDXGISwapChain から BackBuffer を取り出し、Direct3D からアクセスするための
ID3D10RenderTargetView を作成します。

ID3D10Texture2D* iBackBuffer= NULL;
g_iSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ),
  reinterpret_cast( &iBackBuffer ) );
g_iDevice->CreateRenderTargetView( iBackBuffer, NULL, &g_iRenderTargetView );
ZRELEASE( iBackBuffer );

次に Depth Buffer を作成しています。
ここでは何も考えずに Stencil のない D3D10 新フォーマットと思われる
D32_FLOAT を使っています。

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

D3D10_DEPTH_STENCIL_VIEW_DESC vdesc= {
 DXGI_FORMAT_D32_FLOAT,
 D3D10_DSV_DIMENSION_TEXTURE2D
};
g_iDevice->CreateDepthStencilView( iTexture, &vdesc, &g_iDepthStencilView );
ZRELEASE( iTexture );

初期化はこれでおしまいです。

ここからは実際にレンダリングに必要な設定を行います。
今回は非常に単純な描画なので、特に毎フレーム実行しなくても良い処理を
初期化の部分に書いてしまっています。
シェーダーの生成以外の部分、パラメータ設定関連は、必要であれば1フレーム
の描画中に何回か書き換えることになるでしょう。

// レンダーターゲットの設定
g_iDevice->OMSetRenderTargets( 1,
  &g_iRenderTargetView, g_iDepthStencilView );

// ビューポートの設定
D3D10_VIEWPORT viewport= {
 0, 0, width, height, 0.0f, 1.0f
};
g_iDevice->RSSetViewports( 1, &viewport );

これら関数はどちらも一度に複数個登録できます。今回は1つだけなので
定数 1 を最初に渡しています。

// shader の作成
ID3D10Blob* iblob= NULL;
if( FAILED( D3DX10CreateEffectFromFile(
  TEXT(“cube.fx”),
  NULL, NULL, “fx_4_0”, 0, 0, g_iDevice,
  NULL, NULL, &g_iEffect, &iblob, NULL ) ) ){

 OutputDebugStringA( reinterpret_cast(
   iblob->GetBufferPointer() ) ); // エラーが発生したら表示
 ZRELEASE( iblob );
}

ここでは fx ファイルから Shader を作成しています。
今回のサンプルでは ID3D10Effect をそのまま使っています。
HLSL のコンパイル時にはエラーが発生することがあるので、
コンパイラのエラーメッセージをそのまま表示出力しています。

最後に Effect の変数を初期化しています。

// projection の設定
D3DXMATRIX projection;
D3DXMatrixPerspectiveFovLH( &projection, 3.141592f/3.0f,
 WINDOW_SIZE_WIDTH/(float)WINDOW_SIZE_HEIGHT, 1.0f, 10000.0f );
g_iEffect->GetVariableByName( “Projection” )->AsMatrix()->SetMatrix( (float*)&projection );

次回は残りの処理と描画です。