Haruskah saya menggunakan spritesheets, karena atau meskipun saya memiliki banyak gambar?

13

Saya mengembangkan game 2D, dan saya memiliki banyak sprite. Saya menggunakan animasi dan model 3D untuk dirender menjadi 2D, untuk memberi mereka tampilan "Fallout" atau "Diablo". Ini juga lebih mudah daripada menggambar dengan tangan, lol.

Saya harus memotong framerate menjadi 15fps, yang merupakan level terendah yang dapat saya turunkan tanpa membuat mereka memiliki tampilan yang berombak. Namun, itu menyedihkan karena betapa 24 frame terlihat sangat halus.

Ada dua alasan saya melakukan ini:

1) Kurangi ruang HDD. Semakin sedikit gambar, semakin kecil total game saya.

2) Kurangi konsumsi RAM. Semakin sedikit gambar dimuat, semakin besar kemungkinan saya untuk menghindari masalah kembung keterbatasan RAM saya.

Namun, jika ada cara untuk memampatkan gambar di ruang HDD dan RAM, saya akan melakukannya. Saya telah mengujinya sebelumnya, dan sebagian besar tidak menerima perubahan kualitas ketika memberikan dari RGBA8888 ke RGBA5555 dan hanya sedikit hit ketika mengkonversi ke RGBA4444 dalam program TexturePacker saya. Saya tidak melakukan ini saat ini, karena SFML tampaknya menggunakan jumlah memori yang sama terlepas dari jenis gambar .PNG itu. Saya mencari cara untuk memuatnya secara berbeda, tetapi gagal menemukan apa pun pada subjek.

Saya telah membaca banyak tentang cara menangani video game 2D. Konsensusnya luar biasa: Kemas Sprite Anda ke dalam Tekstur yang Lebih Besar untuk kinerja hebat! Jadi saya mengemas sprite kecil saya menjadi spritesheet yang jauh lebih besar menggunakan TexturePacker.

Namun, saya berencana memiliki 10-15 animasi per karakter, 5 arah untuk dipindahkan, dan 15-40 frame per animasi (mungkin rata-rata 24). Dengan 15 animasi, 5 arah, dan rata-rata 24 frame per animasi; Itu adalah 1800 frame individu per karakter. Jika dikemas dalam lembar sprite, itu hanya 75 gambar saja. (Satu lembar sprite per Animasi, per Arah. 15 * 5)

Untuk satu karakter bos besar dalam game, saya tidak bisa menggunakan spritesheet dan harus memprogram cara untuk memuat dalam satu gambar pada satu waktu. Saya tidak tahu apakah saya bisa melakukan ini untuk kinerja.

Untuk karakter, saya sudah mengemasnya dalam spritesheet. Untuk satu karakter berjalan-jalan, ini sepertinya bekerja sebagian besar waktu, meskipun kadang-kadang berhenti. Namun, saya mengaitkannya dengan kode saya yang salah yang menukar tekstur alih-alih membuka semua tekstur untuk karakter itu.

Jika saya melakukan preload tekstur, masuk akal untuk sprite sheet. Saya hanya akan membayangkan itu ide buruk untuk memuat lebih awal 1800 gambar kecil untuk setiap karakter.

Namun, saya membayangkan streaming mereka keluar dan masuk memori satu per satu akan sangat cepat, jadi saya hanya perlu memiliki satu gambar dalam memori pada satu waktu. Bukankah ini berarti bahwa setiap saat saya hanya akan meminta masing-masing karakter mengkonsumsi beberapa KB, bukannya 45 + MB?

Saya membayangkan ini akan membunuh kinerja saya, karena streaming harus sangat cepat (15 gambar masuk dan keluar dari memori dan rendering, per detik) dan meskipun gambar akan sangat kecil-itu mungkin ide yang lebih baik untuk memuat spritesheets karakter ke dalam memori saja. Tapi saya harus mengkode sistem render seperti stream gambar tunggal untuk karakter bos saya yang lebih besar.

Saya telah bereksperimen, tetapi itu bukan proses yang sederhana. Terutama mengingat fakta saya sedang mengerjakan bagian-bagian lain dari mesin permainan yang tidak berurusan dengan grafik sekarang.

