Em OpenGL há uma maneira de obter uma lista de todos os uniformes e attribs usados ??por um programa shader?

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

  •  22-07-2019
  •  | 
  •  

Pergunta

Gostaria de obter uma lista de todos os uniformes e attribs usados ??por um objeto programa de shader. glGetAttribLocation() & glGetUniformLocation() pode ser usado para mapear uma string para um local, mas o que eu realmente gostaria é a lista de strings sem ter que analisar o código GLSL.

Nota: Em OpenGL 2.0 glGetObjectParameteriv() é substituída por glGetProgramiv(). E a enumeração é GL_ACTIVE_UNIFORMS & GL_ACTIVE_ATTRIBUTES.

Foi útil?

Solução

variáveis ??compartilhadas entre os dois exemplos:

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

Atributos

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);
}

Fardas

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);
}

OpenGL Documentação / Tipos de variáveis ??

As várias macros que representam tipos de variáveis ??podem ser encontrados no docs. Tais como GL_FLOAT, GL_FLOAT_VEC3, GL_FLOAT_MAT4, etc.

Outras dicas

Houve uma mudança na forma como este tipo de coisa é feito em OpenGL. Então, vamos presente a maneira antiga ea nova forma .

Old Way

sombreamentos vinculadas têm o conceito de uma série de atributos e uniformes activas activas (entradas vértice fase sombreador). Estes são os uniformes / atributos que estão em uso por esse shader. O número destes (assim como algumas outras coisas) pode ser consultado com glGetProgramiv :

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

Você pode consultar blocos uniformes ativos, transformar varyings feedback, contadores atômicas, e coisas semelhantes desta forma.

Assim que tiver o número de atributos / uniformes ativos, você pode começar a consultar informações sobre eles. Para obter informações sobre um atributo, você usa glGetActiveAttrib ; para obter informações sobre um uniforme, você usa glGetActiveUniform . Como um exemplo, estendida a partir do acima:

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);
}

Algo semelhante pode ser feito para uniformes. No entanto, o truque GL_ACTIVE_UNIFORM_MAX_LENGTH​ pode ser buggy em alguns drivers. Assim, gostaria de sugerir este:

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);
}

Além disso, para os uniformes, há glGetActiveUniforms, que pode consultar todos os comprimentos de nome para cada uniforme de uma só vez (assim como todos os tipos, tamanhos matriz, avanços e outros parâmetros).

New Way

Desta forma, permite-lhe aceder praticamente tudo sobre variáveis ??ativos em um programa ligado com sucesso (exceto para globals regulares). A extensão ARB_program_interface_query não está amplamente disponível ainda, mas vamos chegar lá .

Ela começa com uma chamada para glGetProgramInterfaceiv , para consultar o número de atributos ativos / uniformes. Ou o que mais você pode querer.

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

Os atributos são apenas Vertex Shader insumos; GL_PROGRAM_INPUT significa as entradas para o primeiro programa no objeto do programa.

Você pode então loop sobre o número de recursos ativos, pedindo informações sobre cada um por sua vez, a partir de glGetProgramResourceiv e 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);
}

O mesmo código exato iria trabalhar para GL_UNIFORM; apenas numActiveAttribs swap com numActiveUniforms.

Para qualquer um lá fora, que encontra esta pergunta olhando para fazer isso em WebGL, aqui é o equivalente 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);
}

Aqui está o código correspondente em python para obter os 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)

Aparentemente, o 'novo caminho' mencionado por Nicol Bolas não funciona em python.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top