Developpez.com

Plus de 2 000 forums
et jusqu'à 5 000 nouveaux messages par jour

Aperçu de Qt 3D 2.0

Présentation générale

Quand Qt était toujours un produit de Nokia, une équipe de développement de Brisbane, en Australie, a eu l'idée de faciliter l'incorporation de contenu 3D dans les applications Qt. Ces événements ont eu lieu en même temps que le développement du langage QML, il était donc naturel que Qt 3D ait une API QML, en plus d'une interface plus traditionnelle en C++, comme les autres modules de Qt.

4 commentaires Donner une note à l'article (5)

Article lu   fois.

Les deux auteur et traducteur

Traducteur : Profil Pro

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Historique

La première version de Qt 3D a été publiée en même temps que Qt 4 et n'a été que peu utilisée avant que Qt ne passe aux mains de Digia. Durant l'opération, les bureaux de Brisbane ont été fermés : par conséquent, Qt 3D n'a jamais été adapté pour Qt 5. Sans mainteneur, le code est tombé à l'abandon.

OpenGL devenant de plus en plus important dans Qt 5 (notamment pour Qt Quick 2), mais également dans les projets réalisés avec Qt, il paraissait intéressant de reprendre en main le projet Qt 3D, de le ressusciter, mais également de le rendre plus compétitif par rapport aux solutions modernes de 3D.

Cet article est le premier d'une série qui couvrira les possibilités qu'offre ce renouveau, les API et leurs implémentations en détail. Les prochains articles montreront la manière d'utiliser les API pour différents buts, des plus simples aux plus compliqués, à l'aide d'exemples détaillés. Ce premier article donnera un aperçu général des objectifs poursuivis lors de la conception de Qt 3D, mais également des difficultés rencontrées et leur solution, ce qu'il reste à faire avant une finalisation de Qt 3D 2.0 et ce que le futur pourra amener comme progrès.

II. Objectifs de Qt 3D

La plupart des gens qui ne sont pas familiers avec le rendu 3D pensent qu'une brique logicielle telle que Qt 3D devrait être capable de dessiner des formes 3D et de les déplacer, ainsi que de gérer la caméra. C'est un bon début, mais, en creusant un peu plus loin, ils aimeraient également d'autres choses :

  • la 2D autant que la 3D ;
  • les maillages ;
  • les matériaux ;
  • les ombres.

Ensuite, en posant la même question au groupe suivant, ceux qui ont une certaine habitude des complexités de la 3D, les réponses sont plus techniques :

Cette liste est déjà fort complexe, mais la pire d'entre elles est la dernière : l'utilisateur veut configurer le rendu de manière actuellement inimaginable. Qt 3D, premier du nom, offrait des interfaces multiples, que ce soit pour le QML ou le C++ - et cette fonctionnalité reste intéressante à garder. Le concept de « graphe de trame » respecte toutes ces contraintes, c'est-à-dire qu'il permet de configurer complètement le rendu.

Là où le graphe de scène était une description orientée données du contenu à afficher, le graphe de trame est une description orientée données de la manière d'afficher.

Utiliser une description orientée données donne une grande liberté de choix : un simple rendu non différé, avec une profondeur, un affichage différé ou d'objets transparents, etc. Puisque toute la chaîne est configurée à l'aide de données, non de code, tout peut changer très facilement, même de manière dynamique durant l'exécution, sans toucher à du code C++.

Après cet amuse-bouche — afficher du contenu 3D à l'écran —, les utilisateurs voudront aussi effectuer des opérations intéressantes sur ces objets 3D. La liste est longue et variée, mais les points qui reviennent le plus souvent sont :

Il serait bien évidemment impossible de répondre à toutes ces demandes avec des ressources limitées pour le développement. Cependant, il est clair que, pour incorporer toutes ces fonctionnalités dans le futur, l'architecture de Qt 3D 2.0 doit être extensible et flexible. Les travaux préparatoires ont été longs et beaucoup de prototypes ont été développés avant d'atteindre l'architecture actuelle. Elle sera présentée plus loin dans cet article et développée dans un prochain.

En sus de ces objectifs à plus ou moins long terme, Qt 3D devait également avoir de bonnes performances et s'adapter au nombre de cœurs disponibles. Ce dernier point est important à cause de la manière actuelle d'améliorer les performances du matériel : en augmentant le nombre de cœurs plutôt que la fréquence. D'ailleurs, en analysant ces demandes, intuitivement, il semble possible d'exploiter plusieurs cœurs, puisque bien des tâches sont indépendantes les unes des autres. Par exemple, les opérations de recherche de chemin ne chevauchent pas les tâches de rendu (sauf peut-être pour l'affichage d'informations de débogage ou de statistiques).

III. Vue d'ensemble de l'architecture

