Outils d'utilisateurs

Outils du Site


opengl_dans_qt5

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

opengl_dans_qt5 [2014/12/11 17:18]
gbdivers
opengl_dans_qt5 [2016/03/27 20:20] (Version actuelle)
winjerome
Ligne 1: Ligne 1:
-====== OpenGL dans Qt5 ====== +====== Support d'OpenGL dans Qt ======
- +
-**Sommaire**+
  
   * [[qt_opengl_-_introduction|]]   * [[qt_opengl_-_introduction|]]
Ligne 14: Ligne 12:
   * [[qt_opengl_-_annexes|]]   * [[qt_opengl_-_annexes|]]
  
-Le support d’OpenGL dans Qt5 a été modifié pour mieux l’intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt5.+Le support d’OpenGL dans Qt 5 a été modifié pour mieux l’intégrer avec les nouveaux modules de Qt : QtQuick2 et Qt3D. Cet article présente les modifications apportées dans Qt 5.
  
-===== OpenGL dans Qt4 =====+<note>**Note sur les versions d'OpenGL**
  
-Dans Qt4, les fonctionnalités d’OpenGL sont implémentées dans un module spécifiqueQtOpenGLCe module était utilisé par différentes classes pour bénéficier de l’accélération matérielle. Il existe plusieurs méthodes pour activer l’accélération matérielle :+OpenGL fonctionne via un système de versions et d'extensions. Quand on veut utiliser une fonction GLil faut regarder dans quelles versions d'OpenGL elle est disponibleOu l'inverse quand on utilise une version d'OpenGL, il faut vérifier les fonctions disponibles.
  
