Explizite oder automatische Attributspeicherortbindung für OpenGL-Shader

82

Beim Einrichten von Attributpositionen für ein OpenGL-Shader-Programm stehen Ihnen zwei Optionen zur Verfügung:

glBindAttribLocation () vor dem Verknüpfen, um einen Attributspeicherort explizit zu definieren.

oder

glGetAttribLocation () nach dem Verknüpfen, um einen automatisch zugewiesenen Attributspeicherort zu erhalten.

Was ist das Dienstprogramm für die Verwendung übereinander?

Und welches, wenn überhaupt, wird in der Praxis bevorzugt?

Jing
quelle
6
Ich habe mich nicht darum gekümmert, glBindAttribLocationmeine Grafik-Engine zu verwenden, die unter Linux gut funktioniert hat. Als ich auf Windows portierte, verwendete es meine Normalen als Eckpunkte - ich musste ihm explizit die Reihenfolge der Variablen in meinem Shader mitteilen glBindAttribLocation, damit es funktioniert ...
Jarrett

Antworten:

93

Ich kenne einen guten Grund, eine explizite Standortdefinition zu bevorzugen .

Beachten Sie, dass Sie Ihre Geometriedaten in Vertex-Array-Objekten speichern . Für ein bestimmtes Objekt erstellen Sie eine VAO so, dass die Indizes beispielsweise Folgendes entsprechen:

  • Index 0 : Positionen,
  • Index 1 : Normalen,
  • Index 2 : Texcoords

Stellen Sie sich nun vor, Sie möchten ein Objekt mit zwei verschiedenen Shadern zeichnen . Ein Shader benötigt Positions- und Normaldaten als Eingabe, der andere - Positionen und Texturkoordinaten .

Wenn Sie diese Shader kompilieren, werden Sie feststellen, dass der erste Shader die Positionen bei Attributindex 0 und Normalen bei 1 erwartet. Der andere erwartet Positionen bei 0, aber Texturkoordinaten bei 1.

Zitieren von https://www.opengl.org/wiki/Vertex_Shader :

Automatische Zuordnung

Wenn keine der beiden vorherigen Methoden einem Attributindex eine Eingabe zuweist, wird der Index automatisch von OpenGL zugewiesen, wenn das Programm verknüpft wird. Der zugewiesene Index ist völlig willkürlich und kann für verschiedene verknüpfte Programme unterschiedlich sein, selbst wenn sie genau denselben Vertex-Shader-Code verwenden.

Dies bedeutet, dass Sie Ihr VAO nicht mit beiden Shadern verwenden können. Anstatt beispielsweise eine VAO pro Objekt zu haben, benötigen Sie im schlimmsten Fall eine separate VAO pro Objekt und Shader .

Wenn Sie die Shader dazu zwingen, Ihre eigene Attributnummerierungskonvention zu verwenden, glBindAttribLocationkann dieses Problem leicht gelöst werden. Sie müssen lediglich eine konsistente Beziehung zwischen Attributen und ihren etablierten IDs beibehalten und die Shader zwingen, diese Konvention beim Verknüpfen zu verwenden.

(Das ist kein großes Problem, wenn Sie keine separaten VAOs verwenden, aber Ihren Code möglicherweise klarer machen.)


Übrigens:

Beim Einrichten von Attributpositionen für ein OpenGL-Shader-Programm stehen Ihnen zwei Optionen zur Verfügung

In OpenGL / GLSL 3.3 gibt es eine dritte Option: Geben Sie den Speicherort direkt im Shader-Code an . Es sieht aus wie das:

layout(location=0) in vec4 position;

Dies ist jedoch in der GLSL ES-Shader-Sprache nicht vorhanden.

Kos
quelle
1
Ich verstehe den Punkt nicht. VAO sind sehr leicht und werden normalerweise für jeden Frame neu erstellt. In Ihrem Fall würden Sie einfach verschiedene VAOs erstellen, bevor Sie jeden Shader aufrufen, nicht wahr?
PierreBdR
1
Ja, das kannst du natürlich. Es wird genauso gut funktionieren, wir diskutieren hier nur Konventionen. :)
Kos
4
Die dritte Option ist tatsächlich in GLES2.0 verfügbar, das Format unterscheidet sich jedoch geringfügig: layout (location = 0) attribute vec4 position; Beachten Sie, dass Sie dies auch oben in Ihrer GLSL-Datei benötigen: #extension GL_EXT_separate_shader_objects: enable
Gavin Maclean
35
"VAO sind wirklich leicht und werden normalerweise für jeden Frame neu erstellt. In Ihrem Fall würden Sie einfach verschiedene VAOs erstellen, bevor Sie jeden Shader aufrufen, nicht wahr?" - Nein, das tun Sie normalerweise nicht, da dies letztendlich den gesamten Zweck von VAOs völlig ungültig macht. Warum dann überhaupt eine VAO verwenden?
Christian Rau
2
Nur eine Notiz. Sie würden Ihre Geometriedaten nicht in einem VAO speichern. Das wäre in einem VBO. VAOs haben keinen Datenspeicher.
Durchschnitt Joe
20

Eine andere Antwort hier ist, dass glGetAttribLocation Daten an den Aufrufer zurückgibt, was bedeutet, dass implizit ein Pipeline-Flush erforderlich ist. Wenn Sie es direkt nach dem Kompilieren Ihres Programms aufrufen, erzwingen Sie im Wesentlichen die synchrone Kompilierung.

Litherum
quelle
Danke, das ist eine sehr wichtige Überlegung.
Jing
1
Nach meinem Verständnis müssten Sie in den meisten Situationen glGetUniformLocationsowieso anrufen . Ist diese besondere Überlegung noch relevant?
Mike Weir
@MikeWeir Seit GL 4.3 können Sie eine explizite einheitliche Position festlegen .
Ruslan
1
@ Ruslan Sie verwenden OpenGL ES.
Mike Weir
9

Die dritte Option, dh layout(location=0) in vec4 position;im Shader-Code, ist jetzt in OpenGL ES 3.0 / GLSL 300 es verfügbar. Nur für Vertex-Shader-Eingabevariablen.

Fahrbahn
quelle
7
Wie sie andeuten, unterstützen Intel-Karten dies möglicherweise nicht (obwohl sie ansonsten perfekt 3.0+ -konform sind, wie ich es verstehe), was ekelhaft ist :)
mlvljr