Bagaimana kita mengatasi kebutuhan memori video besar dalam game 2D?

40

Bagaimana kita mengatasi kebutuhan memori video besar dalam game 2D?


Kami sedang mengembangkan game 2D (Factorio) di allegro C / C ++, dan kami menghadapi masalah dengan meningkatnya kebutuhan memori video saat konten game meningkat.

Kami saat ini mengumpulkan semua info tentang gambar yang akan digunakan pertama, memotong semua gambar ini sebanyak mungkin dan mengaturnya menjadi atlas besar sekencang mungkin. Atlas ini disimpan dalam memori video, yang ukurannya tergantung pada keterbatasan sistem; saat ini biasanya 2 gambar hingga 8192x8192, sehingga mereka membutuhkan memori video 256Mb hingga 512Mb.

Sistem ini bekerja sangat baik bagi kami, karena dengan beberapa optimasi kustom dan memisahkan render dan memperbarui utas kami dapat menggambar puluhan ribu gambar di layar dalam 60 fps; kami memiliki banyak objek di layar, dan memungkinkan zoom-out besar adalah persyaratan penting. Karena kami ingin menambahkan lebih banyak, akan ada beberapa masalah dengan persyaratan memori video, sehingga sistem ini tidak mungkin dapat menampung.

Salah satu hal yang ingin kami coba adalah memiliki satu atlas dengan gambar yang paling umum, dan yang kedua sebagai cache. Gambar akan dipindahkan ke sana dari bitmap memori, sesuai permintaan. Ada dua masalah dengan pendekatan ini:

  1. Gambar dari bitmap memori ke bitmap video sangat lambat, allegro.
  2. Tidak mungkin untuk bekerja dengan bitmap video selain dari utas utama, di allegro, sehingga secara praktis tidak dapat digunakan.

Berikut adalah beberapa persyaratan tambahan yang kami miliki:

  • Gim harus bersifat tekad, sehingga masalah kinerja / waktu pemuatan tidak pernah dapat mengubah status gim.
  • Gim ini real-time, dan akan segera menjadi multipemain. Kita perlu menghindari bahkan gagap terkecil di semua biaya.
  • Sebagian besar permainan adalah satu dunia terbuka yang berkelanjutan.

Tes terdiri dari menggambar 10.000 sprite dalam satu batch untuk ukuran dari 1x1 hingga 300x300, beberapa kali untuk setiap konfigurasi. Saya melakukan tes pada Nvidia Geforce GTX 760.

  • Bitmap video ke gambar bitmap video mengambil 0,1us per sprite, ketika bitmap sumber tidak berubah di antara bitmap individu (varian atlas); ukurannya tidak masalah
  • Bitmap video ke gambar bitmap video, sedangkan bitmap sumber dialihkan di antara gambar (varian non atlas), mengambil 0,56us per sprite; ukurannya juga tidak masalah.
  • Memori bitmap ke gambar bitmap video benar-benar mencurigakan. Ukuran dari 1x1 hingga 200x200 mengambil 0,3us per bitmap, jadi tidak terlalu lambat. Untuk ukuran yang lebih besar, waktu mulai meningkat secara dramatis, pada 9us untuk 201x201 hingga 3116us untuk 291x291.

Menggunakan atlas meningkatkan kinerja dengan faktor lebih besar dari 5. Jika saya memiliki 10ms untuk rendering, dengan atlas saya dibatasi hingga 100.000 sprite per frame, dan tanpa itu, batas 20.000 sprite. Ini akan bermasalah.

Saya juga mencoba menemukan cara untuk menguji kompresi bitmap dan format bitmap 1bpp untuk bayangan, tetapi saya tidak dapat menemukan cara untuk melakukan ini di allegro.

