Qt GUIで3Dプリミティブの境界ボックスを描画する:QOpenGLExtraFunctions::glPrimitiveBoundingBox()徹底解説


QOpenGLExtraFunctions::glPrimitiveBoundingBox()は、OpenGL ES 3.x、OpenGL 3.x、またはOpenGL 4.xコンテキストで使用できる関数で、3Dプリミティブの境界ボックスを描画するために使用されます。境界ボックスは、プリミティブを完全に囲む最小と最大の立方体です。

関数詳細

void QOpenGLExtraFunctions::glPrimitiveBoundingBox(
    GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW,
    GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW
);
  • maxW: 境界ボックスの最大幅
  • maxX, maxY, maxZ: 境界ボックスの最大座標(x, y, z)
  • minW: 境界ボックスの最小幅
  • minX, minY, minZ: 境界ボックスの最小座標(x, y, z)

使い方

  1. QOpenGLExtraFunctionsインスタンスを取得します。
  2. initializeOpenGLFunctions()を呼び出して、コンテキストを指定します。
  3. glPrimitiveBoundingBox()を呼び出して、境界ボックスの座標と幅を指定します。
QOpenGLExtraFunctions glFuncs(context);
glFuncs.initializeOpenGLFunctions();

// プリミティブを描画
...

// 境界ボックスを描画
glFuncs.glPrimitiveBoundingBox(-1.0f, -1.0f, -1.0f, 0.0f,
                             1.0f, 1.0f, 1.0f, 0.0f);
  • 境界ボックスは、デバッグや視覚化に役立ちます。
  • 境界ボックスのスタイルは、glLineWidth()glPolygonMode()などの関数で設定できます。
  • 境界ボックスの色は、glColorMaterial()glMaterial()などの関数で設定できます。
  • OpenGL ES、OpenGL 3.x、OpenGL 4.xの詳細については、OpenGL仕様を参照してください。
  • この説明は、Qt GUI 6.7.1を対象としています。他のバージョンでは、関数の名前や引数が異なる場合があります。


#include <QCoreApplication>
#include <QOpenGLWidget>

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

protected:
    void paintGL() override {
        QPainter painter;
        painter.begin(this);

        // OpenGLの設定
        glViewport(0, 0, width(), height());
        glEnable(GL_DEPTH_TEST);
        glShadeModel(GL_SMOOTH);

        // 立方体の描画
        glBegin(GL_QUADS);
            glVertex3f(-0.5f, -0.5f, -0.5f);
            glVertex3f( 0.5f, -0.5f, -0.5f);
            glVertex3f( 0.5f,  0.5f, -0.5f);
            glVertex3f(-0.5f,  0.5f, -0.5f);

            glVertex3f(-0.5f, -0.5f,  0.5f);
            glVertex3f( 0.5f, -0.5f,  0.5f);
            glVertex3f( 0.5f,  0.5f,  0.5f);
            glVertex3f(-0.5f,  0.5f,  0.5f);
        glEnd();

        // 境界ボックスの描画
        QOpenGLExtraFunctions glFuncs(context());
        glFuncs.initializeOpenGLFunctions();
        glFuncs.glPrimitiveBoundingBox(-1.0f, -1.0f, -1.0f, 0.0f,
                                     1.0f, 1.0f, 1.0f, 0.0f);

        // 赤色で境界ボックスを描画
        glColor3f(1.0f, 0.0f, 0.0f);

        painter.end();
    }
};

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

    MyWidget widget;
    widget.show();

    return app.exec();
}

このコードは、200x200ピクセルのウィンドウに赤い立方体を表示し、その境界ボックスを赤色で描画します。

例2: 円柱の境界ボックスを描画

#include <QCoreApplication>
#include <QOpenGLWidget>

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

