【OpenGL x Qt GUI】シェーダーとUniform変数でワンランク上の描画を実現
QOpenGLExtraFunctions::glUniform4uiv()
関数は、OpenGLシェーダープログラム内の4要素ベクトルをUniform変数に設定するために使用されます。Uniform変数は、シェーダープログラム内で共有されるグローバル変数のようなものです。
関数詳細
void QOpenGLExtraFunctions::glUniform4uiv(GLint location, GLsizei count, const GLuint* value);
value
: 設定する4要素ベクトルの配列をポインタで渡します。count
: 設定する4要素ベクトルの個数を指定します。location
: Uniform変数の場所を指定します。これは、シェーダープログラム内で宣言されたUniform変数のインデックスです。
使い方
QOpenGLExtraFunctions
インスタンスを取得します。glUniform4uiv()
関数を呼び出して、Uniform変数の場所、設定するベクトルの個数、ベクトルの配列を渡します。
例
QOpenGLExtraFunctions* glFuncs = QOpenGLContext::currentContext()->extraFunctions();
// シェーダープログラム内で宣言されたUniform変数の場所を取得
GLint uniformLocation = glGetUniformLocation(programId, "uniformColor");
// 設定する4要素ベクトルを準備
GLuint uniformValues[4] = { 255, 0, 0, 255 };
// Uniform変数に4要素ベクトルを設定
glUniform4uiv(uniformLocation, 1, uniformValues);
- Uniform変数に設定する値は、整数型(unsigned int)である必要があります。
- Uniform変数の場所は、シェーダープログラム内で
glGetUniformLocation()
関数を使用して取得できます。 glUniform4uiv()
関数は、OpenGL ES 3.0以降で使用できます。
シェーダープログラム
// 頂点シェーダー
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;
out vec4 vertexColor;
void main() {
vertexColor = aColor;
gl_Position = vec4(aPos, 1.0);
}
// フラグメントシェーダー
#version 330 core
out vec4 FragColor;
in vec4 vertexColor;
void main() {
FragColor = vertexColor;
}
#include <QCoreApplication>
#include <QOpenGLWidget>
#include <QShader>
class MyGLWidget : public QOpenGLWidget {
public:
MyGLWidget() {
setWindowTitle("OpenGL Triangle");
setFixedSize(500, 500);
}
protected:
void initializeGL() override {
// シェーダープログラムのコンパイル
QShader vertexShader(QShader::Vertex);
vertexShader.sourceCode(vertexShaderSource);
if (!vertexShader.compile()) {
qCritical() << "Vertex shader compilation failed:" << vertexShader.log();
return;
}
QShader fragmentShader(QShader::Fragment);
fragmentShader.sourceCode(fragmentShaderSource);
if (!fragmentShader.compile()) {
qCritical() << "Fragment shader compilation failed:" << fragmentShader.log();
return;
}
shaderProgram.addShader(&vertexShader);
shaderProgram.addShader(&fragmentShader);
if (!shaderProgram.link()) {
qCritical() << "Shader program linking failed:" << shaderProgram.log();
return;
}
// 三角形の頂点データ準備
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
// 頂点バッファオブジェクト (VBO) 作成
glGenBuffers(1, &vboId);
glBindBuffer(GL_ARRAY_BUFFER, vboId);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 頂点属性レイアウト設定
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
}
void paintGL() override {
// シェーダープログラムを有効化
shaderProgram.bind();
// Uniform変数に値を設定
QOpenGLExtraFunctions* glFuncs = QOpenGLContext::currentContext()->extraFunctions();
GLint uniformLocation = glGetUniformLocation(shaderProgram.programId(), "uniformColor");
glUniform4uiv(uniformLocation, 1, uniformValues);
// 三角形を描画
glDrawArrays(GL_TRIANGLES, 0, 3);
}
private:
// シェーダーソースコード
const char* vertexShaderSource =
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec4 aColor;\n"
"\n"
"out vec4 vertexColor;\n"
"\n"
"void main() {\n"
" vertexColor = aColor;\n"
" gl_Position = vec4(aPos, 1
QOpenGLExtraFunctions::glUniform4uiv()
の代替方法として、以下の方法があります。
glUniform4iv()関数を使用する
glUniform4iv()
関数は、glUniform4uiv()
関数とほぼ同じですが、Uniform変数に設定する値を整数型(int)で指定する必要があります。
void QOpenGLContext::currentContext()->functions()->glUniform4iv(location, count, value);
glUniform1i()関数とglUniform3iv()関数を組み合わせて使用する
glUniform1i()
関数とglUniform3iv()
関数を組み合わせて使用することで、glUniform4uiv()
関数と同じように4要素ベクトルをUniform変数に設定することができます。
glUniform1i(location + 0, value[0]);
glUniform1i(location + 1, value[1]);
glUniform1i(location + 2, value[2]);
glUniform1i(location + 3, value[3]);
glUniformBlockBinding()関数とUniformブロックを使用する
GLuint uniformBlockIndex = glGetUniformBlockIndex(programId, "uniformBlockName");
glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockIndex);
glBindBuffer(GL_UNIFORM_BLOCK, uniformBlockId);
glBufferData(GL_UNIFORM_BLOCK, sizeof(uniformValues), uniformValues, GL_STATIC_DRAW);
C++11以降の機能を使用する
C++11以降の機能を使用すると、Uniform変数に直接値を代入することができます。
program.setUniformValue("uniformColor", QVector4U(255, 0, 0, 255));
どの方法を使用するべきか
どの方法を使用するべきかは、状況によって異なります。
- C++11以降の機能を使用できる場合は、Uniform変数に直接値を代入することができます。
- Uniformブロックを使用したい場合は、
glUniformBlockBinding()
関数とUniformブロックを使用する必要があります。 - 古いバージョンのOpenGLを使用している場合は、
glUniform4iv()
関数またはglUniform1i()
関数とglUniform3iv()
関数を組み合わせて使用する必要があります。 - OpenGL ES 3.0以降を使用している場合は、
glUniform4uiv()
関数を使用するのが最も簡単です。