【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変数のインデックスです。

使い方

  1. QOpenGLExtraFunctionsインスタンスを取得します。
  2. 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()関数を使用するのが最も簡単です。