XNAのSpriteBatchはどのように機能しますか?


38

もっと正確に言えば、別のAPI(OpenGLなど)でこの機能をゼロから再作成する必要がある場合、何ができる必要がありますか?

正射投影行列を作成し、描画呼び出しごとにクワッドを作成する方法など、いくつかのステップの一般的なアイデアがあります。

ただし、バッチ処理自体についてはあまり詳しくありません。すべてのクワッドは同じ頂点バッファーに格納されていますか?インデックスバッファが必要ですか?異なるテクスチャはどのように処理されますか?

可能であれば、少なくともデフォルトのDeferredモードを使用している場合は、SpriteBatch.Begin()が呼び出されてからSpriteBatch.End()までのプロセスを案内していただければ幸いです。


それはOpenGLの経由MonoGameに実装されているかを見てみましょう: github.com/mono/MonoGame/blob/master/MonoGame.Framework/...
デン

Microsoft.Xna.GraphicsでDotPeekまたはReflectorを使用しようとしましたか(ただし、違法なことを行うことはお勧めしません:)。
デン

リンクをありがとう。そして、その考えは私を横断しました(私はここにdotPeekさえ持っています)が、私は以前にそれをすでにしている可能性があり、メモリによって手順を知っている誰かから一般的な説明を求める方が良い考えかもしれません。そうすれば、答えはここに保存され、他の人が利用できるようになります。誰もそのような説明を提供していない場合、分析を自分で行い、自分の質問への回答を投稿しますが、今はもう少し待ちます。
デヴィッドゴーベイア

ええ、それが私がコメントを使用した理由です。アンドリュー・ラッセルはこの質問に答えるのにいい人かもしれないと思う。彼はこのコミュニティで積極的に活動しており、MonoGameの代替であるExEnに取り組んでいます:andrewrussell.net/exen
デン

ええ、これは通常、アンドリューラッセル(またはXNAフォーラムに戻ったショーンハーグリーブス)が多くの洞察を提供できるような質問です。
デヴィッドゴー

回答:


42

私は、作業中のクロスプラットフォームエンジンの遅延モードでのSpriteBatchの動作をある程度複製したので、これまでにリバースエンジニアリングを行った手順を次に示します。

  1. SpriteBatchコンストラクタは:作成しDynamicIndexBufferDynamicVertexBufferおよびアレイVertexPositionColorTextureの固定サイズの(この場合は、最大バッチサイズ-頂点のスプライト2048及び8192)。

    • インデックスバッファは、描画される四角形の頂点インデックスで埋められます(0-1-2、0-2-3、4-5-6、4-6-7など)。
    • SpriteInfo構造体の内部配列も作成されます。これは、バッチ処理時に使用される一時的なスプライト設定を保存します。
  2. SpriteBatch.Begin:内部の値を格納しBlendStateSamplerStateそれをせずに二度呼ばれてきた場合などには、指定されたとチェックSpriteBatch.Endの間インチ

  3. SpriteBatch.Draw:すべてのスプライト情報(テクスチャ、位置、色)を取得し、にコピーしSpriteInfoます。最大バッチサイズに達すると、新しいスプライト用のスペースを確保するためにバッチ全体が描画されます。

    • SpriteBatch.DrawStringDrawカーニングとスペースを考慮して、文字列の各文字に対してを発行するだけです。
  4. SpriteBatch.End:次の操作を実行します。

    • で指定されたレンダリング状態を設定しますBegin
    • 正投影図法マトリックスを作成します。
    • SpriteBatchシェーダーを適用します。
    • バインドDynamicVertexBufferDynamicIndexBuffer
    • 次のバッチ操作を実行します。

      startingOffset = 0;
      currentTexture, oldTexture = null;
      
      // Iterate through all sprites
      foreach SpriteInfo in SpriteBuffer
      {
          // Store sprite index and texture
          spriteIndex = SpriteBuffer.IndexOf(SpriteInfo);
          currentTexture = SpriteInfo.Texture;
      
          // Issue draw call if batch count > 0 and there is a texture change
          if (currentTexture != oldTexture)
          {
              if (spriteIndex > startingOffset)
              {
                  RenderBatch(currentTexture, SpriteBuffer, startingOffset,
                              spriteIndex - startingOffset);
              }
              startingOffset = spriteIndex;
              oldTexture = currentTexture;
          }
      }
      
      // Draw remaining batch and clear the sprite data
      RenderBatch(currentTexture, SpriteBuffer, startingOffset,
                  SpriteBuffer.Count - startingOffset);
      SpriteBuffer.Clear();
  5. SpriteBatch.RenderBatch:SpriteInfoバッチ内のそれぞれに対して次の操作を実行します。

    • スプライトの位置を取得し、原点とサイズに従って4つの頂点の最終位置を計算します。既存の回転を適用します。
    • UV座標を計算し、指定さSpriteEffectsれたものに適用します。
    • スプライトの色をコピーします。
    • これらの値は、VertexPositionColorTexture以前に作成された要素の配列に保存されます。すべてのスプライトが計算されている場合は、SetData上と呼ばれているDynamicVertexBufferと、DrawIndexedPrimitivesコールが発行されます。
    • 頂点シェーダーは変換操作のみを実行し、ピクセルシェーダーはテクスチャから取得した色に色付けを適用します。

それはまさに私が必要としたものです、ありがとう!そのすべてを吸収するために少し時間がかかりましたが、最終的にすべての詳細を把握したと思います。私の注意を引いたものの、以前はまったく気づいていなかったのは、遅延モードでも、SpriteBatch.Drawの呼び出しをテクスチャで並べ替えることができる場合(つまり、これらの呼び出しの順序を気にしない場合) RenderBatch操作の数を減らし、おそらくレンダリングを高速化します。
デヴィッドゴーベイア

ところで、私はドキュメントで見つけることができないようです-バッファがいっぱいになる前に行うことができるDraw呼び出しの制限は何ですか?そして、DrawTextを呼び出すと、文字列内の全文字数でそのバッファがいっぱいになりますか?
デヴィッドゴーベイア

印象的!あなたのエンジンはExEnやMonoGameと比較してどうですか?MonoTouchとMonoAndroidも必要ですか?ありがとう。
デン

@DavidGouveia:2048個のスプライトが最大バッチサイズです-回答を編集し、便宜上追加しました。はい、テクスチャでソートし、zバッファにスプライトの順序付けを任せると、最小限の描画呼び出しが使用されます。必要な場合は、実装SpriteSortMode.Textureしてみて、好きな順序で描画SpriteBatchし、ソートを実行してください。
r2d2rigo

1
@Den:ExEnとMonoGameは、Windows以外のプラットフォームでXNAコードを実行できる低レベルのAPIです。私が取り組んでいるプロジェクトは、純粋にC#で記述されたコンポーネントベースのエンジンですが、システムAPIへのアクセスを提供するために非常に薄いレイヤーが必要です(私が取り組んでいるところです)。SpriteBatch便宜上、再実装することを選択しました。はい、すべてC#なのでMonoTouch / MonoDroidが必要です!
r2d2rigo

13

XNA SpriteBatchコードがDirectXに移植され、XNAチームの以前のメンバーによってOSSとしてリリースされたことを指摘したいだけです。XNAでどのように機能するかを正確に確認したい場合は、こちらをご覧ください。


「私は決して使用しないが、ざっと目を通すのが面白い」というコードの+1
カイルバラン14年

ネイティブC ++としてのXNA SpriteBatchの最新バージョンは、GitHub h / cppにあります。ボーナスとして、DirectX12バージョンもh / cppで利用可能です
チャック・ウォルボーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.