OpenGLには、すべてのユニフォームのリストを取得する方法があります。シェーダープログラムで使用される属性?
質問
すべてのユニフォームのリストを取得したい&シェーダープログラムオブジェクトによって使用される属性。 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ドキュメント/変数タイプ
変数タイプを表すさまざまなマクロは、
docs。 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&#8203;
のトリックがバグになる可能性があります。だから私はこれをお勧めします:
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)
明らかに、ニコル・ボーラスが言及した「新しい方法」はpythonでは機能しません。