Errore di istanza di oggetti veloci OpenGL


8

Ho del codice che scorre attraverso una serie di oggetti e rende le istanze di quegli oggetti. L'elenco di oggetti che devono essere sottoposti a rendering è memorizzato come std :: map>, dove un oggetto della classe MeshResource contiene i vertici e gli indici con i dati effettivi e un oggetto di classMeshRenderer definisce il punto nello spazio in cui deve essere la mesh reso a.

Il mio codice di rendering è il seguente:

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);

La funzione in MeshResource che gestisce l'impostazione delle uniformi è la seguente:

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
}

Il codice che rende l'oggetto è questo:

void MeshResource::render()
{
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

E il codice che pulisce è questo:

void MeshResource::cleanupAfterRendering()
{
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
}

Il risultato finale di questo è che ottengo uno schermo nero, sebbene la fine della mia pipeline di rendering dopo il codice di rendering (essenzialmente disegnando solo assi e linee sullo schermo) funzioni correttamente, quindi sono abbastanza sicuro che non sia un problema con passaggio delle uniformi. Se, tuttavia, modifico leggermente il codice in modo che il codice di rendering richiami l'installazione immediatamente prima del rendering, in questo modo:

void MeshResource::render()
{
    setupBeforeRendering();
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

Il programma funziona come desiderato. Non voglio farlo, tuttavia, poiché il mio obiettivo è impostare i dati vertice, materiale, ecc. Una volta per tipo di oggetto e quindi rendere ogni istanza aggiornando solo le informazioni di trasformazione.

UniformizeModelMatrix funziona come segue:

void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
    glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}

Ho una configurazione quasi identica per il rendering dei miei modelli. Tranne che la mia chiamata di rendering lega il buffer e imposta i puntatori degli attributi ogni volta. Stai riscontrando problemi di prestazioni con questo? Funziona molto velocemente per me.
MichaelHouse

Non ho riscontrato problemi di prestazioni se non ho sullo schermo centinaia di oggetti identici, ma non riesco ancora a capire cosa non va qui, e sarebbe bello sapere perché il codice non funziona come previsto.
HJ Media Studios,

1
Dobbiamo solo attirare l'attenzione di @NicolBolas, lui è l'esperto openGL residente.
MichaelHouse

Potrebbe essere una buona idea da usare offsetofquando si specificano gli attributi del vertice
JBeurer il

Risposte:


2

Prima di tutto, OpenGL è pieno di cose strane quindi un bug del driver, per quanto improbabile possa essere, è ancora un'opzione - considera di testare l'app su diverse configurazioni (nVidia vs AMD, driver più vecchi) e altre piccole modifiche al codice. Ad esempio, è possibile iniziare con la rimozione di "glBindBuffer (GL_UNIFORM_BUFFER, 0);" linea - sembra non fare nulla di utile comunque.

Poiché tutto qui sembra corretto, molto probabilmente il problema non è qui. Esistono due opzioni: gDEBugger e scorrere il codice nel debugger C ++. Sembra che qualcosa venga ripristinato poco prima del disegno. In gDEBugger, c'è una funzione "cronologia chiamate" che potrebbe aiutarti a vedere quali chiamate sono state effettuate prima della chiamata di disegno e in quale ordine.

A proposito, ti consiglio vivamente di racchiudere ogni chiamata che restituisce errori con una macro che controlla tutti i possibili errori e li lancia. Deve essere una macro per supportare il debug esteso (file di stampa, riga e la riga di codice difettosa stessa) che può essere disabilitata nelle build di rilascio. Se una regola segreta viene infranta, tale impostazione dovrebbe avvisarti immediatamente di ciò.


5
Eviterei il collegamento al sito Gremedy. Quella versione di gDEBugger è antica, non supportata e molto difettosa. developer.amd.com/tools/heterogeneous-computing/amd-gdebugger è la versione aggiornata di AMD supportata, con supporto per Windows e Linux (purtroppo senza OS X). Ci sono anche altri fantastici strumenti di debug / perf GL sul sito di AMD, per non parlare degli strumenti che NVIDIA e Intel offrono.
Sean Middleditch,

0

Sono abbastanza sicuro che l'attributo dovrebbe essere associato al buffer corrente, quindi non c'è motivo di ripetere questa attività con gli attributi ogni frame a meno che non si ricostruisca il buffer ogni volta ....

Quindi dovresti probabilmente farlo in un modo o nell'altro - o lasciarlo o ricostruire il tutto in ogni fotogramma.


0

TL; DR: bug del driver.

Nei miei test di oggi (ottobre 2016) i buffer uniformi non sono supportati correttamente dalla maggior parte dei driver.

Alcuni non rispettano glUniformBlockBindingalcuni non aggiornano i dati uniformi ( glBufferSubDatae glBufferData) correttamente, dove le copie interne memorizzate nella cache degli shader / GPU di detti buffer non vengono mantenute coerenti.


Il modo in cui lo capisco (e il modo in cui anche Nvidia lo capisce)

  • Associa / mappa il tuo oggetto buffer uniforme a una tabella globale condivisa da tutti gli shader all'interno del driver / GPU OpenGL usando glBindBufferBaseo glBindBufferRange.
  • Mappare gli accessi del buffer uniforme dello shader ad una voce in quella tabella globale usando glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);questa impostazione è per programma shader , non condiviso globalmente.

Nota: global_ubo_index NON è il nome dell'oggetto buffer uniforme ma un indice in quella tabella globale.

Questa "complessità" (che è una grande caratteristica per condividere gli UBO tra diversi shader, come i valori di illuminazione) sembra essere ciò che la maggior parte dei driver OpenGL sbaglia. Ad essere onesti, la formulazione nella documentazione di OpenGL non è nemmeno la più chiara.

Ho dovuto ricorrere all'utilizzo di vecchie uniformi semplici per altri conducenti.

Entrambi gli screenshot utilizzano oggetti buffer uniformi, due driver diversi:

Uniform Buffer Bugs


Con quali driver hai provato? Quale piattaforma?
Akaltar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.