Tous ces besoins se sont révélés être épineux, très épineux à concilier. Heureusement, il a été possible de trouver des solutions abordables pour la plupart des problématiques.

Les commentaires sur leur résolution commenceront à un très haut niveau : comment implémenter un module Qt suffisamment extensible pour gérer non seulement l'affichage, mais également les autres fonctionnalités — et d'autres encore, impossibles à prévoir ?

Le cœur de Qt 3D est de simuler des objets en temps réel puis, très probablement, d'afficher l'état de ces objets à l'écran, d'une manière ou d'une autre. Cet énoncé propose déjà une question intéressante : qu'est-ce qu'un objet ?

II-A. Notion d'objet

Bien évidemment, dans ce genre de système de simulation, le nombre de types différents d'objets sera probablement très grand. Un jeu simple, comme Space Invaders, peut déjà en comporter un grand nombre. Une application réelle sera très certainement beaucoup plus complexe, mais ce jeu pointera déjà une série de questions. Parmi les objets très probablement présents dans un tel jeu, on peut compter :

  • le canon du joueur, au sol ;
  • le sol ;
  • les blocs de défense ;
  • les vaisseaux de l'ennemi ;
  • la soucoupe volante du boss ;
  • les balles, tirées tant par le joueur que par l'ennemi.
Image non disponible

Dans une conception de la plus pure tradition C++, ces objets seront très probablement implémentés en utilisant des classes, dans une certaine hiérarchie d'héritage. Les différentes branches pourront apporter des fonctionnalités aux objets, comme « accepte une entrée de la part de l'utilisateur », « émet des sons », « peut être animé », « entre en collision avec d'autres objets », « doit être affiché à l'écran ». Cependant, concevoir une telle hiérarchie, même pour un problème aussi simple, n'est pas facile.

