XNA'nın SpriteBatch tam olarak nasıl çalışır?


38

Daha kesin olmak gerekirse, bu işlevselliği başka bir API'de (örn. OpenGL'de) sıfırdan yeniden yaratmam gerekirse, ne yapması gerekiyor?

Bir ortografik izdüşüm matrisini nasıl hazırladığı ve her bir çekiliş çağrısı için bir dörtlü oluşturduğu gibi bazı adımlar hakkında genel bir fikrim var.

Bununla birlikte, dozajlama işleminin kendisiyle de aşina değilim. Tüm dörtlüler aynı köşe arabelleğinde mi saklanıyor? İndeks tamponuna ihtiyacı var mı? Farklı dokular nasıl kullanılır?

Mümkünse, en azından varsayılan Ertelenmiş modu kullanırken, SpriteBatch.Begin () işlevinin SpriteBatch.End () yöntemine çağrılmasından sonraki süreçte bana rehberlik ederseniz minnettar olurum.


MonoGame'de OpenGL aracılığıyla nasıl uygulandığına bir göz atın: github.com/mono/MonoGame/blob/master/MonoGame.Framework/…
Den

DotPeek veya Reflector'ı Microsoft.Xna.Graphics'te kullanmaya çalıştınız mı (kaçak bir şey yapmayı önermiyorum :)?
Den

Bağlantı için teşekkürler. Ve bu düşünce beni geçti (burada elimde DotPeek bile var), ama daha önce bunu yapmış ve prosedürü hafızadan bilen birinden genel bir açıklama istemek daha iyi bir fikir olabilir diye düşündüm. Bu şekilde cevap burada korunacak ve başkaları için uygun olacaktır. Hiç kimsenin böyle bir açıklama yapmaması durumunda, analizi kendim yapacağım ve kendi soruma bir cevap göndereceğim, ancak şimdilik biraz daha bekleyeceğim.
David Gouveia

Evet, bu yüzden bir yorum kullandım. Andrew Russell'ın bu soruyu cevaplamak için iyi bir insan olabileceğini düşünüyorum. Bu toplulukta aktif ve MonoGame'e alternatif olan ExEn üzerinde çalışıyor: andrewrussell.net/exen .
Den

Evet, bu, Andrew Russel'in (ya da XNA forumunda Shawn Hargreaves'in geri döndüğü) genellikle çok fazla içgörü sağlayabildiği bir soru.
David Gouveia

Yanıtlar:


42

Üzerinde çalıştığım bir çapraz platform motoru için SpriteBatch davranışının ertelenmiş moddaki davranışını çoğalttım, şimdiye dek tersine uyguladığım adımlar:

  1. SpriteBatch yapıcı: bir oluşturur DynamicIndexBuffer, DynamicVertexBufferve bir dizi VertexPositionColorTexturesabit boyutta (bu durumda, en yüksek parti boyutu - köşeler için spritelar 2048 ve 8192).

    • İndeks tamponu, çizilecek dörtlelerin tepe indeksleriyle doldurulur (0-1-2, 0-2-3, 4-5-6, 4-6-7 ve benzeri).
    • Ayrıca bir iç SpriteInfoyapı dizisi yaratılır. Bu, harmanlama sırasında kullanılacak geçici sprite ayarlarını kaydeder.
  2. SpriteBatch.Begin: içten değerlerini saklar BlendState, SamplerStatebir olmadan iki kez denilen edilmişse belirtilen vb çekler SpriteBatch.Endarasında.

  3. SpriteBatch.Draw: Tüm sprite bilgilerini (doku, konum, renk) alır ve a'ya kopyalar SpriteInfo. Eğer maksimum parti büyüklüğüne ulaşılırsa, yeni parti için yer açmak için partinin tamamı çekilir.

    • SpriteBatch.DrawStringsadece Drawkarakter aralığı ve boşlukları dikkate alarak dizenin her karakteri için bir sayı verir .
  4. SpriteBatch.End: aşağıdaki işlemleri yapar:

    • 'De belirtilen oluşturma durumlarını ayarlar Begin.
    • Ortografik projeksiyon matrisini oluşturur.
    • Uygular SpriteBatchshader.
    • Bağlanır DynamicVertexBufferve DynamicIndexBuffer.
    • Aşağıdaki harmanlama işlemini gerçekleştirir:

      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 toplu işte her biri için aşağıdaki işlemleri gerçekleştirir :

    • Sprite pozisyonunu alır ve dört köşenin son pozisyonunu orijin ve boyuta göre hesaplar. Mevcut dönüşü uygular.
    • UV koordinatlarını hesaplar ve SpriteEffectskendilerine belirtilenleri uygular .
    • Sprite rengini kopyalar.
    • Bu değerler daha sonra VertexPositionColorTextureyaratılmış olan elemanlar dizisinde saklanır . Tüm spritelar hesaplandığında SetDataçağrılır DynamicVertexBufferve bir DrawIndexedPrimitivesçağrı yapılır.
    • Köşe gölgelendirici yalnızca bir tranform işlemi gerçekleştirir ve piksel gölgelendirici dokudan alınan renge renk tonu uygular.

