DirectX一覧

透明ウィンドウとWindows8

ようやくWindows8が発売されていろいろと話題になっているようですが、Aeroがなくなってしまった点は個人的に残念に思います。また、このAeroがなくなったことで、透明なウィンドウの扱いがちょっと困ったことになっているように見受けられます。

参考: http://umezawa.dyndns.info/wordpress/?p=3335

Windows Vista/Windows7 では、DWMの機能をつかってうまく実現できていたようですが、これが半透明は無効状態になったことで出来なくなったのかなと思います。

具体的に出来なくなっているように見られたのが、DirectXやOpenGLを用いた結果をデスクトップ上に半透明を有効にした状態での合成という点です。単純にアルファ無しの不透明で、背景を抜くような方法についてはうまくいくようです。

今回DirectX用に使ったサンプルは DWMTestという下記のサイトで公開されていたものを利用させて頂きました。

参考: http://nyaruru.hatenablog.com/entry/20060628/p2

また、OpenGL用には自分で作ったプログラムです。うまく行かなくてちょっと試行錯誤していたので、こちらはWin7ではかろうじて動いているもののもしかしたらよくない作りをしているかもしれません。

これらのプログラムをWindows7で動かすとこのようになります。

どちらの場合もDirectX, OpenGLでのアルファ付き描画の結果を、透過なウィンドウに対してうまく動いているように見えています。

これらをAeroをOFFにして動かす(ベーシックやクラシックのテーマで動かす)と、以下のようになります。

透過して欲しいところが全く抜けていない状態となっています。

さて、これをWindows8で動かしてみて画面をキャプチャしてみます。

このキャプチャ結果を見ると一見うまく動いているようにみえますが、先ほどの結果と比較すると色がちょっとおかしいことに気付くと思います。DirectXのほうは概ね問題ないように見え、OpenGL側はちょっとアルファが効き過ぎている、そんな感じでしょうか。

しかし、キャプチャしたデータではなく実際に動かすと、これらの両方ともの透明部分が妙な動きをするのです!それゆえどちらも正常に動いているとは言いがたい状況です。この部分は参考(1)のサイトさんのほうに詳しくかかれています。

まとめ

どうも今までの作りでうまくいっていた半透明ウィンドウ(透過型のアプリ)はちょっと作りを考え直さないといけないのかもしれません。Vista, Windows7とAeroの流れはどうやらここで終わりのようです。半透明のウィンドウ枠は結構好きだったので残念です。

※ Windows8でもこれらDirectXやOpenGLを併用した半透明でもうまく合成できる方法をご存じの方は教えて頂けるとうれしいです。


スキニングメッシュのバウンディングボックス

久しぶりにスキニングメッシュ(エンベロープモデル)のネタです。
キャラクターのモデルでバウンディングボックスやスフィアを使って、あたり判定を行っていましたが、
結構無駄な部分が出来てしまい、結果厳密なチェックが出来ないという残念な結果になってしまいます。

かといって、頂点変形をCPUで全ての頂点で行って厳密なバウンディングボックスを作るのもこのご時世に何かあっていないようなそんな気がします。今だとシェーダーでスキニングロジック実装しちゃいますしね。

そんなわけでもう少しまともなバウンディングボックスを作れないかチャレンジしてみました。今回はこの中身に触れたいと思いますが、まずは処理結果の図を以下に示します。

割と各部位に従ってボックスが出来ているのがわかると思います。これが動きに合わせて追従してくれるので、使い勝手はよいかなと思っています。ボックス自体の頂点情報は固定で、単にボーンの行列に合わせて変形されるので処理も結構軽い物となっています。

処理手順

