В OpenGL есть способ получить список всех униформ и атрибутов, используемых шейдерной программой? - PullRequest
40 голосов
/ 13 января 2009

Я хотел бы получить список всех униформ и атрибутов, используемых программным объектом шейдера. glGetAttribLocation() & glGetUniformLocation() можно использовать для сопоставления строки с местоположением, но мне действительно нужен список строк без необходимости разбора кода glsl.

Примечание: в OpenGL 2.0 glGetObjectParameteriv() заменяется на glGetProgramiv(). И перечисление GL_ACTIVE_UNIFORMS & GL_ACTIVE_ATTRIBUTES.

Ответы [ 4 ]

62 голосов
/ 14 января 2009

Переменные, используемые в обоих примерах:

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 / Типы переменных

Различные макросы, представляющие типы переменных, можно найти в Docs. Например, GL_FLOAT, GL_FLOAT_VEC3, GL_FLOAT_MAT4 и т. Д.

45 голосов
/ 27 сентября 2012

Произошли изменения в том, как это делается в 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 означает входные данные для первой программы в программном объекте.

Затем вы можете циклически перебирать количество активных ресурсов, запрашивая информацию по каждому из них по очереди: glGetProgramResourceiv и 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);
}

Точно такой же код будет работать для GL_UNIFORM; просто поменяйте numActiveAttribs на numActiveUniforms.

16 голосов
/ 27 сентября 2012

Для любого, кто найдет этот вопрос и хочет сделать это в 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);
}
0 голосов
/ 17 мая 2018

Вот соответствующий код в 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.

...