DirectX一覧

続・ATIドライバの謎?

Direct3D9: (INFO) :Failed to create driver indexbuffer を調べてみた。
海外のForumでは割とよくあがっている話っぽい。このメッセージが意味するところは、
IndexBufferをVRAM上に作るときに、VRAM上に作れなかった、という話になるっぽい。
あとは、ドライバがハードウェアのインデックスバッファに対応していないということもあるらしい。

考えられる原因は以下の通り

  • DrawPrimitiveUPを使用した
  • HWが対応していてもドライバで無効状態

また、INFOカテゴリに入っているメッセージなので、
操作している側には特に問題はないメッセージであるとのことで無視してもよさそう。

なお、この場合のインデックスバッファは
AGPメモリやシステムメモリに確保されるような感じです。


DirectX9のRenderStateからGL読替

DirectX9のRenderState設定がGLのどれにつながるかわからないって話を聞いた。
知っている範囲で書いてみます。

DirectX9 OpenGL
D3DFILL_WIREFRAME glPolygonMode( GL_FRONT_AND_BACK, GL_LINE )
D3DCULL_NONE glDisable( GL_CULL_FACE )
D3DCULL_CW,CCW GL_CULL_FACE有効化してGL_CW,GL_CCWらも設定
D3DRS_SCISSORTESTENABLE GL_SCISSOR_TEST
D3DRS_STENCILENABLE GL_STENCIL_TEST
D3DRS_ZENABLE GL_DEPTH_TEST
D3DRS_ZWRITEENABLE glDepthMaskで設定
D3DRS_STENCILREF glStencilFuncで設定

各種比較関数、ブレンド設定の列挙値は大変なので除外で。
調べてみるとすぐにわかりそうな感じですし。

感想

OpenGL側はDirectXとちがって、必要要素を一括に設定する気配を感じる。
このほうがデバイスに値を流すのには適しているんだろう。

○○さんへ

他にこれは?というのがあれば、コメントにでも~。
知ってる範囲で追記しようかと思います。


DirectX9でATIカードに振り回される

どうもATIのグラフィックボードおよびドライバは
DirectXを正しく使わないと描画が不正になる模様。DrawIndexedPrimitiveでnMinVertex, nMaxVertexを正しく設定しないと、
それだけでポリゴンが壊れて描画されたりすることを確認できた。
ちなみにNVIDIAではこれらの情報を参考にしていないのか、
適当な値を放り込んでもきちんと動いてくれる。

症状としては、全く描画されないか、変な部分とくっついたりしたポリゴンなどが確認できたので、
動作としては未定義動作に近いのかもしれない。

環境

Core i7 870, 4GB
RADEON 5450 1GB(Catalyst 10.7)
Windows7 Ultimate(x64)

まとめ

開発環境では NVIDIAのカードがおすすめ。
ドライバで振り回されることも比較的少なめ。
でもテスト環境にATIのカードを準備しておくとよさそう。
なぜならATIの環境では、正しく命令(API)を使えているかの確認に使えそうだからである。

むしろ、NVIDIAが緩いせいか、NVIDIAのカードでしか動作確認していないと、
ATIの環境に持って行ったときにうまく動かないということが発覚しそうな気がする。

いやはや、勉強になった。


続・CubeMapGS

以前の7/29日記で、CubeMapGSの動作を書いたので、
NVIDIAのGeforce9800GTではどうだったんだろうと思ってチェックしてみた。

球体モデルの結果

カード Instancing fps値
RADEON 5450 TRUE 28.2
RADEON 5450 FALSE 38.2
GeForce9800GT TRUE 119.2
GeForce9800GT FALSE 61.2

これだけ見ると世代的には前の9800GTのほうが性能がいい。
またインスタンシングフラグの影響がそれぞれ逆転しているのも不思議。

車体モデルの結果

カード Instancing fps値
RADEON 5450 TRUE 8.8
RADEON 5450 FALSE 9.7
GeForce9800GT TRUE 44.8
GeForce9800GT FALSE 32.6

製品のレンジが違うとはいえ、ここまで差があるのか。
GSはNVIDIAの圧勝です。

まとめ

