Erreur d'instanciation d'objet rapide OpenGL


8

J'ai du code qui parcourt un ensemble d'objets et rend des instances de ces objets. La liste des objets qui doivent être rendus est stockée sous la forme std :: map>, où un objet de la classe MeshResource contient les sommets et les index avec les données réelles, et un objet de classMeshRenderer définit le point dans l'espace où le maillage doit être rendu à.

Mon code de rendu est le suivant:

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 fonction dans MeshResource qui gère la configuration des uniformes est la suivante:

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
}

Le code qui rend l'objet est le suivant:

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

Et le code qui nettoie est le suivant:

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

Le résultat final est que j'obtiens un écran noir, bien que la fin de mon pipeline de rendu après le code de rendu (essentiellement juste dessiner des axes et des lignes à l'écran) fonctionne correctement, donc je suis presque sûr que ce n'est pas un problème avec le passage d'uniformes. Si, cependant, je modifie légèrement le code pour que le code de rendu appelle la configuration immédiatement avant le rendu, comme ceci:

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

Le programme fonctionne comme vous le souhaitez. Cependant, je ne veux pas avoir à le faire, car mon objectif est de configurer les données de sommet, de matériau, etc. une fois par type d'objet, puis de rendre chaque instance en mettant à jour uniquement les informations de transformation.

Le uniformizeModelMatrix fonctionne comme suit:

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

J'ai une configuration presque identique pour le rendu de mes modèles. Sauf que mon appel de rendu lie le tampon et définit les pointeurs d'attribut à chaque fois. Vous rencontrez des problèmes de performances avec cela? Ça marche très vite pour moi.
MichaelHouse

Je n'ai pas rencontré de problèmes de performances à moins d'avoir des centaines d'objets identiques à l'écran, mais je ne peux toujours pas comprendre ce qui ne va pas ici, et ce serait formidable d'apprendre pourquoi le code ne fonctionne pas comme prévu.
HJ Media Studios

1
Nous avons juste besoin d'attirer l'attention de @NicolBolas, il est l'expert résident openGL.
MichaelHouse

Cela pourrait être une bonne idée à utiliser offsetoflors de la spécification des attributs de sommet
JBeurer

Réponses:


2

Tout d'abord, OpenGL est plein de choses étranges, donc un bug de pilote, aussi improbable soit-il, est toujours une option - envisagez de tester l'application sur différentes configurations (nVidia vs AMD, anciens pilotes) et d'autres petites modifications de code. Par exemple, vous pouvez commencer par supprimer le "glBindBuffer (GL_UNIFORM_BUFFER, 0);" ligne - il semble ne rien faire d'utile de toute façon.

Étant donné que tout ici semble être correct, le problème n'est probablement pas là. Il existe deux options: gDEBugger et parcourir le code dans le débogueur C ++. Il semble que quelque chose soit réinitialisé juste avant le dessin. Dans gDEBugger, il existe une fonction "historique des appels" qui pourrait vous aider à voir quels appels ont été effectués avant l'appel de tirage et dans quel ordre.

Soit dit en passant, je vous suggère fortement d'envelopper chaque appel de retour d'erreur avec une macro qui vérifie toutes les erreurs possibles et les jette. Il doit s'agir d'une macro pour prendre en charge le débogage étendu (fichier d'impression, ligne et ligne de code défectueuse elle-même) qui peut être désactivée dans les versions. Si une règle secrète est violée, une telle configuration devrait vous en avertir immédiatement.


5
Je voudrais éviter de créer un lien vers le site Gremedy. Cette version de gDEBugger est ancienne et non prise en charge et très boguée. developer.amd.com/tools/heterogeneous-computing/amd-gdebugger est la version à jour prise en charge par AMD, avec prise en charge de Windows et Linux (malheureusement pas OS X). Il existe également d'autres fantastiques outils de débogage / perf GL sur le site d'AMD, sans parler des outils proposés par NVIDIA et Intel.
Sean Middleditch

0

Je suis presque sûr que l'attribut doit se lier au tampon actuel, il n'y a donc aucune raison de refaire cette affaire avec les attributs à chaque trame, à moins que vous ne reconstruisiez le tampon à chaque fois ....

Donc, vous devriez probablement le faire dans un sens ou dans l'autre - soit le laisser soit reconstruire le tout à chaque image.


0

TL; DR: bogues du pilote.

Dans mes tests à partir d'aujourd'hui (octobre 2016), la plupart des pilotes ne prennent pas correctement en charge les tampons uniformes .

Certains ne respectent pas glUniformBlockBindingcertains ne mettent pas à jour les données uniformes ( glBufferSubDataet glBufferData) correctement, où les copies internes mises en cache par les shaders / GPU desdits tampons ne sont pas cohérentes.


La façon dont je le comprends (et la façon dont Nvidia le comprend aussi)

  • Liez / mappez votre objet tampon uniforme à une table globale partagée par tous les shaders à l'intérieur du pilote / GPU OpenGL à l'aide de glBindBufferBaseou glBindBufferRange.
  • Mappez les accès uniformes du tampon du shader à une entrée dans cette table globale à l'aide de glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index);ce paramètre, par programme de shader , non partagé globalement.

Remarque: global_ubo_index n'est PAS le nom de l'objet tampon uniforme mais un index dans cette table globale.

Cette "complexité" (qui est une excellente fonctionnalité pour partager des UBO entre différents shaders, comme les valeurs d'éclairage) semble être ce que la plupart des pilotes OpenGL se trompent. Pour être juste, le libellé de la documentation OpenGL n'est pas non plus le plus ambigu possible.

J'ai dû recourir à de vieux uniformes simples pour les autres conducteurs.

Les deux captures d'écran utilisent des objets tampons uniformes, deux pilotes différents:

Bugs tampons uniformes


Avec quels pilotes avez-vous testé? Quelle plateforme?
akaltar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.