Carter81
sumber
1. Anda tidak menentukan batasan RAM atau HDD Anda. Berapa banyak karakter yang perlu diakses dengan cepat? 2. Ada beberapa pertanyaan di sepanjang teks, mungkin Anda bisa memfokuskannya dengan huruf tebal atau bahkan membagi pertanyaan menjadi beberapa bagian?
Kromster mengatakan mendukung Monica
Oh maafkan saya. Tidak banyak. Saya akan membayangkan bahwa jumlah maksimum masing-masing karakter di layar pada satu waktu adalah sekitar 40. Jika orang-orang berusaha keras untuk menghancurkan klien mereka, maka ... 130 adalah nilai absolut absolut. Biasanya, hanya perlu ada 10 untuk max tipikal, dan max absolut tidak akan lebih dari <40. Apa pun di atas 40 akan menjadi ekstrem, kelangkaan ekstrem, dengan pengguna yang sengaja mencoba menjejalkan karakter tanpa alasan selain tangkapan layar atau untuk bersenang-senang menjejalkan karakter. Apa pun di atas 10 jarang, dan apa pun di sekitar 40 sangat, sangat langka.
Carter81
Gim ini adalah rpg 2D khusus PC (tanpa seluler), namun saya tidak ingin mengesampingkan platform seluler kecuali itu tidak layak. Saya membayangkan bahwa ruang RAM yang saya miliki terbatas pada apa pun RAM pada PC pengguna, dan VRAM pengguna. Saya sangat meragukan itu akan menjadi HDD yang sangat besar. Hanya saja selalu benar untuk konsumsi HDD bahwa semakin kecil, semakin baik.
Carter81
Berapa banyak karakter UNIK yang perlu Anda miliki di layar?
Kromster mengatakan mendukung Monica
Tidak lebih dari 20. Apa pun di atas yang hampir mustahil kecuali mereka curang. Biasanya 5-10.
Carter81

Jawaban:

16

Kami memiliki kasus serupa dengan Remake RTS kami. 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 alasan utama di balik atlas adalah:

  • RAM lebih sedikit terbuang (di hari-hari yang lebih tua ketika Anda mengunggah NPOT ke GPU itu membentang / melipatnya ke POT, saya membaca itu masih sama dengan iOS dan beberapa kerangka kerja. Anda lebih baik memeriksa berbagai perangkat keras yang Anda targetkan)
  • switch tekstur kurang
  • pemuatan yang lebih cepat dari segalanya dalam potongan yang lebih sedikit

Apa yang tidak berhasil bagi kami:

  • tekstur palet. Fitur hanya ada di OpenGL 1.x 2.x dan itupun sebagian besar dijatuhkan oleh pembuat GPU. Namun jika Anda membidik OpenGL + Shaders, Anda dapat melakukannya sendiri dalam kode shaders!
  • Tekstur NPOT, kami mengalami masalah dengan batas yang salah dan sprite kabur, yang tidak dapat diterima dalam seni piksel. Penggunaan RAM juga jauh lebih tinggi.

Sekarang kita memiliki segalanya yang dikemas dalam beberapa lusin 1024x1024 atlas (GPU modern mendukung dimensi yang lebih besar) dan itu bekerja dengan baik hanya memakan ~ 300mb memori, yang cukup baik untuk gim PC. Beberapa optimasi yang kami miliki:

  • tambahkan opsi pengguna untuk menggunakan RGB5_A1 alih-alih RGBA8 (bayangan kotak-kotak)
  • hindari 8bit Alpha jika memungkinkan dan gunakan format RGB5_A1
  • kemas erat sprite ke dalam atlas (lihat Algoritma Pengemasan Bin)
  • menyimpan dan memuat semuanya dalam satu potongan dari HDD (file sumber daya harus dihasilkan secara offline)
  • Anda juga dapat mencoba format kompresi perangkat keras (DXT, S3TC, dll.)

Ketika Anda serius mempertimbangkan untuk pindah ke perangkat seluler, Anda akan khawatir tentang kendala. Untuk sekarang, mainkan saja gim dan tarik pemain! ;)

