web-dev-qa-db-fra.com

Mappage d'attribut de vertex shader dans GLSL

Je code un petit moteur de rendu avec des shaders GLSL:

Chaque maillage (enfin, sous-maillage) a un certain nombre de flux de sommets (par exemple, la position, la normale, la texture, la tangente, etc.) en un grand VBO et un MaterialID.

Chaque matériau a un ensemble de textures et de propriétés (par exemple, couleur spéculaire, couleur diffuse, texture couleur, carte normale, etc.)

Ensuite, j'ai un shader GLSL, avec ses uniformes et ses attributs. Disons:

uniform vec3 DiffuseColor;
uniform sampler2D NormalMapTexture;
attribute vec3 Position;
attribute vec2 TexCoord;

Je suis un peu coincé en essayant de concevoir un moyen pour le shader GLSL de définir les mappages de flux (sémantique) pour les attributs et les uniformes, puis de lier les flux de vertex aux attributs appropriés.

Quelque chose dans les lignes de dire au maillage: "mettez votre flux de position dans l'attribut" Position "et vos coordonnées tex dans" TexCoord ". Mettez également la couleur diffuse de votre matériau dans" DiffuseColor "et la deuxième texture de votre matériau dans" NormalMapTexture "

Pour le moment, j'utilise des noms codés en dur pour les attributs (c.-à-d. Vertex pos est toujours "Position", etc.) et vérifie chaque nom uniforme et attribut pour comprendre à quoi le shader l'utilise.

Je suppose que je cherche un moyen de créer une "déclaration de sommet", mais aussi des uniformes et des textures.

Je me demande donc comment les gens font cela dans les moteurs de rendu à grande échelle.

Éditer:

Récapitulation des méthodes suggérées:

1. La sémantique d'attribut/uniforme est donnée par le nom de la variable (ce que je fais maintenant) Utiliser des noms prédéfinis pour chaque attribut possible. Le classeur GLSL interrogera le nom de chaque attribut et liez le tableau de sommets en fonction du nom de la variable:

//global static variable

semantics (name,normalize,offset) = {"Position",false,0} {"Normal",true,1},{"TextureUV,false,2}

 ...when linking
for (int index=0;index<allAttribs;index++)
{
   glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
   semantics[index]= GetSemanticsFromGlobalHardCodedList(name);
} 
... when binding vertex arrays for render
 for (int index=0;index<allAttribs;index++)
{
    glVertexAttribPointer(index,size[index],type[index],semantics[index]->normalized,bufferStride,semantics[index]->offset);

}  

2. Emplacements prédéfinis pour chaque sémantique

Le classeur GLSL liera toujours les tableaux de sommets aux mêmes emplacements. Il appartient au shader d'utiliser les noms appropriés pour correspondre. (Cela semble terriblement similaire à la méthode 1, mais à moins que je ne comprenne mal, cela implique de lier TOUTES les données de vertex disponibles, même si le shader ne les consomme pas)

.. when linking the program...
glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");

. Dictionnaire des attributs disponibles de Material, Engine global, Renderer and Mesh

Gérer la liste des attributs disponibles publiés par le matériau actif, les globaux du moteur, le rendu actuel et le nœud de scène actuel.

par exemple:

 Material has (uniformName,value) =  {"ambientColor", (1.0,1.0,1.0)}, {"diffuseColor",(0.2,0.2,0.2)}
 Mesh has (attributeName,offset) = {"Position",0,},{"Normals",1},{"BumpBlendUV",2}

puis en shader:

 uniform vec3 ambientColor,diffuseColo;
 attribute vec3 Position;

Lors de la liaison des données de sommet au shader, le classeur GLSL bouclera sur les attributs et se liera à celui trouvé (ou non?) Dans le dictionnaire:

 for (int index=0;index<allAttribs;index++)
    {
       glGetActiveAttrib(program,index,bufSize,length,size[index],type[index],name);      
      semantics[index] = Mesh->GetAttributeSemantics(name);
}

et la même chose avec les uniformes, interroge uniquement le matériel actif et les globaux.

38
Radu094

Attributs:

Votre maillage comporte un certain nombre de flux de données. Pour chaque flux, vous pouvez conserver les informations suivantes: ( nom, type, données ).

Lors de la liaison, vous pouvez interroger le programme GLSL pour les attributs actifs et former un dictionnaire d'attributs pour ce programme. Chaque élément ici est juste ( nom, tapez ).

Lorsque vous dessinez un maillage avec un programme GLSL spécifié, vous parcourez le dictionnaire d'attributs de programmes et liez les flux de maillage correspondants (ou signalez une erreur en cas d'incohérence).

niformes:

Soit le dictionnaire de paramètres du shader l'ensemble de ( nom, type, liaison de données ). En règle générale, vous pouvez disposer des dictionnaires suivants:

  • Matériau (diffus, spéculaire, brillant, etc.) - extrait du matériau
  • Moteur (caméra, modèle, lumières, minuteries, etc.) - tiré du moteur singleton (global)
  • Rendu (paramètres personnalisés liés au créateur du shader: rayon SSAO, quantité de flou, etc.) - fournis exclusivement par la classe du créateur du shader (rendu)

