Setelah menambahkan kecepatan ke permainan saya, saya merasa seperti tekstur saya berkedut. Saya pikir itu hanya mata saya, sampai akhirnya saya menangkapnya dalam tangkapan layar:
Yang di sebelah kiri adalah apa yang merender dalam game saya; yang di sebelah kanan adalah sprite asli, ditempelkan. (Ini adalah tangkapan layar dari Photoshop, diperbesar 6x.)
Perhatikan ujungnya alias - hampir seperti rendering sub-pixel. Bahkan, jika saya tidak memaksa sprite saya (yang memiliki posisi dan kecepatan sebagai ints) untuk menggambar menggunakan nilai integer, saya bersumpah bahwa MonoGame sedang menggambar dengan nilai floating point. Tapi ternyata tidak.
Apa yang bisa menjadi penyebab hal-hal ini tampak buram? Itu tidak terjadi tanpa kecepatan diterapkan.
Lebih tepatnya, SpriteComponent
kelas saya memiliki Vector2 Position
bidang. Ketika saya menelepon Draw
, pada dasarnya saya gunakan new Vector2((int)Math.Round(this.Position.X), (int)Math.Round(this.Position.Y))
untuk posisi itu.
Saya punya bug sebelum di mana bahkan objek stasioner akan gugup - itu karena saya menggunakan Position
vektor lurus dan tidak membulatkan nilai ints
. Jika saya menggunakan Floor
/ Ceiling
bukannya bulat, sprite tenggelam / melayang (perbedaan satu pixel bagaimanapun juga) tetapi masih menarik buram.
Jawaban:
Yah, ini memalukan.
Ternyata saya tidak menggambar menggunakan posisi integer, tetapi posisi mengambang. Archy menunjuk saya ke jalan yang benar dengan komentarnya
@ashes999 did you debug this call and checked this.X, this.Y and this.origin?
Segera setelah saya menambahkan pernyataan jejak, saya perhatikan bahwa tidak ada yang terlacak. Ternyata
SpriteComponent
kelas saya benar menggunakan nilai integer, tetapiSpriteSheetComponent
nilai float saya masih digunakan dari mentahVector2 Position
.Meskipun saya tidak mencoba penyaringan dan penjepitan tekstur, saya curiga ini bukan perubahan yang benar, karena saya menggambar gambar 2D dengan lebar dan tinggi yang sama dengan gambar sumber (tanpa penskalaan).
sumber
XNA menggunakan DirectX9 yang menggunakan pusat piksel sebagai lokasinya. Ini terlihat ketika menggunakan overload berbasis Vector2 dari kelas draw. Saya percaya bahwa mengurangi (0,5, 0,5) harus memperbaiki masalah Anda.
Info lebih lanjut di sini.
sumber
int, int
sebagai argumen. Selain itu, semuanya terlihat sangat baik ketika saya tidak memiliki benda bergerak.SpriteComponent
memilikiVector2
posisi, yang bertambah sebagai mengapung tergantung pada kecepatan; ketika saya menggambar, saya membuat versi baruVector2
dengan integer (bulat) dariposition
X dan Y saya. Ini bukan masalah, karena objek stasioner tanpa kecepatan tampak baik-baik saja.p += v
selamaUpdate
, dan membuat dengannew Vector2((int)Math.Round(p.X), (int)Math.Round(p.Y)))
.Rendering tidak tahu apa-apa tentang kecepatan Anda, jadi baik posisi, ukuran, atau apa pun yang Anda berikan kepada SpriteBatch. Gambar berbeda atau ada kesalahan sebelum Anda menambah kecepatan. Bagaimana tepatnya Anda memanggil SpriteBatch.Draw?
Apakah Anda men-debug panggilan ini dan memeriksa this.X, this.Y dan this.origin? Apa ini diatur untuk orisinal? Pada dasarnya tidak mungkin hasil render dengan kecepatan berbeda ketika Draw call ini sama.
sumber
Masalahnya adalah kemungkinan penyaringan tekstur dihidupkan. Jika Anda tidak yakin apa artinya itu, pertimbangkan situasi di mana Anda memiliki gambar dengan lebar 2 piksel: Pixel pertama berwarna hitam, piksel kedua berwarna putih. Jika Anda memperbesar tekstur ini, jika pemfilteran tekstur aktif, Anda akan melihatnya kabur dan area antara piksel hitam dan putih menggunakan warna abu-abu gradien.
Contoh klasik game dengan dan tanpa pemfilteran adalah Super Mario 64 yang memiliki pemfilteran sedangkan Doom tidak.
Ketika Anda tidak menggunakan kecepatan, Sprite Anda kemungkinan diposisikan sedemikian rupa sehingga pusat tekstur berada pada titik sampel dimana XNA (atau api apa pun yang digunakan sedang digunakan) meraih warna. Ketika Anda bergerak dengan kecepatan mengambang, maka posisi Sprite Anda berubah, sehingga titik sampel mungkin tidak berbaris langsung dengan pusat piksel, sehingga hasil akhirnya adalah bahwa warna yang merupakan rata-rata dari piksel terdekat sedang digunakan untuk membuat.
Anda dapat memverifikasi bahwa penyaringan dihidupkan dengan hanya membuat Sprite Anda sangat besar di layar. Jika buram, maka itu masalahnya.
Jika Anda harus memiliki akurasi piksel-sempurna dalam rendering, Anda akan ingin memiliki nilai float untuk posisi disimpan di suatu tempat, tetapi gunakan nilai integer untuk posisi objek yang Anda render ... atau tentu saja Anda bisa mematikan penyaringan jika gim Anda tidak membutuhkannya.
Anda mungkin juga ingin membaca ini .
sumber
Draw
. Jadi saya tidak yakin bagaimana itu bisa terjadi - tapi saya akan mencoba rendering skala besar dan melihat apakah mematikan penyaringan tekstur akan membantu.Cobalah mengatur SamplerState Anda ke SamplerState.PointClamp di panggilan SpriteBatch.Begin.
sumber