Básicamente, se encuentra con el tipo de situación que hace que NVIDIA Cg sea una pieza de software tan atractiva (aparte del hecho de que no es compatible con GL | ES, que usted dijo que estaba usando).
También tenga en cuenta que realmente no debe usar glGetAttribLocation. Esa función es mala juju desde los primeros días de GLSL antes de que la gente a cargo de GL realmente comenzara a entender cómo debería funcionar un buen lenguaje de sombreado. No está en desuso, ya que tiene un uso ocasional, pero en general, prefiere glBindAttibLocation o la extensión de ubicación de atributo explícita (núcleo en GL 3.3+).
Lidiar con las diferencias en los lenguajes de sombreado es, con mucho, la parte más difícil de portar software entre GL y D3D. Los problemas de API con los que se encuentra en relación con la definición de diseño de vértices también pueden considerarse como un problema de lenguaje de sombreador, ya que las versiones GLSL anteriores a la 3.30 no admiten la ubicación explícita de atributos (similar en espíritu a la semántica de atributos en HLSL) y las versiones GLSL anteriores 4.10 iirc no admite enlaces uniformes explícitos.
El "mejor" enfoque es tener una biblioteca de lenguaje de sombreado de alto nivel y un formato de datos que encapsule sus paquetes de sombreadores. NO alimente simplemente un montón de GLSL / HLSL sin procesar a una clase de Shader delgada y espere poder crear cualquier tipo de API sana.
En su lugar, coloca tus sombreadores en un archivo. Envuélvalos en un poco de metadatos. Podría usar XML y escribir paquetes de sombreadores como:
<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>
Escribir un analizador mínimo para eso es trivial (solo use TinyXML por ejemplo). Deje que su biblioteca de sombreadores cargue ese paquete, seleccione el perfil adecuado para su renderizador de destino actual y compile los sombreadores.
También tenga en cuenta que si lo prefiere, puede mantener la fuente externa a la definición del sombreador, pero aún tiene el archivo. Simplemente ponga nombres de archivo en lugar de fuente en los elementos fuente. Esto puede ser beneficioso si planea precompilar sombreadores, por ejemplo.
La parte difícil ahora, por supuesto, es lidiar con GLSL y sus deficiencias. El problema es que necesita vincular ubicaciones de atributos a algo similar a la semántica de HLSL. Esto se puede hacer definiendo esas semánticas en su API y luego usando glBindAttribLocation antes de vincular el perfil GLSL. El marco del paquete de sombreadores puede manejar esto explícitamente, sin ninguna necesidad de que su API de gráficos exponga los detalles.
Puede hacerlo extendiendo el formato XML anterior con algunos elementos nuevos en el perfil GLSL para especificar explícitamente las ubicaciones de los atributos, p. Ej.
<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>
El código del paquete de sombreador leería en todos los elementos de atributo en el XML, tomaría el nombre y la semántica de ellos, buscaría el índice de atributo predefinido para cada semántica y luego llamaría automáticamente glBindAttribLocation por usted al vincular el sombreador.
El resultado final es que su API ahora puede sentirse mucho mejor de lo que probablemente se haya visto su antiguo código GL, e incluso un poco más limpio de lo que D3D11 permitiría:
// 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));
También tenga en cuenta que no necesita estrictamente el formato del paquete de sombreado. Si desea simplificar las cosas, tiene la libertad de tener un tipo de función loadShader (const char * name) que toma automáticamente los archivos GLSL name.vs y name.fs en modo GL y los compila y los vincula. Sin embargo, absolutamente querrá los metadatos de ese atributo. En el caso simple, puede aumentar su código GLSL con comentarios especiales fáciles de analizar, como:
#version 150
/// ATTRIB(inPosition,POSITION)
in vec4 inPosition;
/// ATTRIB(inColor,COLOR0)
in vec4 inColor;
out vec4 vColor
void main() {
vColor = inColor;
gl_Position = inPosition;
}
Puede ser tan elegante como se sienta cómodo con el análisis de comentarios. Más de unos pocos motores profesionales llegarán a hacer extensiones de lenguaje menores que analizarán y modificarán, incluso, simplemente agregando directamente declaraciones semánticas de estilo HLSL. Si su conocimiento sobre el análisis es sólido, debería poder encontrar de manera confiable esas declaraciones extendidas, extraer la información adicional y luego reemplazar el texto con el código compatible con GLSL.
No importa cómo lo haga, la versión corta es aumentar su GLSL con la información semántica del atributo faltante y hacer que su abstracción del cargador de sombreadores se ocupe de llamar a glBindAttribLocation para arreglar las cosas y hacer que se parezcan más a las versiones modernas y eficientes de GLSL y HLSL.