Spec-Zone.ru › Qt 5.13

Класс QOpenGLWidget

Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL. Подробнее...

Заголовок: #include <QOpenGLWidget>
qmake: QT += widgets
С момента: Qt 5.4
Наследуется от: QWidget

Этот класс был представлен в Qt 5.4.

  • Список всех членов, включая наследуемые

Общие типы

Перечисление UpdateBehavior { NoPartialUpdate, PartialUpdate }

Общие функции

QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
виртуальный ~QOpenGLWidget()
QOpenGLContext * context() const
GLuint defaultFramebufferObject() const
void doneCurrent()
QSurfaceFormat format() const
QImage grabFramebuffer()
bool isValid() const
void makeCurrent()
void setFormat(const QSurfaceFormat &format)
void setTextureFormat(GLenum texFormat)
void setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)
GLenum textureFormat() const
QOpenGLWidget::UpdateBehavior updateBehavior() const

Сигналы

void aboutToCompose()
void aboutToResize()
void frameSwapped()
void resized()

Защищенные функции

виртуальный void initializeGL()
виртуальный void paintGL()
виртуальный void resizeGL(int w, int h)

Переопределенные защищенные функции

виртуальный void paintEvent(QPaintEvent *e) override
виртуальный void resizeEvent(QResizeEvent *e) override

Подробное описание

QOpenGLWidget предоставляет функциональность для отображения графики OpenGL, интегрированной в приложение Qt. Использовать его очень просто: сделайте свой класс наследником от него и используйте подкласс как любой другой QWidget, за исключением того, что у вас есть выбор между использованием QPainter и стандартными командами OpenGL.

QOpenGLWidget предоставляет три удобные виртуальные функции, которые вы можете переопределить в своем подклассе, чтобы выполнить типичные задачи OpenGL:

  • paintGL() — отрисовывает сцену OpenGL. Вызывается всякий раз, когда виджету требуется обновление.
  • resizeGL() — настраивает область OpenGL, проекцию и т.д. Вызывается всякий раз, когда виджет был изменен по размеру (а также при его первом показе, поскольку все недавно созданные виджеты автоматически получают событие изменения размера).
  • initializeGL() — настраивает ресурсы и состояние OpenGL. Вызывается один раз перед первым вызовом resizeGL() или paintGL().

Если вам нужно запустить перерисовку из мест, отличных от paintGL() (типичный пример — использование таймеров для анимации сцен), вы должны вызвать функцию update() виджета, чтобы запланировать обновление.

Контекст OpenGL вашего виджета становится текущим, когда вызывается paintGL(), resizeGL() или initializeGL(). Если вам нужно вызвать стандартные функции API OpenGL из других мест (например, в конструкторе вашего виджета или в собственных функциях рисования), вы должны сначала вызвать makeCurrent().

Вся отрисовка происходит в объекте буфера OpenGL. makeCurrent() гарантирует, что он связан в контексте. Помните об этом при создании и привязке дополнительных объектов буферов в коде отрисовки в paintGL(). Никогда не перепривязывайте буфер с идентификатором 0. Вместо этого используйте defaultFramebufferObject() для получения ID, который должен быть привязан.

QOpenGLWidget позволяет использовать различные версии и профили OpenGL, когда платформа их поддерживает. Просто установите требуемый формат через setFormat(). Однако помните, что наличие нескольких экземпляров QOpenGLWidget в одном окне требует, чтобы все они использовали один и тот же формат или, по крайней мере, форматы, которые не делают контексты несделяемыми. Чтобы решить эту проблему, используйте QSurfaceFormat::setDefaultFormat() вместо setFormat().

Примечание: Вызов QSurfaceFormat::setDefaultFormat() перед созданием экземпляра QApplication обязателен на некоторых платформах (например, macOS), когда запрашивается контекст OpenGL с ядром профиля. Это гарантирует, что совместное использование ресурсов между контекстами останется работоспособным, поскольку все внутренние контексты создаются с правильной версией и профилем.

Методы рисования

Как описано выше, подклассируйте QOpenGLWidget, чтобы отрисовать чисто 3D-содержимое следующим образом:

  • Переопределите функции initializeGL() и resizeGL() для настройки состояния OpenGL и обеспечения перспективной трансформации.
  • Переопределите paintGL(), чтобы нарисовать 3D-сцену, вызывая только функции OpenGL.