Marwin
sumber
1
Penggemar game Anda, saya mendukung kampanye Indiegogo. Saya memakannya setiap beberapa bulan. Kerja bagus sejauh ini! Saya menghapus pertanyaan "teknologi mana yang harus digunakan" yang berada di luar topik situs. Pertanyaan yang tersisa masih cukup luas, jika Anda memiliki sesuatu yang lebih spesifik, Anda harus mencoba mempersempit ruang lingkup.
MichaelHouse
Terima kasih atas dukungannya. Jadi di mana tempat untuk bertanya teknologi mana yang akan digunakan? Saya tidak mencari jawaban dengan rekomendasi mesin tertentu, tetapi saya tidak dapat menemukan perbandingan mendalam dari mesin 2d dan memeriksanya secara manual satu per satu termasuk pengujian kinerja dan kegunaan akan memakan waktu lama.
Marwin
Lihatlah bagian bawah halaman ini untuk beberapa tempat untuk mengajukan pertanyaan seperti "teknologi mana yang harus digunakan". Anda memiliki pertanyaan yang benar-benar valid dan masuk akal, hanya saja bukan jenis pertanyaan yang kami tangani di situs ini. Meskipun Anda tidak mencari mesin tertentu, itu satu-satunya cara untuk menjawab pertanyaan "Apakah ada teknologi yang menggunakan X?". Seseorang bisa saja menjawab "ya" dan tidak memberikan rekomendasi untuk yang spesifik, tetapi itu tidak akan sangat membantu. Semoga berhasil!
MichaelHouse
2
Apakah Anda mengompresi tekstur Anda?
GuyRT
3
@ Marwin, Tekstur terkompresi dapat melakukan jauh lebih baik daripada tekstur tidak terkompresi karena mereka mengurangi bandwidth memori yang dibutuhkan (ini terutama berlaku pada platform seluler di mana bandwidth jauh lebih rendah). Anda dapat menyimpan sejumlah besar memori hanya dengan mengompresi tekstur Anda. Sungguh, satu-satunya downside adalah artefak yang pasti diperkenalkan.
GuyRT

Jawaban:

17

Kami memiliki kasus serupa dengan RTS kami (Remake KaM). Semua unit dan rumah adalah sprite. Kami memiliki 18.000 sprite untuk unit, rumah, dan medan, ditambah 6.000 lainnya untuk warna tim (diterapkan sebagai topeng). Jangka panjang kami juga memiliki sekitar ~ 30 000 karakter yang digunakan dalam font.

Jadi ada beberapa optimisasi terhadap atlas RGBA32 yang Anda gunakan:

  • Pisahkan kumpulan sprite Anda menjadi banyak atlas yang lebih kecil terlebih dahulu dan gunakan sesuai permintaan sebagaimana tercakup dalam jawaban lain. Itu juga memungkinkan untuk menggunakan teknik optimasi yang berbeda untuk setiap atlas secara individual . Saya menduga Anda akan memiliki sedikit RAM yang terbuang, karena ketika mengemas tekstur sedemikian besar biasanya ada area yang tidak digunakan di bagian bawah;

  • Cobalah menggunakan tekstur palet . Jika Anda menggunakan shader Anda dapat "menerapkan" palet dalam kode shader;

  • Anda mungkin ingin menambahkan opsi untuk menggunakan RGB5_A1 alih-alih RGBA8 (jika misalnya bayangan kotak-kotak tidak masalah untuk game Anda). Hindari 8bit Alpha jika memungkinkan dan gunakan format RGB5_A1 atau setara dengan presisi yang lebih kecil (sama seperti RGBA4), mereka mengambil setengah ruang;

  • Pastikan Anda mengemas sprite dengan ketat menjadi atlas (lihat Algoritma Pengemasan Bin), putar sprite bila perlu dan lihat apakah Anda dapat tumpang tindih sudut transparan untuk spanduk belah ketupat;

  • Anda dapat mencoba format kompresi perangkat keras (DXT, S3TC, dll.) - mereka dapat secara dramatis mengurangi penggunaan RAM, tetapi memeriksa artefak kompresi - pada beberapa gambar perbedaannya tidak terlalu mencolok (Anda dapat menggunakan ini secara selektif seperti dijelaskan pada poin pertama), tetapi pada beberapa - sangat diucapkan. Format kompresi yang berbeda menyebabkan artefak yang berbeda, sehingga Anda dapat memilih yang terbaik untuk gaya seni Anda.

  • Lihatlah ke sprite besar yang membelah (tentu saja tidak secara manual, tetapi di dalam pengemas atlas tekstur Anda) menjadi sprite latar belakang statis dan sprite yang lebih kecil untuk bagian animasi.

Kromster berkata mendukung Monica
sumber
2
+1 untuk menggunakan DXT, itu adalah hal yang sangat baik untuk dimiliki. Kompresi hebat dan digunakan langsung oleh GPU sehingga overhead-nya minimal.
1
Saya setuju dengan dxt. Anda juga dapat meminta dukungan DXT7 (perangkat keras DX11 +), yang ukurannya sama dengan DXT1 tetapi (tampaknya) berkualitas lebih tinggi. Namun Anda harus menggandakan tekstur (satu DXT7 dan satu DXT1), atau kompres / dekompresi saat memuat.
Programmdude
5

