2013/03/28

ベクトルのパック値とレンダ ターゲットでハマる

XNA Particels 3D サンプルと Shadow Mapping サンプルを移植していて、色々とハマりました。

まず、Particels 3D では PackedVector の Short2 を頂点データの一部に利用し、シェーダでは float2 でこれを受け取りますが、同様にした所、どうにも float2 で受け取れませんでした。int2 ならば受け取れます。頂点要素のフォーマット指定に従って、パック値から(バイトの並びから)自動的に float へ展開するものと思っていたのですが、違うのですかね・・・。
パック化の目的は頂点サイズを減らす事にあると思うので、int2 で受け取れるならそれで良いかという事にしてしまいました・・・納得はしていませんが。

続いて、Shadow Mapping はバック バッファ以外のレンダ ターゲットを利用するので、レンダ ターゲット周りの動作確認に良いかと思って移植してみたのですが、光源からの深度を書き込んだレンダ ターゲットがシェーダに渡されない状態にハマっていました。Shadow Mapping サンプルでは左上隅にレンダ ターゲットに書き込まれた深度マップを表示するので、書き込みの成功をこれで確認できるのに、深度マップと合わせてモデルを描画する際に、何故か参照できない(全深度が 0 になっている)状態でした。

結論としては、レンダ ターゲットとして利用しているテクスチャは、レンダ ターゲットとして設定する際には RenderTargetView、シェーダへ渡す際には ShaderResourceView で包んで利用する事になりますが、この両方がアクティブな状態となっている場合、ShaderResourceView で渡している側には 0 埋めされたテクスチャが設定される事が原因でした。MSDN を良く読むと、ID3D11DeviceContext.PSSetShaderResources の Remarks 等に、これを示唆する事が書いてありました。
ShaderResourceView として利用した後に参照を外してやれば良いだけですが、参照の外し忘れで同じ問題にハマるのも怖いので自動解決する方法を模索しましたが、あまり良い方法が思い浮かばないなぁと。
追記:その後、よくよく調べてみると、RenderTargetView を DeviceContext へ設定する際に ShaderResourceView 等の読み取りビューが設定されたスロットが null でリセットされる事が原因でした。素直に書く場合、必要な時に ShaderResourceView を設定するため、仮に null であっても再設定されるコードになるはずですが、僕はラッパークラスで参照をキャッシュするなどしていたため、D3D 内では null であるにも関わらず、ラッパークラスでは null ではないという状態の不整合が発生していたようです。
これらの他に、ハードウェア オクルージョン カリングを使う必要があるので、XNA の OcclusionQuery に相当するクラスを作り、Lens Flare サンプルを移植して試していました。
そろそろ必要な機能が揃い、動作も安定してきましたが、インスタンシングに関する枠組みを作ってみてから、ブロック地形のコードを新たな枠組みの上に乗せてみようかなと思っています。

2013/03/23

XNB モデル データの読み込みと描画まで到達

XNB ファイルを読み込み、自分のモデル クラスへデシリアライズし、描画が可能という所まで来ました。
公式サイトの XNB フォーマットの説明にコード例(C++)も含まれているので、読み込みに関する実装は簡単でしたが、自分が作成した Texture2D クラスのバグと言うか、自分の知識不足のために難儀しました・・・。

ただ、読み込めるデータには制約を設け、例えば、モデルで扱えるエフェクトを BasicEffect に限定したりなどしています。また、今はモデルを読み込みたいだけなので、その他は無視しています。

モデルがデフォルトのまま BasicEffect を用いる場合、BasicEffect へ設定するプロパティが XNB に埋め込まれるだけです。このため、読み込んだプロパティを自作クラスへ設定するだけで済みます。カスタム エフェクトを用いる場合、エフェクトのバイトコード、および、エフェクトに設定するプロパティがディクショナリ形式で埋め込まれます。それらの読み込みは簡単ですが、データの利用には汎用的なエフェクトの枠組みが必要であろうかと思います。XNB はシェーダ モデル 3.0 以下だと思うので、その考慮も大変そうです。

これで、FBX ファイルの読み込みと最適化を XNA コンテンツ プロジェクトに任せてしまい、自分は XNB を利用するだけ、という事が可能になったので、テスト コードやデバッグ コードの記述が随分と楽になるんじゃないかなぁと。

ただ、こうなると、「SpriteFont もコンテンツ プロジェクトで管理して XNB から読み込めばいいんじゃないの?」・・・みたいな。自分で専用コードを実装してしまいましたが、破棄しようかなぁ~と。

2013/03/20

非 XNA プロジェクトから XNA コンテンツ プロジェクトを参照する