Также возможно рисовать 2D-графику на подклассе QOpenGLWidget с помощью QPainter:

  • В paintGL(), вместо выдачи команд OpenGL, создайте объект QPainter для использования на виджете.
  • Отрисовывайте примитивы с помощью функций члена QPainter.
  • Прямые команды OpenGL всё ещё могут быть выполнены. Однако вы должны убедиться, что они заключены в вызов beginNativePainting() и endNativePainting() художника.

При выполнении рисования только с помощью QPainter, также возможно выполнить рисование так же, как и для обычных виджетов: переопределив paintEvent().

  • Переопределите функцию paintEvent().
  • Создайте объект QPainter, ориентированный на виджет. Либо передайте виджет в конструктор, либо функцию QPainter::begin().
  • Отрисовывайте примитивы с помощью функций члена QPainter.
  • Рисование завершается, когда экземпляр QPainter уничтожается. В качестве альтернативы, явно вызовите QPainter::end().

Вызовы функций OpenGL, заголовки и QOpenGLFunctions

При выполнении вызовов функций OpenGL настоятельно рекомендуется избегать непосредственного обращения к функциям. Вместо этого предпочтительнее использовать QOpenGLFunctions (при создании переносимых приложений) или версионные варианты (например, QOpenGLFunctions_3_2_Core и аналогичные, при нацеливании на современные, только для настольных компьютеров OpenGL). Таким образом, приложение будет работать корректно во всех конфигурациях сборки Qt, включая те, которые выполняют динамическую загрузку реализации OpenGL, что означает, что приложения не связываются напрямую с реализацией GL, и поэтому прямые вызовы функций невозможны.

В paintGL() текущий контекст всегда доступен путем вызова QOpenGLContext::currentContext(). Из этого контекста можно получить уже инициализированный, готовый к использованию экземпляр QOpenGLFunctions, вызвав QOpenGLContext::functions(). Альтернативой префиксации каждого вызова GL является наследование от QOpenGLFunctions и вызов QOpenGLFunctions::initializeOpenGLFunctions() в initializeGL().

Что касается заголовков OpenGL, обратите внимание, что в большинстве случаев нет необходимости напрямую включать какие-либо заголовки, такие как GL.h. Заголовки Qt, относящиеся к OpenGL, включат qopengl.h, который, в свою очередь, включит соответствующий заголовок для системы. Это может быть заголовок OpenGL ES 3.x или 2.0, самая последняя доступная версия, или системный заголовок gl.h. Кроме того, копия заголовков расширений (называемая glext.h на некоторых системах) предоставляется в Qt как для OpenGL, так и для OpenGL ES. Они будут включаться автоматически на платформах, где это возможно. Это означает, что константы и определения типов указателей функций из расширений ARB, EXT, OES автоматически доступны.

Примеры кода

Для начала, самый простой подкласс QOpenGLWidget может выглядеть следующим образом:

class MyGLWidget : public QOpenGLWidget
{
public:
    MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { }

protected:
    void initializeGL() override
    {
        // Set up the rendering context, load shaders and other resources, etc.:
        QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
        f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        ...
    }

    void resizeGL(int w, int h) override
    {
        // Update projection matrix and other size related settings:
        m_projection.setToIdentity();
        m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);
        ...
    }

    void paintGL() override
    {
        // Draw the scene:
        QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
        f->glClear(GL_COLOR_BUFFER_BIT);
        ...
    }

};

В качестве альтернативы, можно избежать префиксации каждого вызова OpenGL, унаследовав от QOpenGLFunctions вместо этого:

class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    ...
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(...);
        ...
    }
    ...
};

Чтобы получить контекст, совместимый с заданной версией или профилем OpenGL, или чтобы запросить буферы глубины и трафарета, вызовите setFormat():

QOpenGLWidget *widget = new QOpenGLWidget(parent);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
widget->setFormat(format); // must be called before the widget or its parent window gets shown

С контекстами OpenGL 3.0+, когда переносимость не важна, версионные варианты QOpenGLFunctions обеспечивают легкий доступ ко всем современным функциям OpenGL, доступным в данной версии:

    ...
    void paintGL() override
    {
        QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
        ...
        f->glDrawArraysInstanced(...);
        ...
    }
    ...

Как описано выше, проще и надежнее установить запрашиваемый формат глобально, чтобы он применялся ко всем окнам и контекстам в течение всего срока службы приложения. Ниже приведен пример этого:

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

    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setVersion(3, 2);
    format.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(format);

    MyWidget widget;
    widget.show();

    return app.exec();
}

