OpenGL ile modern bir şekilde çok sayıda karo çizilmesi


35

İnsanlardan oluşan bir ekiple küçük bir karo / sprite tabanlı PC oyunu üzerinde çalışıyorum ve performans sorunlarıyla karşı karşıyayız. OpenGL'i en son kullandığım 2004 civarındaydı, bu yüzden kendime çekirdek profili nasıl kullanacağımı öğretiyorum ve kendimi biraz karışık buluyorum.

Her kareye ekrana 250-750 adet 48x48 fayans çizmem gerekiyor, belki de yaklaşık 50 sprite. Döşemeler yalnızca yeni bir seviye yüklendiğinde değişir ve sprite her zaman değişir. Döşemelerin bir kısmı dört adet 24x24 parçadan oluşuyor ve spriteların çoğu (hepsi değil) karolarla aynı boyutta. Birçok fayans ve sprite alfa harmanı kullanır.

Şu anda bunların hepsini acil modda yapıyorum, ki bunun kötü bir fikir olduğunu biliyorum. Aynı şekilde, ekip üyelerimizden biri onu çalıştırmaya çalıştığında, çok kötü kare hızları alır (~ 20-30 fps) ve daha fazla kiremit olduğunda, özellikle de bu kiremitlerin çoğu türün parçalar halinde kesilir. Tüm bunlar bana sorunun yapılan aramaların sayısı olduğunu düşündürüyor.

Bunun için birkaç olası çözüm düşündüm, ama ne hakkında konuştuğunu bilen bazı insanlar tarafından işletmek istedim, böylece zamanımı aptal bir şeyle harcamam.

KAROLAR

  1. Bir seviye yüklendiğinde, tüm döşemeleri bir kez büyük korna dokusuna tutturulmuş bir çerçeve tamponuna bir kez çizin ve üzerine her çerçevenin üzerinde o dokuya sahip büyük bir dikdörtgen çizin.
  2. Tüm döşemeleri, seviye yüklendiğinde statik köşe tamponuna koyun ve bu şekilde çizin. Tek tek bir çağrı ile farklı dokularla nesneler çizmenin bir yolu olup olmadığını ya da bu yapmak istediğim bir şey olup olmadığını bilmiyorum. Belki de tüm döşemeleri dev bir dokuya yerleştirin ve VBO'da komik doku koordinatlarını kullanın.

sprite:

  1. Her sprite glDrawElements için ayrı bir çağrı ile çizin. Bu bana kötü olduğu söylenen çok sayıda doku değiştirmeyi içeriyor gibi görünüyor. Burada doku dizileri yararlı olabilir mi?
  2. Bir şekilde dinamik bir VBO kullanın. Yukarıdaki 2 numaralı ile aynı doku sorusu.
  3. Nokta sprite? Bu muhtemelen aptalca.

Bu fikirlerden herhangi biri mantıklı mı? Bakabileceğim bir yerde iyi bir uygulama var mı?


Döşemeler hareket etmiyor veya değişmiyorsa ve tüm seviyeyle aynı görünüyorsa, ilk fikir - çerçeve tamponunu kullanmalısınız. En verimli olacak.
zacharmarz

Doku atlası kullanmayı deneyin, böylece dokuları değiştirmek zorunda kalmazsınız, fakat her şeyi aynı tutar. Şimdi onların kare hızı nasıl?
kullanıcı253751

Yanıtlar:


25