Tam olarak ihtiyacım olan şey buydu, çok teşekkürler! Bunları almam biraz zaman aldı ama sanırım sonunda tüm detayları aldım. Dikkatimi çekti ve daha önce hiç farkında değildim, Ertelenen modda bile, SpriteBatch'imi bir şekilde sıralayabilirsem. RenderBatch işlemlerinin sayısını azaltın ve muhtemelen görüntülemeyi hızlandırın.
David Gouveia

Bu arada, dokümantasyonda bulamıyorum - arabellek dolmadan önce yapabileceğiniz Draw aramaların sınırı nedir? DrawText'i çağırmak, bu arabelleği dizedeki tüm karakter sayısına göre dolduruyor mu?
David Gouveia

Etkileyici! Motorunuz ExEn ve MonoGame ile nasıl karşılaştırılacak? MonoTouch ve MonoAndroid'i de gerektirecek mi? Teşekkürler.
Den

@DavidGouveia: 2048 sprite maksimum parti büyüklüğü - cevabı düzenledi ve kolaylık sağlamak için ekledi. Evet, dokuya göre sıralama ve z-arabelleğinin sprite sıralamasına dikkat etmesine izin vermek minimum çizim çağrılarını kullanır. İhtiyacınız SpriteSortMode.Textureolursa, istediğiniz sıraya göre çizmeyi deneyin SpriteBatchve sıralama yapalım .
r2d2rigo

1
@Den: ExEn ve MonoGame, XNA kodunun Windows dışı platformda çalışmasına izin veren alt düzey API'lerdir. Üzerinde çalıştığım proje tamamen C # ile yazılmış, bileşen tabanlı bir motordur, ancak sistem API'lerine erişim sağlamak için (üzerinde çalıştığım yer) çok ince bir katmana ihtiyacımız var. Biz sadece SpriteBatchkolaylık sağlamak için yeniden yerleştirmeyi seçtik . Ve evet, hepsi C # olduğu için MonoTouch / MonoDroid gerektiriyor!
r2d2rigo

13

Sadece XNA SpriteBatch kodunun DirectX'e taşındığını ve XNA ekibinin önceki bir üyesi tarafından OSS olarak yayınlandığını belirtmek istiyorum. XNA'da tam olarak nasıl çalıştığını görmek istiyorsanız, burada gidersiniz.


+1 "kodunu asla kullanmayacağım ama gözden kaçırmak ilginç" için +1
Kyle Baran

XNA SpriteBatch dosyasının yerel C ++ olarak en son sürümü GitHub h / cpp . Bonus olarak, DirectX12 versiyonu da mevcuttur h / cpp
Chuck Walbourn
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.