画像を見てもわかるようにDirectXサンプルの定番 tiny.x を使用しています。
そして、SkinnedMeshサンプルの改造です。

  1. 各ボーンの影響頂点群を取得して、各頂点で一番大きなボーンはどれなのかの情報を保持します。
    D3DXにはこの操作に便利な GetBoneInfluence, GetNumBoneInfluence というID3DXSkinInfoのメンバ関数が用意されているので楽に処理できます。
  2. 各頂点を走査して、自身が一番影響を受けるボーンのボーン行列と頂点位置を乗算します。
  3. 計算されたボーンローカルの位置で、そのボーンがもつバウンディングボックス情報を更新します。
    位置が最小、最大なら現在の値で置き換えるという処理。

これらの処理により、各ボーンが自分の影響する範囲でのバウンディングボックスを構築することが出来ます。

その他

動かしてみていると若干つなぎ目部分で隙間が出来ていたりします。
あたり判定に使うにはちょっとまずい場合があるのかもしれません。
あと、ConvertToIndexedBlendedMesh でメッシュを更新したあとだと、GetBoneInfluenceで返ってくる値と食い違いが出て悩みました。どうやらこれは変換前の頂点データ群についての結果を返してくるようです。
変換前後での頂点のマップを用意して処理してあげることが必要でした。


VisualStudio 2012とDirectX SDK

どうやらVisualStudio2012を使う状況においては、DirectXSDKにも注意が必要のようです。
VisualStudio2010を使う際にもDirectXSDKの諸注意がありましたが、2012においても同様に注意が必要のようです。

まず結論からいうと、うまく動作するDirectX SDK にはある範囲があるようです。
手元にインストールしてあったSDKを調べてみるとこんな感じです。

  • DirectX SDK 2008 Nov NG
  • DirectX SDK 2009 Aug OK
  • DirectX SDK 2010 June OK

以下、失敗したときの参考事例と言うことでメモっておきます。

よく言われているのがDXSDK_DIRのインクルードを設定する部分です。
プロジェクトのプロパティで”C/C++” / “追加のインクルードディレクトリ” に $(DXSDK_DIR)Include を追加すると下記のようにエラーが出ます(一部抜粋)。

これについては、プロジェクトのプロパティから、
“VC++ディレクトリ”/”インクルードディレクトリ”の末尾に、$(DXSDK_DIR)include を追加してあげることでエラーが消えます。

しかし、先ほど言ったようにこれだけでは不完全でした。
XAudio2.hをインクルードするソースコードだとこの対策をしても下記のようなエラーが環境によっては出てしまうことがあります。

これは、_WIN32_WINNT がどこかで定義されていることが原因です。
それがVisualStudio2012が標準で参照するWindowsSDKDirの中にあるXaudio2.hでエラーとなっています。このヘッダでは_WIN32_WINNTはWindows8の値がくることを想定しているようです。

よって、このままではWindows8以外を想定したビルドは通りません。
WindowsXP~7等で動作するアプリケーションのためにはDirectX SDKに含まれているXAudio2のヘッダを使う必要がありそうです。

このためには、DirectXのヘッダを読み込む優先順をあげる必要があります。
それは先ほどの$(DXSDK_DIR)Includeを設定した部分にあります。
優先順をあげて、VisualStudio2012の標準ヘッダ群より先にするために、”C/C++”/”追加のインクルードディレクトリ”のほうに設定します。ただし、2008Novのバージョンではエラーとなったことを上記の方で既に体験しています・・・・。

そこで、DirectX SDKのバージョンを上げてみます。2009Augではどうだろうか、と。
試してみたところ、うまくビルドが通りました。
インクルードの順序を確認してみましたが、DirectXSDKのほうのヘッダを参照していることも確認できました。

同様に2010Juneでも確認してみましたが、同様に成功しました。

まとめると、DirectXSDKを正しく使用するためには以下の手順となります。

  1. DirectX SDKは2009Aug以降を使用すること。できれば公式にVisualStudio2010対応してるとされていた2010Juneがよいと思います。
  2. DirectXSDKのインクルードパスの設定は、プロジェクトのプロパティのVC++ディレクトリに対して行わず、”C/C++”の”追加のインクルードディレクトリ”にて行うこと。

