DirectX一覧

DDSのRGB 10bitフォーマットの罠

今更といえば今更な話なのですが、あまり情報がないようにみえたのでここにメモしておきます。DDSフォーマットの A2R10G10B10 や A2B10G10R10 の並びの画像データについて罠というか、マイクロソフトも承知のバグが潜んでいました。具体的には、チャンネルのマスクビットが逆転しています・・・。

続きを読む


VRAMの使用量を取得するライブラリ

先日公開したVRAMの使用状況をグラフ化するツールで使用しているDLL部分について、ヘッダとライブラリの形式でまとめた物を公開します。
純粋にCインターフェースで作成しているため、C#からの呼出も割と楽に実現できます。
(通常のWin32APIの呼出手続きと同じように記述が可能です)

ダウンロード

VRAMSpaceLib ver 1.00 をダウンロード
VRAMSpaceLib ver 1.01 をダウンロード
VRAMSpaceLib ver 1.02 をダウンロード

コード使用例

以下のような感じで使います。

使ってみて動いたor動かない、改良案、感想などありましたらコメントでお願い致します。


Windows 8でXAudio2のトラブルに出遭う 解説編

前回の日記でふれたVisualStudio 2012 + XAudio2 + Windows 8 というコンボ発動で、アプリケーションを正常に起動出来ない!という罠にはまった内容を説明したいと思います。

実は、Windows 7で使用している(できる)最新のXAudio2は、 2.7 というバージョンのもので、これは DirectX SDK 2010 Juneに含まれています。またDirectXの再頒布ランタイムをインストールすることで導入できます。
一方、Windows 8で標準で使用するXAudio2は 2.8 というバージョンのものになります。これは VisualStudio 2012付属のWindows SDKを使用してアプリケーションを作成するとこちらを使うようになります。

標準状態の Windows 8 では、XAudio2は 2.8 のものだけが入っており、従来のDirectX SDKを使用していると 2.7のものを要求するために動作しません。
.Net framework をインストールした後で、DirectXのランタイムをインストールすると、Windows 8でも動作するようになりますが、これをアプリケーションを単に動かしたい人々がやるには手間もいいところです。
できるなら、そのままアプリケーションが動くのを目指したいところです。

これを表にするとこうなります。

DirectX SDKを使ってXAudio2 Windows 8ではそのまま動作しない
VS2012のWindowsSDKでXAudio2 Windows8では動作、Windows7では動かない

Windows7までの環境では対応したDirectX再頒布パッケージがあるのでそれをインストールすることができます。
ただそれらをインストールすること無しで XPから8まで、単一アプリケーションとしてサウンドを再生するには、実はDirectSoundを使用すると良さそうです(XPの標準状態でもDirectSoundは含まれていました)。

おそらくVista以降のDirectSoundはXAudio2より上位にレイヤーとしては位置付けられているようなので、
これを使うことでXAudio2に関係する依存関係を断ち切ってくれそうです。
ただし、DirectSoundは既にレガシーなAPIとなっているため、そのあたりが懸念事項でしょうか。
ただ互換性の点からOSから使用できない・削除されているわけではないため、XPから8まで一応使うことは出来るようです。

※ そのため単一アプリとして提供する際にはとても都合がよかったり。

DirectX9とXAudio2と。

D3DX関連のAPIもVS2012のWindows SDKに入っていないので、DirectX9+XAudio2という構成は VisualStudio 2012での開発にとってはなかなかの鬼門といえそうです。シェーダーのコンパイルはD3DXですし、XAudio2は今回のような問題があるし。

再頒布ランタイムをとりあえず強引にででもインストールさせるのであれば、DirectX SDK 2010 Juneを使って開発しておくでOKでしょう。
なるべくなら標準の状態で開発&配布したいと考えるなら、DirectX9やXAudio2を諦めて、OpenGLとDirectSoundを選択しておくと、余計なことを考えずともどこでも動く状態の物ができあがるように思います。

Windows Vista以降だけでよいというなら、WASAPI も選択肢に上がってくるかと思いますが、これは使うのが大変なので手軽にという点も考慮するなら、やはり情報も多いDirectSoundでお茶を濁しておくのが手っ取り早いでしょう。

参考元
XAudio2 Versions


VisualStudio 2012とDirectX SDK 再び

以前の日記にて、Visual Studio 2012 と DirectX SDK (2010June) を使って開発する際の手順を書きましたが、
どうやら最近ではマイクロソフトのほうに注意書きが用意されているようです。