-  * pour activer par défaut l’utilisation de OpenGLutiliser la ligne de commande « -graphicssystem opengl » ou la fonction QApplication::setGraphicsSystem(« opengl »+Les extensions sont un complément aux versions. Elles permettent d'appeler des fonctions non disponibles dans une version donnée (par exempleappeler une fonction de GL 4 dans GL 3).
-  * pour QGraphicsView (QtGraphics) ou QDeclarativeView (QtQuick), utiliser la fonction setViewport(new QGLWidget) ; +
-  * on peut également utiliser QPainter directement sur un QGLWidget ; +
-  * avec le QML Viewer, utilisez la commande « -opengl ».+
  
-===== L’organisation des modules =====+Et bien sûr, tout cela va dépendre du matériel et des capacités de la carte graphique. (Ce qui signifie qu'avant d'utiliser une fonction, il faut vérifier que le matériel la supporte).
  
-Dans Qt4on a donc un problème dans l’organisation des modulesBeaucoup de classes de QtGui peuvent dépendre des classes appartenant à QtOpenGL alors que ce module dépend normalement de QtGui. +Brefpas simple.
-C’est pour cela que de nouvelles classes font leur apparition dans Qt5 et que les différents modules ont été réorganisés :+
  
-  * les classes QOpenGL appartiennent au module QtGui et fournissent les fonctionnalités de base permettant l’accélération matérielle pour toute les classes de rendu de Qt +Qt propose plusieurs outils pour gérer cela
-  * la classe QWidget n’est plus le parent de toutes les classes de rendu. Cette classe et ses dérivées (QGraphicsView) sont transférées dans le module « widgets » ; +
-  * QtQuick 2 utilise maintenant scenegraph à la place de QWidget et la classe QDeclarativeView devient QQuickView et OpenGL est utilisé par défaut ; +
-  * QtOpenGL continue d’exister pour fournir la classe QGLWidget et ses dérivés. Le code OpenGL Qt4 est donc compatible avec Qt5 ; +
-  * le module Qt3d fait son apparition pour fournir un moteur 3D plus avancé. Ce module est suffisamment important et fera donc l’objet d’un article spécifique.+
  
-Remarque : il faut faire attention de ne pas confondre le module QtOpenGL, contenant les classes commençant par QGLet le module QtGui, contenant les classes commençant par QOpenGL (sans t).+QOpenGLFunctions fournit les fonctions de base que tout système DOIT supporter pour pouvoir faire tourner une application Qt 5. C'est donc la base minimale que l'on peut utiliser en ayant la garantie que cela fonctionne partout. (C'est en gros basé sur un sous ensemble d'OpenGL ES 2.) 
 +les classes QOpenGLFunctions_x_y, qui permettent d'utiliser une version spécifique de GL (par exemple http://doc.qt.io/qt-5/qopenglfunctions-2-0.html ou http://doc.qt.io/qt-5/qopenglfunctions-4-5-core.html). Mais il faut vérifier que le matériel supporte cela avant d'utiliser une version particulière de GL 
 +QOpenGLContext::hasExtension et QOpenGLContext::getProcAddress permettent de gérer manuellement les extensions. Idemil faut tester le matériel. 
 +Toutes les fonctions plus haut niveau QOpenGLXxx (par exemple QOpenGLTexture, QOpenGLShaderProgram, QOpenGLFramebufferObjectpermettent d'utiliser des fonctionnalités de GL sans se préoccuper des versions de GL. Ces classes vérifient en interne les fonctions GL utilisables, pour optimiser au mieux les tâches. 
 +Bref, pas simple tout cela.
  
-===== Les classes de QtGui dans Qt5 =====+Je vous conseille de prendre un cours/tutos/livre sur une version d'OpenGL pas trop ancienne, de créer un contexte Qt avec une version de GL correspondante et de bosser avec cela.
  
-Le module QtGui de Qt5 réutilise des classes existantes du module QtOpenGL de Qt4Les noms sont explicites :+Dans un programme pro, on ne pourra bien sûr pas faire comme cela. Il faudra faire un code minimal qui fonctionne sur un maximum de matériel, puis écrire du code spécifique pour chaque fonctionnalité/matériel qui permettent d'optimiser le rendu. C'est beaucoup de boulot. 
 +</note>
  
-  * QOpenGLBuffer ; 
-  * QOpenGLContext ; 
-  * QOpenGLFramebufferObject ; 
-  * QOpenGLFramebufferObjectFormat ; 
-  * QOpenGLShader ; 
-  * QOpenGLShaderProgram. 
  
-Plusieurs nouvelles classes font leur apparition :+===== Activer OpenGL dans Qt 4 =====
  
-  * QOpenGLContextGroup : groupe de contextes OpenGL pouvant partager des ressources. Cette classe est gérée automatiquement par les objets QOpenGLContext ; +Dans Qt 4, les fonctionnalités d’OpenGL sont implémentées dans un module spécifique, QtOpenGL. Ce module était utilisé par différentes classes pour bénéficier de l’accélération matérielle. Il existe plusieurs méthodes pour activer l’accélération matérielle :
-  * QOpenGLFunctions : fournit un accès indépendant de la plateforme aux fonctions d’OpenGL +
-  * QOpenGLPaintDevice : permet de dessiner dans un contexte OpenGL avec QPainter ; +
-  * QOpenGLStaticContext : manque de documentation ; +
-  * QOpenGLContextData manque de documentation ; +
-  * QWindowsGLContext : manque de documentation.+
  
-===== Que faut-il modifier pour utiliser OpenGL dans Qt5 =====+  * pour activer par défaut l’utilisation de OpenGL, utilisez la ligne de commande "-graphicssystem opengl" ou la fonction ''QApplication::setGraphicsSystem("opengl")'', dans la fonction ''main'' par exemple ; 
 +  * pour ''QGraphicsView'' (QtGraphics) ou ''QDeclarativeView'' (QtQuick), utilisez la fonction ''setViewport(new QGLWidget)'' ; 
 +  * on peut également utiliser ''QPainter'' directement sur un ''QGLWidget'', qui est une classe dérivée de ''QWidget'' avec un contexte OpenGL 
 +  * avec le QML Viewer, utilisez la commande "-opengl".
  
-**La procédure d'installation ci-dessous concerne les anciennes versions de Ubuntu**+===== L’organisation des modules dans Qt 5 =====
  
-Tout d’abord, il faut Qt5. Le plus simple est d’utiliser les dépôts PPA sur Ubuntu : https://launchpad.net/~forumnokia/+archive/fn-ppa. Qt5 sera installé dans le répertoire /opt/qt5. Pour ajouter cette version de Qt dans QtCreatoril faut aller dans le menu « Outils » puis « Options… »allez dans « Compiler et exécuter… » puis l’onglet « Versions de Qt »Cliquer sur « Ajouter » et aller chercher le fichier « /opt/qt5/bin/qmake ». Voilà, Qt5 est prêt à être utilisé.+Dans Qt 4, le support d'OpenGL était donc optionnel, dans un module dédiéIl fallait créer spécifiquement un contexte OpenGL et le passer en paramétré pour bénéficier de l’accélération matérielle.
  
-**Pour les versions récentes de Ubuntu (à partir de 13.04 je crois ?)il est possible d'utiliser les paquets libqt5* ou le paquet ubuntu-sdk**+Dans Qt 5l'objectif a été de fournir un support minimal d'OpenGL dans QtGui, ce qui permet de l'utiliser dans tous les modules graphiques (widgets, Qt Quick) qui dépendent de QtGui.
  
-&lt;code> +  * les classes ''QOpenGLXxx'' appartiennent au module QtGui et fournissent les fonctionnalités de base permettant l’accélération matérielle pour toute les classes de rendu de Qt ; 
-sudo apt-get update &amp;&ampsudo apt-get install libqt5+  * la classe ''QWidget'' n’est plus le parent de toutes les classes de rendu. Cette classe et ses dérivées (''QGraphicsView'' par exemple) sont transférées dans le module &quot;widgets" ; 
-// ou +  * les vues QtQuick 2 ne sont plus basées sur ''QWidget'', la classe ''QDeclarativeView'' devient ''QQuickView'' et OpenGL est utilisé par défaut ; 
-sudo apt-get update &amp;&ampsudo apt-get install ubuntu-sdk+  * le module QtOpenGL continue d’exister pour fournir la classe ''QGLWidget'' et ses dérivés (les classes qui commencent par ''QGLXxx''). Ce module permet de conserver le code Qt 4 compatible avec Qt 5, mais ces classes sont dépréciées au profit des classes ''QOpenGLXxx''. 
 + 
 +Remarque : il faut faire attention de ne pas confondre le module QtOpenGL, contenant les classes commençant par ''QGLXxx'', et le module QtGui, contenant les classes commençant par ''QOpenGLXxx'' (sans t). 
 + 
 +===== Overview QtOpenGL ===== 
 + 
 +<note>**Notes de mise à jour** 
 + 
 +Ce tutoriel concerne que les classes de Qt Gui, non QtOpenGL.  
 +&lt;/note&gt; 
 + 
 +==== Surfaces et contextes ==== 
 + 
 +Un contexte est une "zone" de travail d'OpenGL, contient les informations permettant à OpenGL de fonctionner. Peut correspondre à une fenêtre visible à l'écran, et dans ce cas, tous les rendus réalisés avec ce contexte seront visible dans cette fenêtre, ou hors écran. 
 + 
 +  QOpenGLContext (Qt 5.0) : information a propos du contexte OpenGL, par exemple version d'OpenGL prise en charge, gestion des extensions OpenGL, la surface correspondante à ce contexte. 
 + 
 +  * QSurface : classe abstraite, qui représente n'importe quelle surface. Peut être une surface visible (QWindow) ou une surface non visible à l'écran (QOffscreenSurface). 
 +    * supportsOpenGL() : teste si cette surface supporte OpenGL ou non (une surface peut également servir pour dessiner sans utiliser OpenGL, avec le moteur Raster). 
 +    * format() : retourne un QSurfaceFormat, qui contient les informations sur le format... (à détailler). Contient en particulier version(), qui permet  de tester la version d'OpenGL prise en charge (peut être différent de la version demandée lors de la création de la surface). 
 +    * size() : dimensions de la surface. 
 + 
 +  * QWindow : surface visible à l'écran. Nombreuses informations non spécifiques à OpenGL (titre de la fenêtre,  gestion des events, etc.). Sera généralement utilisé via QWidget ou QQuickView, sauf si on travaille directement avec OpenGL. 
 +  * QOffscreenSurface : surface non visible. Partager des ressources avec d'autres contexte OpenGL pour charger des textures ou dessiner dans un FBO de façon asynchrone. Remarque : à créer dans le thread principal. 
 +  * QOpenGLWindow et QOpenGLWidget (Qt 5.4) : hérite de QWindow et QWidget, en creant un contexte OpenGL en interne et proposent les fonctions ''initializeGL'', ''paintGL'' et ''resizeGL''. 
 + 
 +<code cpp> 
 +QOpenGLContext* context = new QOpenGLContext(parent); 
 +context-&gt;setFormat(...); 
 +context-&gt;create(); 
 + 
 +context->makeCurrent(this); 
 +context->swapBuffers(this);
 </code> </code>
  
-Je vous conseille d'installer également les dernières versions des compilateurs C++ : GCC 4.9 et Clang 3.4 (il y a également Clang 3.5 dans les version unstable je croisà tester) :+  * QOpenGLContextGroup (Qt 5.0) : Possibilité de partager des ressources entre plusieurs contextes (par exemple, si une texture est utilisée dans 2 contexteson évite de la charger 2 fois, on la partage). Plus de 2 contextes ? 
 +  * QOpenGLVersionProfile (Qt 5.1) : permet de créer un contexte avec une version spécifique de GL avec versionFunctions. Préférer la version avec template.
  
-<code> +==== Debug et profiling ==== 
-sudo apt-get update &amp;&ampsudo apt-get install gcc-snapshoot clang-3.4 clang-3.5+ 
 +  * Debug contexte. Permet d'avoir des messages de debug générés par le driver ou le GPU. Cf [[deboguer_avec_opengl_4|]] 
 +  * QOpenGLDebugLogger (Qt 5.1) 
 +  * QOpenGLDebugMessage (Qt 5.1) 
 + 
 +<code cpp
 +// gestion des erreurs  
 +GLenum error = GL_NO_ERROR; 
 +do { 
 +    error = glGetError(); 
 +    if (error != GL_NO_ERROR) 
 +        // handle the error 
 +} while (error != GL_NO_ERROR); 
 + 
 +// création d'un contexte debug 
 +QSurfaceFormat format; 
 +// asks for a OpenGL 3.2 debug context using the Core profile 
 +format.setMajorVersion(3); 
 +format.setMinorVersion(2); 
 +format.setProfile(QSurfaceFormat::CoreProfile); 
 +format.setOption(QSurfaceFormat::DebugContext); 
 + 
 +QOpenGLContext *context = new QOpenGLContext; 
 +context-&gt;setFormat(format); 
 +context-&gt;create(); 
 + 
 +QOpenGLContext *ctx = QOpenGLContext::currentContext(); 
 +ctx->hasExtension(QByteArrayLiteral("GL_KHR_debug")) 
 +QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this); 
 +logger->initialize(); // initializes in the current context, i.ectx 
 + 
 +// read logs 
 +QList<QOpenGLDebugMessage> messages = logger->loggedMessages(); 
 +foreach (const QOpenGLDebugMessage &message, messages) 
 +    qDebug() << message; 
 +     
 +// connexion directe 
 +connect(logger, &QOpenGLDebugLogger::messageLogged, receiver, &LogHandler::handleLoggedMessage); 
 +logger->startLogging(); 
 + 
 +// send message 
 +QOpenGLDebugMessage message = 
 +    QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("Custom message")); 
 +logger->logMessage(message);
 </code> </code>
  
