Tingkat abstraksi yang benar untuk komponen rendering 3d?

8

Saya telah melihat banyak pertanyaan di area ini tetapi bukan pertanyaan yang tepat ini, jadi minta maaf jika ini adalah duplikat.

Saya membuat game 3d kecil. Yah jujur ​​saja, ini hanya proyek hobi kecil dan kemungkinan tidak akan berubah menjadi game yang sebenarnya, saya akan dengan senang hati membuat demo grafis yang bagus dan belajar tentang rendering 3d dan desain c ++.

Maksud saya adalah menggunakan direct3d9 untuk rendering karena saya memiliki sedikit pengalaman tentang hal itu, dan tampaknya memenuhi persyaratan saya. Namun jika saya telah mempelajari satu hal sebagai seorang programmer, ia bertanya " apakah ada alasan yang memungkinkan bahwa komponen ini dapat diganti dengan penerapan yang berbeda " dan jika jawabannya adalah ya maka saya perlu merancang abstraksi yang tepat dan antarmuka ke komponen itu. . Jadi meskipun saya berniat untuk mengimplementasikan d3d9 saya perlu merancang antarmuka 3d yang dapat diimplementasikan untuk d3d11, opengl ...

Pertanyaan saya kemudian adalah pada level apa yang terbaik untuk melakukan ini? Saya berpikir bahwa antarmuka mampu membuat dan menggambar nanti

  • Buffer verteks dan buffer indeks
  • Tekstur
  • Vertex dan Pixel "shaders"
  • Beberapa representasi dari negara gambar (blending mode dll ...)

Dengan kata lain antarmuka tingkat yang cukup rendah di mana kode saya untuk menggambar misalnya model animasi akan menggunakan antarmuka untuk mendapatkan buffer vertex abstrak dll. Namun saya khawatir itu terlalu rendah untuk abstrak semua fungsi yang saya butuhkan secara efisien.

Alternatifnya adalah melakukan ini di tingkat yang lebih tinggi di mana antarmuka dapat menggambar objek, animasi, lanskap dll, dan mengimplementasikannya untuk setiap sistem. Ini sepertinya lebih banyak pekerjaan, tapi kurasa lebih fleksibel.

Jadi itulah pertanyaan saya, ketika mengabstraksi sistem menggambar, tingkat antarmuka apa yang paling baik?

JohnB
sumber
Ini mungkin tidak menjawab pertanyaan Anda sepenuhnya, tetapi saya akan menyarankan melihat sumber-sumber mesin DirectX + OpenGL seperti OGRE dan Irrlicht untuk melihat bagaimana mereka mengabstraksikannya.
Bebek Komunis

Jawaban:

8

Permintaan maaf atas panjangnya tanggapan ini!

"Apakah ada alasan yang memungkinkan bahwa komponen ini dapat diganti dengan implementasi yang berbeda" dan jika jawabannya adalah ya maka saya perlu merancang abstraksi yang tepat dan antarmuka ke komponen itu.

"Alasan yang masuk akal" adalah sikap yang terlalu ekstrem untuk diambil. Hampir setiap fungsi dapat parameter dengan beberapa cara, setiap modul diberi strategi atau kebijakan yang berbeda, dan setiap perubahan konstan. Jika Anda memberikan tingkat abstraksi ekstra untuk masing-masing ini, maka Anda akhirnya menulis kode 2x lebih banyak tanpa keuntungan langsung, hanya potensi keuntungan nanti jika Anda memerlukan fleksibilitas itu.

Jika Anda turun rute menyediakan antarmuka sehingga masing-masing hal ini dapat menjadi fasad untuk salah satu dari beberapa opsi yang berbeda, Anda kemudian harus memutuskan bagaimana Anda menyediakan opsi-opsi yang berbeda ini, termasuk default, dan ketika Anda mencoba dan membuatnya sesederhana itu. sebagai objek asli adalah Anda sering berakhir dengan seluruh lapisan ekstra di atasnya. Ini bisa (dan memang) masuk akal di banyak perangkat lunak 'perusahaan' dunia nyata - bolehkah saya dengan rendah hati menyarankan membaca bagian sindiran ini yang sayangnya terlalu dekat dengan rumah dalam banyak kasus: Mengapa Saya Benci Kerangka .

Argumen terbesar yang menentang hal ini adalah kompleksitas. Mari kita membuat (mungkin salah) asumsi bahwa ada antarmuka yang bagus yang dapat berlaku sama baiknya untuk dua API rendering 3D, dan bahwa seseorang dapat menggambarkan ini kepada Anda dalam jawaban di sini. Anda kemudian akan bekerja untuk antarmuka ini, yang, karena sifatnya yang multi-guna, tidak diragukan lagi mencakup elemen-elemen yang tidak digunakan DX9 - misalnya, kebanyakan ekstensi API yang tersedia di OpenGL tetapi tidak di DirectX 9. Ini adalah komplikasi tambahan yang akan membuat kode Anda lebih sulit untuk dipahami dan dipelihara, dan memperlambat proses belajar Anda. Sudah cukup buruk ketika menggunakan pustaka multi-platform yang ada seperti SDL, karena orang selamanya menemukan fungsi dan batasan aneh yang ada murni untuk memperbaiki sesuatu pada satu platform, tetapi Anda ' d tidak hanya harus belajar mengapa bagian antarmuka itu ada tetapi juga bagaimana hal itu dapat berinteraksi dengan bagian yang saat ini akan Anda tulis. misalnya. Anda akhirnya akan menulis objek abstrak yang merangkum aspek ekstensi OpenGL yang diperlukan dalam kode rendering inti Anda, meskipun Anda belum memiliki cara untuk menggunakannya.

