OpenGL Fast-Object Instancing-Fehler

8

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);
}
HJ Media Studios
quelle
Ich habe ein nahezu identisches Setup für das Rendern meiner Modelle. Außer mein Render-Aufruf bindet den Puffer und setzt jedes Mal die Attributzeiger. Stoßen Sie dabei auf Leistungsprobleme? Es läuft sehr schnell für mich.
MichaelHouse
Ich habe keine Leistungsprobleme, es sei denn, ich habe Hunderte identischer Objekte auf dem Bildschirm, aber ich kann immer noch nicht herausfinden, was hier falsch läuft, und es wäre toll zu erfahren, warum der Code nicht wie erwartet funktioniert.
HJ Media Studios
1
Wir müssen nur die Aufmerksamkeit von @NicolBolas auf sich ziehen, er ist der ansässige openGL-Experte.
MichaelHouse
offsetof
Könnte

Antworten:

2

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.

Schlange5
quelle
5
Ich würde es vermeiden, auf die Gremedy-Site zu verlinken. Diese Version von gDEBugger ist uralt und nicht unterstützt und sehr fehlerhaft. developer.amd.com/tools/heterogene-computing/amd-gdebugger ist die aktuelle AMD-unterstützte Version mit Windows- und Linux-Unterstützung (leider kein OS X). Es gibt auch einige andere fantastische GL-Debugging- / Perf-Tools auf der AMD-Website, ganz zu schweigen von den Tools, die NVIDIA und Intel anbieten.
Sean Middleditch
0

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.

Yudrist
quelle
0

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, glUniformBlockBindingandere aktualisieren die einheitlichen Daten ( glBufferSubDataund glBufferData) 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)

  • Bind / Ordnen Sie Ihre Uniform Puffer - Objekt zu einer globalen Tabelle geteilt von allen Shadern in der OpenGL - Treiber / GPU glBindBufferBaseoder glBindBufferRange.
  • Die Zuordnung der einheitlichen Pufferzugriffe des Shaders zu einem Eintrag in dieser globalen Tabelle mit 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:

Uniform Buffer Bugs

Stephane Hockenhull
quelle
Mit welchen Treibern haben Sie getestet? Welche Plattform?
Akaltar