271568 Des Widgets en 3d Avec Qt

of 17/17
Des widgets en 3D avec Qt Par Midnight Falcon www.openclassrooms.com Licence Creative Commons 6 2.0 Dernière mise à jour le 9/07/2010
  • date post

    19-Oct-2015
  • Category

    Documents

  • view

    22
  • download

    4

Embed Size (px)

Transcript of 271568 Des Widgets en 3d Avec Qt

  • Des widgets en 3Davec Qt

    Par Midnight Falcon

    www.openclassrooms.com

    Licence Creative Commons 6 2.0Dernire mise jour le 9/07/2010

  • Sommaire 2Sommaire ........................................................................................................................................... 3 Des widgets en 3D avec Qt ............................................................................................................... 3Insrer des widgets dans une scne ................................................................................................................................ 3Quelques classes utiles .............................................................................................................................................................................................. 4Dplacer les objets dans la scne .............................................................................................................................................................................. 7Les transformations avec QTransform .............................................................................................................................. 7Utiliser un QTransform avec un QGraphicsItem ......................................................................................................................................................... 9Composer les matrices ...............................................................................................................................................................................................

    10Des widgets en 3D ! ........................................................................................................................................................ 10Que la rotation soit .................................................................................................................................................................................................... 12Et que a bouge ! ...................................................................................................................................................................................................... 13Grer plusieurs transformations diffrentes ..............................................................................................................................................................

    15Pour aller plus loin : gestion de la camra ...................................................................................................................... 15La camra : reprenons l'envers ! ............................................................................................................................................................................ 15Crer une camra ..................................................................................................................................................................................................... 17Partager .....................................................................................................................................................................................................................

    2/18

    www.openclassrooms.com

  • Des widgets en 3D avec Qt

    Par Midnight Falcon

    Mise jour : 09/07/2010Difficult : Intermdiaire Dure d'tude : 3 heures

    Vous utilisez Qt pour raliser des interfaces graphiques et vous vous tes dj demand s'il tait possible d'afficher des formesou des widgets en leur donnant un aspect 3D sans l'aide d'une bibliothque extrieure ? Ce tutoriel est fait pour vous.

    En effet, je vais vous expliquer comment utiliser la classe QGraphicsItem, qui permet de faon gnrale d'intgrer des objets dansune scne 2D mais aussi de leur donner un aspect 3D, moyennant quelques astuces. Attention toutefois, je ne parlerai pas de lamthode permettant de se promener dans la scne comme dans un jeu vido : Qt n'est pas vraiment conu pour a, mme s'il estpossible de le faire avec de bonnes connaissances (voir le lien la fin de ce tutoriel).

    J'aborderai donc l'intgration d'objets dans une scne en deux dimensions grce Qt, avant de vous montrer comment simuler laprofondeur afin de donner une impression de 3D ces objets.

    Dans ce tutoriel, le mot objet dsignera toute instance d'une classe drive de QGraphicsItem. Qt fournit en effetsuffisamment de classes pour pouvoir reprsenter toutes sortes de choses dans une scne, et je ne voulais pas utiliserde terme trop spcifique justement pour ne pas oublier ce dtail.

    Sommaire du tutoriel :

    Insrer des widgets dans une scneLes transformations avec QTransformDes widgets en 3D !Pour aller plus loin : gestion de la camra

    Insrer des widgets dans une scneQuelques classes utiles

    Afin de visualiser des widgets (et plus gnralement des objets graphiques) dans une scne, il faut commencer par en crer unequi va contenir tout ce beau monde. La classe fournie par Qt s'appelle sobrement QGraphicsScene et permet d'insrer desQGraphicsItem. La classe abstraite QGraphicsItem, assez gnrique, reprsente tout ce qui est affichable dans uneQGraphicsScene. On trouve notamment un nombre important de classes permettant de grer des polygones, des textes, desQPixmap et... des widgets !

    En effet, la classe hrite QGraphicsProxyWidget est particulirement adapte l'insertion des widgets dans uneQGraphicsScene. Il suffit de crer votre QGraphicsProxyWidget, de lui attacher le widget que vous dsirez intgrer la scnepuis de l'y intgrer en tant qu'objet. Vous manipulez donc votre widget travers le proxy, tout ceci tant transparent une fois quele proxy et le widget sont attachs. Il est de plus tout fait possible d'intgrer des widgets complexes, comme une QTabWidget,qui contient lui-mme d'autres widgets...

    Dans les exemples, j'appliquerai les notions de ce tutoriel des widgets car c'est leur intgration qui m'a pouss utiliser ces classes. Cependant, les mthodes utilises sont pour la plupart hrites de QGraphicsItem, vous pourrezdonc les adapter d'autres objets que des widgets.

    Enfin, comme la scne n'est pas un widget, il faut aussi crer une vue avec la classe QGraphicsView, qui permet d'afficher le

    Sommaire 3/18

    www.openclassrooms.com

  • contenu de notre scne.Sans plus attendre, commenons par crer notre premire scne, avec un bouton au milieu.

    Code : C++

    #include #include

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

    QPushButton *bouton = new QPushButton("Mon bouton entre en scne!"); QGraphicsScene scene; QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(); proxy->setWidget(bouton); scene.addItem(proxy);

    QGraphicsView view(&scene); view.show();

    return app.exec();}

    Ce code devrait vous afficher un joli bouton au milieu d'un cran blanc. Vous venez d'intgrer votre premier widget dans unescne ! Avouez-le, ce n'tait pas si difficile !

    Dplacer les objets dans la scne

    Une fois le widget intgr la scne travers notre proxy, Qt nous offre un grand nombre de mthodes pour modifier sonpositionnement.

    Les coordonnes

    Si les systmes de coordonnes 2D ne vous sont pas familiers, sachez que l'axe X est l'axe horizontal orient vers la droite, et quel'axe Y est l'axe vertical orient vers le bas. A priori, si vous avez dj un peu manipul Qt ou la SDL par exemple, vous devriezvous y retrouver.

    TranslationLa fonction setPos() de QGraphicsItem prend deux paramtres, dx et dy, qui sont les dplacements relatifs respectivement surl'axe X et l'axe Y de la scne, paramtres qui deviendront alors les nouvelles coordonnes de notre objet. savoir qu'unemthode surcharge existe, prenant en paramtre un QPointF. vous de voir laquelle vous prfrez. Il est aussi possibled'appeler la fonction move(), qui ajoute le dplacement sur les deux axes la position actuelle de l'objet. Essayons tout de suitede dplacer notre objet dans la scne :

    Des widgets en 3D avec Qt 4/18

    www.openclassrooms.com

  • Code : C++

    #include #include

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

    QPushButton *bouton = new QPushButton("Mon bouton entre en scne!"); QGraphicsScene scene; QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(); proxy->setWidget(bouton); scene.addItem(proxy);

    proxy->setPos(150, 200);

    QGraphicsView view(&scene); view.show();

    return app.exec();}

    Eh, mon widget n'a pas boug d'un iota par rapport tout l'heure !

    En effet, c'est une des particularits de la QGraphicsScene qui m'a un peu perturb au dbut. En fait, par dfaut, la scnes'arrange toujours pour placer vos objets au milieu de la vue. C'est un peu embtant si l'on veut voir du mouvement l-dedans.

    Heureusement, il est possible de dfinir la zone de la scne que l'on dsire voir l'cran. Ajoutez cette ligne aprs la cration de lascne :

    Code : C++

    scene.setSceneRect(-150, -150, 300, 300)

    Les deux premiers nombres sont les coordonnes du point qui doit tre plac dans le coin suprieur gauche de la vue (ici, (-150, -150)). Les deux nombres suivants sont la largeur et la hauteur de la scne que je dsire afficher. Ainsi, comme le point (-150, -150)est le coin suprieur gauche de ma fentre, je vais retrouver l'origine de la scne au centre de l'cran. Si vous relancez votre codeavec et sans le dplacement du bouton, vous devriez voir cette fois-ci une diffrence de position.

    Des widgets en 3D avec Qt 5/18

    www.openclassrooms.com

  • RotationAfin d'appliquer une rotation l'objet, il suffit d'utiliser la mthode setRotation(), pour laquelle vous devrez fournir l'angle derotation en degrs. Un angle positif tourne l'objet dans le sens des aiguilles d'une montre, un angle ngatif le tourne dans le sensinverse.

    Par exemple :

    Code : C++

    proxy->setRotation(45);

    Mise l'chelleEnfin, la mthode setScale() vous permet d'augmenter ou de diminuer la taille prise par l'objet dans la scne. Un nombre suprieur 1 agrandit l'image, tandis qu'un nombre compris entre 0 et 1 la rduit. Cette fonction prend aussi en compte les nombres

    Des widgets en 3D avec Qt 6/18

    www.openclassrooms.com

  • ngatifs, ce qui permet d'effectuer une symtrie de l'image en plus de modifier sa taille.

    Ces oprations de base sont en gros le minimum vital pour pouvoir grer vos objets dans la scne 2D.Je parle ici de scne 2D puisque, si vous avez bien suivi mes explications, je n'ai parl que de deux axes pour la translation, etuniquement d'une rotation autour de l'axe perpendiculaire votre cran. En effet, un QGraphicsItem est bien affich en deuxdimensions dans la scne et ne prend pas directement la profondeur en paramtre.

    Attends, on n'tait pas censs pouvoir manipuler des widgets en 3D ?

    C'est bien sr l'objectif de ce tutoriel. Mais avant cela je voulais vous prsenter la manipulation en deux dimensions, parce quea pourra toujours vous servir. Et puis il fallait bien que vous compreniez pourquoi dans les parties suivantes j'utilise un nouvelobjet pour faire mes transformations !

    Avant de donner pour de bon de la profondeur notre scne, il va falloir passer un peu de temps sur des aspectsmathmatiques. Rassurez-vous, ce ne sera pas long, et en plus Qt nous donne tous les outils ncessaires pour limiter les calculs faire.

    Les transformations avec QTransformOn a vu que les QGraphicsItem proposaient diverses mthodes pour dplacer, tourner ou agrandir les widgets insrs.Seulement, tout cela n'a pas vraiment l'air d'avoir la profondeur qu'on attend d'une scne 3D. Pour cela, on va utiliser unenouvelle classe de Qt, la classe QTransform.

    Si vous avez travaill un peu les mathmatiques dans vos tudes suprieures, ce qui suit devrait vous tre familier. Sinon nevous inquitez pas, Qt s'occupe de tous les calculs pour vous, comme d'habitude.

    Utiliser un QTransform avec un QGraphicsItem

    Un QTransform reprsente un objet mathmatique appel matrice, que l'on peut reprsenter dans notre cas comme un tableaucomportant trois lignes et trois colonnes et contenant toutes les informations ncessaires pour effectuer des modifications surles coordonnes d'un objet dans l'espace.

    Voici comment on reprsente gnralement une matrice :

    Mais comment je fais moi pour savoir comment je vais remplir ton tableau ? a fait quand mme neuf nombres trouvertout seul, je les devine comment ?

    Ne vous inquitez pas : comme je vous le disais, Qt s'occupe de toute la partie mathmatique en proposant des fonctions vouspermettant de gnrer et modifier ces matrices.Comme un exemple vaut mieux qu'un long discours, voici tout de suite comment raliser une translation avec un QTransform :

    Code : C++

    #include #include

    Des widgets en 3D avec Qt 7/18

    www.openclassrooms.com

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

    QPushButton *bouton = new QPushButton("Mon bouton entre en scne!");

    QGraphicsScene scene; scene.setSceneRect(-150 , -150, 300, 300);

    QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(); proxy->setWidget(bouton); scene.addItem(proxy);

    QTransform matrix;matrix.translate(150, 200)proxy->setTransform(matrix);

    QGraphicsView view(&scene); view.show();

    return app.exec();}

    Comme prcdemment, j'ai juste eu renseigner les valeurs de mon vecteur dplacement et Qt a gnr tout seul la matricecorrespondante.

    Excutez ce code et vous verrez... la mme chose que tout l'heure ! Oui, en l'occurence, le rsultat est le mme lorsque l'onregarde notre fentre. Le widget s'est bien dplac de 150 pixels vers la droite et de 200 pixels vers le bas.

    De mme, vous pouvez gnrer des rotations et des agrandissements l'aide des mthodes rotate() et scale() de la classeQTransform.

    Donc les QTransform servent la mme chose qu'avant, sauf que je dois instancier une classe en plus pour m'en servir.C'est un peu inutile !

    En fait, c'est un peu plus compliqu que cela. Il faut plutt voir les QTransform comme un moyen de faire des transformationscomposes en une seule opration. Bien sr, les QTransform permettent aussi d'effectuer les oprations de base, dont les troisque nous avons vues plus haut. Simplement, leur usage est diffrent.

    Par exemple, les modifications effectues par un QTransform ne sont rcuprables que par la mthode transform() duQGraphicsItem modifi. Cela veut dire que les coordonnes de l'objet, auxquelles on pouvait accder par QGraphicsItem::x() etQGraphicsItem::y(), n'ont pas t modifies, et valent toujours 0 !

    Code : C++

    QTransform matrix;matrix.translate(150, 200);proxy->setTransform(matrix);

    matrix = QTransfrom().translate(proxy->x(), proxy->y())proxy->setTransform(matrix);

    Si vous remplacez le code surlign prcdemment par ces lignes, vous vous rendrez compte que votre widget n'a pas boug del'origine. En effet, la dernire transformation tant celle qui prend en compte les paramtres x() et y() de notre proxy, il est revenu sa position (0, 0).

    Des widgets en 3D avec Qt 8/18

    www.openclassrooms.com

  • De plus, il ne faut pas confondre les transformations effectues avec les mthodes fournies par QGraphicsItem que je vous aiprsentes par exemple et les transformations passant par un QTransform. En effet, les deux mthodes ne sont pas directementcompatibles, moins de faire toute une gymnastique informatique, et comme on est trs feignants on va viter a.

    Pour l'exemple, essayez de dplacer votre objet vers la droite avec la mthode setPos(), puis de le replacer la verticale del'origine de la scne en passant par le QTransform.Plutt que de prendre en compte la dernire transformation demande et de se contenter de descendre l'objet, vous voyez quevotre programme l'a plac en bas ET droite. C'est parce que la mthode setPos() dplac votre objet vers la droite, puis queQTransform l'a affich la verticale de cette nouvelle position.

    Avant d'aller plus loin et de voir comment utiliser les QTransform de faon optimale, mon conseil est le suivant.

    L'utilisation des QTransform doit se faire sans celle des mthodes de transformation de la classe QGraphicsItem, afind'viter que les dplacements ne s'additionnent entre eux, ce qui devient vite ingrable.

    Le QTransform a donc plus pour but de modifier la faon dont est affich l'objet plutt que de modifier l'objet lui-mme.C'est pour cette raison que lorsque j'utilise les QGraphicsItem dans mes applications et que je veux utiliser la classe QTransform,je cre des classes drives de QGraphicsItem dans lesquelles je stocke les paramtres dont j'ai besoin, comme la position, larotation, l'chelle, etc., qui servent ensuite crer ma matrice.

    Composer les matrices

    Un outil bien pratique

    Maintenant qu'on a vu comment utiliser les matrices avec les objets de la scne, voyons pourquoi j'ai introduit cette nouvellenotion : c'est un outil trs puissant, souvent utilis lorsque l'on travaille en trois dimensions.

    Une matrice (et donc ici un QTransform) ne se limite pas effectuer une seule opration la fois. Elle peut en effet contenir lesinformations ncessaires pour effectuer la fois une rotation, une translation et une mise l'chelle ! Il ne suffira plus qued'appliquer la matrice l'objet et le tour est jou.

    Mathmatiquement, la composition de matrices s'obtient en les multipliant entre elles, pour donner une nouvelle matrice quicontient les deux transformations. Cependant, Qt permet de faire ces transformations directement via des mthodes de la classeQTransform.

    Par exemple, si je veux crer une matrice de rotation puis que je veux rajouter une translation, je vais crire ceci :

    Code : C++

    QTransform matrix;matrix.rotate(30, Qt::YAxis);matrix = translate(20, 15);

    Il est aussi possible d'utiliser directement la multiplication pour composer vos matrices. Cependant il faut faire attention l'ordredes calcul. La matrice la plus gauche dans la multiplication correspond la transformation effectue en dernier. Les QTransformtiennent compte de cela, l'utilisation des mthodes rotate() et translate() place la matrice paramtre au dbut du calcul, et non lafin. Par exemple, voici deux lignes de code qui effectuent le mme calcul :

    Code : C++

    matrix.rotate(30, Qt::YAxis);matrix = QTransform::rotate(30, Qt::Axis) * matrix;

    Par consquent, soyez encore plus prudent dans le choix de l'ordre de vos lignes de code.Si vous utilisez les multiplications directement, placez vos matrices dans l'ordre inverse dans lequel vous devez faire vos

    Des widgets en 3D avec Qt 9/18

    www.openclassrooms.com

  • transformations. Si vous utilisez les mthodes fournies par Qt, vous devrez les crire dans l'ordre normal, ce qui est plus intuitif.Mais je me devais de vous prciser rapidement le fonctionnement, pour votre culture.

    Je n'ai plus qu' appliquer la matrice mon objet situ dans la scne pour que ces deux transformations soient prises en compte.

    Une question d'ordre

    Sachez maintenant que lorsque vous voudrez composer vos transformations, il faudra les agencer dans un ordre prcis.

    En effet, les deux codes suivants donneront deux matrices (et donc deux transformations) diffrentes :

    Code : C++

    QTransform matrix;matrix.translate(10, 10);matrix.rotate(45, Qt::YAxis);

    Code : C++

    QTransform matrix;matrix.rotate(45, Qt::YAxis);matrix.translate(10, 10);

    Avec mon premier code, j'ai dplac mon objet avant de le faire tourner autour de l'origine ; dans le second, je l'ai dplac aprsl'avoir fait tourner autour de l'origine.

    Dans le premier cas, la transformation finale pourrait se schmatiser ainsi :

    L'objet a parcouru le chemin en pointills et ne se trouve ainsi plus dans le plan (x, y) ! L'autre cas en revanche correspond bien ce qu'on attend intuitivement, c'est--dire un objet situ dans le plan (x, y) mais qui a tourn sur lui-mme.

    Ainsi, pour placer un objet dans la scne, il est plus judicieux d'effectuer d'abord la rotation suivant l'angle voulu, puis ledplacement. La seconde solution est donc celle vous devriez utiliser.

    Maintenant que ces rgles sont tablies, voyons ce que l'on va pouvoir afficher l'cran !

    Des widgets en 3D !

    Des widgets en 3D avec Qt 10/18

    www.openclassrooms.com

  • Que la rotation soit

    Nous allons tout d'abord voir comment faire faire nos widgets des rotations autour d'un axe vertical. Un petit tour dans la docet hop hop hop, je trouve que la mthode rotate() de QTransform, qui prend en paramtre un angle en degrs, correspond tout fait mes besoins !

    Il vaut mieux utiliser un widget plus carr et plus gros qu'un QPushButton pour voir la perspective, vous risquezd'tre dus sinon.

    Voyons ce que a va donner avec un QWebView par exemple (n'oubliez pas d'ajouter la ligne QT += webkit votre fichier.pro).

    Code : C++ - main.cpp

    #include #include #include

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

    QWebView *web = new QWebView(); web->load(QUrl("http://www.siteduzero.com")); web->show();

    QGraphicsScene scene; scene.setSceneRect(0 , 0, 1000, 800);

    QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(); proxy->setWidget(web); scene.addItem(proxy);

    QTransform matrix; matrix.rotate(45, Qt::YAxis); proxy->setTransform(matrix);

    QGraphicsView view(&scene); view.show();

    view.setWindowTitle("Ma premire scne"); return app.exec();}

    Compilez a et miracle, la rotation fut vous avez une jolie perspective sur votre widget, dont les fonctionnalits sont toujoursutilisables ! Un QTextEdit continuera tre ditable dans l'espace, une QWebView continuera charger les pages demandes,etc. Bien sr, on peut se contenter de formes gomtriques plus basiques, mais il est bon de savoir que cela fonctionne avectous les widgets. (Vous pouvez essayer d'intgrer zNavigo, je vous assure que ca marche aussi. )

    Je vous prsente donc le SdZ vu... de profil.

    Des widgets en 3D avec Qt 11/18

    www.openclassrooms.com

  • Et que a bouge !

    Maintenant, nous pouvons ajouter un peu d'interaction notre scne, en permettant notre vision de bouger par rapport auxobjets. Pour cela je vais crer une classe spciale hrite de QGraphicsProxyWidget qui va contenir les informations dont jesouhaite garder la trace : orientation, position, chelle...

    Voici le header de la classe que je vous propose :

    Code : C++ - MyProxy.h

    #include

    class MyProxy : public QGraphicsProxyWidget{public: MyProxy();

    qreal rotationY(); void setRotationY(qreal rotation);

    QPointF center();

    private: qreal m_rotationY; // enregistre la rotation autour de l'axe Y

    QPointF m_center; // contient la position du centre du widget}

    Puis nous allons crer une classe drive de QGraphicsScene pour grer les vnements de la souris. Je vous laisse crer laclasse tout seul, il suffit de rimplmenter la mthode mouseMoveEvent(), appele en cas de dplacement de la souris.

    Nous allons par exemple demander d'effectuer une rotation autour de l'axe Y lorsque la souris est dplace latralement et que leclic gauche est enfonc.

    Code : C++ - MyScene.cpp

    void MyScene::mouseMoveEvent(QGraphicsSceneMouseEvent*e){ if(e->buttons() & Qt::LeftButton) {

    Des widgets en 3D avec Qt 12/18

    www.openclassrooms.com

  • QPointF delta(e->scenePos() - e->lastScenePos()); qreal rotation = delta().x(); m_proxy->setRotationY(rotation); QTransfrom matrix; matrix.rotate(rotation); m_proxy.setTransform(matrix); }}

    Il faut bien penser remplacer vos dclarations de scene et proxy dans le main par MyScene et MyProxy, sinon videmment ane fonctionnera pas !

    Maintenant, lorsque vous dplacez la souris avec le clic gauche enfonc, votre widget devrait se mettre tourner verticalementautour de l'origine de la scne.

    Attends, mon widget tourne autour de son ct gauche, moi je veux qu'il tourne sur lui-mme !

    En effet, la rotation du widget s'effectue par rapport l'origine de la scne (c'est la raison pour laquelle l'ordre destransformations est important). Par consquent, pour remdier ce problme, il faut dplacer le widget pour que son centre sesitue au point (0, 0) !

    Reprenons notre scne avec la QWebView. Le dplacement effectuer est reprsent par le schma ci-dessous : pour que larotation s'effectue par rapport au centre du widget, il faut ramener ce centre l'origine de la scne. C'est donc le dplacementreprsent par la flche rouge qui va nous permettre de raliser cela.

    A priori, vous devriez savoir faire a tout seul. Il suffit de composer notre matrice d'une translation supplmentaire pour dplacernotre widget vers la gauche et en haut, sur une longueur respective de la moiti de la largeur et la moiti de la hauteur (avec unsigne ngatif, car on va vers la gauche et vers le haut). Vous pouvez rcuprer la taille de vos widgets avec les mthodes proxy->widget()->width() et proxy->widget()->height() et les ajouter comme attributs de votre classe MyProxy pour ne plus avoir lesrechercher. Si vous n'y arrivez pas, jetez un coup d'il l'exemple la fin du paragraphe suivant, qui effectue le centrage duwidget.

    Pensez dplacer l'origine de la scne au centre de la fentre avec QGraphicsScene::setSceneRect() si ce n'est dj fait,ou votre widget sera coup par le bord de l'cran cause de ce dcalage.

    Grer plusieurs transformations diffrentes

    Des widgets en 3D avec Qt 13/18

    www.openclassrooms.com

  • Tout a c'est bien beau, mais comment va-t-on faire lorsque l'on se retrouve avec des widgets comportant plusieurstransformations, on va devoir appliquer la matrice chaque intervention de l'utilisateur ?

    On pourrait envisager a, mais a ne serait pas judicieux. D'une part parce qu'il faudrait recalculer la matrice de chaque objet chaque fois qu'un vnement est enregistr, d'autre part parce qu'on risquerait d'intervertir deux transformations, ce quidonnerait un rsultat... inattendu.

    Souvenez-vous, nous avons cr une classe spcialement pour enregistrer toutes les transformations subies par notre objet(pour l'instant sa position et son orientation actuelle).

    L'ide est donc d'enregistrer toutes les modifications apportes l'objet dans les attributs de celui-ci puis, intervalles rguliers,d'appliquer un QTransform l'objet qui va le placer l o il est cens tre au moment du rafrachissement.

    Pour cela, on va utiliser un QTimer, qui s'occupera d'appeler notre fonction de mise jour de la scne intervalles rguliers. Onpeut le crer dans le constructeur de notre scne :

    Code : C++ - MyScene.cpp

    QTimer *timer = new QTimer(this);timer->setInterval(30);connect(timer, SIGNAL(timeout()), this, SLOT(updateScene()));timer->start();

    Ensuite, pour pouvoir grer plusieurs objets, on va ajouter un attribut la classe MyScene, qui va contenir des pointeurs surtous les objets de la scne. Sachez qu'il existe la fonction QGraphicsScene::items() qui permet de faire ce que je vais vousmontrer, mais elle retourne des QGraphicsItem, d'o le besoin de faire un cast. C'est toujours possible mais je n'aime pasbeaucoup cette mthode, voici donc comment je me suis dbrouill :

    Code : C++ - MyScene.h

    QList m_objets;

    Pour ajouter un objet la liste c'est trs simple, vous pouvez utiliser l'oprateur de flux

  • Voici la fonction placeObjet(), qui s'occupe de crer la matrice de transformation et de l'appliquer notre objet. Attention l'ordredes transformations !

    Code : C++ - MyScene.cpp

    void MyScene::placeObjet(MyProxy *objet){ QTransform m; // rotation de l'objet m.rotate(item->rotationY(), Qt::YAxis); // positionnement du widget dans la scne m.translate(objet->center().x(), objet->center().y()); // centrage du widget m.translate(-objet->largeur(), -objet->hauteur());

    objet->setTransform(m);}

    Vous pouvez donc maintenant essayer de faire tourner votre widget et de le dplacer avec le clavier !

    Pour aller plus loin : gestion de la camraLa camra : reprenons l'envers !

    Je vous ai dj dit que l'ordre dans lequel vous composez vos transformations tait important. a le devient encore plus si vousvoulez grer une camra dans l'espace !

    Prenons un exemple. Considrons la tourelle d'un tank dans la scne. Pour la placer correctement, vous allez devoir lui appliquersa rotation par rapport au tank, puis la rotation du tank par rapport la scne, puis enfin la translation qui la positionnera l'endroit voulu.Si maintenant vous voulez placer une camra (votre point de vue) dans la scne, que se passe-t-il ? Dans ce cas, si vous tournezsur vous-mme, vous voyez le monde 3D entier qui tourne autour de votre position. La rotation de la camra doit donc treapplique aprs sa translation !

    Autant vous prvenir tout de suite, cet exemple ne vous permettra pas de tourner sur vous-mme et de vous dplacerdans l'espace, mais plutt de dplacer tous les objets de la scne d'un coup ou bien de tous les faire tourner devantvous. La construction des matrices utilises dans les jeux vido, par exemple pour afficher correctement la scne devantla camra, n'est pas vidente faire la main et dpasse le cadre de ce tutoriel.

    Voyons donc tout de suite concrtement comment on peut donner l'impression que l'on se dplace dans la scne.

    Crer une camra

    Dterminons tout de suite de quelles informations nous allons principalement avoir besoin pour notre camra : position dans lascne et orientation, tout comme les objets de notre scne.

    Code : C++ - Camera.h

    #include

    class Camera{public: Camera(); QPointF pos(); qreal zpos();

    Des widgets en 3D avec Qt 15/18

    www.openclassrooms.com

  • qreal rotationY();

    void setPos(QPointF pos); void setZPos(qreal pos); void setRotationY(qreal angle);

    private: QPointF m_pos; qreal m_zpos; qreal m_rotationY;

    };

    Je vous laisse deviner le contenu du fichier Camera.cpp, il ne s'agit que de getters et de setters, rien de bien sorcier.

    Vous remarquerez aussi que j'ai ajout un attribut m_zpos la camra.C'est en fait une astuce que je voulais vous montrer et qui permettra de donner l'impression que l'on dplace celle-ci vers l'avanto l'arrire. Nous verrons comment faire lors de l'implmentation dans la scne. Sachez simplement que la valeur de cet attributest modifie lors de l'appui d'une touche, par exemple des flches haut et bas ou bien la molette de la souris, au choix.

    Ainsi, il n'y a pas grand chose de plus implmenter pour avoir une camra de base. Notez qu'ici je ne considre qu'une rotationpar rapport l'axe Y, mais libre vous d'ajouter les deux autres axes si vous le voulez.

    L'avantage d'utiliser un objet camra dans cette scne, c'est que vous n'avez que les paramtres de ladite camra modifierlorsque vous la tournez ou la dplacez, plutt que de redplacer tous les objets un par un.

    Il suffit maintenant d'ajouter un attribut camra dans la classe MyScene, et de modifier la fonction placeItem() comme suit :

    Code : C++ - MyScene.cpp

    void MyScene::placeObjet(MyProxy *objet){ QTransform m; m.translate(objet->center().x(), objet->center().y()); m.translate(-objet->largeur(), -objet->hauteur());

    // ajout des transformations lies la position de la camra m.translate(-m_camera.pos().x(), -m_camera.pos().y()); m *= QTransform().rotate(m_camera.yaw(), Qt::YAxis);

    // simulation du dplacement suivant Z qreal scale = m_camera.zpos(); m *= QTransform().scale(scale, scale);

    item->setTransform(m);}

    Enfin vous remarquez l'utilisation de la fonction QTransform::scale() qui a un paramtre dpendant de l'attribut m_zpos de macamra. En effet, si je considre que lorsque ma position en Z augmente je me rapproche de la scne, alors cela revient voir lesobjets dans la scne en plus gros... donc les agrandir ! Ici j'ai fait une implmentation assez basique pour que vous compreniezle principe, on peut cependant affiner le comportement en ajoutant des coefficients multiplicateurs pour gagner en prcision.Voil ! J'espre que les classes QGraphics**** de Qt vous paraissent plus familires et que vous avez une ide du genre descnes qu'il est possible de raliser.Bien sr, les notions prsentes ici ne vous permettent pas de coder le prochain Half Life, mais aprs tout, il y a d'autresbibliothques pour cela.

    Voici pour terminer un lien vers un post trouv sur les Qt Labs Blogs, o l'on peut voir une vido d'un dveloppeur qui s'estamus prouver qu'il tait possible de faire un Wolfenstein-like avec les QGraphisItem. Vous pourrez d'ailleurs aller jeter un coupd'il son code, qui m'a beaucoup aid pour comprendre le fonctionnement de toutes ces classes. C'est par ici.

    Des widgets en 3D avec Qt 16/18

    www.openclassrooms.com

  • Partager

    Ce tutoriel a t corrig par les zCorrecteurs.

    Des widgets en 3D avec Qt 17/18

    www.openclassrooms.com

    Sommaire Des widgets en 3D avec QtInsrer des widgets dans une scneQuelques classes utilesDplacer les objets dans la scneLes coordonnesTranslationRotationMise l'chelle

    Les transformations avec QTransformUtiliser un QTransform avec un QGraphicsItemComposer les matricesUn outil bien pratiqueUne question d'ordre

    Des widgets en 3D !Que la rotation soitEt que a bouge !Grer plusieurs transformations diffrentes

    Pour aller plus loin : gestion de la camraLa camra : reprenons l'envers !Crer une camraPartager