Отношение к QGLWidget

Модуль QtOpenGL устаревшей версии (классы с префиксом QGL) предоставляет виджет под названием QGLWidget. QOpenGLWidget призван быть современным заменителем для него. Поэтому, особенно в новых приложениях, рекомендуется использовать QOpenGLWidget.

Хотя API очень похож, между двумя классами есть важное различие: QOpenGLWidget всегда рендерит вне экрана, используя объекты фреймбуфера. С другой стороны, QGLWidget использует родное окно и поверхность. Последнее вызывает проблемы при использовании в сложных пользовательских интерфейсах, так как в зависимости от платформы такие родные дочерние виджеты могут иметь различные ограничения, например, относительно порядков стекирования. QOpenGLWidget избегает этого, не создавая отдельного родного окна.

Благодаря поддержке объекта фреймбуфера, поведение QOpenGLWidget очень похоже на QOpenGLWindow с поведением обновления, установленным в PartialUpdateBlit или PartialUpdateBlend. Это означает, что содержимое сохраняется между вызовами paintGL(), что позволяет выполнять инкрементное рендерирование. С QGLWidget (и, естественно, QOpenGLWindow с поведением обновления по умолчанию) это обычно не так, потому что обмен буферами оставляет задний буфер с неопределенным содержимым.

Примечание: Большинству приложений не требуется инкрементное рендерирование, поскольку они будут рендерить все в представлении при каждом вызове paint. В этом случае важно вызвать glClear() как можно раньше в paintGL(). Это помогает мобильным графическим процессорам, использующим архитектуру на основе плиток, распознать, что буфер плитки не нужно перезагружать с предыдущим содержимым фреймбуфера. Пропуск вызова clear может привести к значительным потерям производительности на таких системах.

Примечание: Избегайте вызова winId() для QOpenGLWidget. Эта функция запускает создание родного окна, что приводит к снижению производительности и, возможно, артефактам рендеринга.

Отличия от QGLWidget

Помимо основного концептуального различия, связанного с поддержкой объекта фреймбуфера, существует ряд небольших внутренних различий между QOpenGLWidget и более старым QGLWidget:

  • Состояние OpenGL при вызове paintGL(). QOpenGLWidget настраивает viewport с помощью glViewport(). Он не выполняет никаких очисток.
  • Очистка при запуске рисования с помощью QPainter. В отличие от обычных виджетов, QGLWidget по умолчанию имел значение true для autoFillBackground. Затем он выполнял очистку до фонового цвета палитры каждый раз, когда использовался QPainter::begin(). QOpenGLWidget не следует этому: autoFillBackground по умолчанию имеет значение false, как и для любого другого виджета. Исключением является использование в качестве области просмотра для других виджетов, таких как QGraphicsView. В таком случае autoFillBackground будет автоматически установлен в значение true, чтобы обеспечить совместимость с областями просмотра на основе QGLWidget.

Многократная выборка

Чтобы включить многократную выборку, установите количество запрашиваемых выборок в QSurfaceFormat, который передается в setFormat(). На системах, которые не поддерживают это, запрос может быть проигнорирован.

Поддержка многократной выборки требует поддержки многократной выборки renderbuffers и фреймбуфера blits. На реализациях OpenGL ES 2.0, скорее всего, этих функций не будет. Это означает, что многократная выборка будет недоступна. Современные версии OpenGL и OpenGL ES 3.0 и выше обычно не вызывают этой проблемы.

Потоки

Поддерживается выполнение рендеринга вне экрана в потоках задач, например, для генерации текстур, которые затем используются в GUI/главном потоке в paintGL(), путем экспонирования QOpenGLContext виджета, чтобы можно было создавать дополнительные контексты, использующие совместное использование с ним, в каждом потоке.

Рисование непосредственно в фреймбуфер QOpenGLWidget вне GUI/главного потока возможно путем переопределения paintEvent() на пустую функцию. Необходимо изменить аффинити потока контекста с помощью QObject::moveToThread(). После этого makeCurrent() и doneCurrent() могут быть использованы в потоке задач. Следите за тем, чтобы вернуть контекст в GUI/главный поток после этого.

В отличие от QGLWidget, не представляется возможным выполнить обмен буферами только для QOpenGLWidget, так как для него нет реальной, отображаемой родной поверхности. Вместо этого управление композицией и обменом буферов в потоке GUI возлагается на стеки виджетов. Когда поток задач закончит обновление фреймбуфера, вызовите update() в GUI/главном потоке для планирования композиции.