この2点が大切です。
これを守らないと変なインクルードの順序となり、予期せぬ不都合が起こるかもしれません。

チェック環境

  • Windows7 Pro SP1 (x64)
  • VisualStudio 2012 RTM
  • DirectX SDK  2008Nov, 2009Aug, 2010Jun

現在はもっと新しい記事があります。
VisualStudio 2012とDirectX SDK 再び


remoteFX環境下で試してみた

ちょっとだけ調べてみました。
動作環境ではRADEON5450を搭載しています。

Fetch4は使えるのか?

使えないです。

DepthTextureは使える?

使えるようです。

まとめ

やはりGPUを抽象化した別のデバイスとしてみえるため、
ベンダ拡張の機能がまだ強い物は扱えないようです。
Fetch4もダメとなるとNVIDIAのTransparency Antialiasもダメだろうなぁ。

ついでに、デバイスが別物なのでCUDA,(GPU側の)OpenCLもダメかなと思います。


DirectX11とDirectX9比較

DirectX11(D3D11)はDirectX9ハードウェア上でも動きます。
そういう場合に、DirectX11とDirectX9ではどちらを選択すべきだろうか、と思ってちょっと比較をしてみようかと思います。

チェック環境

  • RADEON HD 5450(DX11対応ハード)
  • Geforce9600GT
  • Geforce6800GT

サンプルプログラムとしてBasicHLSL11というSDK付属の物を使います。
これを実行してFPSの計測を行います。

チェックしてみる項目は以下の通り

  • D3D11デバイスでD3D_FEATURE_LEVEL_11_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_10_0
  • D3D11デバイスでD3D_FEATURE_LEVEL_9_3
  • D3D9デバイス

結果

それぞれの場合でFPSを計測すると以下のようになりました。
(解像度は800×600)

条件 FPS値(5450) FPS値(9800GT) FPS値(GF6800)
D3D11+D3D_FEATURE_LEVEL_11_0 1170
D3D11+D3D_FEATURE_LEVEL_10_0 3625
D3D11+D3D_FEATURE_LEVEL_9_3 1220 4183 1604
D3D9 965 1367 1201

D3D9 vs D3D11では、圧倒的にD3D11の方が高速に動作しているようです。
そして貧弱なハードウェアだからか、レベルを落とした方が若干高速でした。
この結果を見ると、DX9とDX11(9_3レベル)を悩むならDX11のほうがよいと言えます。


ハードウェアシャドウマップをやってみる -エラー編-

うまく行きそうで失敗

AMD RADEON 5450の環境でもハードウェアシャドウマップが使える*1というので
ちょっと試してみました。
しかしながら、DirectXのデバッグランタイムを使用すると
エラーメッセージが表示される結果となってしまい現在調査中。

同プログラムはNVIDIA製グラフィックボード使ったときには正常だったのですが。

表示されるエラーメッセージは以下のようなものです。

ちなみに、デプステクスチャは、D24S8で作成していましたが、D24X8でも同様。
D16にすると上記のメッセージは出なくなるのですが、出来ることなら24bit精度使いたいと思いますし、
いったい何が悪いのかをしばらく調査しようかと思います。

デプステクスチャ
512×512 D24S8, D24X8 エラーメッセージが出る
512×512 D16 正常

動作環境としては、Windows7(x64), Catalyst 10.7、DXSDK2009Aug を使用しています。
なお、NVIDIA環境では260.99ドライバで9800GTを用いています。

