在OpenGL中,有一种方法可以获得着色器程序使用的所有制服和属性列表吗?

我想获得一个着色器程序对象使用的所有制服和属性列表。 glGetAttribLocation()glGetUniformLocation()可以用来映射一个string到一个位置,但我真正喜欢的是string列表,而不必分析glsl代码。

注意:在OpenGL 2.0中, glGetObjectParameteriv()glGetObjectParameteriv()所取代。 枚举是GL_ACTIVE_UNIFORMSGL_ACTIVE_ATTRIBUTES

两个例子之间共享的variables:

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

OpenGL文档/variablestypes

表示variablestypes的各种macros可以在文档中find。 如GL_FLOATGL_FLOAT_VEC3GL_FLOAT_MAT4

  • glGetActiveAttrib
  • glGetActiveUniform

OpenGL中的这种事情已经发生了变化。 所以让我们来陈述一下旧的方式和新的方式 。

旧的方式

链接的着色器具有许多活动的制服和活动属性(顶点着色器阶段input)的概念。 这些是着色器正在使用的制服/属性。 可以用glGetProgramiv来查询这些(以及其他一些事情)的数量 :

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

您可以查询活动的统一块,以这种方式转换反馈变化,primefaces计数器和类似的东西。

一旦你有活动的属性/制服的数量,你可以开始查询有关他们的信息。 要获取有关属性的信息,请使用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​技巧在一些驱动程序中可能会有问题。 所以我会build议这样的:

 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 ,它可以一次查询所有制服的名称长度(以及所有types,数组大小,步幅和其他参数)。

新方法

通过这种方式,您可以访问成功链接的程序中的所有活动variables(除了常规全局variables)。 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); 

属性只是顶点着色器的input; GL_PROGRAM_INPUT表示程序对象中第一个程序的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 ; 只是用numActiveUniforms交换numActiveUniforms

对于那些在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); }