Необходимо проявлять особую осторожность, чтобы избежать использования фреймбуфера, когда GUI/главный поток выполняет композицию. Сигналы aboutToCompose() и frameSwapped() будут отправляться при запуске и завершении композиции. Они отправляются в GUI/главном потоке. Это означает, что с помощью прямой связи aboutToCompose() может заблокировать GUI/главный поток, пока поток задач не завершит рендеринг. После этого поток задач не должен выполнять дальнейшего рендеринга до отправки сигнала frameSwapped(). Если это неприемлемо, поток задач должен реализовать механизм двойного буферирования. Это включает рисование с использованием альтернативной области рендеринга, полностью контролируемой потоком, например, дополнительного объекта фреймбуфера, и копирования в фреймбуфер QOpenGLWidget в подходящее время.

Совместное использование контекста

Когда несколько QOpenGLWidgets добавляются как дочерние элементы к одному верхнему виджету, их контексты будут совместно использовать ресурсы друг с другом. Это не относится к экземплярам QOpenGLWidget, которые принадлежат разным окнам.

Это означает, что все QOpenGLWidgets в одном окне могут обращаться к общим ресурсам друг друга, например, к текстурам, и нет необходимости в дополнительном «глобальном контексте совместного использования», как это было в случае с QGLWidget.

Чтобы настроить совместное использование между экземплярами QOpenGLWidget, принадлежащими различным окнам, установите атрибут приложения Qt::AA_ShareOpenGLContexts до создания QApplication. Это позволит производить совместное использование всех экземпляров QOpenGLWidget без дополнительных шагов.

Также возможно создание дополнительных экземпляров QOpenGLContext, которые совместно используют ресурсы, такие как текстуры, с контекстом QOpenGLWidget. Просто передайте указатель, возвращаемый функцией context(), в QOpenGLContext::setShareContext() перед вызовом QOpenGLContext::create(). Результирующий контекст также может быть использован в другом потоке, что позволяет производить генерацию текстур и асинхронные загрузки текстур в потоках.

Обратите внимание, что QOpenGLWidget ожидает стандартной реализации совместного использования ресурсов, когда речь идет об основных графических драйверах. Например, некоторые драйверы, в частности, для мобильных и встраиваемых устройств, имеют проблемы с настройкой совместного использования между существующим контекстом и другими, созданными позже. Некоторые другие драйверы могут вести себя неожиданным образом при попытке использовать общие ресурсы между различными потоками.

Инициализация и очистка ресурсов

В ассоциированном с QOpenGLWidget контексте OpenGL гарантируется текущее состояние всякий раз, когда вызываются initializeGL() и paintGL(). Не пытайтесь создавать ресурсы OpenGL до вызова initializeGL(). Например, попытка компиляции шейдеров, инициализации объектов буфера вершин или загрузки данных текстуры завершится ошибкой, если выполняется в конструкторе подкласса. Эти операции должны быть отложены до initializeGL(). Некоторые вспомогательные классы Qt для OpenGL, такие как QOpenGLBuffer или QOpenGLVertexArrayObject, обладают аналогичным отложенным поведением: их можно создать без контекста, но вся инициализация откладывается до вызова create() или подобного. Это означает, что они могут использоваться как обычные (не указатели) члены данных в подклассе QOpenGLWidget, но функция create() или подобная может вызываться только из initializeGL(). Однако имейте в виду, что не все классы спроектированы таким образом. В случае сомнений сделайте член данных указателем и создайте и уничтожьте экземпляр динамически в initializeGL() и деструкторе соответственно.

Освобождение ресурсов также требует, чтобы контекст был текущим. Поэтому ожидается, что деструкторы, выполняющие подобную очистку, вызовут makeCurrent() перед уничтожением любых ресурсов OpenGL или обёртки. Избегайте отложенного удаления с помощью deleteLater() или механизма наследования от QObject. Нет гарантии, что правильный контекст будет текущим в момент фактического уничтожения экземпляра.

Типичный подкласс, следовательно, часто выглядит следующим образом, когда дело доходит до инициализации и уничтожения ресурсов:

class MyGLWidget : public QOpenGLWidget
{
    ...

private:
    QOpenGLVertexArrayObject m_vao;
    QOpenGLBuffer m_vbo;
    QOpenGLShaderProgram *m_program;
    QOpenGLShader *m_shader;
    QOpenGLTexture *m_texture;
};

