動的テクスチャとその注意点

パーティクルシステムなどで動的に頂点データを変更する場合、GPUとCPUが競合しないように、DynamicVertexBuffer(動的頂点バッファ)、そしてNoOverwriteとDiscardオプションを使う方法を以前紹介しました。

では、テクスチャを動的頂点バッファのように扱うにはどうしたら良いでしょうか?そもそもDynamicTexture2Dというクラスもないし、Texture2D.SetDataSetDataOptionsを受け取るメソッドもない……。

その答えは

XNA Game Studio 4.0でのTexture.SetDataメソッドはSetDataOptions.Discardを指定した時と同じ振る舞いをする(但し注意点あり)

となります。

振る舞い的にはTexture2D/Texture3D/TextureCube、それぞれDiscardオプションを指定した時と同じように、指定したテクスチャがGPUで使われていた場合、内部で自動的に同じサイズ、フォーマットのテクスチャを生成し、その新しいテクスチャへデータを書き込むようになっています。

但し、この時にSetDataに渡されるパラメーターがテクスチャの一部分を書き換える設定になっていると、以前のテクスチャからデータを新しいテクスチャへコピーするようになっています。コピーだけならそれ程時間が掛からないのですが、このコピーする際に以前のテクスチャをGPUが使い終わるまで待ってからコピーするようになっているので、結局はDiscardオプションをつけていない時と同じ状態になってしまいます。

私のところでテストしたところ、256x256のテクスチャの一部分を書き換えた時、以下のような結果になりました。

方法

SetDataに掛かった時間

同じテクスチャでSetData

6.8ミリ秒

テクスチャを切り替えてSetData

0.3ミリ秒

 

まとめると、

  1. テクスチャ全体を書き換える場合は、パフォーマンス問題は発生しない
  2. テクスチャの一部分を書き換える場合、複数のテクスチャを切り替えながら書き込むようにしないと遅くなる

となります。

テクスチャを切り替えながらSetDataを呼ぶ方法としては「頂点テクスチャでスキンアニメーション」の記事のサンプルコード内にあるFlipTexture2D.csが参考になるでしょう。