Bir 2D oyunda büyük video belleği gereksinimlerini nasıl çözeriz?


40

Bir 2D oyunda büyük video belleği gereksinimlerini nasıl çözeriz?


Allegro C / C ++'da 2D oyun (Factorio) geliştiriyoruz ve oyun içeriği arttıkça video belleği gereksinimlerinde bir sorunla karşı karşıyayız.

Halihazırda ilk önce kullanılacak görüntüler hakkında tüm bilgileri topluyoruz, bu görüntüleri mümkün olduğunca kırpıyoruz ve mümkün olduğu kadar sıkı şekilde büyük atlaslarda düzenliyoruz. Bu atlaslar, büyüklüğü sistem sınırlamalarına bağlı olan video belleğinde saklanır; şu anda 8192x8192'ye kadar genellikle 2 görüntü olduğundan, 256Mb ila 512Mb video belleği gerektirir.

Bu sistem bizim için oldukça iyi çalışıyor, bazı özel optimizasyonlarda ve oluşturma ve güncelleme iş parçacığını böldüğümüzde, ekranda 60 fps'de on binlerce görüntü çizebiliyoruz; Ekranda birçok nesnemiz var ve büyük bir yakınlaştırmaya izin vermek kritik bir gereklilik. Daha fazla eklemek istediğimiz gibi, video belleği gereklilikleri ile ilgili bir sorun olacaktır, bu nedenle bu sistem muhtemelen tutamaz.

Denemek istediğimiz şeylerden biri, en yaygın imgeleri olan bir atlası ve ikincisini önbellek olarak kullanmak. Görüntüler isteğe bağlı olarak oraya bellek bitmapinden taşınacaktı. Bu yaklaşımla ilgili iki sorun var:

  1. Hafıza bitmapinden video bitmap'e çizim allegro'da acı verici bir şekilde yavaş.
  2. Video bitmap ile ana iş parçacığından başka, allegro içinde çalışmak mümkün değildir, bu yüzden pratik olarak kullanılamaz.

İşte sahip olduğumuz bazı ek şartlar:

  • Oyun belirleyici olmalı, bu nedenle performans sorunları / yükleme süreleri oyun durumunu asla değiştiremez.
  • Oyun gerçek zamanlı ve yakında çok oyunculu olacak. Her ne pahasına olursa olsun en küçük kekemelerden bile kaçınmamız gerekir.
  • Oyunun çoğu sürekli bir açık dünya.

Test, her konfigürasyon için birkaç kez 1x1 ila 300x300 arasındaki boyutlar için bir partide 10000 sprite çekilmesinden ibaretti. Nvidia Geforce GTX 760 üzerinde testler yaptım.

  • Video bitmap ile video bitmap çizimi, kaynak bitmap bireysel bitmapler (atlas varyantı) arasında değişmediğinde sprite başına 0.1us aldı; boyut önemli değildi
  • Video bitmap video bitmap çizimine, kaynak bitmap çizimler arasında geçiş yaparken (atlas olmayan değişken) sprite başına 0.56us aldı; Boyut da önemli değildi.
  • Video bitmap çizimine yönelik bellek bitmap'i gerçekten şüpheliydi. 1x1'den 200x200'e kadar olan boyutlar bitmap başına 0.3us aldı, bu yüzden çok yavaş değil. Daha büyük boyutlar için, zaman çok çarpıcı bir şekilde artmaya başladı, 9x'de 201x201 için 31us için 311US.

Atlas kullanmak, performansı 5'ten daha büyük bir faktörle artırır. Oluşturma için 10ms'm varsa, atlas ile çerçevede 100 000 spitter ile sınırsızım ve onsuz 20.000 sprit sınırındayım. Bu sorunlu olurdu.

Ayrıca gölgeler için bitmap sıkıştırmasını ve 1bpp bitmap formatını test etmenin bir yolunu bulmaya çalışıyordum, ancak bunu allegro'da yapmanın bir yolunu bulamadım.


1
Oyununun büyük hayranı Indiegogo kampanyasını destekledim. Birkaç ayda bir üstüne tıkarım. Şimdiye kadar iyi iş çıkardın! Site için geçerli olmayan "hangi teknolojiyi kullanacağım" sorularını kaldırdım. Kalan sorular hala oldukça geniştir, daha belirgin bir şeyiniz varsa, kapsamı daraltmaya çalışmalısınız.
MichaelHouse

