Saya memiliki mesin gim 2D yang menggambar tilemaps dengan menggambar ubin dari gambar tileset. Karena secara default OpenGL hanya dapat membungkus seluruh tekstur ( GL_REPEAT
), dan bukan hanya sebagian saja, setiap ubin dibagi menjadi tekstur yang terpisah. Kemudian daerah dari ubin yang sama diberikan berdekatan satu sama lain. Begini tampilannya saat berfungsi sebagaimana dimaksud:
Namun begitu Anda memperkenalkan penskalaan pecahan, lapisan muncul:
Mengapa ini terjadi? Saya pikir itu karena penyaringan linier memadukan batas paha depan, tetapi itu masih terjadi dengan penyaringan titik. Satu-satunya solusi yang saya temukan sejauh ini adalah untuk memastikan semua penentuan posisi dan penskalaan hanya terjadi pada nilai integer, dan menggunakan penyaringan titik. Ini dapat menurunkan kualitas visual game (khususnya bahwa penempatan sub-pixel tidak lagi berfungsi sehingga gerakannya tidak begitu mulus).
Hal-hal yang saya coba / pertimbangkan:
- antialiasing mengurangi, tetapi tidak sepenuhnya menghilangkan, lapisannya
- mematikan mipmapping, tidak berpengaruh
- merender setiap ubin secara individual dan mengekstrusi tepinya dengan 1px - tetapi ini adalah de-optimisasi, karena tidak dapat lagi merender wilayah ubin dalam sekali jalan, dan membuat artefak lain di sepanjang tepi bidang transparansi
- tambahkan perbatasan 1px di sekitar gambar sumber dan ulangi piksel terakhir - tetapi kemudian tidak lagi menjadi dua, yang menyebabkan masalah kompatibilitas dengan sistem tanpa dukungan NPOT
- menulis shader khusus untuk menangani gambar ubin - tetapi lalu apa yang akan Anda lakukan secara berbeda?
GL_REPEAT
harus mengambil piksel dari sisi berlawanan dari gambar di perbatasan, dan tidak memilih transparansi. - geometri persis berbatasan, tidak ada kesalahan pembulatan titik mengambang.
- jika shader fragmen dikode keras untuk mengembalikan warna yang sama, jahitannya hilang .
- jika teksturnya diatur
GL_CLAMP
sebagai gantiGL_REPEAT
, pelipatannya hilang (meskipun renderingnya salah). - jika tekstur diatur ke
GL_MIRRORED_REPEAT
, jahitannya hilang (walaupun renderingnya salah lagi). - jika saya membuat latar belakang merah, jahitannya masih putih. Ini menunjukkan bahwa sampel itu berwarna putih buram dari suatu tempat daripada transparansi.
Jadi jahitan hanya muncul ketika GL_REPEAT
diatur. Untuk beberapa alasan dalam mode ini saja, di tepi geometri ada beberapa perdarahan / kebocoran / transparansi. Bagaimana itu bisa terjadi? Seluruh teksturnya buram.
GL_NEAREST
pengambilan sampel dalamR
arah koordinat juga berfungsi sama baiknya dengan tekstur array untuk sebagian besar hal dalam skenario ini. Pemetaan pemetaan tidak akan berfungsi, tetapi menilai dengan aplikasi Anda, Anda mungkin tidak perlu memetakan peta mini.Jawaban:
Jahitan adalah perilaku yang benar untuk pengambilan sampel dengan GL_REPEAT. Pertimbangkan ubin berikut:
Pengambilan sampel pada tepi ubin menggunakan nilai fraksional mencampur warna dari tepi dan tepi yang berlawanan, menghasilkan warna yang salah: Tepi kiri harus hijau, tetapi merupakan campuran dari hijau dan krem. Tepi kanan harus krem, tetapi juga merupakan warna campuran. Terutama garis-garis krem pada latar belakang hijau sangat terlihat, tetapi jika Anda melihat lebih dekat Anda dapat melihat perdarahan hijau ke tepi:
MSAA bekerja dengan mengambil lebih banyak sampel di sekitar tepi poligon. Sampel yang diambil kiri atau kanan tepi akan "hijau" (sekali lagi, mengingat tepi kiri gambar pertama), dan hanya satu sampel akan "di" tepi, pengambilan sampel sebagian dari area "beige". Ketika sampel dicampur efeknya akan berkurang.
Solusi yang memungkinkan:
Bagaimanapun Anda harus beralih ke
GL_CLAMP
untuk mencegah pendarahan dari piksel di sisi berlawanan dari tekstur. Maka Anda memiliki tiga opsi:Aktifkan anti-aliasing untuk memperlancar transisi antar ubin sedikit.
Atur penyaringan tekstur ke
GL_NEAREST
. Ini memberikan semua piksel tepi yang keras, sehingga tepi poligon / sprite menjadi tidak bisa dibedakan, tetapi itu jelas mengubah gaya permainan sedikit.Tambahkan batas 1px yang sudah dibahas, pastikan perbatasan memiliki warna ubin yang berdekatan (dan bukan warna tepi yang berlawanan).
GL_LINEAR
penyaringan-seperti di tepi poligon / sprite.sumber
Pertimbangkan tampilan quad, textured quad biasa di OpenGL. Apakah ada jahitan, pada skala berapa pun? Tidak, tidak pernah. Tujuan Anda adalah untuk mendapatkan semua ubin adegan Anda dikemas dengan erat ke dalam satu tekstur, lalu mengirimkannya ke layar. EDIT Untuk memperjelas ini lebih lanjut: Jika Anda memiliki simpul pembatas diskrit pada setiap quad ubin, Anda akan memiliki jahitan yang tampaknya tidak dapat dibenarkan dalam sebagian besar keadaan. Begitulah cara kerja perangkat keras GPU ... kesalahan floating point membuat kesenjangan ini berdasarkan perspektif saat ini ... kesalahan yang dihindari pada manifold terpadu, karena jika dua wajah berdekatan dalam manifold yang sama(submesh), perangkat keras akan membuatnya tanpa jahitan, dijamin. Anda telah melihat ini di banyak game dan aplikasi. Anda harus memiliki satu tekstur yang sangat padat pada satu submesh tanpa simpul ganda untuk menghindari ini sekali dan untuk semua. Ini adalah masalah yang muncul berulang kali di situs ini dan di tempat lain: jika Anda tidak menggabungkan simpul sudut ubin Anda (setiap 4 ubin berbagi sudut sudut), harapkan jahitan.
(Pertimbangkan bahwa Anda bahkan mungkin tidak perlu simpul kecuali pada keempat sudut seluruh peta ... tergantung pada pendekatan Anda terhadap naungan.)
Untuk mengatasi: render (pada 1: 1) semua tekstur ubin Anda menjadi FBO / RBO tanpa celah, lalu kirim FBO itu ke framebuffer default (layar). Karena FBO itu sendiri pada dasarnya adalah satu tekstur, Anda tidak bisa berakhir dengan celah pada penskalaan. Semua batas texel yang tidak jatuh pada batas piksel layar akan tercampur jika Anda menggunakan GL_LINEAR .... yang persis seperti yang Anda inginkan. Ini adalah pendekatan standar.
Ini juga membuka sejumlah rute berbeda untuk penskalaan:
sumber
Jika gambar harus muncul sebagai satu permukaan, render ini sebagai satu tekstur permukaan (skala 1x) pada satu bidang / bidang 3D. Jika Anda membuat masing-masing sebagai objek 3D yang terpisah, ia akan selalu memiliki jahitan karena kesalahan pembulatan.
Jawaban oleh @ Nick-Wiggill benar, saya pikir Anda salah paham.
sumber
2 kemungkinan yang mungkin patut dicoba:
Gunakan
GL_NEAREST
sebagai gantiGL_LINEAR
untuk pemfilteran tekstur Anda. (Seperti yang ditunjukkan oleh Andon M. Coleman)GL_LINEAR
akan (pada dasarnya) mengaburkan gambar sedikit (interpolasi antara piksel terdekat), yang memungkinkan transisi warna yang mulus dari satu piksel ke piksel berikutnya. Ini dapat membantu membuat tekstur terlihat lebih baik dalam banyak kasus, karena mencegah tekstur Anda memiliki piksel yang tebal di atasnya. Itu juga membuatnya sehingga sedikit cokelat dari satu piksel lebih dari satu ubin lebih dapat kabur ke piksel hijau yang berdekatan dari ubin yang berdekatan.GL_NEAREST
hanya menemukan piksel terdekat dan menggunakan warna itu. Tidak ada interpolasi. Akibatnya, sebenarnya sedikit lebih cepat.Kecilkan koordinat tekstur untuk setiap ubin sedikit.
Agak seperti menambahkan piksel tambahan di sekitar setiap ubin sebagai buffer, kecuali alih-alih memperluas ubin pada gambar, Anda mengecilkan ubin di perangkat lunak. Ubin 14x14px saat merender bukan ubin 16x16px.
Anda bahkan mungkin bisa lolos dengan 14.5x14.5 ubin tanpa terlalu banyak cokelat tercampur.
--edit--
Seperti yang ditunjukkan pada gambar di atas, Anda masih dapat dengan mudah menggunakan kekuatan dua tekstur. Jadi Anda dapat mendukung perangkat keras yang tidak mendukung tekstur NPOT. Apa yang berubah adalah koordinat tekstur Anda, alih-alih dari
(0.0f, 0.0f)
menjadi(1.0f, 1.0f)
Anda beralih(0.03125f, 0.03125f)
ke(0.96875f, 0.96875f)
.Itu menempatkan tex-coords Anda sedikit di dalam ubin yang mengurangi resolusi efektif dalam gim (meskipun tidak pada perangkat keras sehingga Anda masih memiliki tekstur dua kekuatan), namun harus memiliki efek rendering yang sama dengan memperluas tekstur.
sumber
Inilah yang saya pikir mungkin terjadi: Di mana dua ubin bertabrakan, komponen x pada tepinya harus sama. Jika itu tidak benar, mereka mungkin dibulatkan ke arah yang berlawanan. Jadi pastikan mereka memiliki nilai x yang persis sama. Bagaimana Anda memastikan ini terjadi? Anda dapat mencoba, katakanlah, kalikan dengan 10, bulat dan kemudian bagi dengan 10 (hanya lakukan ini pada CPU, sebelum simpul Anda masuk ke vertex shader). Itu harus memberikan hasil yang benar. Juga, jangan menggambar ubin dengan ubin menggunakan matriks transformasi, tetapi menempatkannya dalam batch VBO untuk memastikan bahwa hasil yang salah tidak datang dari sistem floating point IEEE yang hilang dalam kombinasi dengan perkalian matriks.
Mengapa saya menyarankan ini? Karena dari pengalaman saya, jika simpul memiliki koordinat yang sama persis ketika mereka keluar dari shader puncak, mengisi segitiga yang sesuai akan menghasilkan hasil yang mulus. Perlu diingat bahwa sesuatu yang benar secara matematis, mungkin agak tidak aktif karena IEEE. Semakin banyak perhitungan yang Anda lakukan pada angka-angka Anda, hasilnya akan kurang akurat. Dan ya, perkalian matriks membutuhkan cukup banyak operasi, yang mungkin dilakukan hanya dalam perkalian dan penambahan saat membuat VBO Anda, yang akan memberikan hasil yang lebih akurat.
Yang juga mungkin menjadi masalah adalah bahwa Anda menggunakan spritesheet (juga disebut atlas) dan ketika mengambil sampel tekstur, piksel dari tekstur ubin yang berdekatan akan diambil. Untuk memastikan bahwa ini tidak terjadi adalah membuat perbatasan kecil dalam pemetaan UV. Jadi, jika Anda memiliki ubin 64x64, pemetaan UV Anda harus mencakup sedikit lebih sedikit. Berapa banyak? Saya pikir saya menggunakan dalam game saya seperempat piksel di setiap sisi persegi panjang. Jadi, ganti rugi UV Anda dengan 1 / (4 * widthOfTheAtlas) untuk x komponen dan 1 / (4 * heightOfTheAtlas) untuk komponen y.
sumber
Untuk mengatasi ini dalam ruang 3D, saya mencampur array tekstur dengan saran Wolfgang Skyler. Saya menempatkan batas 8-pixel di sekitar tekstur asli saya untuk setiap ubin (120x120, total 128x128) yang, untuk setiap sisi, yang dapat saya isi dengan gambar "terbungkus" atau sisi yang hanya diperpanjang. Sampler membaca area ini ketika sedang menginterpolasi gambar.
Sekarang dengan penyaringan dan pemetaan, sampler masih dapat dengan mudah membaca melewati seluruh batas 8 piksel. Untuk menangkap masalah kecil itu (saya katakan kecil karena itu hanya terjadi pada beberapa piksel ketika geometri benar-benar miring atau jauh), saya membagi ubin menjadi array tekstur, sehingga setiap ubin memiliki ruang tekstur sendiri dan dapat menggunakan penjepitan pada ujung-ujungnya.
Dalam kasus Anda (2D / datar), saya pasti akan pergi dengan rendering adegan pixel sempurna, dan kemudian menskalakan bagian yang diinginkan dari hasil ke viewport, seperti yang disarankan oleh Nick Wiggil.
sumber