Döşemeleri oluşturmanın en hızlı yolu, köşe verilerini, indekslerle statik bir VBO içine paketlemektir (glDrawElements'ın belirttiği gibi). Başka bir görüntüye yazmak tamamen gereksizdir ve yalnızca daha fazla bellek gerektirir. Doku değiştirme işlemi ÇOK maliyetlidir, bu nedenle muhtemelen tüm döşemeleri Doku Atlası adı verilen bir pakete koymak ve VBO'daki her üçgene doğru doku koordinatlarını vermek isteyeceksiniz . Buna bağlı olarak, donanımınıza bağlı olarak 1000, hatta 100000 döşemenin yapılmasında sorun olmamalıdır.

Döşeme oluşturma ve Sprite oluşturma arasındaki tek fark büyük olasılıkla hareketlilerin dinamik olmasıdır. Böylece en iyi, ancak kolay bir şekilde birleştirilebilen performans için sprite köşelerinin koordinatlarını her kareye VBO akışını çizip glDrawElements ile çizebilirsiniz. Ayrıca tüm dokuları bir Doku Atlası içerisine yerleştirin. Eğer sprite'larınız nadiren hareket ederse, dinamik bir VBO yapmayı ve spritelar hareket ettiğinde güncellemeyi de deneyebilirsiniz, fakat bu sadece bazı sprite'lar yapmak istediğinizde, bu toplamdan fazladır.

OpenGL: Particulate ile C ++ 'da yaptığım küçük prototipleri inceleyebilirsiniz.

Her zamanki bir makinede ortalama 400 fps hızında (Quad Core @ 2.66GHz) sanırım yaklaşık 10000 punto atıyor. CPU başlıklıdır, bu grafik kartının daha da fazla iş yapabileceği anlamına gelir. Burada Doku Atlası kullanmıyorum çünkü parçacıklar için sadece tek bir dokuya sahibim. Parçacıklar GL_POINTS ile üretilir ve gölgelendiriciler daha sonra gerçek dörtlü boyutu hesaplar, ancak bence bir Quad Renderer de var.

Oh, ve evet, kare almadığınız ve doku eşleştirmesi için gölgelendiriciler kullanmadığınız sürece, GL_POINTS oldukça saçma. ;)


Sprite pozisyonlarını ve hangi dokuyu kullandıklarını değiştiriyor ve çoğu bunu her karede yapıyor. Ayrıca, sprite ve çok sık oluşturulan ve tahrip ediliyor. Bir akımın VBO tarafından çizildiği şeyler başa çıkabilir mi?
Nic

2
Akış çizimi temel olarak şu anlama gelir: "Bu verileri grafik kartına gönderin ve çizdikten sonra atın". Böylece her kareye tekrar veri göndermelisiniz ve bu ne kadar sprite yaptığınız, hangi pozisyonda oldukları, hangi doku koordinatlarında veya hangi rengin olduğu önemli değil. Ancak tüm verileri aynı anda gönderin ve GPU'yu işlemesine izin verin, tabii ki acil moddan daha hızlıdır.
Marco

Bunların hepsi mantıklı. Bunun için bir dizin tamponu kullanmaya değer mi? Tekrarlanacak olan köşeler, her dikdörtgenin iki köşesidir, değil mi? (Benim fikrim, endekslerin glDrawElements ve glDrawArrays arasındaki fark olduğudur. Doğru mu?)
Nic

1
Endeksler olmadan genellikle kötü olan GL_TRIANGLES'i kullanamazsınız, çünkü bu çizim yöntemi garantili en iyi performansı gösteren yöntemdir. Ayrıca, GL_QUADS uygulaması OpenGL 3.0'da kullanımdan kaldırılmıştır (kaynak: stackoverflow.com/questions/6644099/… ). Üçgenler, herhangi bir grafik kartının yerel ağlarıdır. Bu nedenle, 2 köşe gölgelendirici çalıştırmasını ve vertex_size * 2 bayt'ı kaydetmek için "2 * 6 bayt" kullanırsınız. Yani, genellikle her zaman daha iyi olduğunu söyleyebiliriz.
Marco

2
Partikül bağlantısı kesildi ... Lütfen yeni bir tane verebilir misiniz?
SWdV

4

Acil modu yavaş olabilir ama değil - beraberlik bu sayı çağırır bile birlikte performans düşüşü bu tür görmemeniz gerektiğini o yavaş (referans için, hatta sevgili-eski Quake düşmeden kare başına birkaç bin acil mod aramaları yönetebilir çok kötü aşağı).

Burada daha ilginç bir şey olacağından şüpheleniyorum. Yapmanız gereken ilk şey, programınızı profillendirmeye biraz zaman ayırmaktır, aksi takdirde, sıfır performans kazancıyla sonuçlanabilecek bir varsayıma dayalı olarak yeniden arama yapma riskiniz yüksek olur. Bu yüzden, onu GLIntercept kadar basit bir şeyden geçirin ve zamanınızın nereye gittiğini görün. Bunun sonuçlarına dayanarak bazı ile sorunu çözmek mümkün olacak gerçek birincil darboğazınızın / engellerinin ne olduğu hakkında bilgilerle çıkabilirsiniz.


Bazı profiller oluşturdum, çünkü performans sorunları geliştirme ile aynı makinede olmadığından garipti. Sorunun başka bir yerde olduğu konusunda biraz şüpheciyim, çünkü problemler kesinlikle kiremit sayısında artıyor ve kiremit kelimenin tam anlamıyla çizilmesi dışında hiçbir şey yapmıyor.
Nic

