「 DirectX 」一覧

DirectX10 (D3D10)


基本からさわってみよう。D3D10

まずは2007Apr版のDXSDKをダウンロードして、サンプルを実行してみてました。
DirectX10がどう動いてくれるか、わくわくしながらサンプルを実行したのですが、

・・・意外と安定動作しない(><

ものによっては放置しておくだけで、GPUが停止し復帰しましたとのメッセージが出まくるし、プログラムの終了時にはエラーメッセージのダイアログが出るし。まだまだきちんと整備されていないということでしょうか。

あとこれは8600GTという点だからかもしれませんが、
ジオメトリシェーダー使ったサンプルが遅い!

極端に速度低下してました。CubeMapGSのサンプルなんか車モデルにしたら 5fpsくらいになってましたし。

それでも基本的にDX9と切り替えられるタイプのサンプルでは、
DX10のほうが高速動作している感じでした。FPSの向上もみられました。

Tutorial01解説もどき

自分のメモも含めて少し解説。DX9の頃と違って、かなり初期化周りも変更になっている。
Tutorial01.cppのソースを抜き出して以下に書いてみます。

※値のセット部分は省いてあるのでコピペしても動きません。

[code lang=”cpp”]
DXGI_SWAP_CHAIN_DESC sd; ZeroMemory( &sd, sizeof(sd) ); // この後、値を詰めていく
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ ) {
g_driverType = driverTypes[driverTypeIndex]; // デバイスとスワップチェインを作成.
hr = D3D10CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice );
if( SUCCEEDED( hr ) ) break;
}

// 次にRenderTargetViewを作成。リソースの種類は2DTextureってことですね
ID3D10Texture2D *pBackBuffer;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D10Texture2D ), (LPVOID*)&pBackBuffer );
if( FAILED(hr) ) return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED(hr) ) return hr;

// 作成したビューをレンダーターゲットとしてセットする
g_pd3dDevice->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );[/code]

どうやら、スワップチェインを作成を作成した後、そのスワップチェインの中にあるバッファデータを取得。

そのデータを2Dのテクスチャデータとしてバインドし直してレンダーターゲット設定している、といったところでしょうか。

Render()処理

[code lang=”cpp”]
float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
g_pSwapChain->Present( 0, 0 );
[/code]

これをみても明らかなように、レンダーターゲットに対してクリアしてます。
今まではPresentもpd3ddeviceでしたが、今回からはPresentはスワップチェインに対して操作しています。
より明確に分かれた感じがしますね。とりあえずTutorial01では、このくらいしか従来と大きく変わった部分は無さそうです。

あ、フォーマットの指定はかなり変わってました。よりデータ型を意識するものになっていました。


メモリリーク追跡


DirectXのメモリリーク

DirectXを使ったプログラムを作っていて、VRAMに確保したデータを解放せずに終了させてしまうこと、よくあることです。
特に適当に作ったプログラムや、実験を重ねて複雑になってしまったものによくあります。

そういうとき、DirectXのデバッグランタイムを使用しているのであれば、
以下のようなメッセージがプログラム終了時に表示されます

こういうときに、実はデバッグランタイムを使用していればどこのタイミングで確保したモノなのかがチェックできるらしいです。

上記の、AllocIDの部分でデバッガのブレークを貼ることが出来ますが、
手元でチェックしてみたところ、一つの目安にしかならない感じがします。

定番なのかもしれませんが、このIDの数が大きい方から処理していった方が良さそうです。
たとえば、上記AllocID=1ですと、CreateDeviceでデバイス作成したところで引っかかります。

考察としては、COMが参照カウンタ方式なため、参照された瞬間にカウンタがインクリメントされ、のちのちまで残ってしまったために、上記で表示されているのだと考えられます。

よって、数が大きいモノ、最後に参照カウンタをいじって生き残っているモノからデバッグ(解放処理?)を入れていくのは正しいのではないかと思います。


SkinnedMesh


スキンメッシュの表示

前回からチャレンジしていて、助言を元に色々と試行錯誤してました。

で、最終的にはコンバータから出力した頂点データが 固定機能のインデックス付き頂点データで、
表示させようとしている側は、シェーダーによる表示方法を選択。という不一致が原因だった模様。

