OpenGL Berorientasi Objek


12

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?


1
Ada permainan sumber terbuka di luar sana serta tutorial yang lebih besar yang memiliki lebih banyak kode. Lihat beberapa di antaranya dan lihat bagaimana kodenya disusun.
MichaelHouse

Apakah Anda seorang pemula ketika datang ke rendering engine?
Samaursa

Pertanyaan ini tidak dapat dijawab secara wajar tanpa mempersempit ruang lingkup. Apa yang sedang Anda coba bangun? Jenis permainan apa, jenis grafik apa yang dimilikinya, dll?
Nicol Bolas

1
@Sullivan: "Saya pikir konsep semacam ini akan berlaku untuk hampir semua permainan." Mereka tidak melakukannya. Jika Anda meminta saya membuat Tetris, saya tidak akan repot membuat lapisan pembungkus besar atau sesuatu di sekitar OpenGL. Cukup gunakan secara langsung. Jika Anda meminta saya membuat sesuatu seperti Mass Effect, maka kami akan membutuhkan beberapa lapisan abstraksi di sekitar sistem render kami. Melempar mesin Unreal di Tetris menggunakan senapan untuk berburu lalat; itu membuat tugas jadi jauh lebih sulit daripada hanya coding tangan secara langsung. Anda hanya harus membangun sistem yang besar dan kompleks seperti yang Anda butuhkan , dan tidak lebih besar.
Nicol Bolas

1
@ Sullivan: Satu-satunya kerumitan yang tersirat oleh pertanyaan Anda adalah di mana Anda berbicara tentang membelah banyak file. Yang merupakan sesuatu yang akan saya lakukan bahkan di Tetris. Dan ada banyak tingkat kompleksitas antara Tetris dan mesin Unreal. Jadi sekali lagi: yang mana yang Anda tanyakan?
Nicol Bolas

Jawaban:


6

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:

  • Traverse SceneManager dan kirim setiap objek ke Renderer untuk rendering
  • Meringkas huruf besar dalam beberapa metode SceneManager
  • Kirim SceneManager ke Renderer sehingga ia menanganinya

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.


Ini adalah jawaban yang saya cari. Namun, ketika Anda mengatakan "... memuat tekstur, model dan shader ke RAM (jika perlu) dan Buffer Objects, dan unggah / kompilasi shaders ..." membawa saya kembali ke pertanyaan awal saya; haruskah saya menggunakan objek untuk merangkum hal-hal seperti model dan shader?
Sullivan

objek adalah turunan dari sebuah kelas, dan 'Anda harus benar-benar menggunakannya'.
edin-m

Maaf, saya bermaksud bertanya 'bagaimana saya harus menggunakan benda'. Salahku.
Sullivan

Yah, itu tergantung dari desain kelas Anda. Beberapa contoh dasar akan intuitif, seperti: object3d (class) has meshes (class); setiap jala memiliki bahan (kelas); setiap bahan memiliki tekstur (bisa kelas, atau hanya id) dan shader (kelas). Tetapi ketika Anda membaca tentang masing-masing komponen Anda akan melihat ada pendekatan yang berbeda tetapi sama untuk membuat SceneManager, Renderer, MemoryManager (semua ini bisa kelas tunggal atau banyak dari mereka, diwarisi dll dll). Lusinan buku ditulis tentang topik ini (arsitektur mesin game), dan untuk menjawab pertanyaan secara terperinci orang dapat menulisnya.
edin-m

Saya pikir ini adalah jawaban terbaik yang akan saya dapatkan. Terima kasih atas bantuan Anda :)
Sullivan

2

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.


2
"Saya sarankan Anda melihat OGLplus. Ini binding C ++ untuk OpenGL." Saya akan merekomendasikan melawan itu. Saya suka RAII, tetapi sepenuhnya tidak pantas untuk sebagian besar objek OpenGL. Objek OpenGL dikaitkan dengan konstruk global: konteks OpenGL. Jadi, Anda tidak akan dapat membuat objek C ++ ini sampai Anda memiliki konteks, dan Anda tidak akan dapat menghapus objek-objek ini jika konteksnya telah dihancurkan. Juga, ini memberikan ilusi bahwa Anda dapat memodifikasi objek tanpa mengubah keadaan global. Ini bohong (kecuali jika Anda menggunakan EXT_DSA).
Nicol Bolas

@NicolBolas: Bisakah saya tidak memeriksa untuk melihat apakah ada konteks dan hanya menginisialisasi kemudian? Atau mungkin hanya mengizinkan manajer untuk membuat objek yang memerlukan konteks OpenGL? --- btw, tutorial yang bagus (tautan di profil Anda)! Entah bagaimana saya tidak pernah menemukan mereka ketika mencari OpenGL / Grafik.
Samaursa

@ Sasama: Untuk tujuan apa? Jika Anda memiliki manajer untuk objek OpenGL, maka ... Anda tidak benar-benar perlu memiliki objek mengurus diri mereka sendiri; manajer dapat melakukannya untuk mereka. Dan jika Anda hanya menginisialisasi ketika ada konteks, apa yang terjadi jika Anda mencoba menggunakan objek yang tidak diinisialisasi dengan benar? Itu hanya menciptakan kelemahan dalam basis kode Anda. Juga tidak mengubah apa pun yang saya katakan tentang kemampuan untuk memodifikasi objek-objek ini tanpa menyentuh keadaan global.
Nicol Bolas

@NicolBolas: "Anda tidak akan dapat membuat objek C ++ ini sampai Anda memiliki konteks" ... apakah itu berbeda dari menggunakan konstruksi OpenGL kosong? Di mata saya, oglplus::Contextkelas membuat ketergantungan ini sangat terlihat - apakah itu menjadi masalah? Saya percaya ini akan membantu pengguna OpenGL baru untuk menghindari banyak masalah.
xtofl

1

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.


0

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.


6
"Anda bisa mengandalkan Carmack untuk mengikuti praktik pengkodean yang hebat" Ya ampun, itu bagus. Carmack mengikuti praktik pengkodean C ++ yang hebat. Itu kerusuhan! Oh ... kamu tidak bercanda. Um ... apakah Anda pernah benar-benar melihat kodenya? Dia seorang programmer C dan begitulah menurutnya. Yang baik untuk C, tetapi pertanyaannya adalah tentang C ++ .
Nicol Bolas

Saya berasal dari latar belakang C sehingga kodenya sangat masuk akal bagi saya: P dan ya, menghabiskan sedikit waktu mengerjakan game berbasis gempa.
chrisvarnz
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.