2016-10-24 9 views
0

Ich versuche etwas völlig Einfaches zu tun und werde unglaublich frustriert. Ich habe einen trivialen Vertex-Shader aufgebaut, da anscheinend man einen braucht OpenGL zu bekommen etwas heute oder die gefürchteten deprecation Götter dich an oder etwas Stirnrunzeln zu tun:Wie sage ich OpenGL, um eine Shaderuniform sofort zu aktualisieren?

#version 110 

uniform mat4 scene_matrix; 
attribute vec4 a_position; 

void main() 
{ 
    gl_Position = scene_matrix * a_position; 
} 

Wunderbar. Nachdem ich 10 Stunden lang herumgespuckt habe, um eine geeignete Matrix zu erstellen, gebe ich sie mit glUniformMatrix4 in den Shader und es funktioniert prächtig. Das heißt, bis ich mehr als eine Sache wiedergeben möchte.

Also mein Ziel ist: Für jedes Objekt in der Szene berechne ich die entsprechende Welt-Matrix basierend auf den Koordinaten des Objekts, rufen Sie , um den Vertex-Shader über die Matrix, rufen Sie glBegin(), dann zeichnen Sie das dumme Objekt, und rufen Sie glEnd(). Unglücklicherweise ist es pathetisch, alle Objekte an demselben dummen Ort (dem Ort des letzten Objekts) zu zeichnen. Offensichtlich puffert er Dinge und puffert den Vertex-Shader nicht bis zum Ende, wenn er alles über die vorherigen Matrizen vergessen hat. Aber wie sage ich es, das nicht zu tun?