この状況を見るとGSで6面のキューブマップについては
リアルタイムに毎フレーム処理できるものではなさそうです。
せいぜいシーン初回で描いてしまうとかその程度かなと思います。
他のメリットは、レンダーパスの処理がシンプルになるというのもあるけど、
ローエンドでもこれくらいの形状ならある程度(60fps維持)の性能が出せないと、
安心して使えないですね。


Scissorによる挙動違い(DX vs GL)

DirectXとOpenGLとで、シザーの設定時のクリア挙動が異なるようです。座標系がそれぞれ異なるってのもあるけど、
そこは上下を逆転して対処したとしても、それだけでは互換動作は不可能。

フレームバッファの縦横と、ビューポートの縦横と、シザー設定の縦横
それぞれ違う設定にしてみて、双方のAPIで実行してみるとわかりやすいかと。

DirectXではビューポートとシザー設定のお互い被っている領域でクリア
GLではシザー設定に従ってクリア。

同じような振る舞いにさせるならシザー領域とビューポートの領域のAND集合を取るようにして、
できあがった矩形でシザーテストするようにしてクリア処理を入れるようにする。

GL面倒だけど、こういうった細かいことをきちんと実装できるだけ
柔軟性はあると思う。


Vertex Texture Fetchによるスキニング

Vertex Texture Fetchを利用して、スキニングメッシュのサンプルを動かしてみました。
ひにけにxnaさんのところでは、XNAを用いての解説があったので、
ここでは、普通のDirectX SDKとC++による組み合わせでこれをやってみたいと思います。

使用するもの

  • SkinnedMeshのサンプルプログラム
  • ShaderModel 3.0に対応したグラフィックボード
    • Radeon X1000シリーズを除く。これはVTFに対応していないため。

ソースコード

各準備

まずは、ボーンのマトリックスを格納するためのテクスチャを準備します。
ここではグローバルにおいて、手抜きしました。
また、毎回書き換えるので、ダイナミックテクスチャにしています。

ボーン用テクスチャの概要

ボーン用のテクスチャは、横方向に使用したいボーンの数、縦方向に4というサイズで作成しました。
というのも、行列は4x4のfloat要素で、今回のテクスチャはRGBA32Fという形式のため、1テクセルに4要素格納できます。
そのため、4テクセル使えば、1つの行列が生成できるということを目的にしています。

横方向(U方向)はボーンのインデックスを示すことにして、
V方向には行列の行を格納することにしました。
このほうが配列っぽく見えるかなと思っています。

マトリックスパレット数調整のための変換部分

またついでに、ConvertToIndexedBlendedMesh を呼び出している部分も
これらの設定のボーン数をみるように修正が必要です。

マトリックスパレットの設定部分の修正

マトリックスパレット設定部分を次のように変更します。

テクスチャにボーンのマトリックスを格納していきます。
注意点としてはテクスチャのY方向へずらすときは、ロックしたときのピッチバイト数でずらさないといけない点です。
それと、シェーダー内ではマトリックスとしては取れず、
float4の4つの組で取れる感じになります。
そのためシェーダーに送る際に転置しておきます。
こうすることで、内積を利用して計算が可能になります。

プロジェクション用行列の設定修正

サンプルのSkinnedMeshのサンプルではmViewProjというシェーダー定数に
実はプロジェクション用の行列しか送っていないです。
ビュー行列はマトリックスパレットに対して適用していました。

この部分を変更します。
mViewProjにg_matProjを設定している部分で、g_matViewとの演算結果を格納するようにしておきます。

シェーダーコード

ほとんどの部分はサンプルのそのままです。
変更点は以下の通り

  • tex2Dlodにて該当するマトリックスパレット相当のテクセルから値を取得
  • 浮動小数用にサンプラを設定
  • VTF使うために、vs_3_0を設定。あわせてピクセルシェーダーも

実行結果

こんな感じになります。
理由はピクセルシェーダーでディフューズ用のテクスチャ等を処理せず、
単純にライトの強度を出しているからです。

しかし、これがVTF利用して動いています。

今は、横方向128でやりましたが、これを256にすることで
ボーンの上限256個までを一度に使うことが出来るようになります。


発想転換、再実装

新・ConvertToIndexedBlendedMesh相当品