Pertama-tama Anda perlu menggunakan lebih banyak, atlas tekstur yang lebih kecil. Semakin sedikit tekstur yang Anda miliki, manajemen memori akan semakin sulit dan kaku. Saya akan menyarankan ukuran atlas 1024, dalam hal ini Anda akan memiliki 128 tekstur bukan 2, atau 2048 dalam hal ini Anda akan memiliki 32 tekstur, yang dapat Anda muat dan bongkar sesuai kebutuhan.

Sebagian besar permainan melakukan manajemen sumber daya ini dengan memiliki batas level, sementara layar pemuatan ditampilkan semua sumber daya yang tidak diperlukan lagi di tingkat berikutnya dibongkar dan sumber daya yang diperlukan dimuat.

Pilihan lain adalah On-Demand loading, yang menjadi perlu jika batas level tidak diinginkan atau bahkan level tunggal terlalu besar untuk masuk ke dalam memori. Dalam hal ini gim akan mencoba memprediksi apa yang akan dilihat pemain di masa depan dan memuatnya di latar belakang. (Misalnya: barang-barang yang saat ini berjarak 2 layar dari pemain.) Pada saat yang sama hal-hal yang tidak digunakan lagi untuk waktu yang lebih lama akan diturunkan.

Namun ada satu masalah, apa yang terjadi ketika sesuatu yang tidak terduga terjadi yang tidak dapat diramalkan oleh game?

  • Panik dan tampilkan layar muat sampai semua barang yang diperlukan dimuat. Ini mungkin terasa mengganggu pengalaman.
  • Memiliki sprite resolusi rendah untuk semua yang dimuat sebelumnya, melanjutkan game dan menggantinya segera setelah sprite resolusi tinggi selesai memuat. Ini mungkin terlihat murah bagi pemain.
  • Buat itu berdampak pada gameplay dan tunda acara selama diperlukan. Misalnya, jangan menelurkan musuh itu sampai gambarnya dimuat. Jangan buka peti harta karun itu sebelum semua gambar untuk jarahan itu dimuat, dll.
API-Beast
sumber
Saya menambahkan beberapa persyaratan yang saya abaikan. Layar memuat, atau segala jenis pemuatan tidak dimungkinkan. Semuanya harus dilakukan di latar belakang, atau di antara kutu individu (kurang dari 15 ms untuk masing-masing) sementara ada sebagian besar waktu yang biasanya sudah digunakan oleh persiapan render dan pembaruan game. Bagaimanapun, pemisahan ke bagian-bagian yang lebih kecil mungkin menambah fleksibilitas dalam pergantian, itu akan lebih cepat pasti. Pertanyaannya adalah seberapa besar itu merugikan kinerja saat rendering, karena mengganti bitmap sumber sambil menggambar memperlambat render. Saya harus melakukan pengukuran yang tepat untuk mengatakan berapa banyak.
Marwin
@Marwin Dampak kinerja, ya, tapi karena Anda berurusan dengan 2D Anda harusnya masih jauh dari itu menjadi masalah. Jika rendering saat ini membutuhkan 1ms per frame, dan dengan menggunakan tekstur yang lebih kecil tiba-tiba dibutuhkan 2ms maka itu masih lebih dari cukup cepat untuk mencapai 60 FPS yang konsisten. (16ms)
API-Beast
@Marwin Multiplayer adalah bisnis yang rumit, selalu, selalu akan. Anda kemungkinan besar harus membuat kompromi di sana. Anda akan mengalami gagap, hanya karena Anda harus mentransfer data melalui internet, paket akan hilang, ping tiba-tiba melonjak, dll. Gagap tidak dapat dihindari sehingga Anda yang lebih penting adalah membuat model jaringan itu sendiri tahan terhadap gagap. Mengetahui kapan harus menunggu & bagaimana menunggu pemain lain.
API-Beast
Halo, gagap hampir dapat dihindari dalam multipemain, kami sedang mengerjakan area itu sekarang, dan saya yakin kami memiliki rencana yang bagus. Saya bahkan bisa memposting dan menjawab pertanyaan saya sendiri yang menjelaskan apa yang kami teliti secara rinci nanti :) Mungkin mengejutkan, tetapi waktu render sebenarnya adalah masalah. Kami telah melakukan banyak optimisasi untuk menjadikan rendering lebih cepat. Render utama sekarang dibuat di utas terpisah dan tweak kecil lainnya. Jangan lupa, bahwa pada zoom maks, pemain dapat dengan mudah melihat puluhan ribu sprite pada saat yang sama. Dan kami bahkan ingin mengizinkan tingkat zoom yang lebih tinggi lagi nanti.
Marwin
@ Marswin Hm, objek 10k biasanya tidak menjadi masalah untuk PC atau laptop modern jika Anda menggunakan batching yang tepat, sudahkah Anda membuat profil kode rendering Anda?
API-Beast
2

