Ada banyak pendekatan, tetapi tidak ada yang sempurna.
Dimungkinkan untuk berbagi kode dengan menggunakan glAttachShader
untuk menggabungkan shader, tetapi ini tidak memungkinkan untuk membagikan hal-hal seperti deklarasi struct atau #define
konstanta -d. Itu berfungsi untuk fungsi berbagi.
Beberapa orang suka menggunakan array string yang diteruskan glShaderSource
sebagai cara untuk menambahkan definisi umum sebelum kode Anda, tetapi ini memiliki beberapa kelemahan:
- Lebih sulit untuk mengontrol apa yang perlu dimasukkan dari dalam shader (Anda memerlukan sistem terpisah untuk ini.)
- Ini berarti pembuat shader tidak dapat menentukan GLSL
#version
, karena pernyataan berikut dalam spesifikasi GLSL:
The # versi direktif harus terjadi dalam shader sebelum hal lain, kecuali untuk komentar dan ruang putih.
Karena pernyataan ini, glShaderSource
tidak dapat digunakan untuk menambahkan teks sebelum #version
deklarasi. Ini berarti bahwa #version
baris tersebut perlu dimasukkan dalam glShaderSource
argumen Anda , yang berarti bahwa antarmuka kompiler GLSL Anda perlu entah bagaimana diberitahu versi GLSL apa yang diharapkan akan digunakan. Selain itu, tidak menentukan #version
akan membuat kompiler GLSL default untuk menggunakan GLSL versi 1.10. Jika Anda ingin membiarkan penulis shader menentukan #version
skrip dalam cara standar, maka Anda harus memasukkan #include
-s setelah #version
pernyataan tersebut. Ini bisa dilakukan dengan menguraikan GLSL shader secara eksplisit untuk menemukan #version
string (jika ada) dan membuat inklusi Anda setelahnya, tetapi memiliki akses ke#include
arahan mungkin lebih disukai untuk dikontrol dengan lebih mudah ketika inklusi tersebut perlu dibuat. Di sisi lain, karena GLSL mengabaikan komentar sebelum #version
baris, Anda dapat menambahkan metadata untuk memasukkan dalam komentar di bagian atas file Anda (yuck.)
Pertanyaannya sekarang adalah: Apakah ada solusi standar untuk #include
, atau Anda perlu menggulung ekstensi preprosesor Anda sendiri?
Ada GL_ARB_shading_language_include
ekstensi, tetapi memiliki beberapa kelemahan:
- Ini hanya didukung oleh NVIDIA ( http://delphigl.de/glcapsviewer/listreports2.php?listreportsbyextension=GL_ARB_shading_language_include )
- Ini bekerja dengan menentukan string termasuk sebelumnya. Oleh karena itu, sebelum kompilasi, Anda perlu menentukan bahwa string
"/buffers.glsl"
(seperti yang digunakan dalam #include "/buffers.glsl"
) sesuai dengan isi file buffer.glsl
(yang telah Anda muat sebelumnya).
- Seperti yang mungkin Anda perhatikan pada poin (2), jalur Anda harus memulainya
"/"
, seperti jalur absolut gaya Linux. Notasi ini umumnya tidak dikenal oleh programmer C, dan berarti Anda tidak dapat menentukan jalur relatif.
Desain umum adalah untuk mengimplementasikan #include
mekanisme Anda sendiri , tetapi ini bisa rumit karena Anda juga perlu mem-parsing (dan mengevaluasi) instruksi preprosesor lain seperti #if
untuk menangani dengan benar kompilasi bersyarat (seperti pelindung kepala.)
Jika Anda menerapkan sendiri #include
, Anda juga memiliki beberapa kebebasan dalam cara Anda ingin menerapkannya:
- Anda dapat melewati string sebelumnya (seperti
GL_ARB_shading_language_include
).
- Anda bisa menentukan callback include (ini dilakukan oleh perpustakaan D3DCompiler DirectX.)
- Anda bisa mengimplementasikan sistem yang selalu membaca langsung dari sistem file, seperti yang dilakukan pada aplikasi C yang khas.
Sebagai penyederhanaan, Anda dapat secara otomatis memasukkan pelindung tajuk untuk masing-masing termasuk dalam lapisan preprocessing Anda, sehingga lapisan prosesor Anda terlihat seperti:
if (#include and not_included_yet) include_file();
(Penghargaan untuk Trent Reed karena menunjukkan saya teknik di atas)
Kesimpulannya , tidak ada solusi otomatis, standar, dan sederhana. Dalam solusi masa depan, Anda bisa menggunakan beberapa antarmuka OpenGL SPIR-V, dalam hal ini kompiler GLSL ke SPIR-V bisa berada di luar API GL. Memiliki kompiler di luar runtime OpenGL sangat menyederhanakan menerapkan hal-hal seperti #include
karena ini adalah tempat yang lebih tepat untuk berinteraksi dengan sistem file. Saya percaya metode luas saat ini adalah dengan hanya mengimplementasikan preprocessor kustom yang bekerja dengan cara yang harus akrab dengan programmer C.