Destek için teşekkürler. Peki hangi teknolojiyi kullanacağınızı soracağınız yer neresi? Belirli motor önerileriyle cevap aramıyorum, ancak 2d motorların derinlemesine karşılaştırmasını bulamadım ve performansları ve kullanılabilirlik testleri de dahil olmak üzere bunları tek tek elle kontrol edemedim.
Marwin,

"Hangi teknolojiyi kullanacaksınız" gibi sorular sorabileceğiniz bazı yerler için bu sayfanın altını inceleyin . Tamamen geçerli ve makul bir sorunuz var, bu sitede ele aldığımız soru türü değil. Belirli bir motor aramasanız da, "X'i yapan herhangi bir teknoloji var mı?" Sorusuna cevap vermenin tek yolu bu. Birisi sadece "evet" cevabını verebilir ve belirli biri için öneride bulunamaz, ancak bu çok yardımcı olmaz. Onunla iyi şanslar!
MichaelHouse

2
Dokularınızı sıkıştırıyor musunuz?
GuyRT

3
@Marwin, Sıkıştırılmış dokular, sıkıştırılmamış dokulardan çok daha iyi performans gösterebilir çünkü gerekli bellek bant genişliğini azaltırlar (bu özellikle bant genişliğinin çok daha düşük olduğu mobil platformlarda geçerlidir). Sadece dokularınızı sıkıştırarak büyük miktarda bellek tasarrufu yapabilirsiniz. Gerçekten de, tek dezavantajı kaçınılmaz olarak tanıtılan eserlerdir.
GuyRT

Yanıtlar:


17

RTS (KaM Remake) ile benzer bir durumumuz var. Tüm birimler ve evler sprite. Birimler, evler ve arazi için 18 000 sprite, ayrıca takım renkleri için (maske olarak uygulanır) bir başka ~ 6 000 Uzun süredir, yazı tiplerinde kullanılan ~ 30 000 karakter de vardır.

Yani kullandığınız RGBA32 atlaslarına karşı bazı optimizasyonlar var:

  • Sprite havuzunuzu önce birçok küçük atlasta bölün ve diğer cevaplarda belirtildiği gibi talep üzerine kullanın. Bu , her atlas için ayrı ayrı farklı optimizasyon teknikleri kullanılmasına olanak sağlar . Sanırım biraz daha az boşa harcanan RAM'e sahip olacağınızdan şüpheleniyorum, çünkü bu kadar büyük dokulara paketleme yaparken genellikle altta kullanılmayan alanlar var;

  • Paletli dokuları kullanmayı deneyin . Gölgelendiriciler kullanıyorsanız, paleti gölgelendiriciler kodunda "uygulayabilirsiniz";

  • RGBA8 yerine RGB5_A1 kullanmak için bir seçenek eklemek isteyebilirsiniz (örneğin, dama tahtası gölgeler oyununuz için uygunsa). Mümkünse 8 bit Alfa'dan kaçının ve RGB5_A1 veya daha küçük hassasiyete sahip eşdeğer biçimleri (RGBA4'te olduğu gibi) kullanın;

  • Sprite'ları atlaslara sıkıca paketlediğinizden emin olun (bkz. Bin Ambalaj algoritmalarına bakın), gerektiğinde spriteları çevirin ve eşkenar dörtgen spritelar için saydam köşeleri üst üste binebilecek misiniz;

  • Sen deneyebilirsiniz donanım sıkıştırma formatlarını (vb DXT, S3TC) - onlar dramatik RAM kullanımını azaltmak, ancak sıkıştırma eserler için kontrol edebilirsiniz - bazı resimlerde fark (eğer seçici olarak İlk maddedeki tarif bu kullanabilirsiniz) fark edilemez olabilir, ama bazılarında - çok telaffuz. Farklı sıkıştırma formatları farklı yapılara neden olur, bu nedenle sanat tarzınıza en uygun olanı seçebilirsiniz.

  • İçine bak bölme büyük sprite (elbette değil elle, ancak paketleyici atlası Texture içinde) statik arka plan sprite ve animasyonlu parçalar için daha küçük sprite.


2
DXT kullanmak için +1, olması çok iyi bir şey. Mükemmel sıkıştırma ve doğrudan GPU tarafından kullanıldığından, ek yük minimum düzeydedir.

1
Dxt ile aynı fikirdeyim. Ayrıca DXT7 desteği (DX11 + hardware) için sorgu yapabilir, bu da DXT1 ile aynı boyuttadır ancak (görünüşte) daha yüksek kalitededir. Ancak, yükleme sırasında çift dokuya (bir DXT7 ve bir DXT1) çift baskı yapmanız veya sıkıştırmayı / sıkıştırmayı açmanız gerekir.
Program