ちなみにメッセージは表示されますが、画面の描画結果は正常だったりします。エラーのメッセージさえ見られなければ、どうということは無いのかもしれません(笑

*1 : Advanced DX9 Capabilities for ATI Radeon Cards.pdfを参照してサポートの状況を確認しています。

動作チェック予定

現在の症状から、以下の変更を行ってみて症状が改善するかを試みる方針です。

  • DXSDKの更新
    • 2010Juneあたりでやってみるといいのかも
  • ドライバの更新
    • Catalyst 10.11などは安定しているという噂も(ミドルレンジはという制約ありで)
  • 動作OSの変更
    • 32bit版Win7
    • Vista, XP
    • これらの環境ではどうなのだろうか

D3DPOOLについて考える

今回はDirectX9でのD3DPOOLについて考えてみました。
最近はDX10の話だったので、ちょっと流れをぶち切ってしまいました。
以下の話は、すべてWindowsXP DirectX9での話となります。
Vista以降のDirectX9Exの話はまた異なるため、そのうちにでも。

説明

http://msdn.microsoft.com/ja-jp/library/ee418784%28v=VS.85%29.aspx
このページを見てしまってから思い悩むことになってしまいました。
今までは、以下の方針でリソース作成を行っておけばいいと思っていたのですが。

  • 途中で更新するデータである
    • → D3DPOOL_DEFAULT + DYNAMIC付き
  • 上記以外
    • → D3DPOOL_MANAGED

この背景には、D3DPOOL_MANAGEDであればデバイスロスト時の処理が楽になる点と、
実際にはVRAMへ転送済みであるということを想定していたからでした。

しかし、この理解は若干間違っているというのが、図によって分かりました。

  • D3DPOOL_DEFAULT
    • VRAM上かAGPメモリに配置される
    • DYNAMICリソースであればAGPメモリに配置される
  • D3DPOOL_MANAGED
    • VRAM上かAGPメモリ上、それとシステムメモリにバッキングストアとして配置される

このようになっていることが図から読み取れます。

理解が間違っていたのはD3DPOOL_DEFAULTは常にVRAMと思っていた点でした。

まとめ

さて、これらの点からどのようにリソースを配置していくべきかを考えてみました。

PC用と想定すれば、実際に動かされる環境はまちまちなので、ドライバに任せる部分は任せて、
多少の動作速度改善に向けた配置を心がけるのが良さそうです。

  • 途中で更新するデータ
    • 頂点orインデックスバッファなら D3DPOOL_DEFAULT + DYNAMIC付き
    • テクスチャなら D3DPOOL_DEFAULT + D3DPOOL_SYSTEMMEMの2重持ち
      • SYSTEMMEMに更新したいデータを埋めて、あとで転送する方式にします
  • データは最初から終わりまで不変
    • D3DPOOL_MANAGEDで配置。
    • D3DPOOL_MANAGEDはドライバによって実際に配置される場所が決定される。
    • この配置決定には、パフォーマンスや使用状況も考慮されるためお勧めの模様。

注意点としては、上記の動的なデータというのは限りなく少なくしておくべきという点でしょうか。
今回ドキュメントを読んで知ったのですが、MANAGEDとDEFAULTの混在はビデオメモリの断片化を招き、よろしくないとのことです。
DEFAULTを先に作成し終えてから、MANAGEDリソースを作るのが良いとのことです。

もしも対象としている動作環境が VRAM 256MB必須 としてしまい、それ以下の搭載メモリの状況では動作を保証しないというのであれば、
D3DPOOL_MANAGEDを使用する代わりにDEFAULTでもいいのかなと思います。
デバイスロストのときには、データを再度読み込むか、あるいは、SYSTEMMEMで最初から持っておくとかそういうようにして準備する必要はあると思います。
実際にDEFAULT+SYSTEMMEMの両方持っているという状況はOpenGLでは(実装の上では)このようにやっているように見えます。
(メモリの使用状況を見ていると、倍くらい使用メモリが多いので)。


HW ShadowMapのために。

HW ShadowMapのために最近の状況をしらべてみました。

  • NVIDIA
    • Geforce7x00くらいのころから搭載*1
    • テクスチャとしてUSAGE_DEPTHSTENCIL付きでD24S8フォーマットで作成可能
    • これをサンプリングするときに4近傍からの平均がとれてしまう。
  • AMD
    • fetch4
      • X1800以外のX1xxxシリーズで使用可能
      • このとき、DF24というフォーマットでテクスチャを作れる
      • このサンプリング時にfetch4機能で4サンプルとって、シェーダー内で平均算出
    • 通常のD24S8テクスチャ
      • RADEON 2000以上で使用可能になっているよう
      • サンプリング時に4近傍からの平均が求まってしまう。

このような相違があります。

では多くの環境でHWシャドウマップ技術を使うには、という点を考えてみます。

*1 : 6×00系ですでに使えたかも

多くの環境でHWシャドウマップ技術を適用するには

まず、環境がNVIDIAかAMDかで振り分けます。

NVIDIA時

D24S8形式のテクスチャ(USAGE_DEPTHSTENCIL付き)が使えるかを調べます。

もし使えないようならば、完全ソフトウェアのシャドウマップを使うしかありません。

AMD時

  1. D24S8形式のテクスチャが使えるかを調べます。
    1. これが使えるのはRADEON 2000以上です。PCFが有効でデプス値はサンプリングだけから求まります。
    2. 使えるならこれを使用します。使えない場合に以下に続きます。
  2. 続いてfetch4機能が使えるかを調べます。
    1. 使えるのは、RADEON X1x00以降です(1800を除く)。PCFはかからないので、自前で平均を計算します
    2. 使えるならこれを使用します。使えない場合に以下に続きます。
  3. 完全ソフトウェアのシャドウマップを使用します

このような感じで適用すべき機能が振り分けられると思います。
ここでいう完全ソフトウェアのシャドウマップとは、
D3DFMT_R32Fなどの単一要素のカラーとしてレンダーテクスチャを作成し、カラー値としてデプスを書き込む感じになります。

まとめ

これらの方針で一度実装してみようかと思います。
現在の多くの環境では、完全ソフトウェアのシャドウマップをやらなきゃいけないということはないと思われます。
DX10対応しているハードであれば、HWシャドウマップは使えるはずですし。
そうでないにしても、fetch4くらいは使える環境が多いのではないでしょうか。

個人的には、この記事を元に、マルペケつくろ~のIKDさんがサンプルおよび、ここよりわかりやすい解説に発展させてくれないかなと、密かに期待しております。


低レベルなDirectX9

ドライバーの内部エラーについて、ここに記載がちょっとありました。http://msdn.microsoft.com/ja-jp/library/ee417865%28VS.85%29.aspx

こんな仕組みになっているけど、デバイスの破棄および再生成で処理を復帰っていうことが、
果たしてどのくらい可能なんだろうか。ちょっと疑問に思います。

でも、IDirect3DDevice9::ValidateDevice というメソッドを DrawPrimitive系の直前に挿入して、
デバイス状態を確認するという手法はなかなか良さそうに思いました。
デバッグビルドとかフラグでそんなコードになるように、元々のコードに準備をしておくのは役立つかもしれません。

コマンドバッファな話

Direct3D API 呼び出しの正確なプロファイリング (Direct3D 9)と題して、MSDNに記載を発見。
以前はどこかのWeb記事でDirectXのコマンドバッファの話を読んだ気がしていましたが。
このドキュメントの本来の意味は、タイトル通りプロファイリングの話です。
しかし、アプリケーションから実デバイスまでに設定データ類がどのように伝達するか、というのが使用されている図と、プロファイリングの注意点より読み取ることが出来ます。

ドキュメントの後方にある構成の図はなかなかわかりやすいです。
結局デバイスに到達するときには、各設定はコマンドバッファというバッファに単純なコマンドとして記録された状態になっています。
GPUはそのバッファを順番に解釈し、実行しているだけに過ぎません。

もちろん、このやりとりにはデバイス制御があるため、
カーネルモードに遷移したりするのですが、この部分まできちんと説明があるため、
このドキュメントはよく出来ていると思いました。