Algoritma pengemasan tekstur


52

Apa itu algoritma pengemasan tekstur yang baik? Secara teknis, pengemasan bin adalah NP-hard , jadi heuristik adalah apa yang saya cari.


Saya berasumsi bahwa Anda menggunakan ini untuk mengoptimalkan peta uv, tapi saya ingin tahu apa aplikasi ini.
Jonathan Fischoff

ftgles adalah pustaka yang menggunakan OpenGL dan freetype untuk merender font. Namun masing-masing mesin terbang disimpan dalam teksturnya sendiri. Saya ingin mengemasnya menjadi satu tekstur.
deft_code

Jawaban:


58

Saya menghabiskan beberapa bulan di satu pekerjaan dengan algoritma pengemasan tekstur yang lebih baik.

Algoritma yang kami mulai dengan sederhana. Kumpulkan semua item input. Urutkan berdasarkan jumlah piksel yang dikonsumsi, besar ke kecil. Letakkan di tekstur Anda dalam urutan scanline, hanya menguji hal-hal dari pixel topleft ke pixel topright, bergerak ke bawah garis, dan ulangi, ulang ke pixel topleft setelah setiap penempatan berhasil.

Anda perlu meng-hardcode lebar atau mencari heuristik lain untuk ini. Dalam upaya untuk melestarikan kuadrat, algoritme kami akan mulai pada 128, lalu meningkat sebesar 128-an sampai muncul dengan hasil yang tidak lebih dalam daripada lebarnya.

Jadi, kami memiliki algoritma itu, dan saya memutuskan untuk memperbaikinya. Saya mencoba banyak heuristik aneh - mencoba menemukan objek yang cocok bersama, melakukan beberapa pembobotan atas sekelompok sifat ruang pengepakan yang diinginkan, berputar dan membalik. Setelah semua pekerjaan saya, secara harfiah tiga bulan kerja, saya akhirnya menghemat ruang 3%.

Ya. 3%.

Dan setelah kami menjalankan rutin kompresi kami di atasnya, itu benar-benar berakhir lebih besar (yang saya masih tidak bisa menjelaskan) jadi kami membuang semuanya dan kembali ke algoritma lama.

Mengurutkan item, selai menjadi tekstur dalam urutan scanline. Itu algoritma Anda. Mudah untuk dikodekan, cepat dijalankan, dan Anda tidak akan menjadi lebih baik tanpa kerja yang luar biasa. Pekerjaan itu tidak bermanfaat kecuali perusahaan Anda setidaknya memiliki 50 orang, dan mungkin lebih.

teks alternatif

Dan sebagai catatan, saya baru saja mengimplementasikan algoritma ini (lebar tetap 512 piksel) untuk aplikasi yang persis sama persis seperti yang Anda lakukan (tidak ada kelemahan, tetapi mesin terbang freetype yang dibuat khusus.) Inilah hasilnya. Itu terlihat buram karena tambang saya menggunakan algoritma rendering teks berbasis jarak-bidang Valve , yang juga menyumbang ruang ekstra antara mesin terbang. Jelas, tidak ada banyak ruang kosong yang tersisa, dan itu melakukan pekerjaan yang baik untuk menjejalkan semuanya ke tempat-tempat terbuka.

Semua kode untuk ini berlisensi BSD dan tersedia di github .


Saya melihat tekstur Anda dan berpikir, "Saya yakin paket tekstur kami sedikit lebih baik dari itu". Dan kemudian saya pergi dan melihatnya, dan menyadari bahwa saya telah memecahkannya beberapa waktu yang lalu dan tidak memperhatikan (karena begitu itu berfungsi, siapa yang melihat tekstur keluarannya?) ... Jadi terima kasih telah memposting - tidak akan menemukan bug sebaliknya :) (setelah saya memperbaiki bug, kelihatannya sangat mirip - mungkin teduh lebih baik, tetapi sulit untuk mengatakannya dengan tepat. "sebagus" mungkin deskripsi yang paling aman).
JasonD

@JasonD, saya ingin tahu apa yang dilakukan algoritme Anda, jika mendapat hasil yang lebih baik :) Sekalipun mendapat hasil yang kurang lebih setara dengan cara yang berbeda.
ZorbaTHut