5

Öncelikle daha küçük doku atlası kullanmanız gerekir. Ne kadar az dokuya sahipseniz o kadar zor ve katı bir hafıza yönetimi olacaktır. 1024'lük bir atlas büyüklüğü öneririm, bu durumda 2 yerine 128 dokuya veya 2048'e, bu durumda da gerektiği gibi yükleyip boşaltabileceğiniz 32 dokuya sahip olacaktınız.

Çoğu oyun bu kaynak yönetimini seviye sınırlarına göre yapar, yükleme ekranı artık bir sonraki seviyede ihtiyaç duyulmayan tüm kaynakları kaldırır ve gerekli kaynaklar yüklenir.

Diğer bir seçenek ise, seviye sınırları istenmediğinde veya tek bir seviye bile belleğe sığmayacak kadar büyük olduğunda gerekli olan Talep Üzerine Yükleme'dir. Bu durumda oyun gelecekte oyuncunun ne göreceğini tahmin etmeye çalışacak ve arka planda bunu yükleyecektir. (Örneğin: şu anda oynatıcıdan 2 ekran uzakta olan şeyler.) Aynı zamanda daha uzun süre kullanılmayan şeyler de kaldırılacak.

Ancak bir sorun var, oyunun öngöremediği bir şey beklenmedik bir şey olduğunda ne olacak?

  • Gerekli tüm şeyler yüklenene kadar yükleme ekranını kaydırma ve görüntüleme. Bu, deneyim için yıkıcı olabilir.
  • Önceden yüklenmiş her şey için düşük çözünürlüklü sprite yapın, oyuna devam edin ve yüksek çözünürlüklü sprite yükleme biter bitmez bunları değiştirin. Bu oyuncu için ucuz görünebilir.
  • Oyunu etkilemesini sağlayın ve etkinliği gerektiği kadar geciktirin. Örneğin, grafikleri yüklenene kadar bu düşmanı ortaya çıkarmayın. Bu yağma için tüm grafikler yüklenmeden önce hazine sandığını açmayın.

İhmal ettiğim bazı gereksinimleri ekledim. Yükleme ekranı veya herhangi bir yükleme mümkün değildir. Her şey arka planda veya bireysel keneler arasında (her biri için 15ms'den az) yapılmalıdır, oysa hazırlıklar ve oyun güncellemesi tarafından genellikle kullanılan çoğu zaman vardır. Her neyse, daha küçük parçalara bölmek, anahtarlamada bir miktar esneklik katabilir, kesinlikle daha hızlı olacaktır. Sorun, çizim sırasında kaynak bitmap'ini değiştirmek render işlemini yavaşlattığından, oluşturma sırasında performansın ne kadar acı vereceğidir. Ne kadar olduğunu söylemek için tam bir ölçüm yapmak zorunda kalacağım.
Marwin

@Marwin Performance'ın etkisi, evet, ama 2D ile ilgilendiğiniz için, sorun olmaktan hala uzak olmalısınız. Görüntü oluşturma şu anda kare başına 1ms alıyorsa ve daha küçük dokuları kullanarak aniden 2ms alıyorsa, o zaman yine de 60 FPS'ye ulaşmak için yeterince hızlıdır. (16ms)
API-Canavar

@Marwin Multiplayer zor bir iş, her zaman olduğu, her zaman olacaktır. Orada muhtemelen uzlaşmalar yapmak zorunda kalacaksınız. Bilgisayarlara veri aktarmanız gerektiğinden, paketlerin kaybolması, ping'lerin aniden yükselmesi vb. Ne zaman bekleyeceğinizi ve diğer oyuncuları nasıl bekleyeceğinizi bilmek.
API-Beast

Merhaba, kekemelik çok oyunculu oyunlarda neredeyse önlenebilir, şu anda bu alanda çalışıyoruz ve iyi bir planımız olduğuna inanıyorum. Daha sonra detaylı olarak araştırdıklarımızı açıklayan kendi sorumu bile gönderebilir ve cevaplayabilirdim :) Bu sürpriz olabilir, ancak oluşturma süresi aslında bir konudur. İşlemeyi daha hızlı hale getirmek için birçok optimizasyon yaptık. Ana render şimdi ayrı dişlerde ve diğer küçük ince ayarlarda yapılır. Unutmayın, maksimum zumda, oyuncu aynı anda on binlerce spriti kolayca görebilir. Daha sonra daha yüksek zoom seviyelerine bile izin vermek istiyoruz.
Marwin

