Произошли изменения в том, как это делается в 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
.