1
Terima kasih atas deskripsi algo + kegagalan yang diterima + kode sumber. Pos yang bagus.
Calvin1602

1
Alasannya menjadi lebih besar setelah kompresi mungkin karena algoritma kompresi. Karena kompresi sering bergantung pada hashing dan menemukan pola biner, jika algoritma dapat mengidentifikasi pola yang cukup maka akan menghasilkan sejumlah besar pola yang dapat menyebabkan ukuran membesar. cara yang bagus untuk mengujinya hanya dengan mem-zip kembali file berulang-ulang dan akhirnya akan mulai menjadi lebih besar lagi karena kurangnya pola.
Hanna

1
Untuk bagaimana mencari versi terbaru dari kode pengepakan ZorbaTHut (font_baker.cpp), Anda dapat menemukannya di sini: github.com/zorbathut/glorp/blob/…
mems

20

Tesis PhD dari Andrea Lodi berjudul Algoritma untuk Pengemasan dan Penugasan Bin Dua Dimensi .
Tesis ini membahas beberapa bentuk yang lebih sulit dari masalah ini. Untungnya, pengemasan tekstur adalah versi yang paling mudah. Algoritma terbaik yang ia temukan disebut Touching Perimeter .

Mengutip dari halaman 52:

Algoritma, yang disebut Touching Perimeter (TPRF), dimulai dengan menyortir item berdasarkan area yang tidak bertambah (memutuskan ikatan dengan nilai min {wj, hj} yang tidak meningkat), dan dengan mengarahkannya secara horizontal. L batas bawah L pada nilai solusi optimal kemudian dihitung, dan L kosong tong diinisialisasi. (Batas bawah kontinu L0 yang didefinisikan pada bagian sebelumnya jelas berlaku untuk 2BP | R | F juga; batas yang lebih baik diusulkan oleh Dell'Amico, Martello dan Vigo [56].) Algoritma mengemas satu item pada satu waktu, baik di tempat sampah yang ada, atau dengan menginisialisasi yang baru. Item pertama yang dikemas dalam nampan selalu ditempatkan di sudut kiri bawah. Setiap item selanjutnya dikemas dalam posisi normal (lihat Christo fi des dan Whitlock [41]), yaitu,
Pilihan nampan dan posisi pengepakan dilakukan dengan mengevaluasi skor, yang didefinisikan sebagai persentase dari perimeter item yang menyentuh nampan dan barang-barang lainnya yang sudah dikemas. Strategi ini mendukung pola di mana barang yang dikemas tidak "menjebak" area kecil, yang mungkin sulit digunakan untuk penempatan lebih lanjut. Untuk setiap posisi pengepakan kandidat, skor dievaluasi dua kali, untuk dua orientasi item (jika keduanya layak), dan nilai tertinggi dipilih. Ikatan skor terputus dengan memilih nampan yang memiliki area pengemasan maksimum. Algoritma keseluruhan adalah sebagai berikut.

touching_perimeter:
  sort the items by nonincreaseing w,h values, and horizontally orient them;
  comment: Phase 1;
  compute a lower bound L on the optimal solution value, and open L empty bins;
  comment: Phase 2;
  for j := 1 to n do
     score := 0;
     for each normal packing position in an open bin do
        let score1 and score2 be scores with tow orientations;
        score := max{score,score1,score2};
     end for;
     if score > 0 then
        pack item j in the bin, position and orientation corresponding to score;
     else
        open a new bin and horizontally pack item j into i;
     end if;
  end for;
end;

Yang juga menarik, makalah ini menjelaskan algoritma untuk menentukan ukuran peta tekstur yang dikemas secara optimal. Itu akan berguna untuk menentukan apakah mungkin untuk mencocokkan semua tekstur dalam satu atlas 1024x1024.


Algoritma ini mengasumsikan bahwa tekstur berbentuk persegi panjang, benarkah itu?
user1767754

17

Jika ada yang masih tertarik, saya telah sepenuhnya menulis ulang pustaka rectpack2D sehingga jauh lebih efisien.

Ini bekerja dengan menjaga std::vectorruang kosong di atlas, dimulai dengan beberapa ukuran maksimum awal (biasanya, ukuran tekstur maksimum yang diperbolehkan pada GPU tertentu), membelah ruang kosong pertama yang layak dan menyimpan pemisahan kembali ke vektor.

Terobosan kinerja datang dengan hanya menggunakan vektor, bukannya menjaga seluruh pohon, seperti yang telah dilakukan sebelumnya.

Prosedur ini dijelaskan secara rinci dalam README .

Perpustakaan berada di bawah MIT, jadi saya senang untuk Anda jika Anda merasa berguna!

Contoh hasil:

Pengujian dilakukan pada Intel (R) Core (TM) i7-4770K CPU @ 3.50GHz. Biner dibangun dengan clang 6.0.0, menggunakan -03 switch.

Sprite permainan sewenang-wenang + Mesin terbang Jepang: total 3264 subjek.

Runtime: 4 milidetik
Pixel Terbuang: 15538 (0,31% - setara dengan 125 x 125 persegi)

Output (2116 x 2382):

3

Dalam warna:
(hitam adalah ruang yang terbuang)

4

Mesin terbang Jepang + beberapa sprite GUI: 3122 subjek.

Runtime: 3,5 - 7 ms
Piksel Terbuang: 9288 (1,23% - setara dengan 96 x 96 persegi)

Output (866 x 871):

5

Dalam warna:
(hitam adalah ruang yang terbuang)

6


2
Saya sudah mengunduh kode Anda. Hanya membaca definisi struct: APA ITU MONSTROSITAS INI ?! Ini seperti kode golf.
akaltar

3
Tetap bekerja, dan itu membantu, jadi terima kasih. Saya tidak ingin bersikap kasar.
akaltar

Tidak yakin mengapa saya melewatkan jawaban ini karena ini adalah pengepak yang lebih cepat dan lebih baik daripada algoritma saya sendiri, terima kasih O_O
GameDeveloper

@akaltar Saya bisa membayangkan itu, saya masih belajar bahasa selama ini :)
Patryk Czachurski

