Dans OpenGL, il existe un moyen d’obtenir une liste de tous les uniformes et attributs utilisés par un programme de shader?

StackOverflow https://stackoverflow.com/questions/440144

  •  22-07-2019
  •  | 
  •  

Question

Je voudrais obtenir une liste de tous les uniformes et attribs utilisés par un objet programme shader. glGetAttribLocation () & amp; glGetUniformLocation () peut être utilisé pour mapper une chaîne sur un emplacement, mais ce que j'aimerais vraiment, c'est la liste des chaînes sans avoir à analyser le code glsl.

Remarque: dans OpenGL 2.0, glGetObjectParameteriv () est remplacé par glGetProgramiv () . Et l’énumération est GL_ACTIVE_UNIFORMS & amp; GL_ACTIVE_ATTRIBUTES .

Était-ce utile?

La solution

Variables partagées entre les deux exemples:

GLint i;
GLint count;

GLint size; // size of the variable
GLenum type; // type of the variable (float, vec3 or mat4, etc)

const GLsizei bufSize = 16; // maximum name length
GLchar name[bufSize]; // variable name in GLSL
GLsizei length; // name length

Attributs

glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &count);
printf("Active Attributes: %d\n", count);

for (i = 0; i < count; i++)
{
    glGetActiveAttrib(program, (GLuint)i, bufSize, &length, &size, &type, name);

    printf("Attribute #%d Type: %u Name: %s\n", i, type, name);
}

Uniformes

glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count);
printf("Active Uniforms: %d\n", count);

for (i = 0; i < count; i++)
{
    glGetActiveUniform(program, (GLuint)i, bufSize, &length, &size, &type, name);

    printf("Uniform #%d Type: %u Name: %s\n", i, type, name);
}

Documentation OpenGL / Types de variable

Les différentes macros représentant les types de variable se trouvent dans le docs. Tels que GL_FLOAT , GL_FLOAT_VEC3 , GL_FLOAT_MAT4 , etc.

Autres conseils

Il y a eu un changement dans la façon dont ce genre de choses est fait dans OpenGL. Présentons donc l'ancienne et la nouvelle façon .

Old Way

Les shaders liés ont le concept d'un certain nombre d'uniformes actifs et d'attributs actifs (entrées de stade de vertex shader). Ce sont les uniformes / attributs utilisés par ce shader. glGetProgramiv permet de connaître leur nombre (ainsi que de nombreuses autres choses). :

GLint numActiveAttribs = 0;
GLint numActiveUniforms = 0;
glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTES, &numActiveAttribs);
glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &numActiveUniforms);

Vous pouvez ainsi interroger des blocs uniformes actifs, transformer des variations de retour d'informations, des compteurs atomiques et des opérations similaires.

Une fois que vous avez le nombre d'attributs / uniformes actifs, vous pouvez commencer à rechercher des informations à leur sujet. Pour obtenir des informations sur un attribut, utilisez glGetActiveAttrib ; Pour obtenir des informations sur un uniforme, vous utilisez glGetActiveUniform . Par exemple, étendu de ce qui précède:

GLint maxAttribNameLength = 0;
glGetProgramiv(prog, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH​, &maxAttribNameLength);
std::vector<GLchar> nameData(maxAttribNameLength)
for(int attrib = 0; attrib < numActiveAttribs; ++attrib)
{
  GLint arraySize = 0;
  GLenum type = 0;
  GLsizei actualLength = 0;
  glGetActiveAttrib(prog, attrib, nameData.size(), &actualLength, &arraySize, &type, &nameData[0]);
  std::string name((char*)&nameData[0], actualLength - 1);
}

Quelque chose de similaire peut être fait pour les uniformes. Cependant, l’astuce GL_ACTIVE_UNIFORM_MAX_LENGTH & # 8203; peut poser problème avec certains pilotes. Je suggère donc ceci:

std::vector<GLchar> nameData(256);
for(int unif = 0; unif < numActiveUniforms; ++unif)
{
  GLint arraySize = 0;
  GLenum type = 0;
  GLsizei actualLength = 0;
  glGetActiveUniform(prog, unif, nameData.size(), &actualLength, &arraySize, &type, &nameData[0]);
  std::string name((char*)&nameData[0], actualLength - 1);
}

De plus, pour les uniformes, il y a glGetActiveUniforms , qui peut interroger toutes les longueurs de noms pour tous les uniformes à la fois (ainsi que tous les types, tailles de tableau, sauts et autres paramètres) .

Nouvelle manière

De cette manière, vous pouvez accéder à peu près à tout tout ce qui concerne les variables actives dans un programme lié avec succès (à l'exception des globales ordinaires). L'extension ARB_program_interface_query n'est pas encore disponible, mais elle y parviendra .

Cela commence par un appel à glGetProgramInterfaceiv , à interroger le nombre d'attributs / uniformes actifs. Ou tout ce que vous voudrez peut-être.

GLint numActiveAttribs = 0;
GLint numActiveUniforms = 0;
glGetProgramInterfaceiv(prog, GL_PROGRAM_INPUT, GL_ACTIVE_RESOURCES, &numActiveAttribs);
glGetProgramInterfaceiv(prog, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numActiveUniforms);

Les attributs ne sont que des entrées de vertex shader; GL_PROGRAM_INPUT désigne les entrées du premier programme de l'objet programme.

Vous pouvez ensuite connaître le nombre de ressources actives et demander successivement des informations à partir de glGetProgramResourceiv et glGetProgramResourceName :

std::vector<GLchar> nameData(256);
std::vector<GLenum> properties;
properties.push_back(GL_NAME_LENGTH​);
properties.push_back(GL_TYPE​);
properties.push_back(GL_ARRAY_SIZE​);
std::vector<GLint> values(properties.size());
for(int attrib = 0; attrib < numActiveAttribs; ++attrib)
{
  glGetProgramResourceiv(prog, GL_PROGRAM_INPUT, attrib, properties.size(),
    &properties[0], values.size(), NULL, &values[0]);

  nameData.resize(values[0]); //The length of the name.
  glGetProgramResourceName(prog, GL_PROGRAM_INPUT, attrib, nameData.size(), NULL, &nameData[0]);
  std::string name((char*)&nameData[0], nameData.size() - 1);
}

Le même code fonctionnerait pour GL_UNIFORM ; Il suffit d’échanger numActiveAttribs avec numActiveUniforms .

Pour ceux qui découvrent cette question dans WebGL, voici l'équivalent WebGL:

var program = gl.createProgram();
// ...attach shaders, link...

var na = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
console.log(na, 'attributes');
for (var i = 0; i < na; ++i) {
  var a = gl.getActiveAttrib(program, i);
  console.log(i, a.size, a.type, a.name);
}
var nu = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
console.log(nu, 'uniforms');
for (var i = 0; i < nu; ++i) {
  var u = gl.getActiveUniform(program, i);
  console.log(i, u.size, u.type, u.name);
}

Voici le code correspondant en python pour obtenir les uniformes:

from OpenGL import GL
...
num_active_uniforms = GL.glGetProgramiv(program, GL.GL_ACTIVE_UNIFORMS)
for u in range(num_active_uniforms):
    name, size, type_ = GL.glGetActiveUniform(program, u)
    location = GL.glGetUniformLocation(program, name)

Apparemment, la "nouvelle façon de faire" mentionnée par Nicol Bolas ne fonctionne pas en python.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top