FloatBuffer matrixBuf = ByteBuffer.allocateDirect(16 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
for (int i = 0; i < 500; i++) { 
    matrixBuf.rewind(); 
    matrices.world.translate(0.1, 0.1, 0.5); 
    matrices.calc(); 
    matrices.combined.put(matrixBuf); 
    matrixBuf.rewind(); 
    glUniformMatrix4(glGetUniformLocation(programId, "scene_matrix"), false, matrixBuf); 

    glBegin(GL_TRIANGLES); 
    { 
     //final int T = 1; 
     final float z = 0f; 
     final float R = 0.5f; 
     //glVertexAttrib2f(T, 0, 1); 
     glVertex3f(-R, -R, z); 

     //glVertexAttrib2f(T, 1, 0); 
     glVertex3f(R, R, z); 

     //glVertexAttrib2f(T, 0, 0); 
     glVertex3f(-R, R, z); 

     /*//glVertexAttrib2f(T, 0, 1); 
     glVertex3f(-R, -R, z); 

     //glVertexAttrib2f(T, 1, 1); 
     glVertex3f(R, -R, z); 

     //glVertexAttrib2f(T, 1, 0); 
     glVertex3f(R, R, z);*/ 
    } 
    glEnd(); 

    //glFlush(); // without this, all the triangles are in the same place 
} 

Ich entdeckte, dass glFlush() nach jedem glEnd() löst das Problem nennen. Dies verursacht jedoch ein Leistungsproblem. Ich zeichne nur 500 Objekte (jedes ein einziges bemitleidenswertes Dreieck) und es reicht bereits die CPU aus und es kommt Kondensatorweinerl aus dem Computer. Es fühlt sich falsch an. Ich bin sicher, glFlush() muss übertrieben sein.

Ich fand, dass das Programm erneut mit glLinkProgram(programId); nach jeder kann auch das Problem lösen, aber es ist eine Größenordnung langsamer noch.

Ich habe überall gesucht. Ich möchte nur wissen, was der Name der Funktion, die verwendet wird, um zu sagen, es zu bekommen und den Vertex-Shader jetzt ausführen, so dass ich die Uniformen für das nächste Objekt neu konfigurieren kann.

Oder ist das nicht, was ich tun soll? Soll ich die Vertexpipeline aufgeben, alle Matrixtransformationen von Vertices auf der Java-Seite durchführen und bereits transformierte Vertices einlesen? Sollte ich mich dem depreyation devil hingeben und den legalen OpenGL-Matrix-Stack verwenden, um zu sehen, ob das kooperativer ist? Jede Hilfe wird geschätzt.

+2

Neue einheitliche Werte für die nächste Ziehung Aufruf verwendet werden, nichts, was Sie über es zu tun. Dies sieht wie ein Fehler in der OpenGL-Implementierung aus. –

+0

@RetoKoradi: Ist es sogar erforderlich, die programmierbaren API-Aufrufe mit der Fixed-Funktion zu synchronisieren? – ybungalobill

+0

@RetoKoradi Wenn das stimmt, würde ich es als eine Antwort akzeptieren. Das ist es, was ich frage, und ich konnte es in der Dokumentation nicht finden. – Boann

Antwort

4

Der erste große Fehler, den Sie tun, ist, dass Sie glBegin/glEnd verwenden. Dies wurde zusammen mit der festen Funktionspipeline veraltet.

Leider sehen Sie, dass die Objekte alle an der gleichen Stelle gezeichnet sind: Weil Ihre Transformationsmatrix unter der Schleifenvariablen invariant ist, dh die Iteration der Schleife hat keinen Einfluss auf den Wert Ihrer Transformationsmatrix: Dieser Block hier :

matrixBuf.rewind(); 
matrices.world.translate(0.1, 0.1, 0.5); 
matrices.calc(); 
matrices.combined.put(matrixBuf); 
matrixBuf.rewind(); 

irgendwie auf i abhängen müssen würde, odermatrices.combined würde mit der Übersetzung tatsächlich kombiniert werden, aber der methiod Name .put macht deutlich, dass es einfach ersetzt wird.

+0

Entschuldigung dafür, dass ich nicht klar bin: Die 'translate' Methode meiner Matrixstack-Sache verkettet sich mit der bestehenden Matrix, so dass sie jedes Objekt fortschreitend bewegt und die' put' Methode den aktuellen Zustand in einen Puffer zur Übergabe an die OpenGL setzt Methode. Es ist nicht schön, aber es ist nicht das Problem. Es funktioniert perfekt mit 'glFlush();' da drin. – Boann

+0

Und ich weiß, dass die feste Funktionspipeline veraltet ist, aber es ist absolut anstrengend zu versuchen, auf all das zu kommen. OpenGL scheint so viele einfach zu benutzende, aber veraltete Methoden zu haben, und ich verstehe, dass die neueren APIs flexibler sind, aber ich möchte nur * etwas * zum Laufen bringen. Ich möchte nur, dass die Uniform-Variable korrekt aktualisiert wird. – Boann

+0

@Boann: Das Problem ist, dass diese lästige kleine '.put' Methode wahrscheinlich überschreibt, was auch immer in Ihrer Matrix war. Sie verwenden offensichtlich Java und einige Java-verwandte Bibliotheken, die ich nicht so gut kenne.Aber ".put" ist normalerweise für Daten ersetzende Operationen reserviert. Der richtige Weg, Matrixoperationen zu "verketten", besteht darin, eine Kette von Multiplikationen durchzuführen. – datenwolf

1

Viele Statusänderungen erfordern das Binden von Objekten, bevor sie für die Renderingpipeline sichtbar sind.

Für Shader Bindung würde bedeuten glUseProgram. Ich kann mich nicht erinnern, was Spec über Uniformen sagt und den Shader wiederverwendet.

Die Verwendung von glDrawArrays ist einfach. Sie müssen nur Vertex-Daten in einem Array einrichten. Aktivieren und setzen Sie glVertexAttribPointer. In einfachen Fallbeispielen müssen Sie nicht einmal Pufferobjekte verwenden. Sie können glEnableVertexAttribArray als glBegin betrachten. Dann werden die Daten als Aufrufe von glVertex *() an das Vertex-Array übergeben. glVertexAttribPointer und glDraw *() können als glEnd hart sein.

Optimierungen gegenüber einfachen DrawArrays bestehen darin, Indizes mit DrawElements zu verwenden, um doppelte Scheitelpunkte in Daten zu vermeiden. Dann macht das Setzen von Scheitelpunkten und Indizes auf Pufferobjekte alles schnell.

Bonus: Dieser Fall sieht ein bisschen so aus, als könnten Sie Matrix überspringen, um Ihre Uniformen nur zum Übersetzungsvektor zu vereinfachen.

0

So lautet die Antwort nach den Kommentaren: gibt es keinen solchen Funktionsaufruf; das soll natürlich funktionieren.

Dann warum nicht? Gott weiss. Könnte ein Buggy Fahrer sein, könnte ich ein Dummkopf sein, könnte beides sein. In jedem Fall verschwindet das Problem sofort und vollständig, wenn ich glDrawArrays oder glDrawElements anstelle von Festnetz-Funktionsaufrufen wie glVertex3 verwenden. (Ja, das ist definitiv die einzige Sache, die ich auswechsle, um zwischen Arbeit und Nicht-Arbeit zu wechseln.) Keine schöne Erfahrung für jemanden, der versucht hatte, am flachen Ende der Dinge zu beginnen, bevor er unter dem vollen Gewicht all der schlechten ertrank. Dokumentierte - sofern Sie nicht bereits wissen, was sie tun sollen - auf einmal.

fand ich diese schöne Stack-Überlauf-Post, die nur zum Teufel dieser Vertex-Spezifikation Funktionen tun was fasst zusammen: https://stackoverflow.com/a/8705304

Für die Zukunft ist hier die Zeichnung Code, der funktioniert:

Ein Vertex-Shader:

#version 110 

uniform mat4 scene_matrix; 
attribute vec4 a_position; 
attribute vec2 a_texcoord; 
varying vec2 v_texcoord; 

void main() 
{ 
    gl_Position = scene_matrix * a_position; 

    // pass texture coordinates on to fragment shader 
    v_texcoord = a_texcoord; 
} 

Ein Fragment-Shader:

#version 110 

uniform sampler2D texture; 
varying vec2 v_texcoord; 

void main() 
{ 
    gl_FragColor = texture2D(texture, v_texcoord); 
    //gl_FragColor = vec4(1, 0, 0, 1); 
} 

-Code, der eine THING zieht:

// Define a shape (a square) 
// First 3 numbers on each line are vertex coords, next 2 are corresponding tex coords 
final float R = 0.5f; 
float[] vertices = { 
    -R, -R, 0, 0, 1, 
    +R, +R, 0, 1, 0, 
    -R, +R, 0, 0, 0, 
    -R, -R, 0, 0, 1, 
    +R, -R, 0, 1, 1, 
    +R, +R, 0, 1, 0, 
}; 

// Create and bind a buffer object 
int bufferId = glGenBuffers(); 
glBindBuffer(GL_ARRAY_BUFFER, bufferId); 

// Just Java fluff: local buffer used for transferring data to the native method 
FloatBuffer vertices1 = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); 
vertices1.put(vertices); 
vertices1.rewind(); 