そのページがこちら(http://msdn.microsoft.com/en-us/library/windows/desktop/ee663275(v=vs.85).aspx)です。

基本的には、DXSDK_DIRのインクルードとライブラリを標準のものより優先されるようにすること、という以前の日記情報と同じです。
ただ上記URLの中身ではそれよりももうちょっと踏み込んで、手順が書いてありました。

  • コンフリクトするので DXGIType.h をインクルードしているコードを修正する(インクルードしないように)。
  • テクスチャ関連は DirectXTex や DirectXTK といったものを利用するように検討すること
  • 算術に関しては D3DX から DirectXMath の実装へ切り替えを検討すること
  • XInput や XAudio2 を使う場合には要注意

気になった点をざっと列挙してみました。
XAudio2は厄介そうです。 使用するDLLがVS2012とDXSDKとで異なってしまうようで・・・。
どこでも動くように、というならば DXSDKのものをつかわないといけない、ということのようです。


D3DXでERROR_MOD_NOT_FOUND

ある環境でプログラムを動かそうとしたら、D3DXAssembleShaderFromFile 関数で ERROR_MOD_NOT_FOUND というエラーコードが返ってきた!
こんなエラーは初めてで、エラーメッセージのログも何もなくとても困った・・・。

よくよく調べてみるとこのエラーは、必要なモジュール(DLL)がロードできなくてエラーとなったことを意味しており、今回の件も、確かに強引にプログラムを動かそうとしていたことが原因となっているようでした。
DirectX の再頒布ランタイムをインストールすれば問題は解決になりそうです。

追記

さらなる調査の結果、どうやらシェーダーコンパイラである D3DCompiler_XX.dll が見つからなかったために起こった模様。
これが原因だとすると、D3DXAssembleShader系だけでなく、D3DXCompileShader系やD3DXEffect系もおそらく同じようなエラーになるだろうと推測します。


透明ウィンドウ(半透明ウィンドウ)の話 その3

透明なウィンドウということで、このシリーズも第3回。今回が最後となりそうです。
ようやく Windows7,Windows8両方ともで動かせるやり方が発見できました。
なお、Windows7のAeroGlassOFF状態でも動くので、注意して実装すればWindowsXPでもこの方法でいけるのではないかと思います。

その方法は、レイヤードウィンドウを使う方法です。
これを使っての半透明ウィンドウはWindows7,Windows8ともに正常に動作することが手元では確認できました。
ただし、レイヤードウィンドウの簡単なサンプルによくあるSetLayeredWindowAttributes関数を使ってしまうと、ウィンドウ全体での半透明設定や、カラーキーによる抜き色指定になってしまうため、背景とうまく溶け込ませた半透明の処理があまりうまく出来ないため、使用しないでおきます。

半透明もうまく処理するレイヤードウィンドウの作り方としては、DIBとUpdateLayeredWindowとを使って実現します。
DIBで半透明用のメモリ上のフレームバッファを用意して、その中にデータを書き込み、その結果をUpdateLayeredWindow関数で転送して、画面に表示します。この部分はGDIに関係する処理となります。
この手順の中で、「その中にデータを書き込み」の部分ですが、レイヤードウィンドウの各ピクセルの条件において、乗算済みアルファであることを要求されるので、その点に注意しながら実装を行います。

さて、ピクセル列にまでなったデータを表示する方法はこれでわかりました。あとはこれをどう用意するかですが、これにはDirectXであれOpenGLであれ、一度書いたデータをメインメモリ上に読み直す、取得し直すことが必要になってきます。いくつかの方法はあるでしょうが、環境に合わせてパフォーマンスと相談しながら実装を検討することになるかと思います。手頃で簡単なものは、DirectXであればバックバッファをロックできるようにフラグを立ててしまうか、OpenGLならglReadPixelsの関数で読み出してしまうとか。
ただ、ラスタライズした結果を読み戻す処理になるのでそれなりに負荷がかかるのは仕方のないことでしょう。
(ただ、今はPCI-Express接続になっているし、昔のAGP接続に比べて転送がネックになることが少なくなってきている、との話もあるので実際に計測してみないことには何とも。)

結果

手元で実装したものの結果を貼っておきます。まずはWindows7で動かした物です。
背景にコードが若干見えると思いますが、これはOpenGLで実装しているものです。

一方で、これをWindows8で実行したものです。こちらはスマホのカメラで撮ったのでちょっと画質がイマイチです。

でも、どちらの場合でも描画した結果をデスクトップ上に半透明も有効にして重ねて描画できていることが確認できるかとおもいます。

 

追記

この透明ウィンドウ関連の話をされている、こちらhttp://umezawa.dyndns.info/wordpress/?p=3455 のページでもレイヤードウィンドウを使ってWindows8で期待通りに動いてくれる、とあります。 Windows8ではやはりこの方法できまり、という感じですかね。


透明ウィンドウの話 その2

アプリで透明なウィンドウっていう部分は1つのウリになる部分で、やっぱりWindows 7(Vista)でしか動かないってのはやっぱまずいと思うんですよ、ということでもう少し調べて何か方法はないかと考えてみました。以下にその考えてみた話をメモっておこうと思います。

まず、DWM OFF状態でそもそも目的の動作が出来ない時点でまずいでしょう。Vista,7でBasicテーマであっても背景透過なアプリとして動くべき。この方法を確立しなくてはいけないのかな。

続いて、Windows8でも動作できること。
挙動から完全なるDWM OFFではなさそうなので、これも厄介そう。上記のベーシックモードでも動くような実装で、こちらの方法が動くようであれば問題は一気に解決する。

現在とりあえず実験中。

前者のWindows7,VistaでのDWM OFF時の状態でも動くようにという点で、いろいろと試してみたところ、LayeredWindowならば、実装の仕方によっては正常に動くようです!
変に実装すると全く描画されないようですが・・・・。(その境目を現在調査中)

これがもしそのままWindows8で動くとすれば、問題は解決になるのかなと思います。

DirectXであれ、OpenGLであれ、レンダリング済み画像をバックバッファのロックという方法で取得して、LayeredWindow用のHBITMAP内のビットイメージに再書き込みという方法でいけるのかなと考えてます。

ちなみに GDIサーフェースに直接描くって方法は、ちょっとできないでしょう。
というのもLayeredWindowで要求される仕様が事前乗算済みアルファの形式を求めてるようで。
この処理をどうしても最後に処理してあげないといけないため、描画して終了という形にはならないのかなと思います。

※ バックバッファのロックってパフォーマンスペナルティが大きいので、どこまで実用になるかは未検証です


透明ウィンドウと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 再び