Kromster berkata mendukung Monica
sumber
Ini adalah solusi terbaik sejauh ini! Sprite saya bahkan tidak terlihat berbeda di RGB5_A1 atau RGBA4444, tetapi menghemat memori. Saran Anda dalam obrolan untuk memuat ulang semua aset saya di RAM dan VRAM sangat cocok. Lebih jauh lagi, Anda menyarankan untuk memiliki level grafik opsional, seperti klien definisi tinggi bagi mereka yang memiliki RAM, atau opsi untuk mengurangi framerate hingga setengahnya, dll. Saran bagus ada di sekitar, dan persis apa yang saya butuhkan!
Carter81
5

Saya memiliki jawaban yang berhubungan secara tangensial di sini , tetapi ide umumnya adalah, jika Anda memuat dan menggambar tekstur pada waktu yang berbeda (Anda tidak memuat tekstur tambahan saat Anda merender), maka ada dua tempat di mana Anda lakukan akan mempengaruhi kinerja Anda:

Memuat waktu:

Ini adalah saat di mana Anda mengunggah tekstur Anda ke dalam memori. The seluruh jumlah data yang mengirim ke VRAM adalah apa yang sebagian besar akan menentukan berapa lama waktu pemuatan Anda akan. Membuat tekstur Anda memiliki format yang lebih kecil, seperti RGBA4444, akan membuatnya lebih cepat. Namun, kecuali Anda mengunggah tekstur dalam ratusan megabyte ke VRAM, Anda mungkin tidak akan mengalami hambatan di sini. Jika Anda melakukannya, layar memuat yang bagus dapat memudahkan menunggu.

Menggabungkan tekstur Anda ke atlases akan berdampak kecil, karena seluruh jumlah informasi yang Anda kirim ke VRAM akan sama. Bahkan, jika Anda menghilangkan tekstur Anda, dan Anda harus meninggalkan ruang kosong di atlas Anda, maka Anda akan benar-benar mengirim lebih banyak data ke dalam VRAM, dan karena itu bagian ini akan lebih lambat!

Kinerja rendering:

Setelah semua tekstur Anda di VRAM, jumlah tekstur yang Anda miliki tidak akan memengaruhi kinerja rendering. Ada empat elemen yang mempengaruhi kinerja rendering Anda:

  1. Perubahan status render : Setiap kali Anda mengubah gambar yang ingin Anda render, akan secara serius meningkatkan waktu yang diperlukan untuk merendernya. Secara umum, Anda ingin meminimalkan jumlah perubahan status, dan Anda dapat mengurangi jumlah perubahan status dengan mengelompokkan beberapa gambar yang akan Anda gambar secara berurutan, menjadi atlas tekstur.

    Atlasing saja tidak cukup. Anda harus atlas dengan cara di mana perubahan negara dikurangi, untuk mendapatkan keuntungan kinerja. Sebagai contoh, orang mungkin berpikir bahwa memiliki karakter utama Anda dalam sprite sheet akan membuat Anda mendapatkan peningkatan kinerja, tetapi jika Anda hanya menggambar satu sprite dari sprite sheet per frame, Anda tidak akan mendapatkan peningkatan kinerja dibandingkan dengan memiliki masing-masing sprite dalam file terpisah.

    Atlasing yang tepat bukanlah hal sepele, tetapi secara umum Anda dapat dengan aman mengelompokkan sprite dari lapisan yang sama. Misalnya, memiliki semua item GUI dalam satu lembar sprite adalah ide yang sangat menjanjikan, sementara mengelompokkan monster secara alfabet mungkin tidak.

  2. Panggilan undian : Secara umum, Anda mungkin ingin menjaga agar panggilan undian Anda minimum. Aturan praktis yang baik adalah bahwa jika tidak ada perubahan render state antara dua panggilan draw, Anda dapat menggabungkannya menjadi satu draw draw. Untuk peningkatan kinerja yang lebih lanjut, Anda dapat menggunakan, katakanlah, 8 sampler tekstur, dan panggilan undian grup untuk setiap 8 tekstur, sehingga Anda hanya perlu mengubah tekstur setiap 8 tekstur.

  3. Jumlah segitiga: Faktanya, semakin banyak segitiga yang Anda gambar, semakin lama waktu yang dibutuhkan untuk menggambarnya. Namun, di komputer modern, dan untuk sebagian besar game 2D, Anda akan sangat jauh dari memaksimalkan ini. Anda dapat dengan aman menggambar ratusan ribu sprite per frame dan masih mendapatkan framerate yang bagus. Anda mungkin akan lebih terikat dengan CPU jika Anda menggambar sprite ekstrim sebelum Anda mendapatkan masalah dengan GPU Anda.

  4. Pengaturan API: Jika Anda melakukan semuanya dengan benar, dan Anda masih mendapatkan framerate yang sangat rendah, periksa pengaturan yang digunakan untuk menggambar sprite Anda. Saya tidak tahu SFML, tetapi misalnya, di Direct3D 9, membuat buffer vertex D3DUSAGE_DYNAMIC, atau di D3DPOOL_MANAGEDdapat dengan mudah meningkatkan waktu rendering Anda sepuluh kali lipat. Tentu saja, menggunakan vSync akan membatasi framerate Anda pada kecepatan refresh monitor Anda. Juga, menggunakan FVF yang tidak selaras dapat menurunkan kinerja di beberapa GPU. Ini juga untuk Direct3D 9.

    Dalam kasus Anda, periksa dokumentasi untuk API yang Anda gunakan.