Assimp を利用するという事は、参照アセンブリを増やす事であり、ならばそれが XNA のアセンブリでも良いのではと考え始め、試行錯誤していました。X ファイルも FBX ファイルも自分にとって本質的には重要ではないとなると、それらのインポート機能を備えた XNA をそのまま利用する方法を模索してみようという所です。

XNA コンテンツ プロジェクト (.contentproj) を非 XNA プロジェクトからビルド時に参照できれば、後は XNB ファイルを自作クラスへデシリアライズする機能を実装する事で、XNA Content Pipeline の恩恵を得られる・・・はず。コンテンツ プロジェクトは XNA 依存であっても、生成される .xnb はただのバイナリ ファイルであり、実行環境を問わないですからね。

XNA コンテンツ プロジェクトは、XNA がインストールされていれば、Visual Studio で簡単に作成できます。しかし、Visual Studio 上では、非 XNA プロジェクトから参照する術がありません。そこで、どうせ MSBuild でビルドしているのだから .proj ファイルを弄れば良いのでは、と思い弄っていたら上手くいきました。

もしかしたら、もっと簡単にやる方法があるのかもしれませんが、以下、要点を記録として記載しておきます。

1. 参照元プロジェクトで XnaPlatformXnaProfile を定義

参照元 .proj に、<XnaPlatform><XnaProfile> を追加します。例えば、以下のように追加します。
<Project ...>
  <PropertyGroup>
    <Configuration ...>
    ...
    <XnaPlatform>Windows</XnaPlatform>
    <XnaProfile>HiDef</XnaProfile>
  </PropertyGroup>
  ...
</Project>

2. コンテンツ プロジェクトへの参照を追加

参照元 .proj に、参照したい .contentproj<ProjectReference> で定義します。例えば、以下のように追加します。
<Project ...>
  ...
    <ItemGroup>
    ...
    <ProjectReference Include="..\SampleXnbContent\SampleXnbContent.contentproj">
      <Name>SampleXnbContent</Name>
      <XnaReferenceType>Content</XnaReferenceType>
      <Project>{nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn}</Project>
    </ProjectReference>
    ...
  </ItemGroup>
<Project> には、参照先 .contentproj で定義されている <ProjectGuid> の値をコピーします。

3. コンテンツ用ビルド定義をインポート

参照元 .proj に、<Import> で XNA コンテンツ用定義をインポートします。例えば、以下のように追加します。
<Project ...>
  ...
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Content.targets" />
  ...
</Project>
$(MSBuildExtensionsPath) は、自分の環境では "C:\Program Files (x86)\MSBuild" です。
ここまでで、参照元プロジェクトのビルドではコンテンツ プロジェクトが同時にビルドされ、参照元プロジェクトの出力先に .xnb ファイルが配置されるかと思います。

4. コンテンツ ルート ディレクトリを定義

ここまででは、参照元プロジェクトの出力先にはコンテンツ プロジェクトの名前がそのままディレクトリとして作られ、その中に .xnb ファイルが出力されます。XNA のデフォルトのように、Content ディレクトリへ .xnb を出力したい場合には、参照先 .contentproj にこれを定義します。
<Project ...>
  <PropertyGroup>
    <ProjectGuid>...</ProjectGuid>
    ...
    <ContentRootDirectory>Content</ContentRootDirectory>
  </PropertyGroup>
</Project>

・・・と、ひとまず出力先に .xnb を含める事が出来たので、後は XNB の内容を解析し、自分のクラスへデシリアライズするだけだなと。

2013/03/19

モデル データを読み込むためのライブラリ: Assimp

XNA 公式サンプルを簡単に移植するには、Model クラスを作り、モデル データを Model へインスタンス化する必要があるなぁ・・・と思い、MonoGame を見ていたら Assimp なる物を呼び出していたので、ダウンロードしてラッパーを作成し、Model クラスの実装を試していました。
Assimp
http://assimp.sourceforge.net/
Assimp 自体は C++ で、これを C# で呼び出すための assimp-net を利用してみました。
assimp-net
https://code.google.com/p/assimp-net/
MonoGame の開発途中の Content Pipeline の FBXImporter を見て Assimp を見つけたのですが、サイトを見る限りでは、Assimp は FBX 非対応なんですよね。実際に FBX ファイルを読み込んでみましたが、インスタンス化は可能な物の、情報は設定されませんでした。X ファイルならば、サイトの機能紹介にあるように読み込めているようです。

