OpenGL: Mengubah Ukuran Tampilan dan glOrtho / glViewport

16

Saya telah meneliti pertanyaan ini dari beberapa sumber dan belum menemukan jawaban yang tegas yang mengatakan bahwa "ya itu pemikiran yang benar" atau "tidak, inilah caranya."

Saya mencoba memastikan independensi resolusi dengan rendering OpenGL. Cara saya pikir saya harus melakukannya, adalah membuat proyeksi menggunakan glOrthoapa pun yang saya inginkan dengan koordinat dunia. Sebagai contoh glOrtho(-50.0, 50.0, -50.0, 50.0, 1.0, -1.0),. Selanjutnya, atur viewport ke resolusi layar , yaitu - glViewport(0, 0, 800, 600). Akhirnya, setiap kali ukuran jendela kembali, lakukan panggilan glViewportdengan resolusi layar yang diperbarui. Ini akan mengukur angka Anda.

Apakah ini cara yang benar untuk memastikan bahwa model mengambil proporsi ruang layar yang sama pada resolusi yang berbeda? Haruskah saya menggunakan proyeksi yang sama dengan resolusi juga? Saya menemukan beberapa jawaban yang mengatakan glOrthoharus menggunakan resolusi jendela Anda, sementara yang lain mengatakan itu harus / bisa berbeda.

Pikiran?

Chris Henderson
sumber

Jawaban:

20

Apa yang telah Anda uraikan sepenuhnya memadai dan sesuai untuk memberikan kebebasan resolusi. Apa pun yang Anda gambar memang akan selalu mengambil proporsi yang sama dari jendela Anda.

Namun, jika Anda melakukan tidak lebih dari ini, Anda akan memiliki masalah rasio aspek . Misalnya, mengingat angka yang Anda tulis, jika Anda menggambar lingkaran, itu akan tergencet - lebih lebar daripada tingginya, karena skala horizontal Anda adalah 800 / (50 + 50) = 8 dan skala vertikal Anda adalah 600 / (50+ 50) = 6.

Tidak ada solusi otomatis untuk masalah ini ; Anda harus memilih hasil grafis apa yang Anda inginkan, dan mempertimbangkan efeknya pada gameplay. Beberapa contoh umum:

  • Dalam permainan 3D proyeksi-perspektif tanpa HUD, solusi sederhana yang biasa (tersedia di OpenGL sebagai bagian dari gluPerspective) adalah untuk memperbaiki bidang pandang proyeksi relatif terhadap dimensi vertikal . Ini berarti bahwa dalam permainan seperti itu, jika Anda mengubah ukuran jendela secara horizontal, Anda akan melihat lebih banyak adegan dan bagian tengah gambar tidak akan berubah sama sekali.

    Ide yang sama dapat diterapkan pada tampilan 2D / 2.5D juga.

    (Perhatikan bahwa ini memungkinkan pemain untuk memperbesar bidang pandang mereka secara horizontal dengan membuat jendela lebar tetapi tidak tinggi. Ini bisa tidak diinginkan dalam permainan multipemain yang kompetitif.)

  • Jika Anda memiliki grafis yang memenuhi layar dengan rasio aspek tetap (misalnya, peta 2D yang tidak bergulir, atau batas dekoratif), atau jika Anda tidak dapat mengubah tata letak, maka Anda harus melakukan sesuatu seperti memiliki bilah hitam pada dua sisi untuk mengisi ruang yang tidak digunakan.

    Atau Anda dapat membuat grafik yang memiliki bahan pengisi yang konsisten secara tematis di tepinya sehingga dapat dipangkas agar sesuai dengan tampilan tanpa merusak gameplay.

  • Jika Anda memiliki HUD di atas grafik lain, Anda dapat memutuskan bahwa setiap elemen HUD ditetapkan ke bagian jendela (kiri atas, tengah bawah, dll) dan menghitung koordinatnya; 'peregangan' dari memvariasikan rasio aspek akan diserap oleh 'ruang putih' antara elemen HUD.

Seperti matematika tertentu dari masalah ini, mengingat bahwa Anda melakukan resolusi kemerdekaan, semua yang Anda butuhkan untuk memulai dengan adalah aspek rasio, satu nomor: width / height. Misalnya, jika jendelanya persegi, itu akan menjadi 1; jika 800 dengan 600 maka akan menjadi 800/600 = 4/3 = 1,333̅.

Misalnya, Anda menginginkan proyeksi ortografis yang Anda tulis untuk mendapatkan ruang tambahan di sisi kiri dan kanan jika jendela diperlebar. Anda dapat melakukannya seperti ini:

float aspect = width / height;
glViewport(0, 0, width, height);
glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);

Ini menjamin bahwa, untuk windows setidaknya selebar tingginya, apa pun yang Anda gambar dengan koordinat x dan y dalam -50 hingga 50 akan terlihat.

Di sisi lain, jika jendela lebih sempit dari tinggi, kisaran -50-ke-50 akan terpotong. Katakanlah Anda ingin memastikan bahwa itu selalu terlihat (sehingga konten Anda berada pada ukuran maksimum jika jendelanya persegi, tetapi sebaliknya lebih kecil); dalam hal ini, Anda cukup melakukan hal yang sama dengan ketinggian alih-alih lebar.

float aspect = width / height;
glViewport(0, 0, width, height);
if (aspect >= 1.0)
  glOrtho(-50.0 * aspect, 50.0 * aspect, -50.0, 50.0, 1.0, -1.0);
else
  glOrtho(-50.0, 50.0, -50.0 / aspect, 50.0 / aspect, 1.0, -1.0);

Perhatikan bahwa dalam kasus kedua kita membagi daripada mengalikan. Ini hanya karena kami menghitung rasio aspek width / heightdaripada height / width; ambil timbal balik jika Anda merasa lebih mudah untuk memahami seperti itu.

Sekali lagi, ini bukan satu-satunya cara untuk mengelola aspek rasio; ini hanya yang sangat sederhana untuk memastikan bahwa konten Anda tidak terjepit atau terputus. Cari tahu apa yang Anda inginkan terjadi ketika jendela Anda lebar, tinggi, atau apa pun; kemudian menyusun matematika itu.

Kevin Reid
sumber
Terima kasih atas tanggapan SANGAT berwawasan. Menjawab pertanyaan saya dengan cukup baik.
Chris Henderson