// Load the vertices into the proper buffer 
glBufferData(GL_ARRAY_BUFFER, vertices1, GL_STREAM_DRAW); 

// Define layout of data in buffer: 
// First, vertex coords (attrib "0"): 
glEnableVertexAttribArray(0); 
glVertexAttribPointer(0, 3, GL_FLOAT, false, 5 * 4, 0 * 4); 
// The last 2 params to glVertexAttribPointer are stride and offset. 
// Stride tells the total number of bytes between the start of one vertex 
// and the start of the next, 5 * 4 because the data rows above have 5 elements 
// and each element is a 4-byte float. 
// Offset tells the byte offset of the start of the first element in the buffer, 
// 0 * 4 because our coord data begins right at the beginning of the buffer. 

// Now, tex coords (attrib "1"): 
glEnableVertexAttribArray(1); 
glVertexAttribPointer(1, 2, GL_FLOAT, false, 5 * 4, 3 * 4); 
// Stride is the same as above, but need non-zero offset because the tex 
// coords start after the 3 vertex coords in each row of data in the buffer. 

// Call glDrawArrays as many times as you want to repeatedly, 
// possibly with different uniform values, and with no need 
// for glBegin(), glEnd(), or repeated glFlush(). 
glDrawArrays(GL_TRIANGLES, 0, vertices.length); 

// Cleanup 
glDeleteBuffers(bufferId); 
Verwandte Themen