Menggulir grafik adegan saya sendiri


23

Halo Pengembangan Game SE!

Saya merangkak melalui OpenGL dengan harapan menciptakan mesin game yang sederhana dan sangat ringan. Saya melihat proyek ini sebagai pengalaman belajar yang mungkin menghasilkan sedikit uang pada akhirnya, tetapi akan menyenangkan juga.

Sejauh ini saya telah menggunakan GLFW untuk mendapatkan beberapa I / O dasar, sebuah jendela (dengan tombol layar penuh F11 yang sangat mewah) dan tentu saja konteks OpenGL. Saya juga menggunakan GLEW untuk mengekspos sisa ekstensi OpenGL karena saya menggunakan Windows dan saya ingin menggunakan semua OpenGL 3.0+.

Yang membawa saya ke grafik adegan. Singkatnya, saya ingin menggulung sendiri. Keputusan ini datang setelah melihat OSG dan membaca beberapa artikel tentang bagaimana konsep grafik adegan menjadi bengkok, bengkok dan rusak. Salah satu artikel tersebut menggambarkan bagaimana grafik adegan telah dikembangkan sebagai ...

Kemudian kami menambahkan semua barang ekstra ini, seperti menggantung hiasan di pohon Natal, kecuali bahwa beberapa ornamennya adalah steak yang enak dan beberapa sapi hidup.

Mengikuti analogi ini, saya suka steak, daging dari apa yang seharusnya adegan grafik, tanpa harus mengikat tumpukan kode tambahan, atau sapi utuh.

Jadi dengan mengingat hal itu, saya mendapati diri saya bertanya-tanya persis seperti apa grafik adegan dan bagaimana grafik adegan sederhana harus diimplementasikan? Inilah yang saya miliki sejauh ini ...

Satu induk, pohon n-anak atau DAG yang ...

  • Harus melacak transformasi objek game (posisi, rotasi, skala)
  • Harus menahan status render untuk optimisasi
  • Harus menyediakan alat pemusnahan objek tidak dalam tampilan frustum

Dengan properti berikut ...

  • Semua node harus diperlakukan sebagai renderable (bahkan jika mereka tidak render) Ini berarti mereka ...

    • Haruskah semua memiliki metode cull (), state () dan draw () (mengembalikan 0 jika tidak terlihat)
    • cull () secara rekursif memanggil cull () pada semua anak, sehingga menghasilkan mesh cull lengkap untuk seluruh node, dan semua anak. Metode lain, hasChanged () dapat memungkinkan apa yang disebut jerat statis tidak perlu memiliki geometri culling mereka dihitung setiap frame. Ini akan berfungsi sedemikian rupa sehingga jika ada simpul di sub-pohon telah berubah maka semua geometri ke root dibangun kembali.
  • Status render akan disimpan dalam enumerasi sederhana, setiap node akan memilih dari enumerasi ini set keadaan OpenGL yang diperlukan dan status itu akan diatur sebelum draw () dipanggil pada node itu. Ini memungkinkan untuk batching, semua node dari set state yang diberikan akan dirender bersama, kemudian set state berikutnya adalah setup dan seterusnya.

  • Tidak boleh ada node yang secara langsung menyimpan data geometri / shader / tekstur, sebaliknya node harus menunjuk ke objek yang dibagikan (mungkin dikelola oleh beberapa objek tunggal seperti manajer sumber daya).

  • Grafik adegan harus dapat mereferensikan grafik adegan lain (mungkin menggunakan simpul proksi) untuk memungkinkan situasi seperti ini , sehingga memungkinkan model / objek multi-jala kompleks untuk disalin di sekitar grafik adegan tanpa menambahkan satu ton data.

Saya berharap mendapat umpan balik yang berharga tentang desain saya saat ini. Apakah itu kehilangan fungsionalitas? Apakah ada cara / pola desain yang jauh lebih baik? Apakah saya kehilangan beberapa konsep yang lebih besar yang perlu dimasukkan dalam desain ini untuk permainan 3D yang agak sederhana? Dll

Terima kasih, -Cody

Jawaban:


15

Konsep

Pada dasarnya, grafik adegan tidak lebih dari grafik asiklik dua arah yang berfungsi untuk mewakili serangkaian hubungan spasial yang terstruktur secara hierarkis.

Mesin-mesin di alam liar cenderung memasukkan barang-barang lain ke dalam grafik adegan, sebagaimana dicatat. Apakah Anda melihatnya sebagai daging atau sapi mungkin tergantung pada pengalaman Anda dengan mesin dan perpustakaan di luar sana.

Menjaga Ringan