Peki ya devlet değişiklikleri? Opak çinilerinizi eyaletlere göre mi gruplandırıyorsunuz?
Maximus Minimus

Bu bir olasılık. Bu kesinlikle benim açımdan daha fazla dikkat hak ediyor.
Nic

2

Tamam, buradaki son cevabım elimizden geldiğinden beri, belki daha faydalı olan yeni bir cevap.


2D Performansı Hakkında

İlk önce bazı genel tavsiyeler: 2D mevcut donanım için zorunluluk arz etmiyor, hatta büyük ölçüde optimize edilmemiş kod bile işe yarayacak. Bu, Orta Mod'da olmanız gerektiği anlamına gelmez, en azından, gerekmediğinde durumları değiştirmediğinizden emin olun (örneğin, aynı doku zaten bağlıyken glBindTexture ile yeni bir doku bağlama, bir işlem CPU tonu ise glBindTexture-call'tan daha hızlı) ve glVertex kadar tamamen yanlış ve aptalca bir şey kullanmamak (hatta glDrawArrays bile çok daha hızlı olacak ve kullanımı daha zor değil, çok "modern" değil). Bu iki basit kuralla, çerçeve süresi en az 10ms (100 fps) olmalıdır. Şimdi daha da hızlanabilmek için bir sonraki mantıksal adım gruplamadır, örneğin bir taneye çok sayıda çağrı çağrısını bir araya getirme, çünkü doku atlaslarını uygulamayı düşünmelisiniz, Böylece doku bağlama miktarını en aza indirebilir ve böylece tek bir çağrı ile çizebileceğiniz dikdörtgen miktarını büyük miktarda artırabilirsiniz. Şimdi yaklaşık 2ms'e (500fps) düşmediyseniz yanlış bir şey yapıyorsunuz :)


Karo haritaları

Karo haritaları için çizim kodunu uygulamak, esneklik ve hız arasındaki dengeyi bulmaktır. Statik VBO'ları kullanabilirsiniz, ancak bu, animasyonlu döşemelerle çalışmaz veya sadece her karede vertex verilerini oluşturabilir ve yukarıda açıkladığım kuralları uygulayabilirsiniz;

Daha önceki cevabımda, parça gölgelendiricinin tüm dokuya dikkat ettiği farklı bir model getirmiştim, ancak bağımlı bir doku araması gerektirdiği ve bu nedenle diğer yöntemler kadar hızlı olamayacağı belirtildi. (Fikir temelde sadece döşeme işaretlerini yüklüyorsunuz ve parça gölgelendiricisinde doku koordinatlarını hesaplıyorsunuz, yani tüm haritayı tek bir dikdörtgenle çizebileceğiniz anlamına geliyor)


Spritelar

Sprite, "2D-Performance Hakkında" bölümünde tartışılanların dışında optimize etmeyi çok zorlaştıran çok fazla esneklik gerektirir. Aynı anda ekranda on binlerce sprite istemiyorsanız, bu muhtemelen çabaya değmez.


1
On binlerce sprite da olsa, modern donanım iyi bir hızda çalıştırılmalıdır :)
Marco

@ API-Canavar ne bekliyor? Doku UV'lerini fragman gölgelendiricisinde nasıl hesaplarsınız? UV'leri parça gölgelendiriciye göndermen gerekmiyor mu?
HgMerk

0

Eğer hepsi hataysa...

Bir flip-flop çizim yöntemi ayarlayın. Her seferinde sadece diğer sprite güncelleme. Yine de, VisualBasic6 ve basit bit karma yöntemlerle bile, çerçeve başına binlerce sprite aktif olarak çizebilirsiniz. Belki de sadece çizim spritleri yapma yönteminiz başarısız gibi göründüğü için bu yöntemlere bakmalısınız. (Bir "oluşturma yöntemi" kullanıyor gibi görünüyorsunuz, ancak bunu bir "oyun yöntemi" gibi kullanmaya çalışıyorsunuz. İşlem yapmak, netlik değil, hız demektir.)

Muhtemelen, sürekli olarak tüm ekranı tekrar tekrar çiziyorsunuz. Sadece değiştirilen alanları yeniden çizmek yerine. Bu bir sürü ek yük. Kavram basittir, ancak anlaşılması kolay değildir.

