Dans OpenGL, il existe un moyen d’obtenir une liste de tous les uniformes et attributs utilisés par un programme de shader?
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
.
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.