在 OpenGL 中,有没有办法获取着色器程序使用的所有制服和属性的列表?

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

  •  22-07-2019
  •  | 
  •  

我想获取着色器程序对象使用的所有制服和属性的列表。 glGetAttribLocation() & glGetUniformLocation() 可用于将字符串映射到某个位置,但我真正想要的是字符串列表,而无需解析 glsl 代码。

笔记:在OpenGL 2.0中 glGetObjectParameteriv() 被替换为 glGetProgramiv(). 。枚举是 GL_ACTIVE_UNIFORMS & GL_ACTIVE_ATTRIBUTES.

有帮助吗?

解决方案

变量之间共享这两个例子:

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

属性

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

制服

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

照片的文档/变量的类型

各种宏表示的变量类型,可以发现在 文档。如 GL_FLOAT, GL_FLOAT_VEC3, GL_FLOAT_MAT4, 等等。

其他提示

OpenGL 中完成此类操作的方式发生了变化。那么让我们来介绍一下 旧方式和新方式.

老方法

链接着色器具有许多活动制服和活动属性(顶点着色器阶段输入)的概念。这些是该着色器使用的制服/属性。这些的数量(以及相当多的其他东西)可以通过以下方式查询 glGetProgramiv:

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

您可以通过这种方式查询活动的统一块、转换反馈变量、原子计数器和类似的东西。

一旦您获得了活动属性/制服的数量,您就可以开始查询有关它们的信息。要获取有关属性的信息,您可以使用 glGetActiveAttrib;要获取有关制服的信息,您可以使用 glGetActiveUniform. 。作为一个例子,从上面扩展:

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

制服也可以做类似的事情。但是,那 GL_ACTIVE_UNIFORM_MAX_LENGTH​ 对于某些驱动程序来说,这个技巧可能会出现问题。所以我建议这样:

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

另外,对于制服,还有 glGetActiveUniforms, ,它可以一次查询每个制服的所有名称长度(以及所有类型、数组大小、步幅和其他参数)。

新方法

这种方式可以让你访问几乎 一切 关于成功链接的程序中的活动变量(常规全局变量除外)。这 ARB_program_interface_query 扩展尚未广泛使用,但它会实现的。

首先调用 glGetProgramInterfaceiv, 查询活动属性/制服的数量。或者任何你可能想要的东西。

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

属性只是顶点着色器的输入; GL_PROGRAM_INPUT 表示程序对象中第一个程序的输入。

然后,您可以循环访问活动资源的数量,依次询问每个资源的信息,从 glGetProgramResourceivglGetProgramResourceName:

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

完全相同的代码适用于 GL_UNIFORM;只是交换 numActiveAttribsnumActiveUniforms.

对于任何人在那里,发现这个问题要做到这一点在WebGL的,这里的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);
}

下面是在python相应的代码用于获取制服:

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)

显然由尼科尔流星锤提到在python不起作用“新途径”。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top