Wow, itu lumayan banyak sprite animasi, dihasilkan dari model 3D saya kira?

Anda seharusnya tidak membuat game ini dalam 2D ​​mentah. Ketika Anda memiliki perspektif tetap, hal lucu terjadi, Anda dapat dengan mulus mencampurkan sprite dan latar yang telah dirender sebelumnya dengan model 3D yang dibuat langsung, yang telah banyak digunakan oleh beberapa game. Jika Anda menginginkan animasi yang begitu bagus, itu sepertinya cara paling alami untuk melakukannya. Dapatkan mesin 3D, konfigurasikan untuk menggunakan perspektif isometrik, dan render objek yang Anda terus gunakan sprite sebagai permukaan datar sederhana dengan gambar di atasnya. Dan Anda dapat menggunakan kompresi tekstur dengan mesin 3D, itu saja merupakan langkah maju yang besar.

Saya tidak berpikir memuat dan membongkar akan banyak membantu Anda karena Anda dapat memiliki hampir semua yang ada di layar pada saat yang sama.

aaaaaaaaaaaa
sumber
2

Pertama-tama temukan format tekstur paling efisien yang Anda dapat sambil tetap senang dengan visual permainan apakah ini RGBA4444, atau kompresi DXT dll. Jika Anda tidak puas dengan artefak yang dihasilkan menjadi gambar yang dikompresi alfa DXT, apakah itu layak membuat gambar non-transparan menggunakan kompresi DXT1 untuk warna yang dikombinasikan dengan tekstur masking abu-abu 4 atau 8 bit untuk alpha? Saya membayangkan Anda akan tetap menggunakan RGBA8888 untuk GUI.

Saya menganjurkan memecah hal-hal menjadi tekstur yang lebih kecil menggunakan format apa pun yang Anda memutuskan. Tentukan item yang selalu ada di layar dan karena itu selalu dimuat, ini mungkin dataran dan GUI atlas. Saya kemudian akan memecah item yang tersisa yang biasanya dirender bersama sebanyak mungkin. Saya tidak membayangkan Anda akan kehilangan terlalu banyak kinerja bahkan hingga 50-100 panggilan imbang pada PC tetapi perbaiki jika saya salah.

Langkah selanjutnya adalah membuat versi mipmap dari tekstur ini seperti yang ditunjukkan seseorang di atas. Saya tidak akan menyimpannya dalam satu file tetapi secara terpisah. Jadi, Anda akan mendapatkan versi 1024x1024, 512x512, 256x256 dll dari setiap file dan saya akan melakukan ini sampai saya mencapai tingkat detail terendah yang ingin saya tampilkan.

Sekarang Anda memiliki tekstur terpisah, Anda dapat membangun sistem level of detail (LOD) yang memuat tekstur untuk tingkat zoom saat ini, dan menurunkan tekstur jika tidak digunakan. Tekstur tidak digunakan jika item yang diberikan tidak ada di layar atau tidak diperlukan oleh level zoom saat ini. Cobalah untuk memuat tekstur ke dalam RAM video dalam utas yang terpisah dengan utas pembaruan / render. Anda dapat menampilkan tekstur LOD terendah hingga yang diperlukan dimuat. Ini kadang-kadang menghasilkan perubahan yang terlihat antara detail rendah / tekstur detail tinggi tapi saya membayangkan ini hanya akan terjadi ketika Anda melakukan zooming yang sangat cepat keluar dan masuk saat bergerak melintasi peta. Anda dapat membuat sistem cerdas dengan mencoba melakukan preload di tempat yang menurut Anda orang tersebut akan bergerak atau memperbesar dan memuat sebanyak mungkin dalam batasan memori saat ini.

Itu adalah hal yang akan saya uji untuk melihat apakah itu membantu. Saya membayangkan untuk mendapatkan tingkat pembesaran yang ekstrem Anda pasti akan membutuhkan sistem LOD.

Kristen
sumber
1

