QOpenGLWidget Class
La clase QOpenGLWidget es un widget para renderizar gráficos OpenGL. Más...
| Cabecera: | #include <QOpenGLWidget> |
| CMake: | find_package(Qt6 REQUIRED COMPONENTS OpenGLWidgets)target_link_libraries(mytarget PRIVATE Qt6::OpenGLWidgets) |
| qmake: | QT += openglwidgets |
| Hereda: | QWidget |
Tipos Públicos
(since 6.5) enum | TargetBuffer { LeftBuffer, RightBuffer } |
| enum | UpdateBehavior { NoPartialUpdate, PartialUpdate } |
Funciones Públicas
| QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) | |
| virtual | ~QOpenGLWidget() |
| QOpenGLContext * | context() const |
(since 6.5) QOpenGLWidget::TargetBuffer | currentTargetBuffer() const |
| GLuint | defaultFramebufferObject() const |
(since 6.5) GLuint | defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const |
| void | doneCurrent() |
| QSurfaceFormat | format() const |
| QImage | grabFramebuffer() |
(since 6.5) QImage | grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer) |
| bool | isValid() const |
| void | makeCurrent() |
(since 6.5) void | makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer) |
| void | setFormat(const QSurfaceFormat &format) |
| void | setTextureFormat(GLenum texFormat) |
| void | setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior) |
| GLenum | textureFormat() const |
| QOpenGLWidget::UpdateBehavior | updateBehavior() const |
Señales
| void | aboutToCompose() |
| void | aboutToResize() |
| void | frameSwapped() |
| void | resized() |
Funciones protegidas
| virtual void | initializeGL() |
| virtual void | paintGL() |
| virtual void | resizeGL(int w, int h) |
Funciones protegidas reimplementadas
| virtual bool | event(QEvent *e) override |
| virtual int | metric(QPaintDevice::PaintDeviceMetric metric) const override |
| virtual QPaintEngine * | paintEngine() const override |
| virtual void | paintEvent(QPaintEvent *e) override |
| virtual QPaintDevice * | redirected(QPoint *p) const override |
| virtual void | resizeEvent(QResizeEvent *e) override |
Descripción Detallada
QOpenGLWidget proporciona funcionalidad para mostrar gráficos OpenGL integrados en una aplicación Qt. Su uso es muy sencillo: Haz que tu clase herede de él y usa la subclase como cualquier otra QWidget, excepto que puedes elegir entre usar QPainter o los comandos de renderizado estándar de OpenGL.
QOpenGLWidget proporciona tres convenientes funciones virtuales que puedes reimplementar en tu subclase para realizar las tareas típicas de OpenGL:
- paintGL() - Renderiza la escena OpenGL. Es llamada cada vez que el widget necesita ser actualizado.
- resizeGL() - Configura la vista OpenGL, proyección, etc. Es llamado cuando el widget ha sido redimensionado (y también cuando se muestra por primera vez porque todos los widgets recién creados reciben un evento de redimensionamiento automáticamente).
- initializeGL() - Establece los recursos y el estado OpenGL. Se llama una vez antes de la primera llamada a resizeGL() o paintGL().
Si necesitas activar un repintado desde otros lugares que no sean paintGL() (un ejemplo típico es cuando se utiliza timers para animar escenas), debes llamar a la función update() del widget para programar una actualización.
El contexto de renderizado OpenGL de tu widget se actualiza cuando se llama a paintGL(), resizeGL(), o initializeGL(). Si necesitas llamar a las funciones estándar de la API OpenGL desde otros lugares (por ejemplo, en el constructor de tu widget o en tus propias funciones de pintura), debes llamar primero a makeCurrent().
Todo el renderizado se realiza en un objeto framebuffer OpenGL. makeCurrent() asegurarse de que está vinculado en el contexto. Ten esto en cuenta cuando crees y vincules objetos framebuffer adicionales en el código de renderizado en paintGL(). Nunca revincule el framebuffer con ID 0. En su lugar, llama a defaultFramebufferObject() para obtener el ID que debe ser vinculado.
QOpenGLWidget permite usar diferentes versiones y perfiles de OpenGL cuando la plataforma lo soporta. Solo establece el formato requerido via setFormat(). Ten en cuenta sin embargo que tener multiples instancias de QOpenGLWidget en la misma ventana requiere que todas usen el mismo formato, o al menos formatos que no hagan los contextos no compartibles. Para superar este problema, prefiere usar QSurfaceFormat::setDefaultFormat() en lugar de setFormat().
Nota: Llamar a QSurfaceFormat::setDefaultFormat() antes de construir la instancia QApplication es obligatorio en algunas plataformas (por ejemplo, macOS) cuando se solicita un contexto de perfil de núcleo OpenGL. Esto es para asegurar que la compartición de recursos entre contextos sigue siendo funcional ya que todos los contextos internos se crean utilizando la versión y el perfil correctos.
Técnicas de pintura
Como se ha descrito anteriormente, subclase QOpenGLWidget para renderizar contenido 3D puro de la siguiente manera:
- Reimplementar las funciones initializeGL() y resizeGL() para configurar el estado OpenGL y proporcionar una transformación de perspectiva.
- Reimplementar paintGL() para pintar la escena 3D, llamando únicamente a funciones OpenGL.
También es posible dibujar gráficos 2D sobre una subclase de QOpenGLWidget utilizando QPainter:
- En paintGL(), en lugar de emitir comandos OpenGL, construye un objeto QPainter para su uso en el widget.
- Dibuja primitivas usando QPainter's member functions.
- Todavía se pueden emitir comandos OpenGL directos. Sin embargo, debes asegurarte de que están incluidos en una llamada a beginNativePainting() y endNativePainting() del pintor.
Cuando se dibuja sólo con QPainter, también es posible pintar como se hace con los widgets normales: reimplementando paintEvent().
- Reimplemente la función paintEvent().
- Construya un objeto QPainter apuntando al widget. Pase el widget al constructor o a la función QPainter::begin().
- Dibuja las primitivas utilizando las funciones miembro de QPainter.
- Al terminar de pintar, se destruye la instancia QPainter. Alternativamente, llame a QPainter::end() explícitamente.
Llamadas a funciones OpenGL, cabeceras y QOpenGLFunctions
Cuando se realicen llamadas a funciones OpenGL, se recomienda encarecidamente evitar llamar a las funciones directamente. En su lugar, prefiera usar QOpenGLFunctions (cuando haga aplicaciones portables) o las variantes versionadas (por ejemplo, QOpenGLFunctions_3_2_Core y similares, cuando se dirija a OpenGL moderno, sólo para escritorio). De esta forma, la aplicación funcionará correctamente en todas las configuraciones de compilación de Qt, incluyendo las que realizan la carga dinámica de la implementación de OpenGL, lo que significa que las aplicaciones no están enlazadas directamente a una implementación de GL y, por tanto, las llamadas directas a funciones no son factibles.
En paintGL() siempre se puede acceder al contexto actual llamando a QOpenGLContext::currentContext(). Desde este contexto se puede recuperar una instancia de QOpenGLFunctions ya inicializada y lista para ser utilizada llamando a QOpenGLContext::functions(). Una alternativa a anteponer prefijos a cada llamada GL es heredar de QOpenGLFunctions y llamar a QOpenGLFunctions::initializeOpenGLFunctions() en initializeGL().
En cuanto a las cabeceras OpenGL, ten en cuenta que en la mayoría de los casos no habrá necesidad de incluir directamente ninguna cabecera como GL.h. Las cabeceras Qt relacionadas con OpenGL incluirán qopengl.h, que a su vez incluirá una cabecera apropiada para el sistema. Puede ser una cabecera OpenGL ES 3.x o 2.0, la versión más alta disponible, o una cabecera gl.h proporcionada por el sistema. Además, se proporciona una copia de las cabeceras de extensión (llamadas glext.h en algunos sistemas) como parte de Qt tanto para OpenGL como para OpenGL ES. Éstas se incluirán automáticamente en las plataformas en las que sea posible. Esto significa que las constantes y punteros de función de las extensiones ARB, EXT, OES están automáticamente disponibles.
Ejemplos de código
Para empezar, la subclase más simple de QOpenGLWidget podría ser como la siguiente:
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); ... } };
Alternativamente, el prefijo de todas y cada una de las llamadas OpenGL puede ser evitado derivando de QOpenGLFunctions en su lugar:
class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { ... void initializeGL() override { initializeOpenGLFunctions(); glClearColor(...); ... } ... };
Para obtener un contexto compatible con una determinada versión o perfil de OpenGL, o para solicitar buffers de profundidad y stencil, llama a 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
Nota: Es responsabilidad de la aplicación asegurarse de que los buffers de profundidad y stencil se solicitan desde la interfaz del sistema de ventanas subyacente. Si no se solicita un tamaño de búfer de profundidad distinto de cero, no hay garantía de que haya un búfer de profundidad disponible y, como resultado, las operaciones de OpenGL relacionadas con las pruebas de profundidad pueden no funcionar como se espera. Las solicitudes de tamaño de búfer de profundidad y stencil más comunes son 24 y 8, respectivamente.
En contextos OpenGL 3.0+, cuando la portabilidad no es importante, las variantes versionadas de QOpenGLFunctions permiten acceder fácilmente a todas las funciones OpenGL modernas disponibles en una versión determinada:
... void paintGL() override { QOpenGLFunctions_3_2_Core *f = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); ... f->glDrawArraysInstanced(...); ... } ...
Como se ha descrito anteriormente, es más sencillo y robusto establecer el formato solicitado de forma global para que se aplique a todas las ventanas y contextos durante el tiempo de vida de la aplicación. A continuación se muestra un ejemplo de ello:
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(); }
Muestreo múltiple
Para habilitar el multimuestreo, establezca el número de muestras solicitadas en la dirección QSurfaceFormat que se pasa a setFormat(). En sistemas que no lo soporten la petición puede ser ignorada.
El soporte de multimuestreo requiere soporte para renderbuffers multimuestreo y framebuffer blits. En las implementaciones de OpenGL ES 2.0 es probable que no estén presentes. Esto significa que el multimuestreo no estará disponible. Con las versiones modernas de OpenGL y OpenGL ES 3.0 y superiores esto ya no suele ser un problema.
Threading
Realizar renderizado fuera de pantalla en hilos de trabajo, por ejemplo para generar texturas que luego se usan en el hilo GUI/principal en paintGL(), está soportado exponiendo el QOpenGLContext del widget para que se puedan crear contextos adicionales que compartan con él en cada hilo.
Dibujar directamente al framebuffer de QOpenGLWidget fuera del hilo GUI/main es posible reimplementando paintEvent() para no hacer nada. La afinidad de hilo del contexto tiene que ser cambiada a través de QObject::moveToThread(). Después de eso, makeCurrent() y doneCurrent() son utilizables en el hilo trabajador. Ten cuidado de volver a mover el contexto al hilo GUI/principal después.
Activar un cambio de buffer solo para el QOpenGLWidget no es posible ya que no hay una superficie nativa real en pantalla para el. Depende de la pila del widget gestionar la composición y los cambios de buffer en el hilo gui. Cuando un hilo termina de actualizar el framebuffer, llama a update() en el hilo GUI/principal para programar la composición.
Hay que tener especial cuidado para evitar el uso del framebuffer cuando el hilo GUI/principal está realizando la composición. Las señales aboutToCompose() y frameSwapped() serán emitidas cuando la composición comience y termine. Se emiten en el hilo GUI/main. Esto significa que utilizando una conexión directa aboutToCompose() puede bloquear el hilo GUI/main hasta que el hilo worker haya terminado su renderizado. Después de eso, el hilo trabajador no debe realizar más renderizado hasta que la señal frameSwapped() sea emitida. Si esto no es aceptable, el subproceso trabajador debe implementar un mecanismo de doble buffering. Esto implica dibujar usando un objetivo de render alternativo, que es totalmente controlado por el hilo, por ejemplo, un objeto framebuffer adicional, y blitting al framebuffer del QOpenGLWidget en un momento adecuado.
Contexto Compartido
Cuando múltiples QOpenGLWidgets son añadidos como hijos al mismo widget de nivel superior, sus contextos se compartirán entre ellos. Esto no aplica para instancias QOpenGLWidget que pertenecen a diferentes ventanas.
Esto significa que todos los QOpenGLWidgets en la misma ventana pueden acceder a los recursos compartidos de los otros, como texturas, y no hay necesidad de un contexto "global compartido" extra.
Para configurar el uso compartido entre instancias de QOpenGLWidget pertenecientes a diferentes ventanas, establece el atributo de aplicación Qt::AA_ShareOpenGLContexts antes de instanciar QApplication. Esto activará la compartición entre todas las instancias de QOpenGLWidget sin ningún otro paso.
Crear instancias extra de QOpenGLContext que compartan recursos como texturas con el contexto de QOpenGLWidget también es posible. Simplemente pasa el puntero devuelto por context() a QOpenGLContext::setShareContext() antes de llamar a QOpenGLContext::create(). El contexto resultante tambien puede ser usado en un hilo diferente, permitiendo la generacion de texturas en hilos y la carga asincronica de texturas.
Ten en cuenta que QOpenGLWidget espera una implementacion estandar de comparticion de recursos cuando se trata de los drivers graficos subyacentes. Por ejemplo, algunos controladores, en particular para móviles y hardware embebido, tienen problemas con la configuración de la compartición entre un contexto existente y otros que se crean más tarde. Otros controladores pueden comportarse de forma inesperada al intentar utilizar recursos compartidos entre diferentes subprocesos.
Inicialización y limpieza de recursos
Se garantiza que el contexto OpenGL asociado al QOpenGLWidget es actual siempre que se invoque a initializeGL() y paintGL(). No intentes crear recursos OpenGL antes de que initializeGL() sea invocado. Por ejemplo, intentar compilar shaders, inicializar objetos vertex buffer o cargar datos de textura fallará si se hace en el constructor de una subclase. Estas operaciones deben ser diferidas a initializeGL(). Algunas de las clases de ayuda OpenGL de Qt, como QOpenGLBuffer o QOpenGLVertexArrayObject, tienen un comportamiento diferido similar: pueden ser instanciadas sin un contexto, pero toda la inicialización es diferida hasta una llamada a create(), o similar. Esto significa que pueden ser usadas como variables miembro normales (no puntero) en una subclase QOpenGLWidget, pero la funcion create() o similar solo puede ser llamada desde initializeGL(). Ten en cuenta que no todas las clases estan diseñadas asi. En caso de duda, haz que la variable miembro sea un puntero y crea y destruye la instancia dinamicamente en initializeGL() y el destructor, respectivamente.
Liberar los recursos también necesita que el contexto sea actual. Por lo tanto, se espera que los destructores que realizan dicha limpieza llamen a makeCurrent() antes de pasar a destruir cualquier recurso o envoltorio de OpenGL. Evite el borrado diferido a través de deleteLater() o el mecanismo parenting de QObject. No hay garantía de que el contexto correcto sea actual en el momento en que la instancia en cuestión es realmente destruida.
Por lo tanto, una subclase típica tendrá a menudo el siguiente aspecto en lo que respecta a la inicialización y destrucción de recursos:
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(...); ... }
Esto funciona para la mayoría de los casos, pero no es del todo ideal como solución genérica. Cuando el widget es reparentado de forma que termina en una ventana de nivel superior completamente diferente, se necesita algo más: conectándose a la señal aboutToBeDestroyed() de QOpenGLContext, se puede realizar una limpieza siempre que el contexto OpenGL esté a punto de ser liberado.
Nota: Para los widgets que cambian su ventana de nivel superior asociada varias veces durante su vida, es esencial un enfoque de limpieza combinado, como se demuestra en el siguiente fragmento de código. Cada vez que el widget o uno de sus padres se reasigna de forma que la ventana de nivel superior cambia, el contexto asociado al widget se destruye y se crea uno nuevo. Esto es seguido por una llamada a initializeGL() donde todos los recursos OpenGL deben ser reinicializados. Debido a esto la única opción para realizar una limpieza adecuada es conectarse a la señal aboutToBeDestroyed() del contexto. Ten en cuenta que el contexto en cuestión puede no ser el actual cuando se emite la señal. Por lo tanto, es una buena práctica llamar a makeCurrent() en la ranura conectada. Además, los mismos pasos de limpieza deben realizarse desde el destructor de la clase derivada, ya que la ranura o lambda conectada a la señal puede no ser invocada cuando el widget está siendo destruido.
MyGLWidget::~MyGLWidget() { cleanup(); } void MyGLWidget::initializeGL() { ... connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); } void MyGLWidget::cleanup() { makeCurrent(); delete m_texture; m_texture = 0; ... doneCurrent(); disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &MyGLWidget::cleanup); }
Nota: Cuando se establece Qt::AA_ShareOpenGLContexts, el contexto del widget nunca cambia, ni siquiera cuando se reparenting porque la textura asociada al widget va a ser accesible también desde el contexto del nuevo nivel superior. Por lo tanto, actuar sobre la señal aboutToBeDestroyed() del contexto no es obligatorio con esta bandera activada.
Una limpieza adecuada es especialmente importante debido a la compartición de contextos. Aunque el contexto asociado a cada QOpenGLWidget es destruido junto con el QOpenGLWidget, los recursos compartidos en ese contexto, como texturas, permaneceran validos hasta que la ventana de nivel superior, en la que vivia el QOpenGLWidget, sea destruida. Adicionalmente, configuraciones como Qt::AA_ShareOpenGLContexts y algunos módulos Qt pueden activar un alcance aún mayor para compartir contextos, llevando potencialmente a mantener vivos los recursos en cuestión durante todo el tiempo de vida de la aplicación. Por lo tanto lo mas seguro y robusto es siempre realizar una limpieza explicita para todos los recursos y envoltorios de recursos usados en el QOpenGLWidget.
Limitaciones y otras consideraciones
Poner otros widgets debajo y hacer el QOpenGLWidget transparente no llevara a los resultados esperados: Los widgets debajo no serán visibles. Esto se debe a que en la practica el QOpenGLWidget se dibuja antes que el resto de widgets normales, no-OpenGL, y por tanto las soluciones transparentes no son factibles. Otro tipo de diseños, como tener widgets encima del QOpenGLWidget, funcionaran como se espera.
Cuando sea absolutamente necesario, esta limitacion puede ser superada estableciendo el atributo Qt::WA_AlwaysStackOnTop en el QOpenGLWidget. Ten en cuenta sin embargo que esto rompe el orden de apilamiento, por ejemplo no sera posible tener otros widgets encima del QOpenGLWidget, asi que solo deberia usarse en situaciones donde se requiera un QOpenGLWidget semitransparente con otros widgets visibles debajo.
Nótese que esto no se aplica cuando no hay otros widgets debajo y la intención es tener una ventana semitransparente. En ese caso, el enfoque tradicional de establecer Qt::WA_TranslucentBackground en la ventana de nivel superior es suficiente. Ten en cuenta que si las areas transparentes solo se desean en el QOpenGLWidget, entonces Qt::WA_NoSystemBackground necesitara volver a false despues de habilitar Qt::WA_TranslucentBackground. Adicionalmente, solicitar un canal alfa para el contexto de QOpenGLWidget via setFormat() puede ser necesario tambien, dependiendo del sistema.
QOpenGLWidget soporta múltiples comportamientos de actualización, al igual que QOpenGLWindow. En modo preservado el contenido renderizado de la anterior llamada a paintGL() esta disponible en la siguiente, permitiendo un renderizado incremental. En modo no preservado el contenido se pierde y se espera que las implementaciones de paintGL() redibujen todo en la vista.
Antes de Qt 5.5 el comportamiento por defecto de QOpenGLWidget era preservar el contenido renderizado entre llamadas a paintGL(). Desde Qt 5.5 el comportamiento por defecto es no preservar porque esto proporciona un mejor rendimiento y la mayoría de las aplicaciones no necesitan el contenido previo. Esto también se asemeja a la semántica de un QWindow basado en OpenGL y coincide con el comportamiento por defecto de QOpenGLWindow en que el color y los buffers auxiliares se invalidan para cada fotograma. Para restaurar el comportamiento conservado, llame a setUpdateBehavior() con PartialUpdate.
Nota: Cuando se añade dinamicamente un QOpenGLWidget a una jerarquia de widgets, p.e. emparentando un nuevo QOpenGLWidget a un widget donde el correspondiente widget de nivel superior ya se muestra en pantalla, la ventana nativa asociada puede ser implicitamente destruida y recreada si el QOpenGLWidget es el primero de su tipo dentro de su ventana. Esto se debe a que el tipo de ventana cambia de RasterSurface a OpenGLSurface y eso tiene implicaciones específicas de la plataforma. Este comportamiento es nuevo en Qt 6.4.
Una vez que se añade un QOpenGLWidget a una jerarquía de widgets, el contenido de la ventana de nivel superior se descarga mediante renderizado basado en OpenGL. Los widgets distintos al QOpenGLWidget continúan dibujando su contenido usando un pintor basado en software, pero la composición final se realiza a través de la API 3D.
Nota: Mostrar un QOpenGLWidget requiere un canal alfa en el almacén de respaldo de la ventana de nivel superior asociada debido a la forma en que funciona la composición con otros contenidos basados en QWidget. Si no hay canal alfa, el contenido renderizado por el QOpenGLWidget no será visible. Esto puede ser particularmente relevante en Linux/X11 en configuraciones de pantalla remotas (como, con Xvnc), cuando se usa una profundidad de color menor a 24. Por ejemplo, una profundidad de color de 16 se asignará típicamente al uso de una imagen de almacenamiento de respaldo con el formato QImage::Format_RGB16 (RGB565), sin dejar espacio para un canal alfa. Por lo tanto, si experimentas problemas para conseguir que el contenido de un QOpenGLWidget se componga correctamente con otros widgets de la ventana, asegúrate de que el servidor (por ejemplo, vncserver) está configurado con una profundidad de 24 o 32 bits en lugar de 16.
Alternativas
Añadir un QOpenGLWidget en una ventana activa la composición basada en OpenGL para toda la ventana. En algunos casos especiales esto puede no ser lo ideal, y se desea el viejo comportamiento estilo QGLWidget con una ventana hija separada y nativa. Las aplicaciones de escritorio que entienden las limitaciones de este enfoque (por ejemplo cuando se trata de superposiciones, transparencia, vistas de desplazamiento y áreas MDI), pueden utilizar QOpenGLWindow con QWidget::createWindowContainer(). Esta es una alternativa moderna a QGLWidget y es más rápida que QOpenGLWidget debido a la ausencia del paso adicional de composición. Se recomienda encarecidamente limitar el uso de este enfoque a los casos en que no hay otra opción. Tenga en cuenta que esta opción no es adecuada para la mayoría de las plataformas embebidas y móviles, y se sabe que también tiene problemas en ciertas plataformas de escritorio (por ejemplo, macOS). La solución estable y multiplataforma es siempre QOpenGLWidget.
Renderizado estereoscópico
A partir de la versión 6.5 QOpenGLWidget tiene soporte para renderizado estereoscópico. Para habilitarlo, establece la bandera QSurfaceFormat::StereoBuffers globalmente antes de crear la ventana, usando QSurfaceFormat::SetDefaultFormat().
Nota: Usar setFormat() no funcionará necesariamente debido a cómo se maneja internamente la bandera.
Esto hará que paintGL() sea llamado dos veces cada frame, una vez por cada QOpenGLWidget::TargetBuffer. En paintGL(), llame a currentTargetBuffer() para consultar a cuál se está dibujando actualmente.
Nota: Para un mayor control sobre los buffers de color izquierdo y derecho, considere usar QOpenGLWindow + QWidget::createWindowContainer() en su lugar.
Nota: Este tipo de renderizado 3D tiene ciertos requisitos de hardware, como que la tarjeta gráfica debe estar configurada con soporte estéreo.
OpenGL es una marca registrada de Silicon Graphics, Inc. en Estados Unidos y otros países.
Véase también QOpenGLFunctions, QOpenGLWindow, Qt::AA_ShareOpenGLContexts, y UpdateBehavior.
Documentación del tipo de miembro
[since 6.5] enum QOpenGLWidget::TargetBuffer
Especifica el búfer que se utilizará cuando esté activada la renderización estereoscópica, que se activa configurando QSurfaceFormat::StereoBuffers.
Nota: LeftBuffer es siempre el valor por defecto y se utiliza como valor de reserva cuando el renderizado estereoscópico está deshabilitado o no es soportado por el controlador gráfico.
| Constante | Valor |
|---|---|
QOpenGLWidget::LeftBuffer | 0 |
QOpenGLWidget::RightBuffer | 1 |
Este enum se introdujo en Qt 6.5.
enum QOpenGLWidget::UpdateBehavior
Este enum describe la semántica de actualización de QOpenGLWidget.
| Constante | Valor | Descripción |
|---|---|---|
QOpenGLWidget::NoPartialUpdate | 0 | QOpenGLWidget descartará el contenido del buffer de color y los buffers auxiliares después de que QOpenGLWidget sea renderizado en pantalla. Este es el mismo comportamiento que puede esperarse llamando a QOpenGLContext::swapBuffers con un QWindow habilitado para opengl por defecto como argumento. NoPartialUpdate puede tener algunos beneficios de rendimiento en ciertas arquitecturas de hardware comunes en el espacio móvil e integrado cuando se utiliza un objeto framebuffer como destino de renderizado. El objeto framebuffer se invalida entre fotogramas con glInvalidateFramebuffer (si está soportado), o, como fallbacks, glDiscardFramebufferEXT (si está soportado) o una llamada a glClear. |
QOpenGLWidget::PartialUpdate | 1 | Los objetos framebuffer color buffer y ancillary buffers no se invalidan entre frames. |
Véase también updateBehavior() y setUpdateBehavior().
Documentación de las funciones miembro
[explicit] QOpenGLWidget::QOpenGLWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
Construye un widget hijo de parent, con las banderas de widget establecidas en f.
[virtual noexcept] QOpenGLWidget::~QOpenGLWidget()
Destruye la instancia QOpenGLWidget, liberando sus recursos.
El contexto de QOpenGLWidget se actualiza en el destructor, permitiendo la destrucción segura de cualquier objeto hijo que pueda necesitar liberar recursos OpenGL pertenecientes al contexto proporcionado por este widget.
Advertencia: si tienes objetos que envuelven recursos OpenGL (como QOpenGLBuffer, QOpenGLShaderProgram, etc.) como miembros de una subclase OpenGLWidget, puede que necesites añadir también una llamada a makeCurrent() en el destructor de esa subclase. Debido a las reglas de destrucción de objetos de C++, esos objetos serán destruidos antes de llamar a esta función (pero después de que el destructor de la subclase se haya ejecutado), por lo tanto hacer el contexto OpenGL actual en esta función ocurre demasiado tarde para su eliminación segura.
Véase también makeCurrent.
[signal] void QOpenGLWidget::aboutToCompose()
Esta señal se emite cuando la ventana de nivel superior del widget está a punto de empezar a componer las texturas de sus QOpenGLWidget hijos y de los otros widgets.
[signal] void QOpenGLWidget::aboutToResize()
Esta señal se emite cuando se cambia el tamaño del widget y por tanto se va a recrear el objeto framebuffer.
QOpenGLContext *QOpenGLWidget::context() const
Devuelve El QOpenGLContext utilizado por este widget o 0 si aún no se ha inicializado.
Nota: El contexto y el objeto framebuffer utilizado por el widget cambia cuando se reparenting el widget a través de setParent().
Véase también QOpenGLContext::setShareContext() y defaultFramebufferObject().
[since 6.5] QOpenGLWidget::TargetBuffer QOpenGLWidget::currentTargetBuffer() const
Devuelve el búfer de destino actualmente activo. Este será el buffer izquierdo por defecto, el buffer derecho sólo se utiliza cuando QSurfaceFormat::StereoBuffers está habilitado. Cuando el renderizado estereoscópico está habilitado, esto puede ser consultado en paintGL() para saber qué búfer está actualmente en uso. paintGL() será llamada dos veces, una por cada objetivo.
Esta función se introdujo en Qt 6.5.
Véase también paintGL().
GLuint QOpenGLWidget::defaultFramebufferObject() const
Devuelve El manejador del objeto framebuffer o 0 si aún no se ha inicializado.
Nota: El objeto framebuffer pertenece al contexto devuelto por context() y puede no ser accesible desde otros contextos.
Nota: El contexto y el objeto framebuffer utilizados por el widget cambian cuando se reparenting el widget a través de setParent(). Además, el objeto framebuffer cambia en cada redimensionamiento.
Véase también context().
[since 6.5] GLuint QOpenGLWidget::defaultFramebufferObject(QOpenGLWidget::TargetBuffer targetBuffer) const
Devuelve el manejador del objeto framebuffer del buffer de destino especificado o 0 si aún no se ha inicializado.
Llamar a esta sobrecarga sólo tiene sentido si QSurfaceFormat::StereoBuffers está habilitado y soportado por el hardware. Si no, este método devolverá el buffer por defecto.
Nota: El objeto framebuffer pertenece al contexto devuelto por context() y puede no ser accesible desde otros contextos. El contexto y el objeto framebuffer utilizado por el widget cambian cuando se reparenting el widget a través de setParent(). Además, el objeto framebuffer cambia en cada redimensionamiento.
Esta función se introdujo en Qt 6.5.
Véase también context().
void QOpenGLWidget::doneCurrent()
Libera el contexto.
No es necesario llamar a esta función en la mayoría de los casos, ya que el widget se asegurará de que el contexto está ligado y liberado correctamente al invocar paintGL().
[override virtual protected] bool QOpenGLWidget::event(QEvent *e)
Reimplementa: QWidget::event(QEvent *event).
QSurfaceFormat QOpenGLWidget::format() const
Devuelve el formato de contexto y superficie utilizado por este widget y su ventana toplevel.
Después de que el widget y su toplevel hayan sido creados, redimensionados y mostrados, esta función devolverá el formato real del contexto. Éste puede diferir del formato solicitado si la plataforma no ha podido satisfacer la petición. También es posible obtener tamaños de búfer de color mayores que los solicitados.
Cuando la ventana del widget y los recursos OpenGL relacionados aún no se han inicializado, el valor devuelto es el formato que se ha establecido mediante setFormat().
Véase también setFormat() y context().
[signal] void QOpenGLWidget::frameSwapped()
Esta señal se emite después de que la ventana de nivel superior del widget haya finalizado su composición y regresado de su llamada potencialmente bloqueante QOpenGLContext::swapBuffers().
QImage QOpenGLWidget::grabFramebuffer()
Renderiza y devuelve una imagen RGB de 32 bits del framebuffer.
Nota: Esta es una operación potencialmente cara porque depende de glReadPixels() para leer los píxeles. Esto puede ser lento y puede bloquear el pipeline de la GPU.
[since 6.5] QImage QOpenGLWidget::grabFramebuffer(QOpenGLWidget::TargetBuffer targetBuffer)
Renderiza y devuelve una imagen RGB de 32 bits del framebuffer del buffer de destino especificado. Esta sobrecarga sólo tiene sentido llamarla cuando QSurfaceFormat::StereoBuffers está habilitado. Tomar el framebuffer del buffer de destino correcto devolverá la imagen por defecto si la renderización estereoscópica está deshabilitada o si no es soportada por el hardware.
Nota: Esta es una operación potencialmente cara porque depende de glReadPixels() para leer los píxeles. Esto puede ser lento y puede bloquear el pipeline de la GPU.
Esta función se introdujo en Qt 6.5.
[virtual protected] void QOpenGLWidget::initializeGL()
Esta función virtual se llama una vez antes de la primera llamada a paintGL() o resizeGL(). Reimpleméntala en una subclase.
Esta función debería configurar cualquier recurso OpenGL necesario.
No es necesario llamar a makeCurrent() porque esto ya se ha hecho cuando se llama a esta función. Ten en cuenta, sin embargo, que el framebuffer aún no está disponible en esta fase, así que evita realizar llamadas a dibujar desde aquí. En su lugar, aplaza dichas llamadas a paintGL().
Véase también paintGL() y resizeGL().
bool QOpenGLWidget::isValid() const
Devuelve true si el widget y los recursos OpenGL, como el contexto, se han inicializado correctamente. Tenga en cuenta que el valor de retorno es siempre falso hasta que se muestre el widget.
void QOpenGLWidget::makeCurrent()
Prepara la renderización del contenido OpenGL para este widget haciendo actual el contexto correspondiente y vinculando el objeto framebuffer en ese contexto.
No es necesario llamar a esta función en la mayoría de los casos, porque se llama automáticamente antes de invocar a paintGL().
Véase también context(), paintGL(), y doneCurrent().
[since 6.5] void QOpenGLWidget::makeCurrent(QOpenGLWidget::TargetBuffer targetBuffer)
Prepara la renderización del contenido OpenGL para este widget haciendo actual el contexto para el buffer pasado y vinculando el objeto framebuffer en ese contexto.
Nota: Esto sólo tiene sentido cuando la renderización estereoscópica está activada. No ocurrirá nada si se solicita el buffer correcto cuando está deshabilitado.
No es necesario llamar a esta función en la mayoría de los casos, porque se llama automáticamente antes de invocar a paintGL().
Esta función se introdujo en Qt 6.5.
Véase también context(), paintGL(), y doneCurrent().
[override virtual protected] int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
Reimplementa: QWidget::metric(QPaintDevice::PaintDeviceMetric m) const.
[override virtual protected] QPaintEngine *QOpenGLWidget::paintEngine() const
Reimplementa: QWidget::paintEngine() const.
[override virtual protected] void QOpenGLWidget::paintEvent(QPaintEvent *e)
Reimplementa: QWidget::paintEvent(QPaintEvent *event).
Maneja eventos de pintura.
Llamando a QWidget::update() se enviará un evento de pintura e, y por lo tanto se invocará a esta función. (NB esto es asíncrono y ocurrirá en algún momento después de volver de update()). Esta función entonces, después de alguna preparación, llamará a la virtual paintGL() para actualizar el contenido del framebuffer de QOpenGLWidget. La ventana de nivel superior del widget compondrá entonces la textura del framebuffer con el resto de la ventana.
[virtual protected] void QOpenGLWidget::paintGL()
Esta función virtual es llamada cada vez que el widget necesita ser pintado. Reimpleméntela en una subclase.
No hay necesidad de llamar a makeCurrent() porque esto ya se ha hecho cuando se llama a esta función.
Antes de invocar esta función, el contexto y el framebuffer están vinculados, y la ventana gráfica se configura mediante una llamada a glViewport(). No se establece ningún otro estado y el framework no realiza ninguna limpieza o dibujo.
La implementación por defecto realiza una llamada a glClear(). No se espera que las subclases invoquen la implementación de la clase base y deberían realizar el borrado por sí mismas.
Nota: Para asegurar la portabilidad, no espere que el estado establecido en initializeGL() persista. En su lugar, establezca todo el estado necesario, por ejemplo, llamando a glEnable(), en paintGL(). Esto se debe a que algunas plataformas, como WebAssembly con WebGL, pueden tener limitaciones en los contextos OpenGL en algunas situaciones, lo que puede llevar a utilizar el contexto usado con QOpenGLWidget para otros propósitos también.
Cuando QSurfaceFormat::StereoBuffers está habilitado, esta función será llamada dos veces - una para cada buffer. Consulta qué búfer está actualmente enlazado llamando a currentTargetBuffer().
Nota: El framebuffer de cada objetivo será dibujado incluso cuando el renderizado estereoscópico no sea soportado por el hardware. Sólo el buffer izquierdo será visible en la ventana.
Ver también initializeGL(), resizeGL(), y currentTargetBuffer().
[override virtual protected] QPaintDevice *QOpenGLWidget::redirected(QPoint *p) const
[override virtual protected] void QOpenGLWidget::resizeEvent(QResizeEvent *e)
Reimplementa: QWidget::resizeEvent(QResizeEvent *event).
Maneja eventos de redimensionamiento que son pasados en el parámetro de evento e. Llama a la función virtual resizeGL().
Nota: Evita sobreescribir esta función en clases derivadas. Si no es posible, asegúrese de que también se invoca la implementación de QOpenGLWidget. De lo contrario, el objeto framebuffer subyacente y los recursos relacionados no se redimensionarán correctamente y darán lugar a un renderizado incorrecto.
[virtual protected] void QOpenGLWidget::resizeGL(int w, int h)
Esta función virtual es llamada cada vez que el widget ha sido redimensionado. Reimpleméntala en una subclase. El nuevo tamaño se pasa en w y h.
No es necesario llamar a makeCurrent() porque esto ya se ha hecho cuando se llama a esta función. Adicionalmente, el framebuffer también se vincula.
Véase también initializeGL() y paintGL().
[signal] void QOpenGLWidget::resized()
Esta señal se emite justo después de que el objeto framebuffer haya sido recreado debido al redimensionamiento del widget.
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
Establece la superficie solicitada format.
Cuando el formato no se establece explícitamente a través de esta función, se utilizará el formato devuelto por QSurfaceFormat::defaultFormat(). Esto significa que cuando se tienen múltiples widgets OpenGL, las llamadas individuales a esta función pueden ser reemplazadas por una única llamada a QSurfaceFormat::setDefaultFormat() antes de crear el primer widget.
Nota: Solicitar un buffer alfa a través de esta función no conducirá a los resultados deseados cuando la intención es hacer otros widgets por debajo visibles. En su lugar, utilice Qt::WA_AlwaysStackOnTop para habilitar instancias semitransparentes de QOpenGLWidget con otros widgets visibles debajo. Tenga en cuenta, sin embargo, que esto rompe el orden de apilamiento, por lo que ya no será posible tener otros widgets encima de QOpenGLWidget.
Véase también format(), Qt::WA_AlwaysStackOnTop, y QSurfaceFormat::setDefaultFormat().
void QOpenGLWidget::setTextureFormat(GLenum texFormat)
Establece un formato de textura interno personalizado de texFormat.
Cuando se trabaja con framebuffers sRGB, será necesario especificar un formato como GL_SRGB8_ALPHA8. Esto puede conseguirse llamando a esta función.
Nota: Esta función no tiene efecto si se llama después de que el widget ya ha sido mostrado y por lo tanto ha realizado la inicialización.
Nota: Esta función normalmente tendrá que ser utilizada en combinación con una llamada a QSurfaceFormat::setColorSpace() que establezca el espacio de color a QColorSpace::SRgb.
Véase también textureFormat().
void QOpenGLWidget::setUpdateBehavior(QOpenGLWidget::UpdateBehavior updateBehavior)
Establece el comportamiento de actualización de este widget en updateBehavior.
Véase también updateBehavior().
GLenum QOpenGLWidget::textureFormat() const
Devuelve el formato de textura interno activo si el widget ya se ha inicializado, el formato solicitado si se estableció uno pero el widget aún no se ha hecho visible, o nullptr si no se llamó a setTextureFormat() y el widget aún no se ha hecho visible.
Véase también setTextureFormat().
QOpenGLWidget::UpdateBehavior QOpenGLWidget::updateBehavior() const
Devuelve el comportamiento de actualización del widget.
Véase también setUpdateBehavior().
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.