で、X で良いのなら FBX も X に変換すれば良いだけですが・・・。過去に FBX と X 間の相互変換を試した事があり、その時の記憶では、どんなツールを落としてきても期待通りに変換できた試しが無いんですよね。それから数年が経過したため、再度、色々と調べてみるのも良い気はしますが・・・。

僕は、自分でモデル データを作る事も、他の人が作ったモデル データを利用することも無く。殆どの場合、僕はコード上でモデル データを自動生成しています。つまり、モデル データのフォーマットに関しては、深く考えるだけ時間の無駄かな、と。

ただし、それ以外の部分で XNA サンプルで試したい事が多いので、強引な対策を採ってみようかなと。XNA 公式サンプルで描画可能なモデル データは、少なくとも XNA 内部で Model インスタンスであるため、XNA で Model インスタンス化した上でデータを抜き出し、自作の JSON データへ出力して読み込む事にしてやろうか、などと考えています。

2013/03/17

SpriteBatch および SpriteFont、ようやく描画に到達

やっとのことで、自作 SpriteFont により文字を描画できる所まで到達しました。故に、記念撮影と日記。


かなり適当なデモ コードによるスクリーン ショットですが、テクスチャ描画、色付け、反転、アウトライン付き文字描画などを試しています。

SpriteBatch および SpriteFont ともに、DirectX Tool Kit (DirectXTK) のソースコードを基本にしています。そして、SpriteFont で用いるフォント データ管理のために、XNA Content Pipeline 風の枠組みも自作していました。
フォント データ:
描画に使用する文字を一枚のスプライト シートに纏めたテクスチャ、および、テクスチャから文字位置を特定するための情報等の全てを纏めたデータ。
DirectXTK では、フォント データを事前に作成するバイナリ データで纏めていますが、これは XNA における XNB の概念かと思います。XNB のファイル形式は、以下で仕様が公開されています。
XBOX LIVE indie games - Compiled (XNB) Content Format:
http://xbox.create.msdn.com/en-us/sample/xnb_format
DirectXTK では、SpriteFont 特化のバイナリ生成アプリケーションを提供していますが、他にも XNB 風に管理したい場合があるだろうと想像し、少し汎用性を持たせるために Content Pipeline の枠組みも自作してみたという所です。
後は、DirectXTK のフォント データの構造が XNA とは異なり、これを XNA に合わせるように調整した感じです。

Content Pipeline の実装では、ひにけに GD で提供されている WPF フォント プロセッサを足がかりに設計を進めていました。
ひにけに GD - 真・簡単(かもしれない)日本語表示:
http://blogs.msdn.com/b/ito/archive/2012/02/19/wpf-font-processor.aspx
上記で紹介されているプロセッサを、ほぼ変更せずに実装できれば、プロセッサとフォント データの生成に関しては概ね正解であろう、という判断です。

XNA 風とは言っても、XNA Content Pipeline には不満が多々あったため、あくまで参考とし、自分が望むように設計していました。好きな所で Content Pipeline の機能を呼び出したい、との理由が大きいですかね。
そもそも、完全に XNA 風とするには Visual Studio や MSBuild との統合が必要であり、これが大変過ぎるので回避一択。

XNA のように高機能ではなく、汎用性もかなり低くなっています。必要となった時に拡張すれば良いかなと。

まぁ、そろそろ花粉がキツくて頭がまともに回らない・・・。

2013/03/16

MonoGame のコードを眺めていた

SpriteFont の実装にあたり、ちょっと XNA Content Pipeline 風の枠組みでも作ってみようか、という事で実装していたらハマり始め、何か参考になるコードは無いだろうかと検索していたら、MonoGame に辿り着きました(と言うか、既に知っていたのに存在を忘れていた・・・)。
MonoGame
http://www.monogame.net/
GitHub: MonoGame
https://github.com/mono/MonoGame
XNA 4.0 のオープンソースかつクロス プラットフォーム対応のプロジェクトだそうです。MonoGame で実装した実ゲーム一覧を見ると、Xbox 360 マーケットプレイスで見かける物がありますね。どれも未プレイですが。

そこで、GutHub から MonoGame のソースコードを落として眺めていました。MonoGame は DirectX 実装に SharpDX を利用しており、Direct3D11 を XNA 4.0 API に合わせてラップしているようです。

Content Pipeline 実装を自分の実装と比べていましたが、そこは似た所で詰まっているなぁと。XNA の API からだけでは、ロジックを推測できない部分が結構あるんですよね。大概は些細な部分であり、互換が目的ではないので代替ロジックで済ますのですが、綺麗な実装は可能ならば模倣したい所です。

ストレートに XNA のソースコードを見たいなぁ・・・。

2013/03/11

SpriteBatch 実装に手こずり中

