Qt GUI プログラミングにおける QOpenGL Extra Functions: glProgramUniformMatrix4x2fv() の詳細解説


QOpenGLExtraFunctions::glProgramUniformMatrix4x2fv() 関数は、OpenGL シェーダープログラムに 4x2 行列をアップロードするために使用されます。この関数は、ユニフォーム変数にアクセスして設定するために使用される OpenGL の標準関数である glUniformMatrix4fv() の拡張版です。glProgramUniformMatrix4x2fv() は、シェーダープログラムオブジェクトとユニフォーム変数の名前に加えて、行列データを含むポインタを引数として受け取ります。

用途

glProgramUniformMatrix4x2fv() 関数は、主に 2D グラフィックスで 2D 変換を表現するために使用されます。例えば、テクスチャの座標変換や 2D オブジェクトの投影変換などに使用できます。

使い方

glProgramUniformMatrix4x2fv() 関数は、次のように使用されます。

void glProgramUniformMatrix4x2fv(
    GLuint program,
    GLint location,
    GLsizei count,
    GLboolean transpose,
    const GLfloat *value
);
  • value: 行列データを含むポインタ
  • transpose: 行列を転置するかどうか。GL_FALSE の場合は転置されません。
  • count: アップロードする行列の数
  • location: ユニフォーム変数の名前
  • program: シェーダープログラムオブジェクト

次の例では、uniformMatrix4x2 という名前のユニフォーム変数に 4x2 行列をアップロードする方法を示します。

GLfloat matrix[4][2] = {
    { 1.0f, 0.0f },
    { 0.0f, 1.0f },
    { 0.5f, 0.5f },
    { 0.0f, 0.0f }
};

glProgramUniformMatrix4x2fv(program, location, 1, GL_FALSE, matrix);
  • 行列データは、OpenGL 形式でなければなりません。OpenGL 形式は、列優先で、要素は float 型である必要があります。
  • ユニフォーム変数の名前は、シェーダープログラムで定義されている必要があります。
  • glProgramUniformMatrix4x2fv() 関数は、シェーダープログラムがアクティブになっている場合にのみ呼び出す必要があります。
  • OpenGL の詳細については、OpenGL ドキュメントを参照してください。


シェーダープログラム (vertex.glsl)

#version 130

layout (location = 0) in vec2 position;
layout (location = 1) in vec2 texCoord;

uniform mat4x2 transform;

out vec2 outTexCoord;

void main() {
    outTexCoord = transform * texCoord;
    gl_Position = vec4(position, 0.0, 1.0);
}

シェーダープログラム (fragment.glsl)

#version 130

uniform sampler2D texture;

in vec2 outTexCoord;

out vec4 fragColor;

void main() {
    fragColor = texture(texture, outTexCoord);
}

Qt ウィジェット (main.cpp)

#include <QApplication>
#include <QOpenGLWidget>
#include <QPainter>

class MyWidget : public QOpenGLWidget {
public:
    MyWidget() {
        setFixedSize(256, 256);
    }

protected:
    void initializeGL() override {
        // シェーダープログラムをコンパイルしてリンクする
        program = new QOpenGLShaderProgram;
        program->addShaderFromSourceFile(QOpenGLShader::Vertex, "vertex.glsl");
        program->addShaderFromSourceFile(QOpenGLShader::Fragment, "fragment.glsl");
        if (!program->link()) {
            qWarning() << "Failed to link shader program";
            return;
        }

        // テクスチャをロードする
        texture = new QOpenGLTexture(QImage("texture.png"));
        if (!texture->isCreated()) {
            qWarning() << "Failed to load texture";
            return;
        }

        // ユニフォーム変数を見つける
        transformLocation = program->uniformLocation("transform");
        if (transformLocation == -1) {
            qWarning() << "Failed to find uniform variable transform";
            return;
        }
    }

    void paintGL() override {
        // シェーダープログラムを有効にする
        program->bind();

        // テクスチャをバインドする
        texture->bind(0);

        // テクスチャ座標変換行列を作成する
        GLfloat matrix[4][2] = {
            { 1.0f, 0.0f },
            { 0.0f, 1.0f },
            { 0.5f, 0.5f },
            { 0.0f, 0.0f }
        };

        // テクスチャ座標変換行列をアップロードする
        glUniformMatrix4x2fv(transformLocation, 1, GL_FALSE, matrix);

        // 四角形を描画する
        glBegin(GL_QUADS);
        glVertex2f(-0.5f, -0.5f);
        glVertex2f( 0.5f, -0.5f);
        glVertex2f( 0.5f,  0.5f);
        glVertex2f(-0.5f,  0.5f);
        glEnd();

        // テクスチャを解除する
        texture->release();

        // シェーダープログラムを無効にする
        program->release();
    }

private:
    QOpenGLShaderProgram *program;
    QOpenGLTexture *texture;
    GLint transformLocation;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    MyWidget widget;
    widget.show();

    return app.exec();
}

この例では、transform という名前のユニフォーム変数を使用して、テクスチャ座標を 2D 変換しています。transformLocation 変数を使用して、シェーダープログラムでこのユニフォーム変数を見つけています。

例 2: 2D オブジェクトの投影変換

この例では、2D オブジェクトを投影変換するシェーダープログラムと、そのプログラムを使用する Qt ウィジェットを示します。

#version 130

layout (location = 0) in vec2 position;

uniform


glProgramUniformMatrix4x2fv() 関数は、シェーダープログラムオブジェクトとユニフォーム変数の名前に加えて、行列データを含むポインタを引数として受け取ります。

代替方法

glProgramUniformMatrix4x2fv() 関数の代替方法はいくつかあります。

  • glUniformMatrix4fv() 関数を使用する
    glUniformMatrix4fv() 関数は、4x4 行列をアップロードするために使用されます。4x2 行列をアップロードするには、次のように変換する必要があります。
GLfloat matrix4x2[4][4] = {
    { matrix[0][0], matrix[0][1], 0.0f, 0.0f },
    { matrix[1][0], matrix[1][1], 0.0f, 0.0f },
    { 0.0f, 0.0f, 1.0f, 1.0f },
    { 0.0f, 0.0f, 0.0f, 1.0f }
};

glUniformMatrix4fv(location, 1, GL_FALSE, matrix4x2);
  • QOpenGLShaderProgram::setUniformValue() メソッドを使用する
    QOpenGLShaderProgram::setUniformValue() メソッドは、ユニフォーム変数の値を設定するために使用できます。次のように使用できます。
QVector<GLfloat> matrixData(8);
for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 2; ++j) {
        matrixData[i * 2 + j] = matrix[i][j];
    }
}

program->setUniformValue(location, matrixData);

どちらの代替方法を選択するかは、状況によって異なります。 glUniformMatrix4fv() 関数は、よりシンプルですが、4x2 行列を 4x4 行列に変換する必要があります。QOpenGLShaderProgram::setUniformValue() メソッドは、より汎用性がありますが、コードが少し長くなります。

上記以外にも、次のような代替方法があります。

  • カスタムシェーダー関数を使用する
    カスタムシェーダー関数を作成して、4x2 行列を処理することができます。
  • QOpenGLShaderProgram::bindAttribute() メソッドを使用する
    QOpenGLShaderProgram::bindAttribute() メソッドを使用して、ユニフォーム変数に Vertex Buffer Object (VBO) をバインドできます。VBO には、4x2 行列データを含むことができます。
  • OpenGL の詳細については、OpenGL ドキュメントを参照してください。