Tekstur lembaran sprite mengambil tepi tekstur yang berdekatan

10

Saya memiliki rutin sprite khusus (openGL 2.0) yang menggunakan sprite sheet sederhana (tekstur saya disusun secara horizontal bersebelahan).

Jadi, misalnya, berikut adalah lembar sprite uji dengan 2 tekstur sederhana:

masukkan deskripsi gambar di sini

Sekarang, apa yang saya lakukan ketika membuat objek sprite openGL saya adalah menentukan jumlah total frame di atlasnya dan ketika menggambar, tentukan frame mana yang ingin saya gambar.

Kemudian berhasil menemukan tempat untuk mengambil tekstur dari dengan:

Membagi jumlah frame yang dibutuhkan dengan jumlah total frame (untuk mendapatkan koordinat kiri)

Dan kemudian menyelam 1 dengan jumlah total frame dan menambahkan hasilnya ke koordinat kiri yang dihitung di atas.

Ini sepertinya berhasil tetapi kadang-kadang saya mendapat masalah. Katakan misalnya, saya ingin menggambar X di bawah ini dan saya dapatkan ...........

masukkan deskripsi gambar di sini

Saya pernah mendengar tentang menempatkan 'padding' 1 px di antara setiap tekstur tetapi dapatkah seseorang menjelaskan dengan tepat bagaimana ini bekerja? Maksud saya jika saya melakukan ini pasti akan membuang perhitungan untuk mendapatkan tekstur.

Jika saya cukup memasukkan padding dalam tekstur yang diambil (jadi sprite digambar dengan batas kosong), maka tentunya ini akan menyebabkan masalah dengan deteksi tabrakan? (yaitu sprite mungkin tampak bertabrakan saat menggunakan kotak pembatas ketika bagian transparan bertabrakan).

Akan menghargai jika seseorang bisa menjelaskan.

BungleBonce
sumber
Apakah Anda menggunakan GL_NEARESTatau GL_LINEARuntuk rendering tekstur?
MichaelHouse
Saya menggunakan GL_Linear @ Byte56
BungleBonce

Jawaban:

15

Masalah dengan menggunakan atlas tekstur dan kebocoran texels yang berdekatan berkaitan dengan cara kerja penyaringan tekstur linier.

Untuk setiap titik dalam tekstur yang tidak disampel secara tepat di tengah texel, pengambilan sampel linier akan mengambil sampel 4 texel yang berdekatan dan menghitung nilai di lokasi yang Anda tanyakan sebagai bobot (berdasarkan jarak dari titik sampel) rata-rata semua 4 sampel.

Berikut visualisasi masalah yang bagus:

  

Karena Anda tidak dapat menggunakan sesuatu seperti GL_CLAMP_TO_EDGEpada atlas tekstur, Anda perlu membuat texels tepi di sekitar tepi setiap tekstur. Teks perbatasan ini akan mencegah sampel tetangga dari tekstur yang sangat berbeda di atlas mengubah gambar melalui interpolasi tertimbang yang dijelaskan di atas.

Perhatikan bahwa ketika Anda menggunakan penyaringan anisotropik, Anda mungkin perlu menambah lebar perbatasan. Ini karena penyaringan anisotropik akan meningkatkan ukuran lingkungan sampel pada sudut ekstrem.


Untuk mengilustrasikan apa yang saya maksud dengan menggunakan batas di sekitar tepi setiap tekstur, pertimbangkan berbagai mode bungkus yang tersedia di OpenGL. Berikan perhatian khusus CLAMP TO EDGE.

  http://lucera-project.com/blog/wp-content/uploads/2010/06/wrap.png

Meskipun ada mode yang disebut "Clamp to Border", itu sebenarnya bukan yang kami minati. Mode itu memungkinkan Anda menentukan satu warna untuk digunakan sebagai batas di sekitar tekstur Anda untuk setiap koordinat tekstur yang berada di luar batas normal [0,0] -1.0] jangkauan.

Yang kami inginkan adalah mereplikasi perilaku CLAMP_TO_EDGE, di mana setiap tekstur berkoordinasi di luar kisaran yang tepat untuk (sub-) tekstur menerima nilai dari pusat texel terakhir ke arah di luar batas. Karena Anda memiliki kontrol penuh atas koordinat tekstur dalam sistem atlas, satu-satunya skenario di mana koordinat tekstur (efektif) mungkin merujuk ke lokasi di luar tekstur Anda adalah selama langkah rata-rata tertimbang penyaringan tekstur.

Kita tahu bahwa GL_LINEARakan mengambil sampel 4 tetangga terdekat seperti yang terlihat pada diagram di atas, jadi kita hanya perlu perbatasan 1-texel. Anda mungkin memerlukan batas texel yang lebih luas jika Anda menggunakan pemfilteran anisotropik, karena ini meningkatkan ukuran lingkungan sampel dalam kondisi tertentu.

Berikut adalah contoh tekstur yang menggambarkan batas lebih jelas, meskipun untuk tujuan Anda, Anda dapat membuat lebar 1 texel atau 2 texel lebar.

  

