Menggambar ubin dalam jumlah besar di Monogame (XNA) secara efisien


8

Saya mengajukan pertanyaan ini karena saya belum menemukan jawaban pasti untuk itu.

Biarkan saya pertama-tama menyatakan beberapa hal tentang permainan dan apa yang telah saya lakukan. Gim ini akan menjadi set RTS di dunia yang dihasilkan secara prosedural menggunakan noise Simplex. Dunia terdiri dari bongkahan yang berukuran 16 x 16 yang terbuat dari sprite yang berukuran 64 x 64. Saya telah berhasil memuat dan membongkar bongkahan secara dinamis, yang berfungsi dengan baik. Dunia akan terlihat sedikit seperti Rimworld, jadi top-down dengan berbagai lapisan sprite (medan pertama, sprite transisi, pohon, decals, dll). Dunia yang baru dihasilkan dapat berisi entitas yang dapat memengaruhi lingkungan (mis. Desa yang telah menjadi kota) dan dengan demikian bagian itu. Saya yakin ini bisa dihitung menggunakan semacam fungsi, tapi itu sesuatu yang perlu diperhatikan.

Masalah utama yang saya miliki adalah ketika saya memperkecil, semakin banyak ubin yang ditarik yang sangat mempengaruhi kinerja. Pada sekitar 30000 sprite, bagian undian mengambil 8 ms yang merupakan setengah dari yang diperlukan untuk dijalankan pada 60 FPS. Dan itu hanya medannya. Saya menggunakan atlas tekstur untuk membatasi jumlah undian (30000 sprite digambar dalam 6 jumlah).

The Tujuan adalah untuk dapat tampilannya keluar dari kota / desa / kota semua jalan untuk dapat melihat seluruh negeri. Ini memiliki harus dilakukan secara dinamis (misalnya. Tidak dengan mengklik pada icon minimap, tetapi hanya gulir kembali seperti di Panglima Tertinggi).

Saya telah membaca banyak artikel tentang masalah ini, tetapi saya belum menemukan atau melihat contoh yang jelas tentang di mana ia akan bekerja. Berikut adalah daftar teknik yang saya temukan yang seharusnya berfungsi:

  • Persegi panjang kotor, seperti yang dijelaskan di sini , di mana Anda hanya menggambar barang baru dan menyimpan sisanya di backbuffer. Ini sangat masuk akal, tapi saya tidak mengerti bagaimana menerapkannya di Monogame.
  • Pilihan pilihan saya: gunakan RenderTarget secara ekstensif, seperti dijelaskan di sini , tempat Anda menggambar RenderTarget dan kemudian simpan sebagai tekstur. Dalam kasus saya potongan 16 x 16 yang terdiri dari 64 x 64 akan menghasilkan tekstur 1024 x 1024. Saya benar-benar ragu ini akan bekerja dalam hal kinerja, tetapi hasilnya akan terdiri dari tekstur yang sangat rinci dan juga bagus untuk digunakan mengingat fakta bahwa sebagian besar itu statis (medan / pohon dll), dan tidak berubah banyak. Tapi ini juga berarti bahwa setiap kali perubahan dilakukan ke chunk, Texture2D harus diubah menggunakan SetData, yang dari apa yang saya alami cukup intensif dengan CPU. Namun jika teksturnya 16 x 16 mungkin benar-benar berfungsi, dan itu juga akan mengurangi penggunaan memori dan disk.
  • Til tekstur dengan menentukan SourceRectangle di SpriteBatch. Untuk padang rumput besar / lautan ini adalah nilai tambah, karena hanya satu sprite yang diambil. Namun untuk medan terperinci dengan warna berbeda dan sprite berbeda dicampur bersama (transisi bioma dan bioma), saya khawatir itu tidak akan membuat perbedaan besar.
  • Solusi saya sendiri, yang mengkompromikan detail, adalah dengan menggunakan ubin putih standar 64 x 64, beri warna 4 ubin di sekitarnya dan kemudian skala sehingga mencakup 4 ubin sebelumnya. Perbedaannya di sini (selain ubin memiliki warna polos) adalah bahwa lanskap tampak berubah. Saya juga harus menyebutkan bahwa hutan masih harus digambar secara individual karena tidak sepenuhnya berbentuk bujur sangkar.

Jika ada yang tahu cara mengatasi masalah ini, bahkan jika itu berarti kompromi hal-hal tertentu (seperti detail, atau menggunakan sprite 16 x 16), saya akan senang mendengarnya.