Après la liaison, le programme GLSL reçoit un ensemble de dictionnaires de paramètres afin de remplir son propre dictionnaire avec le format d'élément suivant: ( emplacement, type, liaison de données ). Cette population est effectuée en interrogeant la liste des uniformes actifs et en faisant correspondre ( nom, type ) la paire avec celle des dictionnaires.

Conclusion: Cette méthode permet de transmettre tous les attributs de sommet et uniformes de shader personnalisés, sans noms/sémantiques codés en dur dans le moteur. Fondamentalement, seuls le chargeur et le rendu connaissent une sémantique particulière:

  • Loader remplit les déclarations de flux de données maillées et les dictionnaires de matériaux.
  • Render utilise un shader qui connaît les noms, fournit des paramètres supplémentaires et sélectionne les maillages appropriés à dessiner.
16
kvark

D'après mon expérience, OpenGL ne définit pas le concept de sémantique d'attributs ou d'uniformes.

Tout ce que vous pouvez faire est de définir votre propre façon de mapper votre sémantique aux variables OpenGL, en utilisant le seul paramètre que vous pouvez contrôler sur ces variables: leurs emplacement .

Si vous n'êtes pas contraint par des problèmes de plate-forme, vous pouvez essayer d'utiliser le `` nouveau '' GL_ARB_explicit_attrib_location (noyau dans OpenGL 3.3 si je ne me trompe pas) qui permet aux shaders d'exprimer explicitement quel emplacement est destiné à quel attribut. De cette façon, vous pouvez coder en dur (ou configurer) les données que vous souhaitez lier à quel emplacement d'attribut et interroger les emplacements des shaders après leur compilation. Il semble que cette fonctionnalité ne soit pas encore mature et peut-être sujette à des bugs dans divers pilotes.

L'autre solution consiste à lier les emplacements de vos attributs à l'aide de glBindAttribLocation . Pour cela, vous devez connaître les noms des attributs que vous souhaitez lier et les emplacements que vous souhaitez leur affecter.

Pour connaître les noms utilisés dans un shader, vous pouvez:

  • interroger le shader pour les attributs actifs
  • analyser le code source du shader pour les trouver vous-même

Je ne recommanderais pas d'utiliser la méthode d'analyse GLSL (bien qu'elle puisse répondre à vos besoins si vous êtes dans des contextes assez simples): l'analyseur peut facilement être vaincu par le préprocesseur. En supposant que votre code de shader devienne quelque peu complexe, vous voudrez peut-être commencer à utiliser #includes, #defines, #ifdef, etc. Une analyse syntaxique robuste suppose que vous avez un préprocesseur robuste, qui peut devenir assez lourd à configurer.

Quoi qu'il en soit, avec vos noms d'attributs actifs, vous devez leur attribuer des emplacements (et/ou sémantiques), pour cela, vous êtes seul avec votre cas d'utilisation.

Dans notre moteur, nous codons avec plaisir des emplacements de noms prédéfinis à des valeurs spécifiques, telles que:

glBindAttribLocation(prog, 0, "mg_Position");
glBindAttribLocation(prog, 1, "mg_Color");
glBindAttribLocation(prog, 2, "mg_Normal");
...

Après cela, c'est au rédacteur du shader de se conformer à la sémantique prédéfinie des attributs.

AFAIK c'est la façon la plus courante de faire les choses, OGRE l'utilise par exemple. Ce n'est pas sorcier mais fonctionne bien dans la pratique.

Si vous souhaitez ajouter un contrôle, vous pouvez fournir une API pour définir la sémantique sur une base de shader, peut-être même avoir cette description dans un fichier supplémentaire, facilement analysable, vivant près du code source du shader.

Je n'entre pas dans les uniformes où la situation est presque la même, sauf que les extensions `` plus récentes '' vous permettent de forcer les blocs d'uniformes GLSL à une disposition de mémoire compatible avec votre application.

Je ne suis pas satisfait de tout cela moi-même, donc je serai heureux d'avoir des informations contradictoires :)

8
rotoglup

Vous voudrez peut-être envisager d'analyser le GLSL lui-même.

La syntaxe de déclaration uniforme/attribut est assez simple. Vous pouvez créer un petit analyseur manuel qui recherche les lignes commençant par uniform ou attribute, obtenir le type et le nom, puis exposer certaines API C++ à l'aide de chaînes. Cela vous évitera les ennuis des noms codés en dur. Si vous ne voulez pas vous salir les mains avec une analyse manuelle, quelques likes de Spirit feraient l'affaire.
. Une complication qui me vient à l'esprit est la compilation conditionnelle à l'aide de macros dans le GLSL.

3
shoosh