Bakire statik arkaplan için bir tampon kullanın. Ekranda hiç leke yoksa, bu asla kendini göstermez. Bu, sürekli olarak bir sprite çizilen yeri geri almak, bir sonraki çağrıdaki sprite'i çekmek için kullanılır. Ayrıca, ekran olmayan "çizmek" için bir arabellek gerekir. Orada çiziyorsun, sonra bir kere çizilirse, onu ekrana çevir, bir kere. Tüm spritelarınız için bir ekran görüşmesi olmalı. (Ekrandaki her bir grafiği çizmek yerine, her seferinde bir defada veya hepsini bir seferde yapmaya çalışmak, bu da alfa karışımınızın başarısız olmasına neden olur.) Belleğe yazma işlemi hızlıdır ve ekranın "çekilmesini gerektirmez" ". Her beraberlik çağrısı, tekrar çizmeye çalışmadan önce bir dönüş sinyali bekleyecektir. (V-sync değil, RAM'deki bekleme süresinden çok daha yavaş olan gerçek bir donanım onay işaretidir.)

Bu sorunu yalnızca bir bilgisayarda görmenizin bir parçası olduğunu hayal ediyorum. Veya, tüm kartların desteklemediği, ALPHA-BLEND'in yazılım sunumuna geri dönüyor. Kullanmaya çalışmadan önce bu özelliğin donanım tarafından desteklenip desteklenmediğini kontrol ediyor musunuz? Eğer yoksa, bir geri dönüşe (alfa harmanı olmayan mod) sahip misiniz? Açıkçası, oyun içeriğinizi bozacağını varsaydığım gibi, sınırlayan (harmanlanmış şeylerin sayısı) bir kodunuz yok. (Bunların yalnızca alfa harmanlanmış parçacık efektleri olmasının aksine, ve dolayısıyla programcıların neden donanım sınırlamaları olsalar da çoğu sisteme yüksek oranda vergi harcıyorlar?

Son olarak, alfa harmanladığın şeyi, sadece ona ihtiyacı olan şeylerle sınırlamayı öneririm. Her şey buna ihtiyaç duyarsa ... Kullanıcılarınızdan daha iyi donanım gereksinimleri olmasını veya oyunu istenen performans için düşürmeyi talep etmekten başka seçeneğiniz yoktur.


-1

Diğer 2B oyunda olduğu gibi, nesneler için bir hareketli sayfa ve arazi için ayarlanmış bir döşeme oluşturun, dokuları değiştirmenize gerek yok.

Döşemeleri oluşturmak acı verici olabilir çünkü her üçgen çifti kendi doku koordinatlarına ihtiyaç duyar. Ancak bu soruna bir çözüm var, buna anlık oluşturma denir .

Verilerinizi bir şekilde sıralayabildiğiniz sürece, örneğin, bir karoların bir listesini ve konumlarını alabilir, her bir karoyu tek bir beraberlik çağrısı ile oluşturabilirsiniz, tek yapmanız gereken bir dizi sağlamaktır. Her karo için dünya matris modeli. Verilerinizi bu şekilde sıralamak, en basit sahne grafiğiyle bile sorun olmamalıdır.


-1: Örnek alma, Bay Beast'un saf gölgelendirici çözümünden daha kötü bir fikirdir. Örnekleme, orta derecede karmaşık nesneleri (~ 100 üçgen vb.) Oluştururken performans için en iyi sonucu verir. Doku koordinatlarına ihtiyaç duyan her üçgen karo bir problem değildir. Sadece bir tilemap oluşturmak için bir sürü gevşek dörtlü bir ağ oluşturursunuz.
Nicol Bolas

1
@ NicoleBolas tamam, öğrenme uğruna cevabını bırakacağım
dreta,

1
Netlik için, Nicol Bolas, tüm bunlarla nasıl başa çıkacağınız için öneriniz nedir? Marco'nun akışı bir şey mi çizdi? Bunun bir uygulamasını görebileceğim bir yer var mı?
Nic

@Nic: Tampon nesnelere akış yapmak özellikle karmaşık kod değildir. Ama gerçekten, eğer sadece 50 spitten bahsediyorsan, bu bir şey değil . Olasılıklar, performans sorununa neden olan arazi çiziminizdir, bu nedenle statik arabelleklere geçmek muhtemelen yeterince iyi olacaktır.
Nicol Bolas,

Aslında, örnekleme olması gerektiği gibi çalışmış olsaydı, en iyi çözüm olurdu - ama işe yaramadığından, tüm örnekleri tek bir statik Vbo'da pişirme yolu budur.
Jari Komppa
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.