Класс QOpenGLWidget
Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL. Подробнее...
| Заголовок: | #include <QOpenGLWidget> |
| qmake: | QT += widgets |
| С тех пор: | Qt 5.4 |
| Наследует: | QWidget |
Общедоступные типы
| Перечисление | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
Общедоступные функции
| QOpenGLWidget(QWidget *parent = Q_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 | setUpdateBehavior(UpdateBehavior updateBehavior) |
| UpdateBehavior | updateBehavior() const |
- 214 общедоступных функций, унаследованных от QWidget
- 32 общедоступных функции, унаследованные от QObject
- 14 общедоступных функций, унаследованных от QPaintDevice
Сигналы
| void | aboutToCompose() |
| void | aboutToResize() |
| void | frameSwapped() |
| void | resized() |
Защищенные функции
| virtual void | initializeGL() |
| virtual void | paintGL() |
| virtual void | resizeGL(int w, int h) |
Переопределённые защищённые функции
| virtual void | paintEvent(QPaintEvent *e) |
| virtual void | resizeEvent(QResizeEvent *e) |
- 35 защищенных функций, унаследованных от QWidget
- 9 защищенных функций, унаследованных от QObject
- 1 защищенная функция, унаследованная от QPaintDevice
Дополнительные унаследованные члены
- 59 свойств, унаследованных от QWidget
- 1 свойство, унаследованное от QObject
- 19 общедоступных слотов, унаследованных от QWidget
- 1 общедоступный слот, унаследованный от QObject
- 5 статических общедоступных членов, унаследованных от QWidget
- 11 статических общедоступных членов, унаследованных от QObject
- 1 защищенный слот, унаследованный от QWidget
Подробное описание
Класс QOpenGLWidget — это виджет для отрисовки графики OpenGL.
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(). Никогда не пересвязывайте буфер с ID 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()
{
// 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)
{
// 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()
{
// Draw the scene:
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
...
}
}; В качестве альтернативы, префикс каждого вызова OpenGL можно избежать, унаследовав от QOpenGLFunctions вместо этого:
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
...
void initializeGL()
{
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()
{
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 с поведением обновления по умолчанию) это обычно не так, потому что переключение буферов оставляет задний буфер с неопределённым содержимым.
Примечание: Большинство приложений не нуждаются в инкрементной отрисовке, потому что они будут отрисовывать все в представлении при каждом вызове отрисовки. В этом случае важно вызвать glClear() как можно раньше в paintGL(). Это помогает мобильным GPU, которые используют архитектуру на основе тайлов, распознать, что буфер тайлов не нужно перезагружать содержимым предыдущего фреймбуфера. Пропуск вызова 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(). На системах, которые не поддерживают это, запрос может быть проигнорирован.
Поддержка многообразной выборки требует поддержки многообразных буферов рендеринга и фреймбуферов. В реализациях OpenGL ES 2.0 такие буферы, скорее всего, отсутствуют. Это означает, что многообразная выборка не будет доступна. В современных версиях OpenGL и OpenGL ES 3.0 и выше это обычно больше не проблема.
Потоки
Поддерживается выполнение отрисовки вне экрана в потоках задач, например, для создания текстур, которые затем используются в графическом интерфейсе/главном потоке в paintGL(), путем экспонирования QOpenGLContext виджета, так что дополнительные контексты, которые делят его, могут создаваться в каждом потоке.
Отрисовка непосредственно в фреймбуфер QOpenGLWidget вне потока графического интерфейса/главного потока возможна путем переопределения paintEvent() на пустое действие. Совместимость потока контекста нужно изменить с помощью QObject::moveToThread(). После этого makeCurrent() и doneCurrent() могут быть использованы в потоке задач. Обратите внимание, чтобы вернуть контекст обратно в поток графического интерфейса/главного потока после этого.
В отличие от 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(). Результирующий контекст также может быть использован в другом потоке, позволяя создавать текстуры в потоках и асинхронные загрузки текстур.
END_OF_DOCUMENT_MARKERОбратите внимание, что 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 не приведёт к ожидаемым результатам: виджеты под ним не будут видны. Это связано с тем, что 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-основанного 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 = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())
Создаёт виджет, который является дочерним элементом parent, с флагами виджета, установленными в f.
QOpenGLWidget::~QOpenGLWidget()
Уничтожает экземпляр QOpenGLWidget, освобождая его ресурсы.
Контекст QOpenGLWidget делается текущим в деструкторе, что позволяет безопасно уничтожить любой дочерний объект, которому может потребоваться освободить OpenGL-ресурсы, принадлежащие контексту, предоставляемому этим виджетом.
Предупреждение: если у вас есть объекты, которые оборачивают OpenGL-ресурсы (такие как QOpenGLBuffer, QOpenGLShaderProgram и т.д.) в качестве членов подкласса OpenGLWidget, вам может потребоваться добавить вызов makeCurrent() и в деструкторе этого подкласса. Из-за правил уничтожения объектов C++, эти объекты будут уничтожены до вызова этой функции (но после того, как выполнится деструктор подкласса), поэтому сделать OpenGL-контекст текущим в этой функции произойдёт слишком поздно для их безопасного удаления.
См. также makeCurrent.
[signal] void QOpenGLWidget::aboutToCompose()
Этот сигнал излучается, когда верхнее окно виджета собирается начать композицию текстур его QOpenGLWidget-потомков и других виджетов.
[signal] void QOpenGLWidget::aboutToResize()
Этот сигнал излучается, когда размер виджета изменяется, и поэтому объект фреймбуфера будет пересоздан.
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().
[signal] void QOpenGLWidget::frameSwapped()
Этот сигнал излучается после того, как верхнее окно виджета завершит композицию и вернётся из потенциально блокирующего вызова QOpenGLContext::swapBuffers().
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-ресурсы, такие как контекст, были успешно инициализированы. Обратите внимание, что возвращаемое значение всегда ложно, пока виджет не показан.
void QOpenGLWidget::makeCurrent()
Готовит к отрисовке OpenGL-содержимого для этого виджета, делая соответствующий контекст текущим и привязывая объект фреймбуфера в этом контексте.
В большинстве случаев вызывать эту функцию необязательно, потому что она вызывается автоматически перед вызовом paintGL().
См. также context(), paintGL() и doneCurrent().
[virtual protected] void QOpenGLWidget::paintEvent(QPaintEvent *e)
Переопределённая функция из QWidget::paintEvent().
Обрабатывает события отрисовки.
Вызов QWidget::update() приведёт к отправке события отрисовки e и, следовательно, к вызову этой функции. (Примечание: это асинхронно и произойдёт в какой-то момент после возвращения из update()). Затем эта функция после некоторой подготовки вызовет виртуальную paintGL(), чтобы обновить содержимое фреймбуфера QOpenGLWidget. Затем верхнее окно виджета комбинирует текстуру фреймбуфера с остальной частью окна.
[virtual protected] void QOpenGLWidget::paintGL()
Эта виртуальная функция вызывается всякий раз, когда виджету нужно выполнить отрисовку. Переопределите её в подклассе.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове этой функции.
Перед вызовом этой функции контекст и фреймбуфер привязываются, и область просмотра настраивается с помощью вызова glViewport(). Никакое другое состояние не устанавливается, и никакое очищение или отрисовка не выполняются фреймворком.
См. также initializeGL() и resizeGL().
[virtual protected] void QOpenGLWidget::resizeEvent(QResizeEvent *e)
Переопределённая функция из QWidget::resizeEvent().
Обрабатывает события изменения размера, переданные в параметре события e. Вызывает виртуальную функцию resizeGL().
Примечание: Избегайте переопределения этой функции в производных классах. Если это невозможно, убедитесь, что реализация QOpenGLWidget также вызывается. В противном случае базовый объект фреймбуфера и связанные с ним ресурсы не будут правильно изменены в размерах и приведут к неправильной отрисовке.
[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)
Эта виртуальная функция вызывается всякий раз, когда виджет изменяется в размерах. Переопределите её в подклассе. Новый размер передаётся в w и h.
Нет необходимости вызывать makeCurrent(), так как это уже сделано при вызове этой функции. Кроме того, фреймбуфер также привязан.
См. также initializeGL() и paintGL().
[signal] void QOpenGLWidget::resized()
Этот сигнал излучается сразу после того, как объект фреймбуфера был пересоздан из-за изменения размера виджета.
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::setUpdateBehavior(UpdateBehavior updateBehavior)
Устанавливает поведение обновления этого виджета на updateBehavior.
Эта функция была добавлена в Qt 5.5.
См. также updateBehavior().
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.9/qopenglwidget.html