Grafik 2D - mengapa menggunakan spritesheets?

62

Saya telah melihat banyak contoh bagaimana membuat sprite dari spritesheet tetapi saya tidak mengerti mengapa itu adalah cara paling umum untuk berurusan dengan sprite di game 2d.

Saya sudah mulai dengan rendering sprite 2d di beberapa aplikasi demo yang saya buat dengan menangani setiap frame animasi untuk setiap jenis sprite yang diberikan sebagai teksturnya sendiri - dan kumpulan tekstur ini disimpan dalam kamus. Ini sepertinya bekerja untuk saya, dan cocok dengan alur kerja saya dengan cukup baik, karena saya cenderung membuat animasi saya sebagai file gif / mng dan kemudian mengekstrak frame ke pngs individu.

Apakah ada keuntungan kinerja yang nyata untuk rendering dari satu lembar daripada dari tekstur individu? Dengan perangkat keras modern yang mampu menggambar jutaan poligon ke layar seratus kali per detik, apakah itu penting untuk game 2d saya yang hanya berurusan dengan beberapa lusin persegi panjang 50x100px?

Detail implementasi memuat tekstur ke dalam memori grafis dan menampilkannya dalam XNA tampaknya cukup abstrak. Yang saya tahu adalah bahwa tekstur terikat ke perangkat grafis ketika mereka dimuat, kemudian selama loop permainan, teksturnya akan diberikan dalam batch. Jadi tidak jelas bagi saya apakah pilihan saya memengaruhi kinerja.

Saya menduga ada beberapa alasan bagus mengapa kebanyakan pengembang game 2d tampaknya menggunakannya, saya hanya tidak mengerti mengapa.

Columbo
sumber
Tidak, itu tidak terlalu penting untuk 50 sprite aneh Anda. Tapi apa ruginya?
Bebek Komunis

Jawaban:

69

Argumen yang kuat untuk menggunakan spritesheets adalah bahwa jumlah tekstur yang tersedia pada kartu grafis dapat dibatasi. Oleh karena itu pustaka grafis Anda harus selalu menghapus tekstur dan mengalokasikan kembali tekstur pada GPU. Jauh lebih efisien hanya mengalokasikan tekstur besar sekali.

Juga pertimbangkan bahwa ukuran tekstur biasanya kekuatan 2. Jadi, jika Anda memiliki Sprite 50x100px, Anda akan mengalokasikan tekstur dengan ukuran 64x128px atau dalam kasus yang lebih buruk 128x128px. Itu hanya membuang-buang memori grafis. Lebih baik mengemas semua sprite ke dalam tekstur 1024x1024px, yang akan memungkinkan sprite 20x10 dan Anda hanya akan kehilangan 24 piksel secara horizontal dan vertikal. Kadang-kadang bahkan sprite dengan ukuran berbeda digabungkan menjadi satu sprite-sheet besar untuk menggunakan tekstur seefisien mungkin.

Tambahan: Alasan yang sangat penting untuk menggunakan sprite-sheet adalah untuk mengurangi jumlah draw-call pada GPU Anda, yang dapat memiliki dampak penting pada kinerja. Ini telah dinyatakan dalam jawaban lain dan saya menambahkan ini demi kelengkapan sehingga ini mendapatkan lebih banyak visibilitas.

