Vertex shader attribut mapping in GLSL

je code un petit moteur de rendu avec les shaders GLSL:

chaque maille (bien, sous-maille) a un certain nombre de flux de sommet (par ex. position, normal, texture, tangente, etc) dans un grand VBO et un Matérialid.

chaque matériau possède un ensemble de textures et de propriétés (p. ex. spéculaire-couleur, diffus, de la couleur, la texture, normal map,etc)

alors j'ai un shader GLSL, avec des uniformes et des attributs. Disons:

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

je suis un peu coincé dans essayer de concevoir un moyen pour le shader GLSL de définir les mappings de flux (sémantique) pour les attributs et les uniformes, puis lier les flux de vertex aux attributs appropriés.

quelque chose dans les lignes de dire au mesh :"mettez votre flux de position dans l'attribut "Position" et vos coordonnées tex dans "TexCoord". Mettez aussi la couleur diffuse de votre matériau dans" DiffuseColor "et la seconde texture de votre matériau dans"NormalMapTexture"

en ce moment j'utilise codé en dur noms pour les attributs (ie. vertex pos est toujours "Position", etc) et en vérifiant chaque nom d'uniforme et d'attribut pour comprendre ce que le shader utilise.

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

alors je me demande comment les gens font ça dans les moteurs de rendu à grande échelle.

Edit:

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

1. Attribut / uniforme sémantique est donnée par le nom de la variable (ce que je fais maintenant) À l'aide de noms prédéfinis pour chaque attribut.Le binder GLSL interrogera le nom de chaque attribut et liera le tableau de vertex basé sur le 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. Des localisations prédéfinies pour chaque sémantique

GLSL binder liera toujours les tableaux de vertex aux mêmes endroits.Il appartient au shader d'utiliser les noms appropriés pour correspondre. (Cela semble affreusement similaire à la méthode 1, mais à moins que je me méprenne, cela implique de lier toutes les données disponibles du vertex, 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");

3. Dictionnaire des attributs disponibles à partir de Matériau, Moteur globals, moteur de Rendu et de Maille

maintenir la liste des attributs disponibles publiés par le matériel actif, les globals du moteur, le Renderer actuel et le noeud 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 dans shader:

 uniform vec3 ambientColor,diffuseColo;
 attribute vec3 Position;

en liant les données du vertex au shader, le binder GLSL bouclera les attributs et se liera à celui trouvé (ou pas? ) 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, interrogez seulement le matériel actif et globals aussi.

36
demandé sur Radu094 2011-02-02 14:03:20

3 réponses

Attributs:

Votre mesh a un certain nombre de flux de données. Pour chaque flux, vous pouvez conserver les informations suivantes: (Nom, type, données).

après le lien, vous pouvez interroger le programme GLSL pour les attributs actifs et former un dictionnaire d'attributs pour ce programme. Chaque élément est juste (nom, tapez).

quand vous dessinez un mesh avec un programme GLSL spécifié, vous passez par le dictionnaire d'attributs de programmes et liez le flux de maillage correspondant (ou déclaration d'une erreur en cas d'incohérence).

Uniformes:

Laissez le paramètre du shader dictionnaire de l'ensemble des (nom, type, lien de données). Généralement, vous pouvez avoir les dictionnaires suivants:

  • Matériau (diffus, spéculaire, brillant, etc) - pris dans le matériau
  • moteur (caméra, modèle, lumières, minuteries, etc) - pris sur moteur singleton (global)
  • Render (paramètres personnalisés liés au créateur de l'ombre: rayon SSAO, flou, etc.) - fourni exclusivement par la classe créateur de l'ombre (render)

après le lien, 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, le type de liaison de données). Cette population se fait en interrogeant la liste des uniformes actifs et en les appariant (nom de, type) jumeler avec celui des dictionnaires.

Conclusion: Cette méthode permet de passer tous les attributs de vertex personnalisés et les uniformes shader, sans noms codés en dur/sémantique dans le moteur. Fondamentalement, seuls le chargeur et le rendu connaissent la 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 est conscient des noms, fournit des paramétrer et sélectionner les maillages appropriés à dessiner.
14
répondu kvark 2011-02-07 21:58:18

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

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

si vous n'êtes pas limité par les problèmes de plate-forme, vous pouvez essayer d'utiliser le 'nouveau' GL_ARB_explicit_attrib_location (core en OpenGL 3.3 si je ne suis pas mistaken) qui permet aux shaders d'exprimer explicitement quel emplacement est prévu pour quel attribut. De cette façon, vous pouvez hardcode (ou configurer) les données que vous voulez lier sur l'emplacement de l'attribut, et interroger les emplacements des shaders après qu'il soit compilé. Il semble que cette fonctionnalité n'est pas encore mature, et peut-être sujet à des bugs dans divers pilotes.

l'inverse est de lier les emplacements de vos attributs en utilisant glbindattribulocation. Pour cela, vous devez connaître les noms des attributs que vous souhaitez lier, et les endroits que vous souhaitez leur attribuer.

Pour trouver les noms utilisés dans un shader, vous pouvez:

  • requête, le shader pour active attributs
  • analysez le code source shader pour les trouver vous-même

Je ne recommande pas d'utiliser la méthode D'analyse GLSL (bien qu'elle puisse convenir à vos besoins si vous êtes dans des contextes assez simples): l'analyseur peut facilement être défait par le préprocesseur. Supposons que votre code shader devienne quelque peu complexe, vous pouvez commencer à utiliser #includes, #defines, #ifdef, etc. Robuste d'analyse suppose que vous avez une solide préprocesseur, qui peut devenir assez lourd à mettre en place.

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

dans notre moteur, nous codons heureusement des emplacements de noms prédéfinis à des valeurs, telles que:

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

après cela, c'est au shader writer de se conformer à la sémantique prédéfinie des attributs.

autant que je sache, c'est la façon la plus commune de faire les choses, OGRE l'utilise par exemple. Ce n'est pas de la science pure, mais ça fonctionne bien dans la pratique.

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

Je ne rentre 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 uniformes GLSL à une disposition de mémoire qui est compatible avec votre application.

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

8
répondu rotoglup 2013-05-31 03:22:02

vous pouvez envisager d'analyser le GLSL lui-même.

la syntaxe de déclaration uniforme/attribut est assez simple. Vous pouvez trouver un petit analyseur manuel qui recherche les lignes qui commencent par uniform ou attribute, récupère le type et le nom puis expose quelques API C++ en utilisant des chaînes. Cela vous évitera les problèmes de noms codés. Si vous ne voulez pas vous salir les mains avec l'analyse manuelle un couple de goûts de Esprit le faire astuce.

Vous ne voudrez probablement pas complètement analyser GLSL donc vous aurez besoin de vous assurer que vous ne faites rien de drôle dans les décélérations qui pourraient modifier le sens réel. Une complication qui vient à l'esprit est la compilation conditionnelle en utilisant des macros dans le GLSL.

3
répondu shoosh 2011-02-07 09:05:11