Pendekatan yang cukup sederhana yang cepat diimplementasikan dan mendapatkan hasil yang baik, terima kasih :)
FlintZA

5

Algoritma heuristik yang baik dapat ditemukan di sini . Ketika saya mencoba sesuatu yang serupa baru-baru ini, saya menemukan ini dirujuk sebagai titik awal dasar untuk sebagian besar implementasi yang saya lihat.

Bekerja sangat baik dengan banyak item berbentuk biasa, berukuran serupa, atau dengan perpaduan yang baik dari gambar kecil dan lebih sedikit. Saran terbaik untuk mencapai hasil yang baik adalah jangan lupa untuk menyortir input Anda dalam hal ukuran gambar, lalu kemas dari yang terbesar ke yang terkecil karena gambar yang lebih kecil akan dimasukkan ke dalam ruang di sekitar gambar yang lebih besar. Bagaimana Anda melakukan ini menyortir Anda dan mungkin tergantung pada tujuan Anda. Saya menggunakan perimeter daripada area sebagai perkiraan urutan pertama karena saya mengambil pandangan bahwa gambar tinggi + tipis / pendek + lebar (yang akan memiliki area rendah) sebenarnya sangat sulit untuk ditempatkan nanti dalam sebuah paket, jadi dengan menggunakan perimeter Anda mendorong bentuk-bentuk aneh menuju bagian depan ordo.

Berikut ini adalah contoh sampel output untuk paket saya pada set acak gambar dari direktori dump gambar situs web saya :). Output pengepak

Angka-angka dalam kotak adalah id dari blok yang mengandung di pohon jadi beri Anda gagasan tentang urutan sisipan. Yang pertama adalah ID "3" karena itu adalah simpul daun pertama (hanya daun yang mengandung gambar) dan akibatnya memiliki 2 orang tua).

        Root[0]
       /      \
   Child[1]  Child[2]
      |
    Leaf[3]

3

Secara pribadi, saya hanya menggunakan sistem pertama-blok-yang-cocok serakah terbesar. Ini tidak optimal, tetapi triknya OK.

Perhatikan bahwa, jika Anda memiliki jumlah blok tekstur yang masuk akal, Anda dapat mencari urutan pemesanan yang lengkap bahkan jika masalahnya adalah NP.


3