(CATATAN: Batas yang saya maksudkan bukan hitam di sekitar keempat tepi gambar, tetapi area tempat pola kotak-kotak berhenti berulang secara teratur)

Jika Anda bertanya-tanya, inilah mengapa saya terus memunculkan penyaringan anisotropik. Ini mengubah bentuk lingkungan sampel berdasarkan sudut dan dapat menyebabkan lebih dari 4 texels digunakan untuk memfilter:

  http://www.arcsynthesis.org/gltut/Texturing/ParallelogramDiag.svg

Semakin besar tingkat anisotropi yang Anda gunakan, semakin besar kemungkinan Anda harus berurusan dengan lingkungan sampel yang mengandung lebih dari 4 texels. Batas 2 texel harus memadai untuk sebagian besar situasi penyaringan anisotropik.


Last but not least, di sini adalah bagaimana atlas tekstur dikemas akan dibangun yang akan mereplikasi GL_CLAMP_TO_EDGEperilaku di hadapan GL_LINEARfilter tekstur:

( Kurangi 1 dari X dan Y dalam koordinat hitam, saya tidak membuktikan membaca gambar sebelum memposting. )   

Karena penyimpanan tepi, menyimpan 4 tekstur 256x256 di atlas ini membutuhkan tekstur dengan dimensi 516x516. Perbatasan diberi kode warna berdasarkan bagaimana Anda akan mengisinya dengan data texel selama pembuatan atlas:

  • Merah = Ganti dengan texel langsung di bawah
  • Kuning = Ganti dengan texel tepat di atas
  • Hijau = Ganti dengan texel langsung ke kiri
  • Biru = Ganti dengan texel langsung ke kanan

Secara efektif dalam contoh yang dikemas ini, setiap tekstur di atlas menggunakan wilayah atlas 258x258, tetapi Anda akan menghasilkan koordinat tekstur yang memetakan ke wilayah 256x256 yang terlihat. Teks pembatas hanya pernah digunakan ketika penyaringan tekstur dilakukan di tepi tekstur di atlas, dan cara mereka dirancang meniru GL_CLAMP_TO_EDGEperilaku.

Jika Anda bertanya-tanya, Anda dapat menerapkan jenis mode bungkus lainnya menggunakan pendekatan serupa - GL_REPEATdapat diimplementasikan dengan menukar texels perbatasan kiri / kanan dan atas / bawah di atlas tekstur dan sedikit koordinat matematika dengan koordinat tekstur pandai dalam sebuah shader. Itu sedikit lebih rumit, jadi jangan khawatir tentang itu untuk saat ini. Karena Anda hanya berurusan dengan sprite sheet, batasi diri Anda GL_CLAMP_TO_EDGE:)

Andon M. Coleman
sumber
Terima kasih @AndonMColeman, dapatkah Anda menunjukkan perbatasan dalam diagram karena saya masih tidak yakin saya mengerti cara kerjanya - lagi apakah ini berarti bahwa ketika tekstur diterapkan pada objek saya, itu akan mencakup perbatasan? Saya ingin tekstur aktual langsung ke tepi quad saya - maaf jika saya tidak memahami ini dengan benar - akan menghargai beberapa detail lagi - terima kasih
BungleBonce
@ user22241 Tentu saja, cara kerja perbatasan ini adalah dengan menduplikasi texel di tepi tekstur.
Andon M. Coleman
@ user22241: Tidak, perbatasan ini tidak akan terlihat dalam keadaan normal. Anda akan memperlakukan tekstur paket Anda memiliki dimensi yang sama untuk perhitungan koordinat tekstur, Anda cukup menerapkan offset untuk melompati melewati batas. Seluruh titik perbatasan adalah untuk mencegah pengambilan sampel tekstur linier dari jangkauan berlebihan dan pengambilan sampel milik gambar terpisah dalam lembar sprite Anda. Jika Anda menggunakan pengambilan sampel tetangga terdekat, ini tidak diperlukan, tetapi kemudian Anda mendapatkan sprite alias alias jahat.
Andon M. Coleman
Jawaban terinci cemerlang - terima kasih! Hanya satu hal terakhir jika aku bisa. Bagaimana cara mengetahui 'offset' untuk ditambahkan ke koordinat tekstur saya? Apakah saya benar mengatakan itu hanya 1 / widthOfTexture?
BungleBonce
@ user22241: Ya, awal dari gambar tekstur adalah + 1 / widthOfTexture di arah X dan + 1 / heightOfTexture di arah Y. Anda akan memiliki batas yang mengelilingi setiap tekstur. Pada saat Anda ingin menghitung koordinat tekstur untuk tekstur horizontal ke-3, lokasi yang dikemas untuk tekstur ini sebenarnya +5 texels (+2 texels untuk batas tekstur pertama, +2 untuk batas tekstur kedua dan +1 untuk awal) tekstur ini) di samping lebar 2 tekstur lainnya. Tampaknya rumit hanya menulisnya; Saya bisa menggambar diagram jika perlu :)
Andon M. Coleman