@Marwin Hm, 10k nesneler, uygun toplu kullanım kullanıyorsanız, bir PC veya modern dizüstü bilgisayar için genellikle sorun olmamalıdır, oluşturma kodunuzu profillediniz mi?
API-Beast

2

Vay canına, bu tahmin ettiğim 3D modellerden üretilen ağır miktarda animasyonlu sprite?

Bu oyunu gerçekten ham 2D ​​olarak yapmamalısın. Sabit bir perspektife sahip olduğunuzda, komik bir şey olduğunda, önceden oluşturulmuş sprite'ları ve arka planları, bazı oyunlar tarafından yoğun olarak kullanılan canlı render 3D modelleriyle sorunsuz bir şekilde karıştırabilirsiniz. Böyle güzel animasyonlar istiyorsanız bunu yapmanın en doğal yolu gibi görünüyor. Bir 3B motoru edinin, izometrik perspektif kullanacak şekilde yapılandırın ve kullanmaya devam ettiğiniz nesneleri, üzerinde bir görüntü bulunan basit düz yüzeyler olarak kullanın. Ve 3D sıkıştırma ile doku sıkıştırmayı kullanabilirsiniz, ki bu tek başına ileriye doğru büyük bir adımdır.

Aynı anda ekranda hemen hemen her şeye sahip olabileceğinizden, yükleme ve boşaltma işlemlerinin sizin için çok fazla olacağını düşünmüyorum.


2

Öncelikle, oyunun görsellerinden memnun olup olmadığını, RGBA4444 veya DXT sıkıştırması vb. Olsun, elde edebileceğiniz en verimli doku formatını bulun. alfa için 4 veya 8 bit gri tonlamalı maskeleme dokusuyla birleştirilen renk için DXT1 sıkıştırmasını kullanarak görüntüleri saydam olmayan hale getirmek için? GUI için RGBA8888’de kalacağınızı hayal ediyorum.

Karar verdiğiniz formatı kullanarak işleri daha küçük dokulara bölmeyi savunuyorum. Her zaman ekranda olan ve dolayısıyla her zaman yüklü olan öğeleri belirleyin; bu, arazi ve GUI atlasları olabilir. Daha sonra, mümkün olduğu kadar birlikte bir araya getirilmiş olan kalan parçaları parçalarım. PC'de 50-100 arama çağrısına kadar çok fazla performans kaybedeceğinizi sanmıyorum, ancak hatalıysam beni düzeltin.

Bir sonraki adım, yukarıda belirtilen birisinin bu dokuların mipmap versiyonlarını oluşturmak olacaktır. Onları tek bir dosyada değil, ayrı bir yerde saklardım. Böylece her dosyanın 1024x1024, 512x512, 256x256 vb. Sürümleriyle bitirdiniz ve şimdiye kadar görüntülenmesini isteyeceğim en düşük ayrıntı seviyesine ulaşana kadar bunu yapacağım.

Artık ayrı dokulara sahip olduğunuza göre, mevcut yakınlaştırma seviyesi için dokuları yükleyen ve kullanılmazsa dokuları kaldıran bir ayrıntı seviyesi (LOD) sistemi oluşturabilirsiniz. Oluşturulan öğe ekranda değilse veya geçerli yakınlaştırma düzeyinde gerekli değilse, doku kullanılmaz. Güncelleme / oluşturma iş parçacıklarından ayrı bir iş parçacığındaki dokuları video RAM'e yüklemeyi deneyin. İstenilen yüklenene kadar en düşük LOD dokusunu görüntüleyebilirsiniz. Bu bazen düşük detay / yüksek detay dokusu arasında görünür bir geçişe neden olabilir, ancak bunun yalnızca harita üzerinde hareket ederken çok hızlı uzaklaştırma ve uzaklaştırma yaptığınız zaman olacağını düşünüyorum. Mevcut bellek kısıtlamaları dahilinde, kişinin hareket edebileceğini veya yakınlaştırabileceğini ve yükleyebileceğini düşündüğü yeri ön yükleyerek sistemi akıllı hale getirebilirsin.

Bu işe yarayıp yaramadığını görmek için test edeceğim bir şey. Aşırı yakınlaştırma seviyelerini elde etmek için kaçınılmaz olarak bir LOD sistemine ihtiyacınız olacağını hayal ediyorum.


1