Namun, di masa depan, setelah Anda kompeten dengan cara kerja sistem DX9, Anda dapat melihat bagaimana sistem OpenGL beroperasi. Anda kemudian akan melihat bagaimana Anda perlu mengadaptasi sistem Anda yang ada untuk membuat kedua bagian bekerja, dan akan melakukannya, dengan keberadaan jalur kode DX9 yang ada sebagai uji unit yang efektif untuk memastikan refactoring Anda benar.

Anda beruntung karena Anda bekerja dengan salah satu bahan yang paling mudah berubah dan lunak yang diketahui oleh rekayasa - kode sumber yang disimpan sebagai data komputer. Rangkul berkat itu dengan melakukan perubahan padanya ketika Anda tahu Anda membutuhkannya, daripada melakukannya berbulan-bulan sebelumnya dan membebani diri Anda sementara itu dengan harus menulis ke abstraksi yang belum Anda dapatkan.

Kylotan
sumber
Ini yang saya rasakan, tetapi pada saat yang sama saran umum yang saya lihat adalah mengabstraksi kode spesifik platform untuk permainan itu mudah dilakukan dan harus dilakukan ... Saya tidak tahu harus berpikir apa.
Rei Miyasaka
5

Namun jika saya telah mempelajari satu hal sebagai seorang programmer, ia bertanya "apakah ada alasan yang memungkinkan bahwa komponen ini dapat diganti dengan penerapan yang berbeda" dan jika jawabannya adalah ya maka saya perlu merancang abstraksi yang tepat dan antarmuka ke komponen itu. .

Ini tidak benar-benar menjawab pertanyaan Anda, tetapi dari pengalaman saya sebagai seorang programmer, generalisasi prematur sama buruknya dengan optimasi prematur. Anda jarang mendapatkan apa pun dan harus memeliharanya selama proyek berlangsung.

Saran saya adalah untuk langsung menggunakan kode klien D3D9 dalam proyek Anda, dan ketika Anda menentukan bahwa Anda perlu beralih antarmuka, buatlah antarmuka dengan semua hal yang saat ini Anda gunakan. Pemrogram sangat buruk dalam memprediksi apa yang mereka butuhkan, jadi dalam kasus Anda di mana Anda tidak terlalu akrab dengan materi, jadi dengan cara ini Anda melakukan pekerjaan yang paling sedikit.

Lihat juga: http://c2.com/xp/YouArentGonnaNeedIt.html

Tetrad
sumber
Masalahnya adalah jika ia kemudian harus melakukan abstraksi, ia kemudian harus menulis ulang semua kode antarmuka. Dan jika D3D9 disertakan secara global di seluruh proyeknya, akan sangat sulit untuk memperbaiki semua kode itu.
DeadMG
1
Lagi pula dia harus menulis ulang semuanya ketika dia memiliki kasus penggunaan yang tidak tercakup oleh asumsi apa pun yang dia buat sekarang. Refactoring harus dianut, terutama untuk proyek pembelajaran.
Tetrad
Saya sedikit mengagungkan kasus ini. Saya juga benci abstraksi yang tidak perlu. Tetapi dalam hal ini saya dapat mengatakan sebenarnya ada peluang bagus saya ingin melakukan ini dengan implementasi yang berbeda ...
JohnB
4

Hm, sepertinya saya tidak memiliki reputasi yang cukup untuk mengirim komentar ke tanggapan.

Baik Kylotan dan Tetrad memberikan jawaban yang sangat baik. Yang ingin saya tambahkan adalah menyarankan Anda memisahkan kode rendering dari logika permainan - ini akan melayani beberapa tujuan:

  • kode Anda akan lebih bersih
  • akan lebih mudah bagi Anda untuk membuat perubahan pada penyaji Anda tanpa menulis ulang setengah dari logika permainan setiap kali
  • akhirnya, menyediakan modul rendering yang sama sekali berbeda lebih mudah dengan cara ini

Sebagai bonus tambahan, dengan cara ini Anda akan membangun abstraksi Anda secara bertahap saat Anda mengerjakan proyek Anda. Seperti yang Anda katakan, ini adalah proyek pembelajaran jadi santai saja dan buatlah sederhana, tambahkan kompleksitas dan abstraksi saat Anda melangkah alih-alih membuat rencana besar karena Anda mungkin kurang keahlian untuk melakukannya dengan benar pada awalnya (seperti yang disarankan Tetrad).