コンバータから出力するデータも若干おかしいと思える箇所を SkinnedMeshサンプルを参考にして修正。
表示側も固定機能による表示方法(D3DINDEXED)を適用することでやっと表示できました。

次はシェーダーによる表示方法にチャレンジしたいと思います。ConvertToIndexedBlendedMeshによる変換作業が具体的に何をやっているかが謎ですね。固定機能にしろシェーダーにしろ特に中身のデータが変わるとは思えないのですが。

追加

シェーダー定数の個数制限のためにパレット制限がかかるということに気付きました。

基本的に26個のマトリックスしかシェーダーに転送できず、
そのためにConvertToIndexedBlendedMeshはデータを変換して、
ボーンコンビネーションを複数回に分割するということをしている模様。

tiny.xの例で言えば、固定機能時はパレット36個は1回のdrawコールでOKだったものが、シェーダーを使うと2回の描画に分かれる。コンビネーション数が2回になってました。

この分け方のアルゴリズムとかは興味ありつつも、調査はしないことにします。
とりあえずもっと先へ進みたいので。

その前にコンバーターのソースを整形しないと不味そうですが…。リークもあるし。


Xファイル解析


前回の反省点

前回のフォント問題は解決できたので、今回はDirectXのモデルファイルについて色々と。

ちなみにフォントの問題で一番引っかかったのが、
SHIFTJIS文字列→UNICODE変換時で変換できなかった文字について、
UNICODEでの”・”に変換されたため、除去に失敗してた…。

モデルフォーマット

今作っているライブラリ専用モデルファイルを作成しようと色々考え中。

DirectXのXファイルを読み込んで、自分の形式にするコンバータ作らないとなぁと思って、まずはそれを準備してみようと思って作業中。よってスキニングの仕組みを改めて調査&勉強してみたり。

スキニングモデルと単なるポリゴンメッシュのモデル、そしてアニメーション付き、
これらをちゃんと読み込んで変換するのはちょっと苦労しそうだ…。

アニメのことを考えると D3DXLoadMeshFromXは使えない。
D3DXLoadSkinMeshFromXofを使用するのか?と思いきや、LPDIRECTXFILEDATAは廃止に向かってるようだし、関数名変わってるし。

素直にアニメーションスキニングメッシュ読み込むサンプルをそのまま実装して、必要なデータだけ抽出するようにするか…。


インスタンシング


今日もインスタンシング

昨日に引き続き、今日はShaderInstancingをトライしていた。しかしHWインスタンシングに比べて動作は理解しやすい。単に形状データを繰り返し、頂点バッファを満たしておけばいい。あとはそれに対する変形パラメータを外部から叩き込めば終わり。必要回数、必要ポリゴン数になるまでdrawPrimitiveを繰り返す。

そんなわけで、さっくり実装できた。

HLSL

今は起動時で読み込んでコンパイルさせているけど、デフォルトのシェーダーくらいはlibに組み込んでしまいたいと思って色々調べてみた。どうやらバイナリのリソースとしてリソーススクリプトで記述すれば良さそうです。

GUIの操作としては、リソースのウィンドウで追加→ファイルから〜
その時の.rcの中身にはこんな風にして追記されることになります。

(グループ名を入れたかったのでそこだけは手作業)

<名前> <グループ名> DISCARDABLE “ファイル名.fx”

ここまでやって気付いたのだが、そのままバイナリファイルに組み込まれるみたい…。

さらに調べてみると .fxから .fxoを作ってしまうという方法もあるようだ。コンパイル済みシェーダーといったところか。

こちらを組み込みにすれば、先ほどよりはマシだろう。読まれたくないならば、
fxoをさらに暗号化してリソースにインポートすればいい話だし。

これには、プロジェクトに追加されている.fxファイルにコンパイルの記述を追加する。

こんな感じでコマンドライン行に追加。最初のはバージョンを決めるためのものだろう。
さらに、出力ファイルの箇所で “bin/$(InputName).fxo” と記述するのも忘れずに。

デバッグ版とリリース版で同じでも問題ないと思うけど、オプションを変更することも可能です。