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);
}
offsetof
lors de la spécification des attributs de sommetRéponses:
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.
la source
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.
la source
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
glUniformBlockBinding
certains ne mettent pas à jour les données uniformes (glBufferSubData
etglBufferData
) 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)
glBindBufferBase
ouglBindBufferRange
.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:
la source