Класс 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() для получения идентификатора, который следует связать.
QOpenGLWidget позволяет использовать различные версии и профили OpenGL, когда платформа это поддерживает. Просто установите требуемый формат через setFormat(). Однако имейте в виду, что наличие нескольких экземпляров QOpenGLWidget в одном окне требует, чтобы все они использовали один и тот же формат или, по крайней мере, форматы, которые не делают контексты несовместимыми. Чтобы обойти эту проблему, предпочтительнее использовать QSurfaceFormat::setDefaultFormat() вместо setFormat().
Примечание: Вызов QSurfaceFormat::setDefaultFormat() перед построением экземпляра QApplication является обязательным на некоторых платформах (например, macOS) при запросе контекста профиля OpenGL core. Это необходимо для обеспечения работоспособности совместного использования ресурсов между контекстами, так как все внутренние контексты создаются с правильной версией и профилем.
Техники рисования
Как описано выше, подклассы 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, как и для любого другого виджета. Исключение составляет случай использования в качестве viewport для других виджетов, таких как QGraphicsView. В таком случае autoFillBackground будет автоматически установлен в значение true для обеспечения совместимости с viewport, основанными на QGLWidget.
Многократная выборка
Для включения многократной выборки установите количество запрашиваемых выборок в QSurfaceFormat, который передается в setFormat(). На системах, которые его не поддерживают, запрос может быть проигнорирован.
Поддержка многократной выборки требует поддержки многократных буферов рендеринга и блинтов фреймбуфера. В реализациях 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 ожидает стандартной реализации совместного использования ресурсов, когда речь идет об основных драйверах графики. Например, некоторые драйверы, особенно для мобильных и встраиваемых устройств, имеют проблемы с настройкой совместного использования между существующим контекстом и другими, созданными позже. Некоторые другие драйверы могут вести себя непредсказуемо при попытке использовать общие ресурсы между различными потоками.
Инициализация и очистка ресурсов
Ассоциированный контекст OpenGL для QOpenGLWidget гарантированно будет текущим всякий раз, когда вызываются 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 не приведет к ожидаемому результату: виджеты под ним не будут видны. Это происходит потому, что на практике QOpenGLWidget рисуется перед всеми другими обычными виджетами, не связанными с OpenGL, поэтому решения с прозрачностью не работают. Другие типы макетов, например, размещение виджетов поверх QOpenGLWidget, будут работать как ожидается.
В случае крайней необходимости это ограничение можно преодолеть, установив атрибут Qt::WA_AlwaysStackOnTop для QOpenGLWidget. Однако имейте в виду, что это нарушит порядок стека, например, невозможно будет разместить другие виджеты поверх 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-базированного 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] QOpenGLWidget::~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().
END_OF_DOCUMENT_MARKERvoid 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.14/qopenglwidget.html