protected:
    void paintGL() override {
        QPainter painter;
        painter.begin(this);

        // OpenGLの設定
        glViewport(0, 0, width(), height());
        glEnable(GL_DEPTH_TEST);
        glShadeModel(GL_SMOOTH);

        // 円柱の描画
        GLUquadric *quadric = gluNewQuadric();
        gluQuadricNormals(quadric, GLU_SMOOTH);

        gluCylinder(quadric, 0.5f, 0.5f, 2.0f);

        gluDeleteQuadric(quadric);

        // 境界ボックスの描画
        QOpenGLExtraFunctions glFuncs(context());
        glFuncs.initializeOpenGLFunctions();
        glFuncs.glPrimitiveBoundingBox(-0.5f, -1.0f, -0.5f, 0.0f,
                                     0.5f, 1.0f, 0.5f, 0.0f);

        // 緑色で境界ボックスを描画
        glColor3f(0.0f, 1.0f, 0.0f);

        painter.end();
    }
};

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

    MyWidget widget;
    widget.show();

    return app.exec();
}

このコードは、200x200ピクセルのウィンドウに緑色の円柱を表示し、その境界ボックスを緑色で描画します。

  • 上記のコードは、Qt Creator 6.4.2とQt 6.7.1


QOpenGLExtraFunctions::glPrimitiveBoundingBox()は、3Dプリミティブの境界ボックスを描画するための便利な関数ですが、いくつかの代替方法があります。

代替方法

  1. gluBox()関数を使用する:

    • 古典的なOpenGLライブラリであるGLUTのgluBox()関数を使用して、境界ボックスを描画できます。
    • gluBox()は、glPrimitiveBoundingBox()よりもシンプルで使いやすいですが、OpenGL ES 2.0以降ではサポートされていません。
    • GLUTライブラリを別途インストールする必要があります。
  2. カスタムシェーダーを使用する:

    • カスタムシェーダーを使用して、境界ボックスを描画できます。
    • カスタムシェーダーは、より柔軟性と制御性がありますが、複雑でコード量が多くなります。
    • シェーダープログラミングの知識が必要です。
  3. glPolygonMode()glColorMaterial()を使用する:

    • glPolygonMode()glColorMaterial()を使用して、プリミティブをワイヤーフレームモードで描画し、境界ボックスの色を設定できます。
    • この方法は、単純な境界ボックスを描画する場合に役立ちますが、複雑な形状には適していません。

各方法の比較

方法利点欠点
gluBox()シンプルで使いやすいOpenGL ES 2.0以降ではサポートされていない
カスタムシェーダー柔軟性と制御性が高い複雑でコード量が多い
glPolygonMode()glColorMaterial()シンプル複雑な形状には適していない

例1: gluBox()関数を使用する

#include <GL/glut.h>

void display() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // プリミティブを描画
    ...

    // 境界ボックスを描画
    gluBox(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f);

    glutSwapBuffers();
}

int main(int argc, char *argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(200, 200);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("OpenGL Example");

    glutDisplayFunc(display);

    glutMainLoop();

    return 0;
}

例2: カスタムシェーダーを使用する

#include <QCoreApplication>
#include <QOpenGLWidget>

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

protected:
    void initializeGL() override {
        // シェーダープログラムの初期化
        ...
    }

    void paintGL() override {
        QPainter painter;
        painter.begin(this);

        // OpenGLの設定
        glViewport(0, 0, width(), height());
        glEnable(GL_DEPTH_TEST);
        glShadeModel(GL_SMOOTH);

        // プリミティブを描画
        ...

        // カスタムシェーダーを使用して境界ボックスを描画
        glUseProgram(boundingBoxProgram);
        glUniformMatrix4fv(projectionLocation, 1, GL_FALSE, projectionMatrix.data());
        glUniformMatrix4fv(viewLocation, 1, GL_FALSE, viewMatrix.data());
        glUniformMatrix4fv(modelLocation, 1, GL_FALSE, modelMatrix.data());

        glDrawArrays(GL_QUADS, 0, 4);

        painter.end();
    }
};

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

    MyWidget widget;
    widget.show();

    return app.exec();
}
#include <QCoreApplication>
#include <QOpenGLWidget>

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

protected:
    void paintGL() override {
        QPainter painter;
        painter.begin(this);

        // OpenGLの設定