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

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

前回の続きで、サンプル ss00 の簡単なソース解説を続けます。
Direct3D 10 ss00 サンプルの解説 (1)

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

●ウィンドウ作成 WinMain()

Windows のアプリケーションは Window を作成する必要があります。
簡単にするために、WinMain() 内部でウィンドウの作成も
メッセージループも記述してしまっています。
フレームレートの調整やウエイト等も一切せずにループしているので
ご注意ください。(一応 Sleep が入っています)

●描画 Render()

最初にフレームバッファをクリアします。

float color[4]= {
 0.0f, 0.0f, 1.0f, 0.0f
};
g_iDevice->ClearRenderTargetView( g_iRenderTargetView, color );
g_iDevice->ClearDepthStencilView( g_iDepthStencilView,
  D3D10_CLEAR_DEPTH|D3D10_CLEAR_STENCIL, 1.0f, 0 );

Direct3D9 以前までは Clear() 命令ひとつで行われていた部分です。
D3D10 では、RenderTarget と Depth Buffer それぞれ個別にクリアします。
またカラー値が R8G8B8A8_UINT ではなく R32G32B32A32_FLOAT による
指定が可能となりました。
Direct3D9 では HDR 値の初期化には Shader を使う等の別の手段が必要でした。

サンプルではデモのためにカメラを回転しているのでその計算が若干入ります。
固定ならば Effect に対して Matrix を書き込んで終わりです。

g_iEffect->GetVariableByName( “WorldToView” )->AsMatrix()->SetMatrix(
 (float*)&view );

ID3D10Effect のパラメータ類を反映させるために

g_iEffect->GetTechniqueByIndex( 0 )->GetPassByIndex( 0 )->Apply( 0 );

を実行します。Effect 内に Technique が1つしかないこと、Pass も 1つ
しかないことがわかっているなら、これだけでも十分動きます。

Direct3D10 では初期値が未登録で、描画前に必ず設定しなければならないのが
この IASetPrimitiveTopology() でした。
オーソドックスな TRIANGLELIST にします。
g_iDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

このシェーダーは頂点バッファもインデックスバッファも不要なので、
いきなり描画です。

g_iDevice->DrawInstanced( 36, 12, 0, 0 );

Cube なので Triangle ×2× 6面分=36頂点、さらに 12個のインスタンスを
描画しています。

最後は g_iSwapChain->Present( 0, 0 ); です。
Direct3D9 以前の BeginScene()~EndScene() 系が必要ないので、
D3D10 では非常にすっきりしています。

Matrix 計算、ID3DEffect への変数アクセス以外には、描画のために 5つの API
しか呼び出していません。

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 );

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

Advanced W-ZERO3[es] のキーコード調査

ようやく Advanced W-ZERO3[es] WS011SH に触ることができました。
1~2時間ほどでしたけどキーコードの調査ができました。
協力してくれた Florian さんありがとうございました。

互換性のない問題の2キー

   es  ades
[,<] BC00 BC36
[.>] BE01 BE35

上記以外は互換性がありました。
ZERO3(WS003/004SH)や EM・ONE も es と同じです。
emobile EMONE のキーコード調査

ades の新規追加キー

[半全] F346

emobile EM・ONE の利用状況

Mugen Power 3400mAh の大容量バッテリーを使い出してから
ちょうど一ヶ月です。
EMOBILE EM・ONE スーパー大容量バッテリー
バッテリーの持ちの良さは満足です。
自分の利用頻度だとぎりぎり一週間持たない程度で、ほぼ6日目の通信中に
空っぽになります。

とはいえバッテリーの分だけ本体は確実に大きく重くなっているので、
  かばんに入れる→取り出す頻度が減る
点も、長寿命化に貢献している可能性が大です。

現在の主な用途は次の2つです

・通信用 HSDPA
  NetFront v3.3
  メールもこれ

・テキストエディタ
  PocketWZ 3.0 + WM5 patch + USB外付けキーボード
  会議の議事録、メモなどもこれ

PC との同期や開発用にデバッガを使う場合は Bluetooth を使っています。
USB はノートPC のモデムとして使うため、モデムモード固定にしています。
ただ最近は ZERO[es] や EM・ONE +キーボード済ませているので、
あまりノートを持ち歩かなくなりました。
(でもUSBキーボードは持ち歩いてます)

もう1つ個人的に非常に重要なアプリとして TOMBO があります。
昔から PDA で書き込んできたメモやデータの閲覧に使っており、
15年以上前の SHARP の電子手帳で、ぽちぽちと打ち込んだデータまで
しっかり手元に残ってます。

PA-8500~ 電子手帳 「メモ機能」
 ↓
PI-3000~ ザウルス 「レポート&自由帳」
 ↓
MI-110M~ ザウルス 「レポート&自由帳」
 ↓
iPAQ h3630 PocketPC 「TOMBO」
 ~ ZERO3 ~ EM・ONE

こんな感じで上位機種へのデータ転送&乗換えを繰り返してきました。
PocketPC に乗り換えるときに、レポート&自由帳のコンバート先として
TOMBO がぴったりでした。蓄積したデータを保持するために今では
なくてはならないものとなっています。
このソフトには本当にお世話になってます。

Direct3D 10 ClearState

Direct3D10 では、SetShaderResources や SetConstantBuffers や
OMSetRenderTargets や SOSetTargets や IASetVertexBuffers など、
レンダリングに必要なリソース登録 API のほとんどが
複数設定可能になっています。
一度に登録可能なスロット数も 16だったり 128だったり、
非常に多くなりました。

Set してあるインターフェースは Release() して解放されず、
Read 用に Set してあるリソースは Write 用に Set することができません。
使い終わったら、または別の用途で設定する場合にそれぞれ
NULL を設定して登録を解除します。

API も Slot も増えたので、シーン終了時など一度に初期化するのは
結構大変になったなと思ってました。
ところがこれ、ID3D10Device::ClearState() だけでいけるようです。
こんな便利な関数があったとは。
マニュアルはきちんと読んでおいた方がいいですね。