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

OpenGL 문서 / 변수 유형

가변 유형을 나타내는 다양한 매크로는 문서에서 찾을 수 있습니다. 와 같은 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 프로그램 객체의 첫 번째 프로그램에 대한 입력을 의미합니다.

그런 다음 활성 리소스 수를 반복하여 각 리소스에 대한 정보를 차례로 요청할 수 있습니다. 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.

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)

Nicol Bolas가 언급 한 '새로운 방법'은 파이썬에서 작동하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top