MyGLWidget::MyGLWidget()
    : m_program(0), m_shader(0), m_texture(0)
{
    // No OpenGL resource initialization is done here.
}

MyGLWidget::~MyGLWidget()
{
    // Make sure the context is current and then explicitly
    // destroy all underlying OpenGL resources.
    makeCurrent();

    delete m_texture;
    delete m_shader;
    delete m_program;

    m_vbo.destroy();
    m_vao.destroy();

    doneCurrent();
}

void MyGLWidget::initializeGL()
{
    m_vao.create();
    if (m_vao.isCreated())
        m_vao.bind();

    m_vbo.create();
    m_vbo.bind();
    m_vbo.allocate(...);

    m_texture = new QOpenGLTexture(QImage(...));

    m_shader = new QOpenGLShader(...);
    m_program = new QOpenGLShaderProgram(...);

    ...
}

Это, естественно, не единственное возможное решение. Альтернативой является использование сигнала aboutToBeDestroyed() объекта QOpenGLContext. Подключившись к слоту, используя прямое подключение, к этому сигналу, можно выполнить очистку всякий раз, когда будет освобождён базовый обработчик нативного контекста или весь экземпляр QOpenGLContext. Следующий фрагмент кода в принципе эквивалентен предыдущему:

void MyGLWidget::initializeGL()
{
    // context() and QOpenGLContext::currentContext() are equivalent when called from initializeGL or paintGL.
    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup);
}

void MyGLWidget::cleanup()
{
    makeCurrent();
    delete m_texture;
    m_texture = 0;
    ...
    doneCurrent();
}

Примечание: Для виджетов, которые многократно меняют свою ассоциированную верхнюю окно в течение своего жизненного цикла, необходим комбинированный подход. Всякий раз, когда виджет или его родитель меняет родителя таким образом, что верхнее окно становится другим, ассоциированный с виджетом контекст уничтожается, и создаётся новый. За этим следует вызов initializeGL(), где все ресурсы OpenGL должны быть повторно инициализированы. По этой причине единственный способ выполнить правильную очистку — подключиться к сигналу aboutToBeDestroyed() контекста. Обратите внимание, что контекст, о котором идёт речь, может не быть текущим в момент отправки сигнала. Поэтому рекомендуется вызвать makeCurrent() в подключённом слоте. Кроме того, те же шаги очистки должны выполняться из деструктора производного класса, так как слот, подключённый к сигналу, не будет вызван при уничтожении виджета.

Примечание: Когда установлено Qt::AA_ShareOpenGLContexts, контекст виджета никогда не меняется, даже при изменении родителя, так как связанная с виджетом текстура гарантированно доступна и из контекста нового верхнего окна.

Правильная очистка особенно важна из-за совместного использования контекстов. Хотя контекст, связанный с каждым QOpenGLWidget, уничтожается вместе с QOpenGLWidget, общие ресурсы в этом контексте, такие как текстуры, останутся действительными до тех пор, пока не будет уничтожено верхнее окно, в котором существовал QOpenGLWidget. Кроме того, настройки, такие как Qt::AA_ShareOpenGLContexts и некоторые модули Qt, могут привести к ещё более широкому охвату совместного использования контекстов, потенциально сохраняя ресурсы в вопросе на протяжении всего жизненного цикла приложения. Поэтому самый безопасный и надёжный способ — всегда выполнять явную очистку всех ресурсов и обёртки ресурсов, используемых в QOpenGLWidget.

Ограничения

Размещение других виджетов под QOpenGLWidget и придание ему прозрачности не приведёт к ожидаемым результатам: виджеты под ним не будут видны. Это связано с тем, что на практике QOpenGLWidget отрисовывается до всех других обычных (не OpenGL) виджетов, и поэтому решения типа «прозрачности» невозможны. Другие типы макетов, такие как расположение виджетов поверх QOpenGLWidget, будут работать как ожидается.

В случае крайней необходимости это ограничение можно обойти, установив атрибут Qt::WA_AlwaysStackOnTop для QOpenGLWidget. Однако имейте в виду, что это нарушает порядок стека, например, не будет возможности разместить другие виджеты поверх QOpenGLWidget, поэтому его следует использовать только в ситуациях, когда требуется полупрозрачный QOpenGLWidget с другими виджетами, видимыми под ним.