Jika Anda hanya memiliki jumlah tekstur yang rendah hingga sedang (kurang dari 1GB), dan Anda menggambar jumlah sprite yang rendah (kurang dari satu juta per frame), maka hal pertama yang akan saya perhatikan adalah mengubah pengaturan API, dan kemudian mengurangi jumlah status render dan membuat panggilan.

Piyama Panda
sumber
Jika saya tidak peduli tentang waktu buka, apakah saya harus berasumsi bahwa kecuali saya kehabisan RAM atau VRAM, saya harus memuat semuanya ke dalam memori sebelumnya?
Carter81
Saya hanya peduli dengan semuanya karena saya takut kehabisan RAM / VRAM. Saya tidak tahu mengapa, tetapi itu membuat saya takut bahwa pengguna yang memainkan permainan saya akan mogok setiap kali mereka mencoba memuat ke daerah yang memiliki terlalu banyak sprite unik, atau akan menabrak setiap kali terlalu banyak karakter berjalan ke layar mereka. Jika saya tidak salah dan masing-masing sprite individu mengkonsumsi 96KB, maka jika setiap karakter unik memiliki 15 animasi, 5 arah, dan rata-rata 24 frame per animasi - setiap karakter individu yang dimuat penuh adalah 173MB. Mungkin ada 10, bahkan mungkin lebih, karakter unik di layar sekaligus.
Carter81
@KromStern: Jika Anda atlas, dan Anda harus meninggalkan ruang kosong (padding), maka data akan lebih besar, dan karena itu waktu pemuatan akan lebih lama. Jelas bahwa penyebab waktu pemuatan yang lebih lama adalah ruang kosong, dan bahwa total waktu pemuatan terkait dengan jumlah total data, dan bukan jumlah tekstur. Saya tidak melihat sesuatu yang menyesatkan di sana, dan saya pikir seseorang dengan pengetahuan yang cukup untuk memahami pertanyaan awal, akan dapat bergabung dengan titik-titik dan membuat kesimpulannya sendiri untuk semua kasus ketika tekstur dan atlasnya adalah PoT dan nPoT.
Panda Pajama
1
@ Carter81: Anda harus memilih konfigurasi perangkat keras target Anda, seperti "i5, 1gb RAM, NVidia GT260, 400mb hdd" dan bekerja darinya. Akan selalu ada PC yang lebih lemah dan memiliki lebih sedikit RAM.
Kromster mengatakan mendukung Monica
Jelas, mereka tidak membutuhkan semua 15 animasi pada waktu tertentu. Namun, bagaimana jika semua 10 karakter unik masuk ke "Combat Mode" pada saat yang sama, dan dengan demikian memerlukan 5 set animasi (berjalan, berlari, menganggur, non-tempur dll) untuk bertukar dengan 5 lebih (berjalan perang, bertarung menganggur, bertempur dll.)? Saya takut bertukar tekstur karena ketika saya mencoba melakukan itu dengan SFML, itu menciptakan pembekuan yang nyata atau jeda klien ketika beralih atlas tekstur. Saya tidak tahu apa hambatan saya dengan berbagai strategi untuk menangani begitu banyak sprite.
Carter81