Sesuatu yang saya gunakan, yang bekerja dengan baik bahkan untuk peta UV yang tidak beraturan, adalah mengubah patch UV menjadi bitmap mask, dan memelihara mask untuk tekstur itu sendiri, mencari posisi pertama patch UV akan cocok. Saya memesan blok sesuai dengan beberapa heuristik sederhana (tinggi, lebar, ukuran, apa pun), dan saya memungkinkan rotasi blok untuk meminimalkan atau memaksimalkan heuristik yang dipilih. Itu memberi ruang pencarian yang bisa dikelola untuk brute force.

Jika Anda kemudian dapat mengulangi bahwa mencoba beberapa heuristik, dan / atau menerapkan faktor acak dalam memilih pemesanan dan mengulangi sampai batas waktu habis.

Dengan skema ini Anda akan mendapatkan pulau-pulau UV kecil yang dikemas ke dalam celah-celah yang dibuat oleh pulau-pulau besar, dan bahkan di dalam lubang yang tersisa di dalam satu tambalan UV sendiri.


1

Kami baru-baru ini merilis skrip python yang akan mengemas tekstur menjadi beberapa file gambar dengan ukuran tertentu.

Dikutip dari blog kami:

"Walaupun ada banyak paket yang dapat ditemukan online, kesulitan kami adalah menemukan apa pun yang dapat menangani gambar dalam jumlah besar di banyak direktori. Dengan demikian, pengemas atlas kami sendiri telah lahir!

Seperti ini, skrip kecil kami akan mulai di direktori dasar dan memuat semua .PNGs ke dalam atlas. Jika atlas itu terisi, itu menciptakan yang baru. Kemudian, ia akan mencoba menyesuaikan sisa gambar di semua atlas sebelumnya sebelum menemukan tempat di yang baru. Dengan begitu, setiap atlas dikemas sekencang mungkin. Atlase dinamai berdasarkan folder tempat gambar mereka berasal.

Anda dapat mengubah ukuran atlas (baris 65), format gambar yang ingin Anda kemas (baris 67), direktori muat (baris 10) dan direktori simpan (baris 13) cukup mudah tanpa pengalaman di Python. Sebagai penafian kecil, ini dikocok bersama dalam beberapa hari untuk bekerja secara khusus dengan mesin kami. Saya mendorong Anda untuk meminta fitur, berkomentar dengan variasi Anda sendiri, dan melaporkan kesalahan apa pun, tetapi setiap perubahan pada skrip akan terjadi di waktu luang saya. "

Jangan ragu untuk memeriksa kode sumber lengkap di sini: http://www.retroaffect.com/blog/159/Image_Atlas_Packer/#b


1

Sangat mudah untuk mengemas font karena semua (atau sebagian besar) dari tekstur mesin terbang hampir ukuran yang sama. Lakukan hal paling sederhana yang terjadi pada Anda dan itu akan sangat dekat dengan optimal.

Kepintaran menjadi lebih penting saat Anda mengemas gambar dengan ukuran yang sangat berbeda. Maka Anda ingin dapat memasukkan ke dalam celah, dll. Meskipun begitu, meskipun demikian, algoritma sederhana seperti pencarian urutan pemindaian yang dibahas sebelumnya akan menghasilkan hasil yang sangat wajar.

Tidak ada algo canggih yang ajaib. Mereka tidak akan 50% lebih efisien daripada algo sederhana, dan Anda tidak akan mendapatkan manfaat yang konsisten dari mereka kecuali Anda memiliki jumlah lembar tekstur yang mengejutkan. itu karena peningkatan kecil yang dibuat oleh algoritma yang lebih baik hanya akan dilihat secara agregat.

Lakukan yang sederhana, dan beralihlah ke sesuatu di mana upaya Anda akan dihargai lebih baik


0

Jika khusus untuk tekstur font, maka Anda mungkin melakukan sesuatu yang tidak optimal tetapi bagus dan sederhana:

Urutkan karakter berdasarkan tinggi, tertinggi terlebih dahulu

Mulai dari 0,0 Tempatkan karakter pertama pada koordinat saat ini, lanjutkan X, tempatkan berikutnya, ulangi sampai kami tidak dapat memasukkan yang lain

Atur ulang X ke 0, naikkan Y ke bawah dengan ketinggian karakter tertinggi di baris, dan isi baris lain

Ulangi sampai kita kehabisan karakter, atau tidak dapat masuk ke baris lain.

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.