Обратите внимание, что это не относится к случаям, когда нет других виджетов под ним и целью является полупрозрачное окно. В этом случае достаточно традиционного подхода — установить Qt::WA_TranslucentBackground для верхнего окна. Обратите внимание, что если прозрачные области требуются только в QOpenGLWidget, то Qt::WA_NoSystemBackground нужно вернуть к false после включения Qt::WA_TranslucentBackground. Кроме того, в зависимости от системы, может потребоваться запросить альфа-канал для контекста QOpenGLWidget через setFormat().

QOpenGLWidget поддерживает несколько режимов обновления, как и QOpenGLWindow. В режиме сохранения содержимое, отрисованное в предыдущем вызове paintGL(), доступно в следующем, что позволяет выполнять инкрементальную отрисовку. В режиме без сохранения содержимое теряется, и реализации paintGL() должны перерисовывать всё в представлении.

До Qt 5.5 поведение по умолчанию QOpenGLWidget заключалось в сохранении отрисованного содержимого между вызовами paintGL(). Начиная с Qt 5.5, поведение по умолчанию — без сохранения, так как это обеспечивает лучшую производительность, и большинство приложений не нуждается в предыдущем содержимом. Это также соответствует семантике OpenGL-based QWindow и соответствует поведению по умолчанию QOpenGLWindow, при котором цветовой и вспомогательные буферы аннулируются для каждого кадра. Чтобы восстановить поведение сохранения, вызовите setUpdateBehavior() со значением PartialUpdate.

Альтернативы

Добавление QOpenGLWidget в окно включает OpenGL-композитинг для всего окна. В некоторых особых случаях это может быть нежелательно, и требуется поведение старого QGLWidget со своим отдельным нативным дочерним окном. Приложения для настольных компьютеров, понимающие ограничения этого подхода (например, когда речь идёт о перекрытиях, прозрачности, прокрутке и областях MDI), могут использовать QOpenGLWindow с QWidget::createWindowContainer(). Это современная альтернатива QGLWidget и быстрее, чем QOpenGLWidget из-за отсутствия дополнительного шага композитинга. Сильно рекомендуется ограничить использование этого подхода случаями, когда нет другого выбора. Обратите внимание, что этот вариант не подходит для большинства встроенных и мобильных платформ, и известно о проблемах на определённых платформах настольных ПК (например, macOS). Стабильное кроссплатформенное решение — всегда QOpenGLWidget.

OpenGL — товарный знак Silicon Graphics, Inc. в США и других странах.

См. также QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts и UpdateBehavior.

Документация типов членов

перечисление QOpenGLWidget::UpdateBehavior

Это перечисление описывает семантику обновления QOpenGLWidget.

Постоянная Значение Описание
QOpenGLWidget::NoPartialUpdate 0 QOpenGLWidget удалит содержимое цветового буфера и вспомогательных буферов после отрисовки QOpenGLWidget на экран. Это такое же поведение, которое можно ожидать, вызвав QOpenGLContext::swapBuffers с QWindow в качестве аргумента, с включённым OpenGL. NoPartialUpdate может иметь преимущества производительности на некоторых аппаратных архитектурах, распространённых в мобильных и встроенных системах, когда буфер фреймбуфера используется в качестве целевой области отрисовки. Буфер фреймбуфера аннулируется между кадрами с помощью glDiscardFramebufferEXT, если это поддерживается, или glClear. Подробнее см. документацию по EXT_discard_framebuffer: https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt
QOpenGLWidget::PartialUpdate 1 Цветовой буфер и вспомогательные буферы объектов фреймбуфера не аннулируются между кадрами.

Это перечисление было введено или изменено в Qt 5.5.

См. также updateBehavior() и setUpdateBehavior().

Документация функций членов

QOpenGLWidget::QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())

Создаёт виджет, который является дочерним элементом parent, со значениями флагов виджета, установленными в f.

[signal] void QOpenGLWidget::aboutToCompose()

Этот сигнал генерируется, когда верхнее окно виджета собирается начать композицию текстур его дочерних элементов QOpenGLWidget и других виджетов.

[signal] void QOpenGLWidget::aboutToResize()

Этот сигнал испускается, когда изменяется размер виджета, и поэтому объект буфера кадра собирается пересоздать.

[signal] void QOpenGLWidget::frameSwapped()

Этот сигнал испускается после того, как верхнее окно виджета завершило композицию и вернулось из потенциально блокирующего вызова QOpenGLContext::swapBuffers().