Saya percaya bahwa pendekatan terbaik adalah dengan membagi tekstur dalam banyak file dan memuatnya sesuai permintaan. Mungkin masalah Anda adalah Anda mencoba memuat tekstur yang lebih besar yang Anda perlukan untuk adegan 3D yang lengkap dan Anda menggunakan Allegro untuk itu.

Untuk zoom-out besar yang ingin Anda terapkan, Anda harus menggunakan mipmaps. Mipmaps adalah versi resolusi rendah dari tekstur Anda yang digunakan ketika objek cukup jauh dari kamera. Ini berarti bahwa Anda dapat menyimpan 8192x8192 Anda sebagai 4096x4096 dan kemudian 2048x2048 dan seterusnya, dan Anda beralih ke resolusi yang lebih rendah semakin kecil Anda melihat sprite di layar. Anda dapat menyimpan keduanya sebagai tekstur terpisah atau mengubah ukurannya saat memuat (tetapi membuat mipmaps saat runtime akan meningkatkan waktu pemuatan untuk game Anda).

Sistem manajemen yang tepat akan memuat file yang diperlukan sesuai permintaan dan melepaskan sumber daya ketika tidak ada yang menggunakannya, ditambah hal-hal lain. Manajemen sumber daya adalah topik penting dalam pengembangan game dan Anda mereduksi manajemen Anda menjadi pemetaan koordinat sederhana menjadi satu tekstur, yang hampir tidak memiliki manajemen sama sekali.

Pablo Ariel
sumber
1
Dengan memisahkan ke file, maksud Anda file di HDD? Saya berasumsi, bahwa saya dapat menyimpan semua gambar pada RAM sebagai permulaan, dan bahkan menyalin dari memori-bitmap ke video-bitmap saat ini terlalu lambat, sehingga memuat dari HDD tentu akan lebih lambat. Memiliki mimpaps tidak akan membantu saya, karena saya masih akan memiliki resolusi terbesar di vram.
Marwin
Ya, Anda tidak harus memuat semuanya, Anda harus memuat hanya apa yang Anda gunakan. Setiap kali Anda ingin mengubah piksel pada tekstur yang dimuat dalam VRAM, sistem harus memindahkan SELURUH TEKSTUR ke RAM, hanya untuk Anda memodifikasi satu piksel, pindahkan kembali ke VRAM. Jika Anda memiliki semuanya dalam satu tekstur, ini melibatkan pemindahan 256 MB ke RAM kemudian kembali ke VRAM, yang mengunci seluruh komputer. Memisahkannya dalam berbagai file dan tekstur adalah cara yang tepat untuk melakukannya.
Pablo Ariel
Modifikasi tekstur yang memicu penyalinan ke memori dan kembali ke ram hanya berlaku untuk bitmap persisten, cache mungkin tidak akan disetel ke persistent, satu-satunya downside adalah kebutuhan untuk menyegarkannya ketika tampilan hilang / ditemukan. Namun dalam allegro, bahkan salinan sederhana gambar 640X480 dari vram ke memori bitmap (save preview game) membutuhkan waktu yang cukup lama.
Marwin
1
Saya perlu memiliki segalanya dalam satu tekstur besar untuk mengoptimalkan gambar itu sendiri, tanpa itu, efek dari beralih konteks di antara sprite individu memperlambat jalan membuat terlalu banyak setidaknya di allegro. Jangan salah paham, tetapi Anda agak kapten di sini, karena Anda secara samar menyarankan saya untuk melakukan sesuatu yang saya minta dalam pertanyaan ini.
Marwin
1
Memiliki tekstur yang dipetakan-mip dalam file yang berbeda akan memaksa saya untuk memuat ulang semua atlas ketika pemain memperbesar. Karena mesin hanya memiliki beberapa unit ms untuk paling banyak, saya tidak melihat cara bagaimana melakukannya.
Marwin
0

Saya sarankan untuk membuat lebih banyak file atlas yang dapat dikompresi dengan zlib dan dialirkan keluar dari kompresi untuk setiap atlas, dan dengan memiliki lebih banyak file atlas dan file ukuran yang lebih kecil Anda dapat menahan jumlah data gambar aktif dalam memori video. Selain itu, terapkan mekanisme triple buffer sehingga Anda menyiapkan masing-masing bingkai gambar lebih cepat dan memiliki kesempatan untuk menyelesaikan lebih cepat sehingga gagap tidak muncul di layar.

Darxval
sumber