Qt GUIで3Dグラフィックスをレンダリング:QOpenGLExtraFunctions::glProgramUniform3fv()徹底解説


QOpenGLExtraFunctions::glProgramUniform3fv() 関数は、OpenGL Shading Language (GLSL) プログラム内の 3D 浮動小数点ベクトルユニフォーム変数の値を設定するために使用されます。これは、Qt GUI アプリケーションで 3D グラフィックスをレンダリングする場合に役立つ関数です。

関数詳細

void QOpenGLExtraFunctions::glProgramUniform3fv(
    GLuint program,
    GLint location,
    GLsizei count,
    const GLfloat *value
);
  • value: 設定するベクトル値の配列へのポインタです。各ベクトルは 3 つの浮動小数点値で構成されます。
  • count: 設定するベクトルの個数です。
  • location: ユニフォーム変数の場所を示す整数値です。これは、glGetUniformLocation() 関数を使用して取得できます。
  • program: ユニフォーム変数が属する GLSL プログラムの ID です。

使い方

QOpenGLExtraFunctions::glProgramUniform3fv() 関数は、次の手順で使用できます。

  1. QOpenGLExtraFunctions オブジェクトを作成します。
  2. initializeOpenGLFunctions() 関数を呼び出して、現在の OpenGL コンテキストを設定します。
  3. glProgramUniform3fv() 関数を呼び出して、ユニフォーム変数の値を設定します。

次のコードは、red, green, blue 変数を使用して fragmentShader プログラム内の uniformColor ユニフォーム変数の値を設定する方法を示しています。

QOpenGLExtraFunctions functions;
functions.initializeOpenGLFunctions();

GLuint program = ...; // GLSL プログラムの ID を取得
GLint uniformLocation = glGetUniformLocation(program, "uniformColor");

GLfloat red = 0.5f;
GLfloat green = 0.8f;
GLfloat blue = 0.2f;

functions.glProgramUniform3fv(program, uniformLocation, 1, &red);
  • ユニフォーム変数の値を設定する前に、glGetUniformLocation() 関数を使用してその場所を取得する必要があります。
  • 複数のベクトルを設定するには、count パラメータを適切な値に設定し、value パラメータをすべてのベクトル値を含む配列にポインタするようにする必要があります。
  • QOpenGLExtraFunctions::glProgramUniform3fv() 関数は、OpenGL ES 3.x、OpenGL 3.x または 4.x コンテキストでのみ使用できます。


例:立方体をレンダリングする

この例では、シンプルな立方体をレンダリングする Qt GUI アプリケーションを作成します。立方体の色は、red, green, blue 変数を使用して制御されます。

main.cpp

#include <QApplication>
#include <QGLWidget>
#include <QShader>

class GLWidget : public QGLWidget
{
public:
    GLWidget(QWidget *parent = nullptr);

protected:
    void initializeGL();
    void paintGL();

private:
    QShader *vertexShader;
    QShader *fragmentShader;
    GLuint program;

    GLfloat red;
    GLfloat green;
    GLfloat blue;
};

GLWidget::GLWidget(QWidget *parent) : QGLWidget(parent)
{
    red = 0.5f;
    green = 0.8f;
    blue = 0.2f;
}

void GLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    // 頂点シェーダーの作成
    vertexShader = new QShader(QShader::VertexShader);
    vertexShader->sourceFile("vertexShader.vert");
    vertexShader->compile();

    // フラグメントシェーダーの作成
    fragmentShader = new QShader(QShader::FragmentShader);
    fragmentShader->sourceFile("fragmentShader.frag");
    fragmentShader->compile();

    // シェーダープログラムの作成
    program = glCreateProgram();
    glAttachShader(program, vertexShader->shaderId());
    glAttachShader(program, fragmentShader->shaderId());
    glLinkProgram(program);

    // ユニフォーム変数の場所を取得
    GLint uniformLocation = glGetUniformLocation(program, "uniformColor");

    // ユニフォーム変数の値を設定
    QOpenGLExtraFunctions functions;
    functions.initializeOpenGLFunctions();
    functions.glProgramUniform3fv(program, uniformLocation, 1, &red);

    // 背景色の設定
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 深度テストを有効にする
    glEnable(GL_DEPTH_TEST);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(program);

    // 立方体の頂点データ
    const GLfloat vertices[] = {
        -0.5f, -0.5f, -0.5f,
        0.5f, -0.5f, -0.5f,
        0.5f, 0.5f, -0.5f,
        -0.5f, 0.5f, -0.5f,
        -0.5f, -0.5f, 0.5f,
        0.5f, -0.5f, 0.5f,
        0.5f, 0.5f, 0.5f,
        -0.5f, 0.5f, 0.5f
    };

    // 頂点バッファの作成
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 頂点属性の設定
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
    glEnableVertexAttribArray(0);

    // 三角形の描画
    glDrawArrays(GL_QUADS, 0, 8);
}

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

    GLWidget widget;
    widget.show();

    return app.exec();
}

vertexShader.vert

#version 330

layout (location = 0) in vec3 vertexPosition;

void main()
{
    gl_Position = vec4(vertexPosition, 1.0);
}
#version


代替方法

QOpenGLExtraFunctions::glProgramUniform3fv() 関数の代替方法として、以下の方法が考えられます。

  • glUniform3fv() 関数
    この関数は、OpenGL 3.x 以降のコンテキストで使用できます。QOpenGLExtraFunctions::initializeOpenGLFunctions() 関数を呼び出す必要はなく、よりシンプルなコードで済みます。
glUniform3fv(uniformLocation, 1, &red);
  • QUniformValue クラス
    このクラスは、ユニフォーム変数の値を保持するために使用できます。QUniformValue::setValue() メソッドを使用して値を設定し、QShaderProgram::setUniformValue() メソッドを使用してシェーダープログラムに設定できます。
QUniformValue uniformValue(red, green, blue);
shaderProgram->setUniformValue("uniformColor", uniformValue);

選択の指針

どの代替方法を選択するかは、状況によって異なります。

  • 互換性
    QOpenGLExtraFunctions::glProgramUniform3fv() 関数は、OpenGL 3.x 以前のコンテキストで使用できます。
  • シンプルさ
    glUniform3fv() 関数は最もシンプルで、コード量が少ないです。

上記以外にも、状況によっては以下の代替方法が考えられます。

  • glProgramUniform1fv() 関数
    1D 浮動小数点ベクトルのユニフォーム変数の値を設定するために使用できます。
  • glProgramUniform1i() 関数
    整数のユニフォーム変数の値を設定するために使用できます。
  • glProgramUniformMatrix4fv() 関数
    4x4 行列のユニフォーム変数の値を設定するために使用できます。
  • glProgramUniformMatrix3fv() 関数
    3x3 行列のユニフォーム変数の値を設定するために使用できます。