BasicEffect 風の枠組みの実装はスムーズに完了し、XNA 公式サンプルの Primitives3D を移植し、見た目は上手く動作しているようで、後はさくさくと進められるな!などと思っていたのですが、SpriteBatch でかなり躓いています。

XNA で実装していた時には、SpriteBatch は当たり前の存在とし過ぎていて、内部まで深く考察する事が無かったんですよね。DirectX Tool Kit のソースを見て、なるほどなぁと。

DirectX Tool Kit を参考にひとまず実装したので、サンプル コードとして何が良いかを探している最中です。ちゃんと動くのかなぁ・・・。

2013/03/05

DirectX Tool Kit のソースを覗いてみる

眠れなかったので、「Windows ストアでの DirectX アプリケーション開発ってどうやるんだろう?」と思い、ストアに興味はないのに何となく調べていたのですが、DirectX 11.1 では DirectX Tool Kit (DirectXTK) なるものを利用するというのもあるようですね。
DirectXTK
http://directxtk.codeplex.com/
そこで、上記サイトからソースコードを落として眺めていました。それは、DirectX Math という算術演算ライブラリも知り、これが XNA Math と呼ばれるものでもあったので、「DirectXTK も XNA に関係しているの?」と考えたからです。

そして、この予想があたって良かったかなと。SpriteBatch や BasicEffect 等、馴染み深いクラス名を見ることができます。調べてみると、XNA ビルトイン エフェクトを DirectXTK へ移植したと、開発者が述べていますね。
Shawn Hargreaves Blog: SpriteBatch and BasicEffect for C++ Direct3D 11
http://blogs.msdn.com/b/shawnhar/archive/2012/03/02/spritebatch-and-basiceffect-for-c-direct3d-11.aspx
SharpDX ラッパーにて、XNA BasicEffect 風クラスを D3D11 で作る方法を模索していて、「恐らく、こうするのがベストかなぁ・・・」と思う設計が纏まって実装開始直前だったのですが、DirectXTK BasicEffect の設計と同一だったので安心した所です。なら、この方針で問題が無いんだろう、と。
XNA の StockEffects サンプルにある BasicEffect.fx を見ていた時から違和感があったのですが、そこでは既にマクロとディレクティブを用いてシェーダ モデル 4.0 と 2.0 をコンパイル時に切り替えられるようになっています。コメントにも「DX11 シェーダ モデル 4.0 対象のマクロ」などと書いてもありますし。確か XNA 4.0 の段階でこうなったと記憶しているので、Windows Phone 対応だったんですかね?WP って D3D10 対応?いずれにせよ、元より想定されていたのだなと。
名前の類似性から、「SharpDX Toolkit も実は DirectXTK をベースに?」と予想もしたのですが、こちらの予想は外れたようです。DirectXTK の BasicEffect は、テクニックやパスを用いず、シンプルに ID3D11VertexShader などを利用する構造ですが、SharpDX.Toolkit はエフェクトとしてシェーダ コードを自前で解析した上で、エフェクトとして BasicEffect を実装している構造に見えます。

こうして見ていくと、Windows 8 や WinRT の対応をキッカケに、一度 DirectX を過去の実装(XNA 等)を含めて整理して改めるって事なんですかねぇ・・・。仮にそうであるとすると、ある程度纏まった段階で、再び XNA のような環境を作るであろうと期待して良いのでしょうか・・・。

2013/03/02

SharpDX ラッパーがひとまず稼働

SharpDX のラッパー実装が、SharpDX の MiniCube サンプル アプリケーションの移植まで辿り着き、一応見た目は動いているといった所です。

しかし、まだ頂点シェーダ ステージとピクセル シェーダ ステージの対応のみ、入力処理未対応など、そもそも機能が充実していない事や、見かけ上正常に稼働しているだけでしかない可能性の高さを考えると、更にサンプルを実装しながら修正を加える必要があると感じます。

サンプル アプリケーションとしては、SharpDX のサンプルは簡単な物ばかりであるため、XNA 公式サンプルを試しに移植してみようかと考えています。それにより、実装すべき物が明らかになると思いますし。その前にデバッグ機能を揃えた方が良いのかな・・・。

ある程度落ち着いたら、Minecraft 風に作ったアプリケーションを移植し、動画作成とタグ付けしてのコード公開をあわせて、一段落としないなぁ・・・と。先は長い。

libgdx いじり

Google が提供している Java 版の Tango Examples は Rajawali をベースにしているため、自分が仕事で開発する Tango アプリも Rajawali ベースとしていましたが、最近は libGDX への移行を進めています。一応、要点については移行が...