Saya menyukai gaya Unity3D memiliki simpul grafik adegan Anda (yang pada dasarnya adalah topologi daripada struktur spasial / topografi) secara inheren mencakup parameter spasial dan fungsionalitas. Di mesin saya, simpul saya bahkan lebih ringan dari Unity3D, di mana mereka mewarisi banyak anggota sampah yang tidak perlu dari superclasses / antarmuka yang diimplementasikan: Inilah yang saya miliki - kira-kira seringan yang Anda bisa dapatkan:

  • anggota pointer orangtua / anak.
  • pra-transform anggota parameter spasial: posisi xyz, pitch, yaw and roll.
  • matriks transformasi; matriks dalam rantai hierarkis dapat dengan cepat & mudah berkembang biak dengan berjalan secara rekursif ke atas / ke bawah pohon, memberi Anda transformasi spasial hierarkis yang merupakan fitur utama grafik adegan;
  • sebuah updateLocal()metode yang update hanya ini simpul yang mengubah matriks
  • sebuah updateAll()metode yang memperbarui ini dan semua matriks transformasi node turunan

... Saya juga memasukkan persamaan persamaan gerak dan dengan demikian anggota kecepatan / percepatan (linier & sudut) di kelas simpul saya. Anda dapat melepaskan itu, dan menanganinya di pengontrol utama Anda jika Anda mau. Tapi itu dia - memang sangat ringan. Ingat, Anda dapat memiliki ini di ribuan entitas. Jadi seperti yang Anda sarankan, tetap ringan.

Membangun Hirarki

Apa yang Anda katakan tentang grafik adegan referensi grafik adegan lain ... Saya sedang menunggu lucunya? Tentu saja mereka lakukan. Itulah kegunaan utama mereka. Anda dapat menambahkan simpul apa pun ke simpul lain mana pun, dan transformasi akan terjadi secara otomatis di dalam ruang lokal transformasi baru. Yang Anda lakukan hanyalah mengubah pointer, tidak seperti Anda menyalin data! Dengan mengubah pointer, Anda kemudian memiliki grafik adegan yang lebih dalam. Jika menggunakan Proxy membuat segalanya lebih efisien maka dengan segala cara, tapi saya belum pernah melihat kebutuhannya.

Hindari Logika terkait Render

Lupakan tentang rendering saat Anda menulis kelas node node grafik Anda, atau Anda akan mengacaukan hal-hal untuk diri Anda sendiri. Yang penting adalah bahwa Anda memiliki model data - apakah itu grafik adegan atau tidak tidak masalah - dan bahwa beberapa penyaji akan memeriksa bahwa model data dan merender objek di dunia sesuai, apakah itu dalam 1, 2 , 3 atau 7 dimensi. Maksud saya adalah: Jangan mencemari grafik adegan Anda dengan logika render. Grafik adegan adalah tentang topologi dan topografi - yaitu konektivitas dan karakteristik spasial. Ini adalah keadaan sebenarnya dari simulasi dan ada bahkan tanpa adanya rendering (yang dapat mengambil bentuk apa pun di bawah matahari dari tampilan orang pertama ke grafik statistik ke deskripsi tekstual). Node tidak menunjuk ke objek yang berhubungan dengan rendering - namun kebalikannya mungkin benar. Pertimbangkan juga ini: Tidak setiap simpul grafik adegan di seluruh pohon Anda akan dapat diulang. Banyak yang hanya akan menjadi wadah. Jadi mengapa bahkan mengalokasikan memori untuk pointer-to-render-object? Bahkan anggota pointer yang tidak pernah digunakan, masih mengambil memori. Jadi balikkan arah penunjuk: Contoh terkait-render merujuk model data (yang mungkin, atau termasuk, simpul grafik adegan Anda), BUKAN sebaliknya. Dan jika Anda ingin cara mudah untuk menjalankan melalui daftar controller Anda belum mendapatkan akses ke tampilan terkait, kemudian gunakan kamus / hashtable, yang mendekati O (1) membaca waktu akses. Dengan begitu tidak ada kontaminasi, dan logika simulasi Anda tidak peduli apa yang diberikan penyaji, yang membuat hari Anda dan malam pengkodean Jadi mengapa bahkan mengalokasikan memori untuk pointer-to-render-object? Bahkan anggota pointer yang tidak pernah digunakan, masih mengambil memori. Jadi balikkan arah penunjuk: Contoh terkait-render merujuk model data (yang mungkin, atau termasuk, simpul grafik adegan Anda), BUKAN sebaliknya. Dan jika Anda ingin cara mudah untuk menjalankan melalui daftar controller Anda belum mendapatkan akses ke tampilan terkait, kemudian gunakan kamus / hashtable, yang mendekati O (1) membaca waktu akses. Dengan begitu tidak ada kontaminasi, dan logika simulasi Anda tidak peduli apa yang diberikan penyaji, yang membuat hari Anda dan malam pengkodean Jadi mengapa bahkan mengalokasikan memori untuk pointer-to-render-object? Bahkan anggota pointer yang tidak pernah digunakan, masih mengambil memori. Jadi balikkan arah penunjuk: Contoh terkait-render merujuk model data (yang mungkin, atau termasuk, simpul grafik adegan Anda), BUKAN sebaliknya. Dan jika Anda ingin cara mudah untuk menjalankan melalui daftar controller Anda belum mendapatkan akses ke tampilan terkait, kemudian gunakan kamus / hashtable, yang mendekati O (1) membaca waktu akses. Dengan begitu tidak ada kontaminasi, dan logika simulasi Anda tidak peduli apa yang diberikan penyaji, yang membuat hari Anda dan malam pengkodean Dan jika Anda ingin cara mudah untuk menjalankan melalui daftar controller Anda belum mendapatkan akses ke tampilan terkait, kemudian gunakan kamus / hashtable, yang mendekati O (1) membaca waktu akses. Dengan begitu tidak ada kontaminasi, dan logika simulasi Anda tidak peduli apa yang diberikan penyaji, yang membuat hari Anda dan malam pengkodean Dan jika Anda ingin cara mudah untuk menjalankan melalui daftar controller Anda belum mendapatkan akses ke tampilan terkait, kemudian gunakan kamus / hashtable, yang mendekati O (1) membaca waktu akses. Dengan begitu tidak ada kontaminasi, dan logika simulasi Anda tidak peduli apa yang diberikan penyaji, yang membuat hari Anda dan malam pengkodeandunia lebih mudah.