[signal] void QOpenGLWidget::resized()

Этот сигнал испускается сразу после пересоздания объекта буфера кадра из-за изменения размера виджета.

[virtual] QOpenGLContext::~QOpenGLWidget()

Уничтожает экземпляр QOpenGLWidget, освобождая его ресурсы.

Контекст QOpenGLWidget устанавливается текущим в деструкторе, что позволяет безопасно уничтожить любой дочерний объект, которому может потребоваться освободить ресурсы OpenGL, принадлежащие контексту, предоставляемому этим виджетом.

Предупреждение: если у вас есть объекты, обертывающие ресурсы OpenGL (такие как QOpenGLBuffer, QOpenGLShaderProgram и т. д.) в качестве членов подкласса OpenGLWidget, вам может потребоваться добавить вызов makeCurrent() и в деструкторе этого подкласса. Из-за правил уничтожения объектов C++ эти объекты будут уничтожены до вызова этой функции (но после того, как будет выполнен деструктор подкласса), поэтому установка контекста OpenGL в текущий в этой функции происходит слишком поздно для их безопасного удаления.

См. также makeCurrent.

QOpenGLContext *QOpenGLWidget::context() const

Возвращает QOpenGLContext, используемый этим виджетом, или 0 если он еще не инициализирован.

Примечание: Контекст и объект буфера кадра, используемые виджетом, изменяются при изменении родительского виджета с помощью setParent().

См. также QOpenGLContext::setShareContext() и defaultFramebufferObject().

GLuint QOpenGLWidget::defaultFramebufferObject() const

Возвращает дескриптор объекта буфера кадра или 0 если он еще не инициализирован.

Примечание: Объект буфера кадра принадлежит контексту, возвращаемому context(), и может быть недоступен из других контекстов.

Примечание: Контекст и объект буфера кадра, используемые виджетом, изменяются при изменении родительского виджета с помощью setParent(). Кроме того, объект буфера кадра изменяется при каждом изменении размера.

См. также context().

void QOpenGLWidget::doneCurrent()

Освобождает контекст.

В большинстве случаев вызывать эту функцию не нужно, так как виджет позаботится о том, чтобы контекст был привязан и освобождён должным образом при вызове paintGL().

QSurfaceFormat QOpenGLWidget::format() const

Возвращает контекст и формат поверхности, используемые этим виджетом и его верхним окном.

После создания виджета и его верхнего окна, изменения размера и отображения, эта функция вернёт фактический формат контекста. Он может отличаться от запрошенного формата, если платформа не смогла выполнить запрос. Также возможно получить большие размеры буфера цвета, чем запрошенное.

Когда окно виджета и связанные ресурсы OpenGL ещё не инициализированы, возвращаемое значение — формат, который был задан через setFormat().

См. также setFormat() и context().

QImage QOpenGLWidget::grabFramebuffer()

Отрисовывает и возвращает 32-битное RGB изображение буфера кадра.

Примечание: Это потенциально дорогостоящая операция, так как она полагается на glReadPixels() для считывания пикселей. Это может быть медленно и может остановить конвейер обработки GPU.

[virtual protected] void QOpenGLWidget::initializeGL()

Эта виртуальная функция вызывается один раз перед первым вызовом paintGL() или resizeGL(). Переопределите её в подклассе.

Эта функция должна настроить все необходимые ресурсы и состояние OpenGL.

Вызывать makeCurrent() не нужно, так как это уже сделано при вызове этой функции. Однако обратите внимание, что буфер кадра ещё недоступен на этом этапе, поэтому избегайте выдачи команд отрисовки отсюда. Отложите такие вызовы до paintGL().

См. также paintGL() и resizeGL().

bool QOpenGLWidget::isValid() const

Возвращает true, если виджет и ресурсы OpenGL, такие как контекст, были успешно инициализированы. Обратите внимание, что возвращаемое значение всегда false до тех пор, пока виджет не будет показан.

void QOpenGLWidget::makeCurrent()

Подготавливает отрисовку контента OpenGL для этого виджета, устанавливая соответствующий контекст текущим и связывая объект буфера кадра в этом контексте.

В большинстве случаев вызывать эту функцию не нужно, так как она вызывается автоматически перед вызовом paintGL().

См. также context(), paintGL() и doneCurrent().

[override virtual protected] void QOpenGLWidget::paintEvent(QPaintEvent *e)

Переопределяет: QWidget::paintEvent(QPaintEvent *event).