-**Modifier le code**+  QOpenGLTimeMonitor (Qt 5.1) 
 +  QOpenGLTimerQuery (Qt 5.1)
  
-Il est également nécessaire de modifier un peu (ou beaucoup, si vous utilisez des fonctionnalités dépréciée de Qt 4) votre code. La première chose à faire est d’ajouter le module "widgets" (remarque : l’ajout des modules "core" et "gui" n’est pas obligatoire puisqu'ils sont inclus par défaut, je les remets pour que cela soit plus clair) :+En fonction des extensions ARB_timer_query et EXT_timer_query extensions. Voir [[deboguer_avec_opengl_4|]] pour les détails.
  
-<code> +<code cpp
-QT *= core gui opengl // *n'ajoute que les nouvelles valeurs +// init 
-greaterThan(QT_MAJOR_VERSION, 4) {  +QOpenGLTimeMonitor::setSampleCount(n); 
-    QT += widgets +QOpenGLTimeMonitor::create(); 
 + 
 +// définir des points de mesure 
 +QOpenGLTimeMonitor::recordSample(); 
 + 
 +// lire les résultats 
 +QOpenGLTimeMonitor::isResultAvailable(); 
 +QOpenGLTimeMonitor::waitForIntervals();  // intervals 
 +QOpenGLTimeMonitor::waitForSamples();    // raw timestamp 
 + 
 +// reset 
 +QOpenGLTimeMonitor::reset(); 
 +</code> 
 + 
 +OpenGL >=3.3 offers full support for all timer query functionality. 
 +* OpenGL 3.2 with the ARB_timer_query extension offers full support for all timer query functionality. 
 +* OpenGL <=3.2 with the EXT_timer_query extension offers limited support in that the timestamp of the GPU cannot be queried. Places where this impacts functions provided by Qt classes will be highlighted in the function documentation. 
 +* OpenGL ES 2 (and OpenGL ES 3) do not provide any support for OpenGL timer queries. 
 + 
 +Granularité de 1 nanosecondes. 
 + 
 +<code cpp> 
 +// simple 
 +QOpenGLTimerQuery::begin(); 
 +QOpenGLTimerQuery::end(); 
 + 
 +QOpenGLTimerQuery::isResultAvailable(); 
 +QOpenGLTimerQuery::waitForResult(); 
 +</code> 
 + 
 +==== Extensions et fonctions ==== 
 + 
 +  * QOpenGLFunctions (Qt 5.0) : support des fonctions OpenGL. Pour utiliser une fonction d'une lib en général, besoin du prototype (nom, paramètres, etc) et l'adresse dans la lib. Fait automatiquement par le link lors de la compilation. 
 +  * QAbstractOpenGLFunctions et QOpenGLFunctions_X_x (Qt 5.1) : chargement des fonctions spécifiques d'une version de GL. 
 + 
 + 
 +OpenGL cas particulier, puisque les fonctions et fonctions dispo dépend du GPU sur lequel s'exécute le programme, peut changer pour chaque utilisateur. Besoin de gestion plus dynamique. 
 + 
 +Versions mineurs et majeur d'OpenGL, ajout de nouvelles fonctions, enums, etc. et retrait d'autres. Donc a chaque version, correspond une liste de fonctions dispo. Possibilité d'utiliser des fonctions ne correspondant pas à la version de contexte utilisée, si supporté par le GPU, en chargeant dynamiquement la fonction par un système d'extension. 
 + 
 +Par exempleGPU qui supporte OpenGL 4.0, création d'un contexte GL 2.0 et chargement d'une fonction de GL 3.0. 
 + 
 +Remarque : a partir de GL 3.2, suppression des anciennes fonctions dans Core, conservée dans Compatibility . 
 + 
 +Qt permet de gérer tout cela (création d'un contexte avec une version spécifique, chargement d'une extension). Par défaut, OpenGL ES 2 (supporté partout, même sur mobile). 
 + 
 +<code cpp> 
 +QOpenGLFunctions: 
 +initializeOpenGLFunctions(); 
 +hasExtension 
 +getProcAddress 
 + 
 +QOpenGLFunctions_3_3_Core* funcs = 0; 
 +funcs = context->versionFunctions<QOpenGLFunctions_3_3_Core>(); 
 +if (!funcs) { 
 +    qWarning() << "Could not obtain required OpenGL context version"; 
 +    exit(1);
 } }
 +funcs->initializeOpenGLFunctions();
 </code> </code>
  
-Le seconde chose à faire est de supprimer la déclaration des modules dans les includes. Par exemple :+==== Shaders ====
  
-<code> +  * QOpenGLShader (Qt 5.0) 
-#include &lt;QtGui/QWidget+  * QOpenGLShaderProgram (Qt 5.0) 
-// devient + 
-#include &lt;QWidget>+<code cpp
 +static const char *vertexShaderSource = 
 +    &quot;attribute highp vec4 posAttr;\n" 
 +    "attribute lowp vec4 colAttr;\n" 
 +    "varying lowp vec4 col;\n" 
 +    "uniform highp mat4 matrix;\n" 
 +    "void main() {\n" 
 +    "   col = colAttr;\n" 
 +    "   gl_Position = matrix * posAttr;\n" 
 +    "}\n"; 
 + 
 +static const char *fragmentShaderSource = 
 +    "varying lowp vec4 col;\n" 
 +    "void main() {\n" 
 +    "   gl_FragColor = col;\n" 
 +    "}\n"; 
 + 
 +// init prog 
 +QOpenGLShaderProgram *m_program; 
 +m_program = new QOpenGLShaderProgram(this); 
 +m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); 
 +m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); 
 +m_program->link(); 
 +m_posAttr = m_program->attributeLocation("posAttr"); 
 +m_colAttr = m_program->attributeLocation("colAttr"); 
 +m_matrixUniform = m_program->uniformLocation("matrix"); 
 + 
 +// load shader 
 +GLuint shader = glCreateShader(type); 
 +glShaderSource(shader, 1, &amp;source, 0); 
 +glCompileShader(shader); 
 + 
 +// render 
 +const qreal retinaScale = devicePixelRatio(); // iOS 
 +glViewport(0, 0, width() * retinaScale, height() * retinaScale); 
 + 
 +glClear(GL_COLOR_BUFFER_BIT); 
 + 
 +m_program->;bind(); 
 + 
 +QMatrix4x4 matrix; 
 +matrix.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f); 
 +matrix.translate(0, 0, -2); 
 +matrix.rotate(100.0f * m_frame / screen()->refreshRate(), 0, 1, 0); 
 + 
 +m_program->setUniformValue(m_matrixUniform, matrix); 
 + 
 +GLfloat vertices[] = { 
 +  0.0f, 0.707f, 
 +  -0.5f, -0.5f, 
 +  0.5f, -0.5f 
 +}; 
 + 
 +GLfloat colors[] = { 
 +  1.0f, 0.0f, 0.0f, 
 +  0.0f, 1.0f, 0.0f, 
 +  0.0f, 0.0f, 1.0f 
 +}; 
 + 
 +glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices); 
 +glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors); 
 + 
 +glEnableVertexAttribArray(0); 
 +glEnableVertexAttribArray(1); 
 + 
 +glDrawArrays(GL_TRIANGLES, 0, 3); 
 + 
 +glDisableVertexAttribArray(1); 
 +glDisableVertexAttribArray(0); 
 + 
 +m_program->release();
 </code> </code>
  
-Dans la majorité des cas, ces deux modifications seront suffisantesSi ce n'est pas le cas, il faudra modifier en cas par cas, n'hésitez pas à demander sur les forums.+==== Buffers et objets ==== 
 + 
 +  * QOpenGLBuffer (Qt 5.0)  
 +  * QOpenGLFramebufferObject (Qt 5.0) + QOpenGLFramebufferObjectFormat (Qt 5.0) 
 +  * QOpenGLTexture (Qt 5.2) 
 +  * QOpenGLVertexArrayObject (Qt 5.1) 
 + 
 +==== A trier ==== 
 + 
 +  * QOpenGLPaintDevice (Qt 5.0) 
 +  * QOpenGLPixelTransferOptions (Qt ???) 
 + 
 +==== Détails ==== 
 + 
 +Vous trouverez la liste de toutes les classes ''QOpenGLXxx'' dans la [[http://doc-snapshot.qt-project.org/qt5-dev/classes.html#o|documentation de Qt]].
  
 {{tag> OpenGL, Qt, Qt5}} {{tag> OpenGL, Qt, Qt5}}
opengl_dans_qt5.1418314695.txt.gz · Dernière modification: 2014/12/11 17:18 par gbdivers