アルゴリズムを見直して再作成しました。
前回は4つのマトリックスパレットで分割しようとした際に、
デバッグビルドだとうちの環境で5分くらいかかって、
かつ、描画バッチ数も200弱という悲惨なことになりましたが、
新しい方はそんな状況にはならず動くようになりました。

実行速度はデバッグで計っています。

パレット数 頂点数 描画バッチ数 変換時間
4 4881 24個 4.2秒
13 4578 4個 3.3秒
26 4474 2個 2.9秒

リリースビルドだと、2桁くらいは高速に動いているので
ようやく実用的になったと思います(13個のパレットのRelease時は15msで変換を完了)。
従来方式が複雑かつ長時間かかるという点で使い物にならなかっただけという話ですが。

プログラムコードは400行ほどに(従来コードは700行)。
STLのデータ構造とアルゴリズムを使いまくってます。
そのせいでデバッグでこの速度を出すのが難しかったです。
ただ気を配って書けばSTL使った場合デバッグで重くて使い物にならない!という状況は避けられると感じました。

ポイント

考えをあらためたポイントは、以下の点です

  • 頂点を共有することにがんばらない
  • 変換アルゴリズムはシンプルに

前回の足りなくなったら頂点を複製という点から、頂点は最初から複製前提で考える
という考えに切り替えたのが大きいです。


アルファブレンディングについて【教えてほしい】

アルファブレンドで下記の合成はわかった

  • 通常合成(1*srcColor + 0*destColor)
  • 加算合成(1*srcColor + 1*destColor)
  • 半加算合成(srcA * srcColor + 1*destColor)
  • 半透明合成(srcA * srcColor + (1-srcA) * destColor)

しかしこれらがアルファ値だけ別の計算が出来るという仕組みが用意されていたりする。
これの有効な利用が思いつかない。

OpenGLやDirectXではアルファブレンドセパレートとして機能があったりするが。

D3DRS_SEPARATEALPHABLENDENABLE を有効化して
なにかやっているサンプルもまた見つからなかったし。
有効に使えている例、使える例を知っている人は是非教えてください。


テクスチャアドレッシングモード

テクスチャアドレッシングモード

テクスチャを張ったときに、1.0以上の値をどう扱って、
テクスチャを張るかのモード設定です。

出来ることの代表的なものとして、

  • 繰り返し貼る(リピート)
  • 反転しながら貼る(ミラー)
  • 繰り返さずに残った部分は引き延ばし

というのがあります。

OpenGL vs DirectX

で今回感じたのが、OpenGLとDirectXでこれらの機能の差違。
同じ挙動をする設定でも、画面の描画結果が違うということになりました。
もっとも大まかな挙動という点では一緒で、
今回の違いというのは、描画ピクセルが完全一致しないということを示しています。

どうも境界あたりの処理でそれぞれ差違が出ていました。
GL_CLAMP_TO_EDGEやGL_CLAMP_TO_BORDERなど標準機能ではなく
拡張機能で試したのですがうまくいきませんでした。

どうでもいいこと

テクスチャラッピングモードというとまた別のことを指すようです。
少しわかりにくい気がするのは自分だけでしょうか…


DirectXのデバッグランタイム不具合

Windows7 (x64)の環境で、DirectX9を用いた開発を行おうとすると、
SDKのバージョンによっては問題を引き起こすことがわかった。検索しても海外でしか、同じ症状が発見されず、また解決法も不明だったので、
問題のあるバージョンを使用しない方法でしか解決が出来ないようだ。
それでも、別バージョンを使えばOKという点はまだ救いなのかもしれない。

問題

Windows7(x64)において、DirectX9のデバッグランタイムを有効にすると、
CreateDeviceで失敗する。
そのときのエラーメッセージは次の通り。

コメントもらったので修正
試したのは全て、Windows7(x64)環境下です。
x86環境では問題が起こらないのかもしれません。
どうやらx86,x64環境ともに発生するようです。

SDKバージョン 使用可否 Windows仕様
2008Nov 使用不可能 Win7(x64)
2009Mar 使用不可能 Win7(x64)
2009Aug 使用可能 Win7(x64)
2010Feb 使用可能 Win7(x64)

 

まとめ

このような結果になったので、Windows7環境でまともに使おうと思っても、
古すぎるSDKは使いにくい。2009Augがいいところだろうか。