En iyi yaklaşımın dokuyu birçok dosyaya bölmek ve istek üzerine yüklemek olduğuna inanıyorum. Muhtemelen sizin probleminiz, tam bir 3B sahne için ihtiyaç duyacağınız daha büyük dokuları yüklemeye çalışmak ve bunun için Allegro kullanıyor olmanızdır.

Başvurabilmek istediğiniz büyük zoom için mipmap kullanmanız gerekir. Mipmap'ler, nesneler kameradan yeterince uzaktayken kullanılan, dokularınızın daha düşük çözünürlüklü versiyonlarıdır. Bu, 8192x8192'nizi 4096x4096 ve sonra başka bir 2048x2048 gibi kaydedebileceğiniz anlamına gelir ve daha düşük çözünürlüklere geçtiğinizde ekrandaki sprite miktarı azalır. Her ikisini de ayrı dokular olarak kaydedebilir veya yüklerken yeniden boyutlandırabilirsiniz (ancak çalışma sırasında mipmap oluşturmak, oyununuzun yükleme süresini artıracaktır).

Uygun bir yönetim sistemi gerekli dosyaları talep üzerine yükler ve hiç kimse kullanmadığında kaynakları ve başka şeyleri kullanırken kaynakları serbest bırakır. Kaynak yönetimi, oyun geliştirmede önemli bir konudur ve yönetiminizi, tek bir dokuya basit bir koordinat eşleştirmesine indirgemezsiniz;


1
Dosyalara bölerek HDD'deki dosyaları mı kastediyorsunuz? Başlangıçta tüm fotoğrafları RAM'de saklayabileceğimi ve bellek-bitmap'ten video-bitmap'e kopyalamanın şu anda çok yavaş olduğunu ve HDD'den yükleme işleminin daha yavaş olacağını düşünüyorum. MIMPAPP'lerin olması bana yardım etmeyecek, çünkü hala en büyük çözünürlüğe sahip olacağım.
Marwin,

Evet, her şeyi yüklemek zorunda değilsin, sadece kullandığın şeyi yüklemek zorundasın. VRAM'da yüklü bir doku üzerindeki bir pikseli değiştirmek istediğinizde, sistemin GİRİŞ DOKUSU'nu RAM'e taşıması gerekir, sadece tek bir pikseli değiştirebilmeniz için VRAM'a geri götürün. Tek bir dokuda her şeye sahipseniz, bu işlem 256 MB RAM’e taşındıktan sonra tüm bilgisayarı kilitleyen VRAM’e geri dönmeyi gerektirir. Farklı dosya ve dokularda ayırmak, doğru yapmanın yoludur.
Pablo Ariel

Kopyayı belleğe ve ram'a geri tetikleyen dokunun değiştirilmesi yalnızca kalıcı bitmapler için geçerlidir; önbellek muhtemelen kalıcı olarak ayarlanmayacaktır, tek dezavantajı ekran kaybolduğunda / bulunduğunda onu yenileme ihtiyacı olacaktır. Ancak allegro'da, 640X480 boyutundaki fotoğrafın basit bir kopyası vram'dan hafıza bitmapine (oyun önizlemesini kaydet) bile oldukça uzun sürüyor.
Marwin

1
Çizimin kendisini optimize etmek için her şeyi tek bir büyük dokuda bulmam gerekiyor, onsuz, bireysel spritelar arasında bağlam değiştirmenin etkisi, en azından allegroda renderleme yolunu çok yavaşlatıyor. Beni yanlış anlama, ama belli ki, bu soru için sorduğum bir şeyi yapmamı önerdiğin gibi, burada açık bir kaptansın.
Marwin

1
Bu mip eşlemeli dokuların farklı dosyalarda olması, oyuncu yakınlaştırdığında tüm atlasları yeniden yüklemem için beni zorlar. Motor bunun için sadece birkaç ms biriminden oluştuğu için, bunun nasıl yapılacağını göremiyorum.
Marwin

0

Zlib ile sıkıştırılabilecek ve her atlas için sıkıştırmanın dışında kalan daha fazla atlas dosyası oluşturmanızı ve daha fazla atlas ve daha küçük boyutlu dosyalara sahip olarak, video belleğindeki aktif görüntü verilerinin miktarını sınırlandırabilirsiniz. Ayrıca, üçlü arabellek mekanizmasını da uygulayın, böylece her bir çekme çerçevesini daha erken hazırlarsınız ve kalıpların ekranda görünmemesi için daha hızlı bir şekilde tamamlama şansınız olur.

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.