Saya telah menggunakan OpenGL untuk sementara waktu dan telah membaca sejumlah besar tutorial. Terlepas dari kenyataan bahwa banyak dari mereka masih menggunakan pipa tetap, mereka biasanya membuang semua inisialisasi, menyatakan perubahan dan menggambar dalam satu file sumber. Ini bagus untuk lingkup tutorial yang terbatas, tapi saya kesulitan mencari cara meningkatkannya menjadi permainan penuh.
Bagaimana Anda membagi penggunaan OpenGL di antara file? Secara konseptual, saya bisa melihat manfaat dari memiliki, katakanlah, kelas rendering yang murni membuat hal-hal yang perlu ditayangkan, tetapi bagaimana hal-hal seperti shader dan lampu bekerja? Haruskah saya memiliki kelas terpisah untuk hal-hal seperti lampu dan shader?
c++
opengl
architecture
objects
Sullivan
sumber
sumber
Jawaban:
Saya pikir OO OpenGL tidak perlu. Ini berbeda ketika Anda berbicara tentang shader, model, dll kelas.
Pada dasarnya Anda akan melakukan inisialisasi game / mesin terlebih dahulu (dan hal-hal lain). Kemudian Anda akan memuat tekstur, model dan shader ke RAM (jika perlu) dan Buffer Objects, dan unggah / kompilasi shader. Setelah itu, Anda, dalam struktur data atau kelas shader, model, memiliki ID int shader, model, dan objek buffer tekstur.
Saya pikir sebagian besar mesin memiliki komponen mesin dan setiap orang memiliki antarmuka tertentu. Semua mesin yang saya lihat memiliki beberapa komponen seperti Renderer atau SceneManager atau keduanya (tergantung pada kompleksitas game / mesin). Daripada Anda dapat memiliki kelas OpenGLRenderer dan / atau DXRenderer yang mengimplementasikan antarmuka Renderer. Kemudian jika Anda memiliki SceneManager dan Renderer, Anda dapat melakukan beberapa hal berikut:
Renderer mungkin akan memanggil fungsi draw objek yang akan memanggil function draw dari setiap mesh yang tersusun dari dan mesh akan mengikat objek tekstur, binding shader, memanggil fungsi draw OpenGL dan kemudian tidak digunakan shader, tekstur dan objek data buffer objek.
CATATAN: ini hanya contoh, Anda harus mempelajari SceneManager lebih detail dan menganalisis use case Anda untuk melihat apa opsi implementasi terbaik
Anda tentu saja, memiliki komponen mesin lainnya, seperti MemoryManager , ResourceLoader dll, yang akan menangani penggunaan memori video dan RAM, sehingga mereka dapat memuat / membongkar model / shader / tekstur tertentu sesuai kebutuhan. Konsep untuk ini termasuk cache memori, pemetaan memori dll. Ada banyak detail dan konsep tentang masing-masing komponen.
Lihatlah deskripsi yang lebih rinci dari mesin game lain, ada banyak dari mereka dan dokumentasinya cukup banyak tersedia.
Tapi ya, kelas membuat hidup lebih mudah; Anda harus benar-benar menggunakannya dan ingat tentang enkapsulasi, warisan, antarmuka, dan hal-hal keren lainnya.
sumber
OpenGL memiliki beberapa konsep 'Objek' di dalamnya.
Misalnya segala sesuatu dengan id dapat melalui sebagai objek (Ada juga hal-hal khusus bernama 'Objek'). Buffer, Tekstur, Objek Penyangga Verteks, Objek Array Vertex, Objek Penyangga Bingkai dan sebagainya. Dengan sedikit kerja Anda bisa membungkus kelas di sekitar mereka. Ini juga memberi Anda cara mudah untuk kembali ke fungsi OpenGL lama yang sudah usang jika konteks Anda tidak mendukung ekstensi. Misalnya VertexBufferObject dapat kembali menggunakan glBegin (), glVertex3f (), dan sebagainya.
Ada beberapa cara yang mungkin Anda perlukan untuk beralih dari konsep OpenGL tradisional, misalnya Anda mungkin ingin menyimpan metadata tentang buffer dalam objek buffer. Misalnya jika buffer menyimpan simpul. Apa format dari simpul (yaitu posisi, normals, texcoords dan sebagainya). Apa primitif yang digunakannya (GL_TRIANGLES, GL_TRIANGLESTRIP, dll ...), informasi ukuran (berapa banyak pelampung yang disimpan, berapa banyak segitiga yang mereka wakili, dll ...). Hanya untuk membuatnya mudah untuk menghubungkannya ke perintah draw arrays.
Saya sarankan Anda melihat OGLplus . Ini binding C ++ untuk OpenGL.
Juga glxx , itu hanya untuk memuat ekstensi sekalipun.
Selain membungkus API OpenGL, Anda harus melihat pembuatan level satu yang sedikit lebih tinggi di atasnya.
Misalnya kelas manajer material yang bertanggung jawab untuk semua shader Anda, memuat dan menggunakannya. Juga akan bertanggung jawab untuk mentransfer properti kepada mereka. Dengan begitu Anda bisa langsung memanggil: materials.usePhong (); material.setTexture (somethingexture); material.setColor (). Ini memungkinkan lebih banyak fleksibilitas karena Anda dapat menggunakan hal-hal yang lebih baru seperti objek buffer seragam bersama untuk hanya memiliki 1 buffer besar yang berisi semua properti yang digunakan shader Anda dalam 1 blok tetapi jika tidak didukung Anda tidak dapat mengunggah kembali untuk mengunggah ke setiap program shader. Anda dapat memiliki 1 shader monolitik besar dan bertukar antara model shader yang berbeda menggunakan rutin yang seragam jika didukung atau Anda dapat kembali menggunakan sekelompok shader kecil yang berbeda.
Anda juga dapat melihat pengeluaran dari spesifikasi GLSL untuk menulis kode shader Anda. Misalnya #include akan sangat berguna dan sangat mudah diimplementasikan dalam kode pemuatan shader Anda (ada juga ekstensi ARB untuk itu). Anda juga dapat membuat kode dengan cepat berdasarkan ekstensi apa yang didukung, misalnya menggunakan objek seragam bersama atau kembali menggunakan seragam normal.
Terakhir, Anda akan menginginkan API pipa render tingkat tinggi yang melakukan hal-hal seperti grafik adegan, efek khusus (blur, cahaya), hal-hal yang memerlukan beberapa proses rendering seperti bayangan, pencahayaan, dan semacamnya. Dan selain itu, API game yang tidak ada hubungannya dengan grafik API tetapi hanya berurusan dengan objek di dunia.
sumber
oglplus::Context
kelas membuat ketergantungan ini sangat terlihat - apakah itu menjadi masalah? Saya percaya ini akan membantu pengguna OpenGL baru untuk menghindari banyak masalah.Dalam OpenGL modern Anda hampir dapat sepenuhnya memisahkan objek yang diberikan satu sama lain, menggunakan program vaos dan shader yang berbeda. Dan bahkan implementasi satu objek dapat dipisahkan menjadi banyak lapisan abstraksi.
Misalnya, jika Anda ingin menerapkan terrain, Anda bisa mendefinisikan TerrainMesh yang konstruktornya membuat simpul dan indeks untuk terrain, dan menetapkannya menjadi arraybuffers, dan - jika Anda memberinya posisi atribut - itu shaderplumbs data Anda. Ia juga harus tahu cara merendernya, dan harus berhati-hati untuk mengembalikan semua perubahan konteks yang telah dilakukan untuk mengatur rendering. Kelas ini sendiri seharusnya tidak tahu apa-apa tentang program shader yang akan merendernya, dan juga tidak harus tahu apa-apa tentang objek lain di tempat kejadian. Di atas kelas ini Anda bisa menentukan Terrain, yang mengetahui kode shader, dan tugasnya adalah membuat koneksi antara shader dan TerrainMesh. Ini harus berarti mendapatkan posisi atribut dan seragam dan memuat dalam tekstur, dan hal-hal seperti itu. Kelas ini seharusnya tidak tahu apa-apa tentang bagaimana medan diterapkan, apa algoritma LoD yang digunakannya, ia hanya bertanggung jawab untuk menaungi medan. Di atas ini, Anda dapat mendefinisikan fungsionalitas non-OpenGL seperti behivour dan deteksi tabrakan dan semacamnya.
Datang ke titik, meskipun OpenGL dirancang untuk digunakan tingkat rendah, Anda masih dapat membangun lapisan abstraksi independen, yang memungkinkan Anda meningkatkan aplikasi dengan ukuran permainan Unreal. Tetapi jumlah lapisan yang Anda inginkan / butuhkan sangat tergantung pada ukuran aplikasi yang Anda inginkan.
Tapi jangan membohongi diri sendiri tentang ukuran ini, jangan mencoba meniru model objek Unity dalam aplikasi 10k line, hasilnya akan menjadi bencana total. Membangun lapisan secara bertahap, hanya menambah jumlah lapisan abstraksi, saat dibutuhkan.
sumber
ioDoom3 mungkin merupakan titik awal yang bagus, karena Anda dapat mengandalkan Carmack untuk mengikuti praktik pengkodean yang hebat. Saya juga percaya dia tidak menggunakan megatexturing di Doom3, jadi ini relatif lurus ke depan sebagai render pipe.
sumber