Jangan biarkan pengguna memperkecil tampilan sebanyak itu
Bálint

Saya juga mengalami masalah kinerja dengan proyek MonoGame saya yang dihasilkan secara prosedural. Solusi saya adalah membatasi apa yang diberikan (membatasi rentang zoom dan hanya menggambar apa yang ada di layar). Sepertinya MonoGame dirancang dengan mantra "gambar semuanya", tapi saya harap seseorang yang lebih berpengalaman dengan MonoGame akan memperbaiki saya.
Logical Fallacy

Bagaimana Anda membuat ubin? Lebih khusus - apakah Anda menggunakan SpriteBatch dan bagaimana Anda menggunakannya?
loodakrawa

Jawaban:


3

Kartu grafis dioptimalkan untuk menggambar beberapa hal berkali-kali daripada sebaliknya.

Dalam kasus Anda, Anda memiliki banyak hal (tekstur berbeda) yang ingin Anda gambar berkali-kali (jumlah ubin).

IMO, optimisasi paling sederhana yang dapat Anda lakukan untuk mendapatkan keuntungan kinerja yang signifikan adalah:

  1. Gabungkan tekstur Anda menjadi atlas. Ini akan mempercepat secara signifikan karena kartu grafis Anda sekarang hanya menggambar satu (atau beberapa) tekstur daripada banyak yang kecil.
  2. Batch ubin Anda dengan SpriteBatch dalam mode SpriteSortMode.Texture. Ini akan mengurutkan sprite Anda berdasarkan tekstur dan meminimalkan jumlah pengalih tekstur ke jumlah aktual berbagai tekstur yang berbeda. Kelemahan dari pendekatan ini adalah bahwa sprite Anda tidak akan diurutkan berdasarkan kedalaman. Yang mungkin baik karena ubin Anda semua pada kedalaman yang sama. Saya berasumsi Anda memiliki hal-hal lain juga sehingga masuk akal untuk memisahkan SpriteBatch untuk ubin dan satu lagi untuk yang lainnya (setel ke SpriteSortMode.BackToFront).

Saya akan merekomendasikan melakukan kedua hal tersebut. Semoga berhasil.


2

Saya menemukan bahwa SpriteBatch tidak cocok untuk menggambar ubin. Salah satu alasannya adalah bahwa sprite dimaksudkan untuk objek dinamis dan digunakan untuk berbagai tujuan. Alasan lain adalah karena sangat terikat dengan CPU , mis. seperti yang dijelaskan dalam gambar deskripsi 30.000 objek biaya 8 ms (sedangkan chipset saya maksimal 30%). Juga, hingga 3000 sprite dapat ditarik sebelum penarikan panggilan baru harus dilakukan ke GPU (batched and all).

Solusinya adalah menggambar ubin saya sendiri menggunakan paha depan bertekstur . Ini dikombinasikan dengan VertexBuffer memungkinkan saya untuk menggambar hingga 500.000 ubin bertekstur dalam 1 panggilan draw di mana metode draw menghabiskan sekitar 1/20 dari satu milidetik. Tentu saja saya mungkin tidak perlu menggambar sebanyak itu, tetapi bagaimanapun saya akhirnya mendapatkan GPU saya memiliki beban kerja 75% pada tingkat stabil 60 fps.


Kedengarannya sangat bagus. Saya ingin mempelajari lebih lanjut tentang itu - apakah Anda mengikuti tutorial atau Anda memiliki tautan dengan deskripsi yang lebih rinci tentang proses ini?
loodakrawa

2
Saya belajar sebagian besar tentang di mana-mana yang menyebutkan XNA / Monogame dan paha depan bertekstur. Namun, riemers.net banyak membantu saya karena ditujukan untuk orang-orang yang hanya ingin mengatur sesuatu dengan cepat yang berfungsi. Anda akan ingin mengikuti tutorial terain 3D-nya secara khusus karena juga mencakup VertexBuffers dan IndexBuffers. Mengubahnya menjadi jenis bidang ubin seharusnya tidak menjadi masalah.
Guguhl Pluhs

Jika itu yang paling menjawab pertanyaan Anda, Anda dapat menandainya sebagai diterima :)
Vaillancourt

@ GuguhlPluhs Saya tahu ini sudah terlambat, tetapi apakah Anda masih memiliki informasi lebih lanjut tentang subjek ini? Saya menghadapi masalah yang sama.
Jelle
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.