Gilead
sumber
Oh memang! Tetapi pertanyaannya adalah level apa yang harus saya pisahkan? Di tingkat menggambar seluruh kota, atau tingkat menggambar segitiga? Atau di mana di antara
JohnB
Cara yang masuk akal adalah dengan tetap membuat panggilan API terpisah. Itu mungkin tentang 'menggambar bangunan atau mobil' dalam analogi Anda (mengingat bangunan dan mobil Anda adalah objek tunggal :)). Contoh: Anda ingin menghidupkan objek Anda (untuk kesederhanaan, anggaplah hanya satu yang dapat dimainkan pada satu waktu). Objek permainan dapat memiliki daftar urutan yang tersedia dan panjangnya dan mengatur animasi aktif dan kecepatannya sementara penyaji akan mengelola, baik, bagian rendering. Anda mungkin juga perlu mendapatkan kembali data dari renderer, mis. Bentuk benturan objek dapat berubah selama animasi.
Gilead
1

Anda tidak dapat menulis abstraksi tingkat rendah atas hal semacam ini, karena detail shader benar-benar berbeda antara D3D9, 11, OGL, dll. Ini tidak mungkin.

Anda dapat memeriksa abstraksi yang diimplementasikan dalam, katakanlah, SFML, SDL, OGRE jika Anda ingin melihat apa yang telah dipilih orang lain untuk melakukan abstraksi.

DeadMG
sumber
Kecuali shader bukan bagian dari abstraksi.
user253751
1

Saya sudah mencoba menulis API yang membungkus D3D dan OGL dengan rapi. Ini adalah usaha besar, saya pelajari. Banyak perbedaan mereka dapat direkonsiliasi. Misalnya, memuat shader. Saya secara efektif merangkum kode shader D3D dan OGL dalam format saya sendiri. IE: Di D3D, Anda perlu menentukan profil shader, sehingga file itu sendiri memiliki profil shader yang tertulis di dalamnya. Ketika sumber shader yang dienkapsulasi diserahkan ke API saya, ia menyebut metode pembuatan shader D3D yang sesuai dengan profil shader yang sesuai dan semacamnya.

Namun, masih ada banyak perbedaan yang belum saya pecahkan, dan mungkin juga tidak, karena saya telah memutuskan bahwa abstraksi tingkat yang lebih tinggi lebih mudah untuk dirancang dan memuaskan untuk kebutuhan saya. Saat ini saya sedang mengerjakan sesuatu yang mirip dengan kerangka D3DXEffect. Objek memiliki teknik render, yang berisi render pass, yang memiliki seperangkat status render, seperangkat shader, dan memerlukan input tertentu. Ini memungkinkan saya untuk abstrak lebih banyak dari API.

Sion Sheevok
sumber
1

Saya tidak tahu mengapa orang secara otomatis beralih ke generalisasi / optimisasi prematur ketika pertanyaan seperti ini muncul. Ada sesuatu yang bisa dikatakan tentang menjadi preemptive dan menyadari kapan komponen dalam suatu sistem kemungkinan akan ditukar. Semua jawaban tentang "jangan khawatir dan kode pergi sampai Anda perlu mengubahnya" umumnya membuat orang mendapat masalah di dunia nyata karena mereka membawa perubahan yang lebih besar di jalan, atau meninggalkan kode yang harus dirancang secara berbeda untuk mulai dengan, tetapi ditinggalkan karena "berfungsi". Melakukan pemikiran lebih dulu dan mengetahui di mana harus berhenti sebelum Anda berpikir berlebihan adalah keterampilan itu sendiri.

Akan jauh lebih mudah untuk memperbaiki antarmuka untuk mengakomodasi perbedaan antara DX / OGL, daripada memperkenalkan implementasi yang sama sekali baru (misalnya DX) ke dalam sistem yang dikodekan secara ketat untuk bekerja dengan OGL. Abstraksi kode harus terjadi pada tingkat tertentu karena Anda tidak ingin mencampur kode grafis dengan kode logika permainan di semua tempat, atau kode berulang. Jika saya mengerjakan sebuah game dan memulai dengan OpenGL (karena saya punya pengalaman dengannya), tetapi juga tahu bahwa saya ingin akhirnya mendapatkan game di Xbox / Windows (DX), itu akan konyol bagi saya untuk tidak mempertimbangkan hal itu saat merancang API grafik saya. Gagasan refactoring sesuatu yang kompleks seperti permainan, dan memperkenalkan API grafis baru adalah membosankan dan rentan kesalahan.

Anda harus mempertimbangkan bagaimana Anda akan menggunakan API Anda, dan membangunnya seiring dengan perubahan kebutuhan / pengetahuan Anda selama proses pengembangan game. Anda tidak melakukan abstraksi pada OGL / DX tingkat rendah, tetapi menciptakan API untuk diri Anda sendiri untuk membantu memuat geometri, memuat / mengkompilasi shader, memuat tekstur, dll.

nenchev
sumber