OpenGL ウィンドウの例
この例では、OpenGLを使用することを目的とした、QWindow をベースとした最小限のアプリケーションの作成方法を示します。

注:これは 、QWindow をOpenGLと組み合わせて使用する方法に関する低レベルの例です。実際には、より高レベルのQOpenGLWindow クラスの使用を検討すべきです。QOpenGLWindow 利便性クラスの実例については、「Hello GLES3」サンプルを参照してください。
OpenGLWindow スーパークラス
当プロジェクトの OpenGLWindow クラスは、実際のレンダリングを行うためのサブクラス化対象となる API として機能します。このクラスには、render() の呼び出しを要求する関数が用意されており、renderNow() を使用すれば即座に、renderLater() を使用すればイベントループが現在のイベントバッチの処理を完了した直後に呼び出しが行われます。 OpenGLWindowのサブクラスは、OpenGLベースのレンダリングを行うためにrender()を再実装するか、QPainter を使用したレンダリングを行うためにrender(QPainter *)を再実装することができます。基盤となるOpenGLドライバで垂直同期が有効になっている場合、render()が垂直リフレッシュレートで呼び出されるようにするには、OpenGLWindow::setAnimating(true)を使用してください。
OpenGLレンダリングを行うクラスでは、通常、OpenGLWindowがそうしているように、QOpenGLFunctions を継承することで、プラットフォームに依存しない形でOpenGL ES 2.0の関数にアクセスできるようにします。QOpenGLFunctions を継承することで、そこに含まれる OpenGL 関数が優先され、アプリケーションを OpenGL および OpenGL ES 2.0 の両方で動作させたい場合でも、それらの関数の解決について心配する必要がなくなります。
class OpenGLWindow : public QWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit OpenGLWindow(QWindow *parent = nullptr);
~OpenGLWindow();
virtual void render(QPainter *painter);
virtual void render();
virtual void initialize();
void setAnimating(bool animating);
public slots:
void renderLater();
void renderNow();
protected:
bool event(QEvent *event) override;
void exposeEvent(QExposeEvent *event) override;
private:
bool m_animating = false;
QOpenGLContext *m_context = nullptr;
QOpenGLPaintDevice *m_device = nullptr;
};ウィンドウのサーフェスタイプは、QSurface::OpenGLSurface に設定する必要があります。これにより、そのウィンドウがOpenGLレンダリングに使用されるものであり、QBackingStore を使用してQPainter でラスタコンテンツをレンダリングするためのものではないことが示されます。
OpenGLWindow::OpenGLWindow(QWindow *parent)
: QWindow(parent)
{
setSurfaceType(QWindow::OpenGLSurface);
}必要な OpenGL の初期化は、render() が最初に呼び出される前に 1 回呼び出される initialize() 関数をオーバーライドすることで実行できます。この際、有効な現在のQOpenGLContext を引数として渡す必要があります。 以下のコードスニペットからわかるように、デフォルトの render(QPainter *) および initialize() の実装は空ですが、デフォルトの render() の実装はQOpenGLPaintDevice を初期化し、その後 render(QPainter *) を呼び出します。
void OpenGLWindow::render(QPainter *painter)
{
Q_UNUSED(painter);
}
void OpenGLWindow::initialize()
{
}
void OpenGLWindow::render()
{
if (!m_device)
m_device = new QOpenGLPaintDevice;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
m_device->setSize(size() * devicePixelRatio());
m_device->setDevicePixelRatio(devicePixelRatio());
QPainter painter(m_device);
render(&painter);
}renderLater() 関数は、単にQWindow::requestUpdate() を呼び出し、システムが再描画の準備が整った時点で更新が行われるようスケジュールします。
また、エクスポーズイベントを受信した際にも renderNow() を呼び出します。exposeEvent() は、ウィンドウの画面上での露出状態(つまり可視性)が変化したことをウィンドウに通知するものです。エクスポーズイベントを受信した際、QWindow::isExposed() を呼び出すことで、ウィンドウが現在露出しているかどうかを確認できます。 ウィンドウが最初のエクスポーズイベントを受信するまでは、そのウィンドウへのレンダリングや `QOpenGLContext::swapBuffers()` の呼び出しを行わないでください。それ以前は、ウィンドウの最終的なサイズが不明である可能性があり、さらに、レンダリングされた内容が画面に表示されない可能性もあるためです。
void OpenGLWindow::renderLater()
{
requestUpdate();
}
bool OpenGLWindow::event(QEvent *event)
{
switch (event->type()) {
case QEvent::UpdateRequest:
renderNow();
return true;
default:
return QWindow::event(event);
}
}
void OpenGLWindow::exposeEvent(QExposeEvent *event)
{
Q_UNUSED(event);
if (isExposed())
renderNow();
}renderNow() では、現在エクスポーズ状態でない場合は処理を終了し、その場合は実際にエクスポーズイベントを受信するまでレンダリングを遅延させます。 まだ行っていない場合は、OpenGLWindowに設定されたものと同じQSurfaceFormat を使用してQOpenGLContext を作成し、サブクラスのためにinitialize()を呼び出し、QOpenGLFunctions スーパークラスが正しいQOpenGLContext に関連付けられるようにinitializeOpenGLFunctions()を呼び出します。 いずれの場合も、QOpenGLContext::makeCurrent()を呼び出してコンテキストを現在のものにし、render()を呼び出して実際のレンダリングを行い、最後にOpenGLWindowをパラメータとしてQOpenGLContext::swapBuffers()を呼び出して、レンダリングされた内容を表示するようにスケジュールします。
QOpenGLContext::makeCurrent() を呼び出し、レンダリング先のサーフェスをパラメータとして指定することで、OpenGL コンテキストを使用したフレームのレンダリングが開始されると、OpenGL コマンドを発行できるようになります。 コマンドは、システムの OpenGL ヘッダーもインクルードする <qopengl.h> をインクルードして直接発行することも、QOpenGLFunctions を使用して発行することもできます。 は、便宜上継承することも、QOpenGLContext::functions() を使用してアクセスすることもできます。QOpenGLFunctions は、OpenGL ES 2.0 およびデスクトップ OpenGL の両方で標準化されていない、OpenGL ES 2.0 レベルのすべての OpenGL 呼び出しへのアクセスを提供します。OpenGL および OpenGL ES API に関する詳細については、公式のOpenGL RegistryおよびKhronos OpenGL ES API Registry を参照してください。
OpenGLWindow::setAnimating(true) によってアニメーションが有効になっている場合は、renderLater() を呼び出して、別の更新要求をスケジュールします。
void OpenGLWindow::renderNow()
{
if (!isExposed())
return;
bool needsInitialize = false;
if (!m_context) {
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
needsInitialize = true;
}
m_context->makeCurrent(this);
if (needsInitialize) {
initializeOpenGLFunctions();
initialize();
}
render();
m_context->swapBuffers(this);
if (m_animating)
renderLater();
}アニメーションを有効にすると、次のコードスニペットに示すように、更新要求もスケジュールされます。
void OpenGLWindow::setAnimating(bool animating)
{
m_animating = animating;
if (animating)
renderLater();
}OpenGL レンダリングのサブクラス例
ここでは、回転する三角形をレンダリングするための OpenGL の使用方法を示すために、OpenGLWindow をサブクラス化しています。QOpenGLFunctions を間接的にサブクラス化することで、OpenGL ES 2.0 レベルのすべての機能にアクセスできるようになります。
class TriangleWindow : public OpenGLWindow
{
public:
using OpenGLWindow::OpenGLWindow;
void initialize() override;
void render() override;
private:
GLint m_matrixUniform = 0;
QOpenGLBuffer m_vbo;
QOpenGLShaderProgram *m_program = nullptr;
int m_frame = 0;
};main関数内で、QGuiApplication を初期化し、TriangleOpenGLWindowをインスタンス化します。マルチサンプルアンチエイリアシングを4サンプル行うことを指定するQSurfaceFormat と、デフォルトのジオメトリを指定します。アニメーションを実行したいので、前述のsetAnimating()関数を引数にtrueを指定して呼び出します。
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QSurfaceFormat format;
format.setSamples(16);
TriangleWindow window;
window.setFormat(format);
window.resize(640, 480);
window.show();
window.setAnimating(true);
return app.exec();
}以下のコードスニペットは、この例で使用されている OpenGL シェーダープログラムを示しています。頂点シェーダーとフラグメントシェーダーは比較的単純で、頂点変換と補間された頂点カラーリングを行っています。
static const char *vertexShaderSource = "attribute highp vec4 posAttr;\n"
"attribute lowp vec4 colAttr;\n"
"varying lowp vec4 col;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
" col = colAttr;\n"
" gl_Position = matrix * posAttr;\n"
"}\n";
static const char *fragmentShaderSource = "varying lowp vec4 col;\n"
"void main() {\n"
" gl_FragColor = col;\n"
"}\n";以下は、シェーダーを読み込み、シェーダープログラムを初期化するコードです。生のOpenGLの代わりにQOpenGLShaderProgram を使用することで、標準の一部ではないデスクトップOpenGLにおいて、highp、mediump、lowpの修飾子を自動的に削除するという利点があります。 各フレームごとにロケーションの検索を行う必要を避けるため、属性およびユニフォームのロケーションをメンバ変数に格納しています。
void TriangleWindow::initialize()
{
static const GLfloat vertices_colors[] = { +0.0f, +0.707f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.500f, 0.0f, 1.0f, 0.0f,
+0.5f, -0.500f, 0.0f, 0.0f, 1.0f };
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(vertices_colors, sizeof(vertices_colors));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), nullptr);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
reinterpret_cast<void *>(2 * sizeof(GLfloat)));
m_program = new QOpenGLShaderProgram(this);
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
m_program->bindAttributeLocation("posAttr", 0);
m_program->bindAttributeLocation("colAttr", 1);
m_program->link();
m_program->bind();
m_matrixUniform = m_program->uniformLocation("matrix");
Q_ASSERT(m_matrixUniform != -1);
}最後に、render() 関数を紹介します。ここでは、OpenGL を使用してビューポートを設定し、背景をクリアし、回転する三角形をレンダリングしています。
void TriangleWindow::render()
{
const qreal retinaScale = devicePixelRatio();
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
QMatrix4x4 matrix;
matrix.perspective(60.0f, 4.0f / 3.0f, 0.1f, 100.0f);
matrix.translate(0, 0, -2);
matrix.rotate(100.0f * m_frame / screen()->refreshRate(), 0, 1, 0);
m_program->setUniformValue(m_matrixUniform, matrix);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
m_program->release();
++m_frame;
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.