2013-09-05 2 views
5

Ich verwende OpenGL ES 2.0 auf Android, aber ich nehme an, dass diese Frage eine allgemeine OpenGL-Frage ist.Was ist der Gültigkeitsbereich von glVertexAttribPointer und glEnableVertexAttribArray?

Ich lerne OpenGL und versuche zu verstehen, genau welche APIs für jeden Rahmen aufgerufen werden müssen, im Gegensatz zu nur einmal. Ich rief zunächst glVertexAttribPointer und glEnableVertexAttribArray jeden Rahmen, aber wenn ich mein Testprogramm änderte, um sie nur einmal für jedes Shader-Programm aufzurufen, bekomme ich Verhalten, das nicht das ist, was ich erwarte.

Es scheint so, als ob glVertexAttribPointer und glEnableVertexAttribArray nur einmal aufgerufen werden sollten und nicht jedes Frame, weil sie nur im Rahmen eines bestimmten Shader-Programms sinnvoll sind. Ich sage dies, weil glVertexAttribPointer als ersten Parameter GLuint index übernimmt, die von glGetAttribLocation zurückgegeben wurde, die eine Zeichenfolge angibt, die einem Variablennamen im Shader-Programm entspricht. So scheint es, als wären die Daten an eine bestimmte "Attribut" -Variable in einem bestimmten Shader-Programm gebunden.

Mein Testprogramm zwei disjunkte Formen (Dreiecke) macht, mit zwei völlig verschiedenen Programmen - verschiedene Fragment-Shader Quelle, verschiedene Vertex-Shader-Quelle, getrennte Anrufe zu glLinkProgram etc. Ich zunächst den folgenden Code für jeden Frame lief, und alles funktioniert wie erwartet - ich sehe beide Formen korrekt gerendert.

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

// Shape/Program 1   
m_glhook.glUseProgram(m_iGlProgramId); 
int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position"); 
m_bfVertices.rewind(); 
m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices); 
m_glhook.glEnableVertexAttribArray(iPositionLocation);  
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

// Shape/Program 2 
m_glhook.glUseProgram(m_iGlProgramId2); 
int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position"); 
m_bfVertices2.rewind(); 
m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2); 
m_glhook.glEnableVertexAttribArray(iPositionLocation2); 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

Dann modifizierte ich die Anrufe für jeden Rahmen wie unten gezeigt. m_bFirstDraw gilt für den ersten Frame und falsch für aufeinanderfolgende Frames.

m_glhook.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); 

// Shape/Program 1   
m_glhook.glUseProgram(m_iGlProgramId); 
if (m_bFirstDraw) 
{ 
    int iPositionLocation = m_glhook.glGetAttribLocation(m_iGlProgramId, "a_Position"); 
    m_bfVertices.rewind(); 
    m_glhook.glVertexAttribPointer(iPositionLocation, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices); 
    m_glhook.glEnableVertexAttribArray(iPositionLocation); 
} 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 

// Shape/Program 2 
m_glhook.glUseProgram(m_iGlProgramId2); 
if (m_bFirstDraw) 
{   
    int iPositionLocation2 = m_glhook.glGetAttribLocation(m_iGlProgramId2, "a_Position"); 
    m_bfVertices2.rewind(); 
    m_glhook.glVertexAttribPointer(iPositionLocation2, 4, GLES20.GL_FLOAT, false, STRIDE, m_bfVertices2); 
    m_glhook.glEnableVertexAttribArray(iPositionLocation2); 
} 
gl.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3); 
m_bFirstDraw = false; 

Das Verhalten, das ich mit dem obigen Code zu sehen ist, dass für das erste Frame noch alles in Ordnung ist (was Sinn macht, da für den ersten Frame der Aufrufsequenzen sind genau die gleiche). Aber für aufeinanderfolgende Frames wird Shape1 mit Shape2-Scheitelpunkten gezeichnet. So sehe ich nur Shape2, da es genau auf Shape1 gezeichnet wird.

Bitte helfen Sie mir, dies zu verstehen ... Warum wirkt sich das Einstellen der Daten (Formscheitelpunkte) für ein Programm auf die Daten aus, die von einem anderen Programm in einem nachfolgenden Frame verwendet werden? Ich vermisse etwas ...

Antwort

6

Obwohl GLSL-Programme (insbesondere Vertex-Shader) Vertex-Attribute basierend auf generischen Slot-Nummern verwenden, liefern Sie das GLSL-Programm nicht mit den Vertex-Zeigern.

Diese Zeiger sind Teil des Vertex Array-Status, der in neueren Versionen von OpenGL vollständig von Vertex Array Objects behandelt wird. Wenn Sie möchten, dass jedes Programm über eigene Zeiger verfügt, würde ich vorschlagen, dass Sie einen VAO erstellen, der den Status speichert und den VAO bindet, wenn Sie Ihr Programm binden.

Wenn VAOs nicht verfügbar sind, müssen Sie Ihre Zeiger beim Wechseln der GLSL-Programme von Hand einrichten. Beachten Sie, dass in diesem Fall ein globaler Kontext vorhanden ist, in dem die Vertexarrayzeiger, gebundenen Vertexpuffer, aktivierten/deaktivierten Arrays usw. gespeichert werden. Sie müssen also vorsichtig sein, um Vertex-Attributzeichen zu deaktivieren, die Sie nicht verwenden, oder Sie können den GL aus dem ungültigen Speicher lesen.

VAOs sind eine viel elegantere Lösung, die Sie bevorzugen sollten, wenn sie verfügbar sind.

+0

Vielen Dank für die Antwort Andon. Wenn man sich die Spezifikation ansieht, sind VAOs in OpenGL ES 2.0 nicht verfügbar, so dass ich sie nicht verwenden kann. Nur zur Bestätigung, ohne VAOs ist es notwendig, 'glVertexAttribPointer' und' glEnableVertexAttribArray' jedes Mal aufzurufen, wenn ich Programme wechsle.Wenn ich mehrere Programme habe, die mit jedem Frame laufen (in der gleichen Reihenfolge), bedeutet das effektiv, dass ich diese Funktionen für jedes Programm aufrufen muss, für jeden Frame. Ist das korrekt? –

+0

@DavidStone: Nicht unbedingt, Sie müssen dies nur tun, wenn Sie mit einem anderen Vertex-Puffer zeichnen möchten oder wenn Sie die Attribuzeiger auf verschiedene Positionen mappen müssen, um den Shader mit den richtigen Daten an der richtigen Bindungsstelle zu versorgen . –

+0

OK ich denke ich verstehe jetzt. Meine zwei Shader müssen auf verschiedenen Scheitelpunkten arbeiten und beide werden in jedem Frame in der gleichen Reihenfolge ausgeführt. In diesem Fall ist es notwendig, 'glVertexAttribPointer' ** zweimal ** für jeden Frame aufzurufen. Aus irgendeinem Grund, wenn ich 'glGetAttribLocation' aufrufen und OpenGL den Vertex-Attributindex für mich wählen lasse, wählt er immer 0, also verwende ich den gleichen Index für beide Eckpunktattribute. Allerdings habe ich festgestellt, dass 'glBindAttribLocation' ** ** in OpenGL ES 2.0 verfügbar ist und ich verschiedene Indizes für die beiden Programme angeben kann, um dieses Problem zu vermeiden. –

Verwandte Themen