bummzack
sumber
1
Terima kasih, saya tidak mempertimbangkan satu pun dari poin-poin itu - Apakah Anda tahu kira-kira berapa batas jumlah tekstur yang tersedia? Saya belum pernah melihat stat ini disebutkan pada spesifikasi grafis - apakah batasnya pada dasarnya sama dengan jumlah RAM grafis?
Columbo
Biasanya batasnya adalah memori GPU, ya. Saya pikir ada beberapa batasan pada jumlah tekstur pada kartu yang lebih tua tetapi saya tidak bisa menemukan referensi yang membuktikan hal itu.
bummzack
12
Bahkan jika tidak ada batasan kuantitas, lalu lintas bus untuk memindahkan banyak gambar kecil tidak seefisien satu (atau beberapa) transfer besar.
Mordachai
5
Poin yang bagus, tetapi aspek terpenting adalah untuk meminimalisir warung saluran pipa dengan menjaga agar draw call terhenti. GPU lebih suka sejumlah kecil pekerjaan besar, daripada ammont besar pekerjaan kecil. Menempatkan semua sprite Anda ke sejumlah kecil lembar besar berarti Anda dapat mengatur panggung textue sekali dan menggambar banyak spites sekaligus dalam satu batch. Spritebatch melakukan ini untuk Anda. Jika Anda memiliki lebih dari satu spritesheet, pastikan untuk memberitahu spritebatch untuk mengurutkan berdasarkan tekstur
Cubed2D
Menambahkan kompresi tekstur akan mengubah ruang kendur menjadi sejumlah kecil overhead, di atas semua itu
Joe Plante
36

Saya akan mengatakan argumen yang digunakan adalah kemampuan untuk merender banyak hal dalam satu panggilan undian. Ambil contoh rendering font, tanpa spritesheet Anda harus merender setiap karakter dengan swap tekstur yang terpisah diikuti oleh draw call. Lemparkan ke dalam spritesheet dan Anda dapat merender seluruh kalimat dengan satu panggilan undian (perbedaan karakter pada font yang dipilih dengan hanya menentukan UV yang berbeda untuk sudut-sudut). Ini adalah cara rendering yang jauh lebih efisien ketika overhead rendering yang sangat nyata pada banyak platform sedang membuat terlalu banyak panggilan API.

Ini juga dapat membantu menghemat ruang, tetapi itu tergantung pada apa kemasan Anda ke dalam spritesheet di tempat pertama.

Roger Perkins
sumber
2
+1 Menyentuh saat menarik panggilan. (sesuatu yang tidak saya lihat dalam jawaban yang diterima)
Michael Coleman
11

Setiap panggilan draw memiliki jumlah overhead tertentu. Dengan menggunakan sprite sheet Anda dapat mengelompokkan gambar hal-hal yang tidak menggunakan bingkai animasi yang sama (atau lebih umum, semua yang ada di materi yang sama) sangat meningkatkan kinerja. Ini mungkin tidak terlalu menjadi masalah bagi PC modern tergantung pada gim Anda, tetapi itu penting, misalnya, iPhone.

Tetrad
sumber
2
Pasti masih penting. Perangkat keras grafis telah dioptimalkan untuk mendorong banyak poligon untuk sejumlah kecil model terperinci (mis. Karakter) karena sebagian besar gim cenderung ke arah itu. Hasilnya adalah bahwa Anda perlu mendorong poligon sebanyak mungkin di masing-masing hanya beberapa lusin panggilan imbang. Mesin gim yang menyajikan adegan besar seperti kota sering kali menggabungkan beberapa tekstur menjadi satu dengan cepat untuk mengurangi panggilan draw.
jhocking
Saya pasti bertanya-tanya apakah tekstur u, v pemetaan di banyak perangkat keras 3D, ditambah operasi bit blitting manfaat dari sprite sheet.
Joe Plante
7

Selain pertimbangan kinerja, sprite sheet bisa berguna saat membuat karya seni; masing-masing karakter dapat di lembar sendiri, dan Anda dapat melihat semua bingkai hanya dengan menggulir di sekitar. Ini membantu saya menjaga tampilan yang konsisten di semua frame.

Selain itu, saya kode dalam AS3, dan setiap file gambar memerlukan instruksi sematan terpisah. Saya lebih suka memiliki satu embed dari seluruh spritesheet daripada 24 embed untuk semua frame, bahkan jika saya menggunakan kelas sumber daya yang terpisah.

