Ich habe einen Code, der eine Reihe von Objekten durchläuft und Instanzen dieser Objekte rendert. Die Liste der Objekte, die gerendert werden müssen, wird als std :: map> gespeichert, wobei ein Objekt der Klasse MeshResource die Eckpunkte und Indizes mit den tatsächlichen Daten enthält und ein Objekt der Klasse MeshRenderer den Punkt im Raum definiert, an dem sich das Netz befinden soll gerendert bei.
Mein Rendering-Code lautet wie folgt:
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
{
it->first->setupBeforeRendering();
cout << "<";
for (unsigned long i =0; i < it->second.size(); i++)
{
//Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
uniformizeModelMatrix(Matrix4::IDENTITY);
/**
* StartHere fix rendering problem.
* Ruled out:
* Vertex buffers correctly.
* Index buffers correctly.
* Matrices correct?
*/
it->first->render();
}
it->first->cleanupAfterRendering();
}
geometryPassShader->disable();
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
Die Funktion in MeshResource, mit der die Uniformen eingerichtet werden, lautet wie folgt:
void MeshResource::setupBeforeRendering()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}
Der Code, der das Objekt rendert, lautet wie folgt:
void MeshResource::render()
{
glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}
Und der Code, der bereinigt, ist folgender:
void MeshResource::cleanupAfterRendering()
{
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
}
Das Endergebnis davon ist, dass ich einen schwarzen Bildschirm bekomme, obwohl das Ende meiner Rendering-Pipeline nach dem Rendering-Code (im Wesentlichen nur das Zeichnen von Achsen und Linien auf dem Bildschirm) ordnungsgemäß funktioniert, sodass ich ziemlich sicher bin, dass dies kein Problem mit dem ist Übergabe von Uniformen. Wenn ich den Code jedoch geringfügig ändere, sodass der Rendering-Code das Setup unmittelbar vor dem Rendern aufruft, wie folgt:
void MeshResource::render()
{
setupBeforeRendering();
glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}
Das Programm funktioniert wie gewünscht. Ich möchte dies jedoch nicht tun müssen, da mein Ziel darin besteht, Scheitelpunkt-, Material- usw. Daten einmal pro Objekttyp einzurichten und dann jede Instanz so zu rendern, dass nur die Transformationsinformationen aktualisiert werden.
Die uniformizeModelMatrix funktioniert wie folgt:
void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
offsetof
Antworten:
Erstens ist OpenGL voller seltsamer Dinge, so dass ein Treiberfehler, so unwahrscheinlich er auch sein mag, immer noch eine Option ist. Erwägen Sie, die App auf verschiedenen Setups (nVidia vs. AMD, ältere Treiber) und anderen winzigen Codeänderungen zu testen. Sie können beispielsweise mit dem Entfernen des "glBindBuffer (GL_UNIFORM_BUFFER, 0)" beginnen. line - es scheint sowieso nichts Nützliches zu tun.
Da hier alles richtig zu sein scheint, liegt das Problem höchstwahrscheinlich nicht hier. Es gibt zwei Möglichkeiten: gDEBugger und Durchlaufen des Codes im C ++ - Debugger. Es scheint, dass etwas kurz vor dem Zeichnen zurückgesetzt wird. In gDEBugger gibt es eine Funktion "Anrufverlauf", mit der Sie sehen können, welche Anrufe vor dem Draw-Anruf in welcher Reihenfolge getätigt wurden.
Übrigens empfehle ich Ihnen dringend, jeden fehlerrückgebenden Aufruf mit einem Makro zu versehen, das nach allen möglichen Fehlern sucht und diese auslöst. Es muss ein Makro sein, um das erweiterte Debuggen (Drucken von Dateien, Zeilen und der fehlerhaften Codezeile selbst) zu unterstützen, das in Release-Builds deaktiviert werden kann. Wenn eine geheime Regel verletzt wird, sollte ein solches Setup Sie sofort davor warnen.
quelle
Ich bin mir ziemlich sicher, dass das Attribut an den aktuellen Puffer gebunden werden sollte, daher gibt es keinen Grund, dieses Geschäft mit den Attributen in jedem Frame zu wiederholen, es sei denn, Sie erstellen den Puffer jedes Mal neu.
Also sollten Sie es wahrscheinlich auf die eine oder andere Weise tun - entweder lassen Sie es oder bauen Sie das Ganze in jedem Frame neu auf.
quelle
TL; DR: Treiberfehler.
In meinen Tests ab heute (Oktober 2016) werden einheitliche Puffer von den meisten Fahrern da draußen nicht richtig unterstützt .
Einige respektieren nicht,
glUniformBlockBinding
andere aktualisieren die einheitlichen Daten (glBufferSubData
undglBufferData
) nicht ordnungsgemäß, wobei die zwischengespeicherten internen Kopien der Puffer / GPU der Puffer nicht kohärent gehalten werden.Wie ich es verstehe (und wie Nvidia es auch versteht)
glBindBufferBase
oderglBindBufferRange
.glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);
dieser Einstellung erfolgt pro Shader-Programm und wird nicht global freigegeben.Hinweis: global_ubo_index ist NICHT der Name des einheitlichen Pufferobjekts, sondern ein Index in dieser globalen Tabelle.
Diese "Komplexität" (eine großartige Funktion, um UBOs zwischen verschiedenen Shadern wie Beleuchtungswerten zu teilen) scheint das zu sein, was die meisten OpenGL-Treiber falsch machen. Um fair zu sein, ist der Wortlaut in der OpenGL-Dokumentation auch nicht der eindeutigste.
Ich musste wieder einfache alte Uniformen für andere Fahrer verwenden.
Beide Screenshots mit einheitlichen Pufferobjekten, zwei verschiedenen Treibern:
quelle