Enlace de ubicación de atributo explícito vs automático para sombreadores OpenGL

82

Al configurar ubicaciones de atributos para un programa de sombreado OpenGL, se enfrenta a dos opciones:

glBindAttribLocation () antes de vincular para definir explícitamente la ubicación de un atributo.

o

glGetAttribLocation () después de vincular para obtener una ubicación de atributo asignada automáticamente.

¿Cuál es la utilidad de usar uno sobre el otro?

¿Y cuál, si corresponde, se prefiere en la práctica?

Jing
fuente
6
No me molesté glBindAttribLocationen usarlo en mi motor gráfico, que funcionaba muy bien en Linux. Cuando porté a Windows, estaba usando mis normales como vértices; tuve que decirle explícitamente el orden de las variables en mi sombreador a través glBindAttribLocationpara que funcionara ...
Jarrett

Respuestas:

93

Conozco una buena razón para preferir una definición de ubicación explícita .

Considere que mantiene sus datos de geometría en Vertex Array Objects. Para un objeto dado, crea un VAO de tal manera que los índices correspondan, por ejemplo:

  • índice 0 : posiciones,
  • índice 1 : normales,
  • índice 2 : texcoords

Ahora considere que desea dibujar un objeto con dos sombreadores diferentes . Un sombreador requiere posición y datos normales como entrada, el otro - posiciones y coordenadas de textura .

Si compila esos sombreadores, notará que el primer sombreador esperará las posiciones en el índice de atributo 0 y las normales en 1. El otro esperaría posiciones en 0 pero las coordenadas de textura en 1.

Citando https://www.opengl.org/wiki/Vertex_Shader :

Asignación automática

Si ninguno de los dos métodos anteriores asigna una entrada a un índice de atributo, OpenGL asigna automáticamente el índice cuando se vincula el programa. El índice asignado es completamente arbitrario y puede ser diferente para los diferentes programas que están vinculados, incluso si usan exactamente el mismo código de sombreado de vértices.

Esto significa que no podrá utilizar su VAO con ambos sombreadores. En lugar de tener un VAO por, digamos, objeto, necesitaría, en el peor de los casos, un VAO separado por objeto por sombreador .

Forzar a los sombreadores a usar su propia convención de numeración de atributos a través de glBindAttribLocationpuede resolver este problema fácilmente; todo lo que necesita hacer es mantener una relación consistente entre los atributos y sus ID establecidos, y forzar a los sombreadores a usar esa convención al vincular.

(Eso no es realmente un gran problema si no usa VAO separados, pero aún así puede aclarar su código).


Por cierto:

Al configurar ubicaciones de atributos para un programa de sombreado OpenGL, se enfrenta a dos opciones

Hay una tercera opción en OpenGL / GLSL 3.3: Especifique la ubicación directamente en el código de sombreado . Se parece a esto:

layout(location=0) in vec4 position;

Pero esto no está presente en el lenguaje de sombreado GLSL ES.

Kos
fuente
1
No veo el punto. Los VAO son realmente livianos y, por lo general, los recreará para cada cuadro. En su caso, simplemente crearía diferentes VAO antes de llamar a cada sombreador, ¿no es así?
PierreBdR
1
Sí, puedes hacerlo, por supuesto. Funcionará igual de bien, solo estamos discutiendo convenciones aquí. :)
Kos
4
La tercera opción está disponible en GLES2.0 pero el formato es ligeramente diferente: diseño (ubicación = 0) atributo vec4 posición; Tenga en cuenta que también necesitará esto en la parte superior de su archivo GLSL: #extension GL_EXT_separate_shader_objects: enable
Gavin Maclean
35
"Los VAO son realmente livianos y normalmente los recreará para cada cuadro. En su caso, simplemente crearía diferentes VAO antes de llamar a cada sombreador, ¿no es así?" - No, normalmente no hará esto, ya que al final invalida por completo el propósito de los VAO. Entonces, ¿por qué utilizar un VAO?
Christian Rau
2
Solo una nota. No mantendría sus datos de geometría en un VAO. Eso estaría en una VBO. Los VAO no tienen almacenamiento de datos.
Joe promedio
20

Otra respuesta aquí es que glGetAttribLocation devuelve datos a la persona que llama, lo que significa que implícitamente requiere un flujo de canalización. Si lo llama justo después de compilar su programa, esencialmente está forzando la compilación asincrónica a que se produzca de forma sincrónica.

Litherum
fuente
Gracias, esta es una consideración muy importante.
Jing
1
Tengo entendido que en la mayoría de las situaciones tendría que llamar de glGetUniformLocationtodos modos; ¿Sigue siendo relevante esta consideración en particular?
Mike Weir
@MikeWeir desde GL 4.3 puede establecer una ubicación uniforme explícita .
Ruslan
1
@Ruslan Están usando OpenGL ES.
Mike Weir
9

La tercera opción, es decir, layout(location=0) in vec4 position;en el código de sombreado, ahora está disponible en OpenGL ES 3.0 / GLSL 300 es. Sin embargo, solo para las variables de entrada del sombreador de vértices.

carril
fuente
7
Como sugieren, es posible que las tarjetas Intel no admitan esto (aunque de lo contrario son perfectamente compatibles con 3.0+, según lo entiendo), lo cual es asqueroso :)
mlvljr