Gregory Avery-Weir
sumber
1
+1. Meskipun OP tidak menggunakan Flash, penyematan atau pemuatan juga merupakan poin yang mendukung spritesheets. Ini juga relevan ketika aset diambil dari server Web di mana 1 permintaan lebih disukai daripada beberapa ratus permintaan (untuk setiap "bingkai").
bummzack
Tentunya Anda ingin mengurangi permintaan server untuk game online. Kami mempertimbangkan apakah lebih baik untuk menempatkan gambar ke .swf atau spritesheet karena keduanya mencapai tujuan utama ini (kami akhirnya memutuskan spritesheets kurang padat karya untuk seniman kami).
jhocking
7

Alasan lain jadi gunakan spritesheets dengan XNA adalah bahwa dengan pengembangan Xbox360 ada masalah yang diketahui dengan waktu penyebaran / pemuatan yang lambat terkait dengan jumlah file yang Anda miliki di proyek Anda. Jadi menggabungkan banyak file gambar kecil menjadi satu file gambar akan membantu mengatasi masalah itu.

George Clingerman
sumber
5

Saya tidak akan menyebutkan memori / GPU di sini, karena ada jawaban yang cukup seperti itu.

Sebagai gantinya, itu dapat membersihkan karya seni Anda saat Anda mengerjakannya - dan setelahnya. Alih-alih harus membolak-balik 10 gambar untuk melihat siklus berjalan, Anda dapat melihat semua frame sekaligus. Jika Anda ingin mendistribusikan ini, Anda hanya punya 1 file untuk ditangani, bukan 10.

Dan kemudian juga lebih bersih (dari sudut pandang pengorganisasian) untuk memiliki character.png dan musuh.png melalui characterwalk01 hingga characterwalk10, kemudian characterattack01 ke characterattack05, dan terus berlanjut.

Bebek Komunis
sumber
4

Memori grafis tidak memiliki manajemen kehabisan memori seperti sistem file pada disk; oposite adalah kasusnya: itu dibuat sederhana dan cepat .

Salah satu pengaturan memori yang sederhana dan cepat tersebut mungkin seperti memiliki hanya satu raksasa tunggal 4096x4096 sprite yang dipotong dalam beberapa sprite yang lebih kecil dengan memisah setengah lebar dan / atau tingginya. (Ada teknik pengelolaan memori 1 dimensi yang serupa, tetapi saya lupa namanya.) Akhirnya, Defragmentasi harus dilakukan.

Untuk melewati manajemen memori seperti itu pada saat run-time , pengembang mengisi satu sprite besar dengan beberapa sprite yang lebih kecil secara otomatis pada waktu kompilasi atau bahkan saat dalam proses desing pada grafik.

comonad
sumber
3

Juga jangan lupa operasi I / O yang mungkin menyelamatkan Anda selama inisialisasi. Jika Anda memuat dari drive CD, setiap file adalah panggilan I / O tambahan, dan mungkin membutuhkan waktu untuk mencari (HDD modern sekitar 15 ms per file, CD mungkin 50-100 ms?). Ini dapat menghemat banyak waktu inisialisasi karena hanya satu file yang harus diambil. Ini juga memungkinkan OS Anda untuk cache operasi I / O ini, jika aplikasi Anda melakukan sesuatu yang lain (seperti menunggu GPU).

Menandai
sumber
1
Di ujung lain jika Anda ingin menyelesaikan masalah pencarian file, Anda dapat memiliki semua sprite Anda dikemas dalam satu file, menggunakan format kustom. Sebagian besar permainan melakukan itu.
tigrou
0

Selain lebih efisien dalam kinerja, saya merasa lebih mudah. Dibutuhkan sedikit kerja ekstra untuk memastikan gambar Anda selalu dalam batas ketika membuat karya seni, tetapi jauh lebih mudah untuk dapat melihat semua gambar yang Anda hadapi saat ini.

Ini juga lebih mudah untuk dikodekan, menurut saya. Saya hanya memiliki array objek seperti:

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

Lalu untuk setiap item saya berikan dua nilai, sheet dan rect. Lembar akan menjadi indeks dalam array objek, dan persegi akan menjadi indeks dalam array rects sheet itu.

tali pengikat
sumber