Cette approche et d'autres variations sur le thème de l'héritage ont un certain nombre de problèmes (qui seront discutés plus en détail dans d'autres articles) :

  • une hiérarchie profonde et large est difficile à comprendre, à maintenir et à étendre ;
  • la taxonomie d'héritage est définie à la compilation et ne peut plus être changée ;
  • chaque niveau de la hiérarchie ne peut classifier que selon un critère ;
  • les fonctionnalités partagées tendent à monter dans la hiérarchie avec le temps ;
  • le concepteur de la bibliothèque ne peut jamais savoir tout ce que les utilisateurs feront.

Toute personne qui a travaillé avec une telle hiérarchie trouvera probablement que, à moins de comprendre et d'être d'accord avec la taxonomie de l'auteur, il peut être très difficile de l'étendre sans bidouiller pour y faire rentrer les extensions requises.

II-B. Système à entités

Pour Qt 3D, le concept d'héritage a été en grande partie abandonné et remplacé par l'agrégation en tant que manière d'importer des fonctionnalités dans une instance d'un objet. Plus précisément, Qt 3D utilise un système à entités (ECS : entity-component system). Ce principe peut être implémenté de diverses manières et les détails spécifiques à Qt 3D seront abordés dans un prochain article.

Une entité représente un objet simulé, mais est, par elle-même, dénuée de tout comportement ou caractéristique. Un comportement peut être greffé sur une entité en agrégeant des composants.

Ainsi, un composant est une partie de comportement ou de fonctionnalité, dans la même veine que ceux décrits pour le Space Invaders. Par exemple, le sol serait une entité attachée à un composant qui indique au système qu'il faut l'afficher, mais également comment l'afficher. Un ennemi sera une entité attachée à un composant qui indique qu'il faut l'afficher à l'écran, un autre pour l'émission de sons, encore un autre pour les collisions, l'animation, un dernier pour l'intelligence artificielle. Le joueur sera fort similaire à l'ennemi, à l'exception qu'il n'aurait pas d'intelligence artificielle, plutôt un composant gérant les entrées du joueur (les déplacements et les tirs).

Image non disponible

Qt 3D implémente la partie système du paradigme, sous la forme d'aspects. Un aspect implémente une partie des fonctionnalités attribuées aux entités par une agrégation d'un ou plusieurs composants. Concrètement, l'aspect du rendu recherche les entités qui ont un maillage, une texture et des composants de transformation ; s'il trouve une telle entité, il sait comment exploiter ces données et effectuer un rendu : par conséquent, il ignore les entités qui n'ont pas ces composants.

De même, un aspect gérant la physique pourrait chercher des entités qui ont une certaine forme de volume de collision comme composant, ainsi qu'un autre composant qui spécifie d'autres propriétés requises pour la simulation, comme la masse ou le coefficient de friction. Une entité qui émet un son pourrait avoir un composant qui indique quel son jouer et à quel moment.

En résumé, Qt 3D construit des entités en agrégeant des composants qui leur communiquent des aptitudes. Le moteur Qt 3D utilise des aspects pour traiter et mettre à jour les entités avec des composants spécifiques.

Une fonctionnalité très intéressante d'un système à entités est que, par l'utilisation de l'agrégation en lieu et place de l'héritage, il est possible de changer, dynamiquement, le comportement d'un objet, simplement en ajoutant ou en retirant des composants. Par exemple, pour laisser le joueur parfois traverser les murs, il suffit de retirer le composant gérant le volume de collision de l'entité, puis de le remettre quand la durée du pouvoir spécial est écoulée. Ce système n'impose donc pas de créer une classe comme JoueurQuiPeutParfoisTraverserLesMurs.

II-C. Implémentation

Ceci donne une bonne indication du niveau de flexibilité du système à entités, c'est d'ailleurs pour cela qu'il a été choisi comme fondation architecturale de Qt 3D. La hiérarchie de classes correspondante est également très simple. La « classe de base » de Qt 3D est QNode, un dérivé très simple de QObject qui gère automatiquement la communication des changements de propriétés à travers le système d'aspects et un identifiant unique dans l'application. Un futur article expliquera les détails des aspects : ils travaillent dans des fils d'exécution séparés, QNode simplifie fortement le transfert de données entre les objets visibles à l'utilisateur et les aspects. Souvent, les sous-classes de QNode fournissent des données supplémentaires, qui sont ensuite référencées par les composants. Par exemple, un QShaderProgram spécifie du code GLSL à utiliser pour l'affichage d'un ensemble d'entités.

Image non disponible

Les composants de Qt 3D sont implémentés en héritant de QComponent et en ajoutant toute information nécessaire pour que les aspects correspondants effectuent leur travail. Par exemple, le composant de maillage Mesh est utilisé par l'aspect de rendu pour récupérer les informations de chaque sommet à envoyer à OpenGL.

Finalement, QEntity est un objet qui agrège simplement un ensemble d'au moins zéro QComponent, comme expliqué plus haut.

Pour ajouter une nouvelle fonctionnalité à Qt 3D, en tant que partie de Qt ou extension spécifique à une application, tout en bénéficiant des aptitudes de parallélisation du système, il suffit de suivre quelques étapes :

  • identifier et implémenter les composants nécessaires pour gérer les données ;
  • enregistrer ces composants auprès du moteur Qt Quick (uniquement pour exploiter l'API QML) ;
  • hériter de QAbstractAspect et implémenter les fonctionnalités du nouveau sous-système.

La gestion du parallélisme est native pour Qt 3D, vu comme un moteur orienté tâches : il demande à chaque aspect, pour chaque trame à dessiner, une liste de tâches à exécuter, ainsi que leurs dépendances. Les tâches sont alors distribuées sur les différents cœurs de calcul de la machine par un ordonnanceur.

Dit comme cela, la chose peut paraître aisée. Après avoir implémenté l'aspect de rendu et effectué quelques recherches sur d'autres aspects potentiels, l'équipe de développement est assez sûre d'elle : ce système sera flexible et extensible, suffisamment pour les besoins de Qt 3D.

IV. Résumé

Les cas d'utilisation de Qt 3D dépassent largement l'implémentation d'un moteur de rendu non configurable, mais accessible depuis QML. Il s'agit plutôt d'une solution de rendu complètement configurable, qui permet d'implémenter rapidement toute technique de rendu souhaitée. De plus, Qt 3D fournit un environnement générique pour des simulations en temps (presque) réel au-delà du rendu. Qt 3D sépare proprement le cœur d'un nombre indéfini d'aspects qui peuvent implémenter n'importe quel type de fonctionnalités. Ces aspects interagissent avec les composants et les entités pour fournir des parties de fonctionnalités. De futurs aspects pourraient gérer la physique, l'audio, les collisions, la recherche de chemin ou encore l'intelligence artificielle.

Les prochains articles de cette série montreront la manière d'utiliser Qt 3D et l'aspect de rendu pour afficher un objet avec des shaders et l'animer depuis QML.

V. Article original

Le blog KDAB est rédigé par les ingénieurs de KDAB s'occupant des formations, de la consultance ainsi que du développement (de Qt et de produits additionnels). Vous pouvez trouver les  versions originales.

Cet article est une traduction de l'article original écrit par Sean Harmer paru le 16 septembre 2014.

Cet article est une traduction de l'un des articles en anglais écrits par KDAB. Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à KDAB.

VI. Remerciements

Au nom de toute l'équipe Qt, j'aimerais adresser le plus grand remerciement à KDAB pour nous avoir autorisés à traduire cet article !

Je tiens à remercier Alexandre Laurent et Claude Leloup pour leurs conseils et relectures.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2015 Sean Harmer. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.