Sedangkan untuk pemusnahan, lihat kembali di atas. Pemusnahan area-minat adalah konsep logika simulasi. Artinya, Anda tidak memproses dunia di luar area ini (biasanya kotak, bundar atau bulat). Ini terjadi di loop controller / game utama, sebelum rendering terjadi. Di sisi lain, pemusnahan frustrasi murni terkait dengan render. Jadi lupakan tentang pemusnahan sekarang. Ini tidak ada hubungannya dengan grafik adegan, dan dengan berfokus padanya Anda akan mengaburkan tujuan sebenarnya dari apa yang Anda coba capai.

Catatan Akhir ...

Saya mendapatkan perasaan yang kuat bahwa Anda berasal dari latar belakang Flash (khusus AS3), mengingat semua detail tentang rendering dimasukkan di sini. Ya, paradigma Flash Stage / DisplayObject mencakup semua logika render sebagai bagian dari skenario. Tetapi Flash membuat banyak asumsi yang tidak perlu Anda buat. Untuk mesin game yang lengkap, lebih baik tidak mencampur keduanya, karena alasan kinerja, kenyamanan, dan pengontrolan kompleksitas kode melalui SoC yang tepat .


1
Terima kasih Nick. Saya sebenarnya seorang animator 3D (3D nyata bukan flash) berubah programmer, jadi saya cenderung berpikir dalam hal grafis. Jika itu tidak cukup buruk, saya mulai di Jawa dan telah mengorek diri dari mentalitas "semuanya harus menjadi objek" yang ditanamkan dalam bahasa itu. Anda telah meyakinkan saya bahwa grafik adegan harus dipisahkan dari rendering dan culling kode, sekarang roda gigi saya berputar tepat bagaimana itu harus dilakukan. Saya berpikir untuk memperlakukan penyaji seperti sistemnya sendiri yang berbeda yang mereferensikan grafik adegan untuk mentransformasikan data, dll.
Cody Smith

1
@CodySmith, Senang itu membantu. Plug tak tahu malu, tapi saya mempertahankan kerangka yang semuanya tentang SoC / MVC. Dengan melakukan hal itu, saya berhadapan dengan kubu yang lebih tradisional di industri yang bersikeras bahwa segala sesuatu harus berada di pusat, objek monolitik. Tetapi bahkan mereka akan memberi tahu Anda secara umum - jaga agar rendering Anda terpisah dari grafik adegan Anda. SoC / SRP adalah sesuatu yang saya tidak bisa cukup menekankan - tidak pernah mencampur lebih banyak logika ke dalam satu kelas daripada yang Anda butuhkan. Saya bahkan akan menganjurkan rantai pewarisan OO kompleks atas logika campuran di kelas yang sama, jika Anda menodongkan pistol ke kepala saya!
Insinyur

Tidak, saya suka konsepnya. Dan hak Anda, ini adalah penyebutan pertama SoC yang pernah saya lihat di mana pun selama bertahun-tahun membaca tentang Desain game. Terima kasih lagi.
Cody Smith

@CodySmith Pikir cepat saat menjelajah ini lagi. Secara umum ada baiknya untuk menjaga hal-hal dipisahkan. Untuk berbagai jenis model objek-controller dalam basis kode Anda yang menjalani rendering, bagaimanapun, adalah baik bagi Anda untuk menyimpan koleksi Renderables (yang merupakan antarmuka atau kelas abstrak) secara internal kepada mereka inti model objek-controller. Contoh bagus untuk ini adalah entitas atau elemen UI. Dengan demikian Anda dapat dengan cepat mengakses hanya penyaji yang berkaitan dengan objek inti tertentu - tanpa implementasi spesifik yang akan mencemari kelas entitas, karenanya penggunaan antarmuka.
Insinyur

@CodySmith Manfaatnya jelas dengan entitas, yang mungkin misalnya. memiliki representasi di viewport dunia dan minimap. Makanya, koleksinya. Atau, Anda dapat mengizinkan slot penyaji tunggal untuk setiap objek pengontrol model, secara internal ke objek itu. Tetapi pertahankan antarmuka umum! Tidak spesifik - adil Renderer.
Insinyur
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.