Pada dasarnya Anda mengalami situasi yang membuat NVIDIA Cg menjadi perangkat lunak yang sangat menarik (selain fakta bahwa NVIDIA Cg tidak mendukung GL | ES, yang Anda katakan sedang Anda gunakan).
Perhatikan juga bahwa Anda seharusnya tidak menggunakan glGetAttribLocation. Fungsi itu adalah juju buruk dari hari-hari awal GLSL sebelum orang-orang yang bertanggung jawab atas GL benar-benar mulai memahami bagaimana bahasa shading yang baik harus bekerja. Ini tidak ditinggalkan karena memiliki penggunaan sesekali, tetapi secara umum, lebih suka glBindAttibLocation atau ekstensi lokasi atribut eksplisit (inti dalam GL 3.3+).
Menangani perbedaan dalam bahasa shader sejauh ini merupakan bagian tersulit dari perangkat lunak porting antara GL dan D3D. Masalah API yang Anda hadapi mengenai definisi tata letak simpul juga dapat dilihat sebagai masalah bahasa shader, karena versi GLSL sebelum 3.30 tidak mendukung lokasi atribut eksplisit (serupa dengan atribut semantik di HLSL) dan versi GLSL sebelum 4.10 iirc tidak mendukung binding seragam eksplisit.
Pendekatan "terbaik" adalah memiliki pustaka bahasa tingkat tinggi dan format data shading yang merangkum paket shader Anda. JANGAN hanya memberi makan sekelompok GLSL / HLSL mentah ke kelas Shader yang tipis dan berharap untuk dapat menghasilkan segala jenis API yang waras.
Sebaliknya, letakkan shader Anda ke dalam file. Bungkus mereka dalam sedikit meta-data. Anda bisa menggunakan XML, dan menulis paket shader seperti:
<shader name="bloom">
<profile type="glsl" version="1.30">
<source type="vertex"><![CDATA[
glsl vertex shader code goes here
]]></source>
<source type="fragment"><![CDATA[
glsl fragment shader code goes here
]]></source>
</profile>
<profile type="hlsl" version="sm3">
<source type="fx"><![CDATA[
hlsl effects code goes here
you could also split up the source elements for hlsl
]]></source>
</profile>
</shader>
Menulis parser minimal untuk itu sepele (cukup gunakan TinyXML misalnya). Biarkan pustaka shader Anda memuat paket itu, pilih profil yang sesuai untuk target renderer Anda saat ini, dan kompilasi shader.
Perhatikan juga bahwa jika Anda mau, Anda dapat menyimpan sumber di luar definisi shader, tetapi masih memiliki file. Masukkan saja nama file alih-alih sumber ke elemen sumber. Ini mungkin bermanfaat jika Anda berencana mengkompilasi shader, misalnya.
Bagian yang sulit sekarang tentu saja berurusan dengan GLSL dan kekurangannya. Masalahnya adalah Anda harus mengikat lokasi atribut ke sesuatu yang mirip dengan semantik HLSL. Ini dapat dilakukan dengan mendefinisikan semantik tersebut di API Anda dan kemudian menggunakan glBindAttribLocation sebelum menautkan profil GLSL. Kerangka paket shader Anda dapat menangani hal ini secara eksplisit, sama sekali tidak perlu API grafik Anda untuk mengekspos detailnya.
Anda dapat melakukannya dengan memperluas format XML di atas dengan beberapa elemen baru di profil GLSL untuk secara eksplisit menentukan lokasi atribut, misalnya
<shader name="bloom">
<profile type="glsl" version="1.30">
<attrib name="inPosition" semantic="POSITION"/>
<attrib name="inColor" semantic="COLOR0"/>
<source type="vertex"><![CDATA[
#version 150
in vec4 inPosition;
in vec4 inColor;
out vec4 vColor;
void main() {
vColor = inColor;
gl_Position = position;
}
]]></source>
</profile>
</shader>
Kode paket shader Anda akan membaca semua elemen attrib di XML, ambil nama dan semantik darinya, cari indeks atribut yang telah ditentukan untuk setiap semantik, dan kemudian secara otomatis panggil glBindAttribLocation untuk Anda saat menautkan shader.
Hasil akhirnya adalah bahwa API Anda sekarang dapat terasa jauh lebih baik daripada kode GL lama Anda yang mungkin pernah terlihat, dan bahkan sedikit lebih bersih daripada D3D11 akan memungkinkan:
// simple example, easily improved
VertexLayout layout = api->createLayout();
layout.bind(gfx::POSITION, buffer0, gfx::FLOATx4, sizeof(Vertex), offsetof(Vertex, position));
layout.bind(gfx::COLOR0, buffer0, gfx::UBYTEx4, sizeof(Vertex), offsetof(Vertex, color));
Perhatikan juga bahwa Anda tidak benar - benar membutuhkan format paket shader. Jika Anda ingin menjaga hal-hal sederhana, Anda bebas hanya memiliki jenis fungsi loadShader (const char * name) yang secara otomatis mengambil nama.vs dan name.fs file GLSL dalam mode GL dan mengkompilasi dan menautkannya. Namun, Anda benar-benar menginginkan metadata atribut itu. Dalam kasus sederhana, Anda dapat menambah kode GLSL Anda dengan komentar khusus yang mudah diurai, seperti:
#version 150
/// ATTRIB(inPosition,POSITION)
in vec4 inPosition;
/// ATTRIB(inColor,COLOR0)
in vec4 inColor;
out vec4 vColor
void main() {
vColor = inColor;
gl_Position = inPosition;
}
Anda bisa menjadi semewah yang Anda inginkan dengan menguraikan komentar. Lebih dari beberapa mesin profesional akan melangkah lebih jauh untuk membuat ekstensi bahasa kecil yang mereka parsing dan modifikasi, bahkan, seperti hanya menambahkan deklarasi semantik gaya HLSL secara langsung. Jika pengetahuan Anda tentang parsing kuat, Anda harus dapat menemukan deklarasi yang diperluas itu, mengekstrak informasi tambahan, dan kemudian mengganti teks dengan kode yang kompatibel dengan GLSL.
Tidak peduli bagaimana Anda melakukannya, versi singkatnya adalah untuk menambah GLSL Anda dengan informasi semantik atribut yang hilang dan meminta abstraksi loader shader Anda dengan memanggil glBindAttribLocation untuk memperbaiki keadaan dan menjadikannya lebih seperti versi GLSL modern dan HLSL yang mudah dan efisien.