Обрабатывает события рисования.

Вызов QWidget::update() приведёт к отправке события рисования e, а значит вызову этой функции. (Обратите внимание, что это асинхронно и произойдёт в какой-то момент после возвращения из update()). Эта функция затем, после некоторой подготовки, вызовет виртуальную paintGL(), чтобы обновить содержимое буфера кадра QOpenGLWidget. После этого верхнее окно виджета объединит текстуру буфера кадра с остальной частью окна.

[virtual protected] void QOpenGLWidget::paintGL()

Эта виртуальная функция вызывается всякий раз, когда виджет нужно перерисовать. Переопределите её в подклассе.

Вызывать makeCurrent() не нужно, так как это уже сделано при вызове этой функции.

Перед вызовом этой функции контекст и буфер кадра привязываются, и область просмотра настраивается вызовом glViewport(). Никакие другие состояния не устанавливаются, и никаких действий по очистке или отрисовке фреймворком не выполняется.

См. также initializeGL() и resizeGL().

[override virtual protected] void QOpenGLWidget::resizeEvent(QResizeEvent *e)

Переопределяет: QWidget::resizeEvent(QResizeEvent *event).

Обрабатывает события изменения размера, переданные в параметре события e. Вызывает виртуальную функцию resizeGL().

Примечание: Избегайте переопределения этой функции в производных классах. Если это не представляется возможным, убедитесь, что реализация QOpenGLWidget также вызывается. В противном случае подлежащий буфер кадра и связанные ресурсы не будут должным образом изменены в размерах, что приведёт к неправильной отрисовке.

[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)

Эта виртуальная функция вызывается всякий раз, когда виджет изменяется в размерах. Переопределите её в подклассе. Новый размер передаётся в w и h.

Вызывать makeCurrent() не нужно, так как это уже сделано при вызове этой функции. Кроме того, буфер кадра также привязан.

См. также initializeGL() и paintGL().

void QOpenGLWidget::setFormat(const QSurfaceFormat &format)

Устанавливает запрашиваемый формат поверхности format.

Если формат не задан явно через эту функцию, будет использован формат, возвращаемый QSurfaceFormat::defaultFormat(). Это означает, что при наличии нескольких виджетов OpenGL отдельные вызовы этой функции могут быть заменены одним вызовом QSurfaceFormat::setDefaultFormat() перед созданием первого виджета.

Примечание: Запрос буфера альфа-канала через эту функцию не приведёт к желаемому результату, если цель состоит в том, чтобы сделать другие виджеты снизу видимыми. Вместо этого используйте Qt::WA_AlwaysStackOnTop, чтобы сделать полупрозрачные экземпляры QOpenGLWidget с другими виджетами, видимыми под ними. Однако имейте в виду, что это нарушает порядок стека, поэтому больше не будет возможности разместить другие виджеты поверх QOpenGLWidget.

См. также format(), Qt::WA_AlwaysStackOnTop и QSurfaceFormat::setDefaultFormat().

void QOpenGLWidget::setTextureFormat(GLenum texFormat)

Устанавливает пользовательский внутренний формат текстуры texFormat.

При работе с буферами кадра sRGB потребуется указать формат, например, GL_SRGB8_ALPHA8. Этого можно добиться, вызвав эту функцию.

Примечание: Эта функция не имеет эффекта, если вызвана после того, как виджет уже был показан и, следовательно, выполнил инициализацию.

Примечание: Эта функция обычно должна использоваться в сочетании с вызовом QSurfaceFormat::setDefaultFormat(), который устанавливает цветовое пространство в QSurfaceFormat::sRGBColorSpace.

Эта функция была добавлена в Qt 5.10.

См. также textureFormat().

void QOpenGLWidget::setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)

Устанавливает поведение обновления этого виджета в updateBehavior.

Эта функция была добавлена в Qt 5.5.

См. также updateBehavior().

GLenum QOpenGLWidget::textureFormat() const

Возвращает активный внутренний формат текстуры, если виджет уже инициализирован, запрошенный формат, если он был установлен, но виджет ещё не виден, или nullptr если setTextureFormat() не вызывалась, и виджет ещё не виден.

Эта функция была добавлена в Qt 5.10.

См. также setTextureFormat().

QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const

Возвращает поведение обновления виджета.

Эта функция была добавлена в Qt 5.5.

См. также setUpdateBehavior().

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.13/qopenglwidget.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API