|
|
|
|
Objet 3D statiqueOn commence à se rendre compte qu'il est temps de créer une classe permettant de gérer les objets 3D. C'est ce que nous allons faire maintenant.
Sommaire du chapitre :
![]() Définition de notre objet 3DOn aimerait que :
La classeSon nomJ'ai choisi d'appeler la classe Objet3DStatique. Elle décrit un objet, 3D, qui ne se déformera pas. On la déclarera dans un fichier objet3DStatique.h et on la définira dans un fichier objet3DStatique.cpp. Ses méthodesLe constructeurUn seul constructeur sera nécessaire ; il prendra en paramètre le nom du fichier sous la forme d'un std::string. Autres méthodesL'objet 3D ne peut qu'être dessiné, on ajoute donc une méthode dessiner3D(). Bien entendu, il pourrait se déplacer, tourner... Mais par soucis de simplicité, nous allons ajouter à notre objet 4 attributs publiques :
Généralement, on ne rend pas publique les attributs d'une classe. Ici je me permets de le faire pour éviter de passer par des accesseurs à chaque fois que je vais les manipuler. On pourra revoir ça plus tard. Les attributs privésEn interne, la classe "embarquera" les textures de l'objet. On peut donc refaire ce qu'on avait déjà fait pour les textures :
Le fichier de l'objet 3DPour pouvoir charger l'objet 3D, nous devons créer un format d'objet 3D. Afin que celui-ci soit facilement modifiable, nous allons le faire en ASCII (en texte). Afin d'accélérer le rendu, nous créerons une liste d'affichage. Les textures doivent exister avant de créer la liste d'affichage. Dans le fichier, on va donc séparer le chargement des textures de la création de la liste d'affichage. Notre classe comportera donc un attribut de plus :
La méthode dessiner3D() fera donc appel à cette liste d'affichage. Le format O3SAprès réflexion, voici à quoi ressemble le fichier de ma skybox que j'ai appelé skybox.o3s. Je vous laisse essayer de comprendre mon format O3S (Objet 3D Statique).
ExplicationsNomLe tag nom permet de donner un nom à notre objet. Pour l'instant, il n'a pas vraiment d'utilité.
Chargement des texturesPar soucis de simplicité, j'ai choisi d'énumérer toutes les textures en tête de fichier.
A chaque fois qu'on rencontrera le tag "image", on chargera la texture en question. Toutes les textures doivent être chargées avant le début de la description de l'objet. Rotation, Redimensionnement, TranslationLe tag rst permet d'adapter la taille et le sens de l'objet au reste de la scène. La taille des objets étant relative aux autres objets, ce choix permet d'adapter notre objet à la scène.
Ce tag aura pour effet d'effectuer les transformations suivantes :
Description de l'objetEnsuite, on décrit l'objet par polygone :
La première ligne signifie que l'on sélectionne la texture skybox\devant.bmp. Ensuite, on ouvre une accolade, ce qui signifie que le dessin du polygone va commencer. Chaque ligne définit un sommet du polygone.
Cette ligne fait correspondre le point (0;0) du BMP (en haut à gauche, les X en premier et vers la droite) au point tridimensionnel (-1;-1;1) de l'objet dans l'espace. ConclusionComme vous pouvez le voir, le format O3S a le mérite d'être simple et facilement modifiable. Il conviendra pour la plupart des objets de notre scène. Il a pour inconvénient de pouvoir ne décrire que des objets 3D statique. Ce format ne convient pas pour un personnage avec des jambes qui bougent lorsqu'il se déplace. La classe de l'objet 3DChargementDans un premier temps, je m'occupe du chargement de l'objet sans m'occuper de l'affichage. Voici ce que j'ai fait pour commencer :
Cela fait beaucoup de ligne d'un coup, c'est vrai. Mais ce code n'est pas très compliqué à comprendre. C'est la raison pour laquelle je ne vais pas expliquer davantage. Prenez le temps de bien comprendre ce qu'il fait avant de continuer. Afin d'éviter la fuite de mémoire liée au chargement des textures, je libère dès maintenant les textures dans le destructeur :
Liste d'affichagePour ceux qui aurait oublié ce qu'est une liste d'affichage, c'est comme un affichage, sauf que ça n'affiche pas, mais ça enregistre les étapes d'affichage dans la carte graphique. On génère une liste d'affichage avec glGenLists(), on la commence avec glNewList() puis on la termine avec glEndList(). On va maintenant distinguer deux modes : le mode création de la liste d'affichage activé de celui désactivé. Au début du chargement, le mode création de la liste d'affichage est désactivé :
La liste d'affichage commence lorsqu'on rencontre la première accolade :
Remarquez que j'ai ajouté un attribut listeAffichage. Pour chaque polygone, on fait une boucle pour parcourir les sommets et les ajouter à la liste d'affichage. Lorsqu'on rencontre l'accolade fermante, on termine le polygone en cours. Remarquez également le changement de la texture courante qui s'effectue lorsqu'on rencontre le tag "image". Pour finir, je fais un appel à glEndList(), puis je libère le fichier. Voici le code de la fonction :
Ce code est encore provisoire, n'aillant pas connaissance de la taille des textures, je me suis retrouvé bloqué lorsqu'il a s'agit de définir les sommets de la textures. Nous verrons plus tard comment s'y prendre pour remédier à ce problème. La gestion des textures sera faite plus tard. Au niveau des appels aux fonctions glTexCoord2f() et glVertex3d(), il y a une petite subtilité. Les textures SDL sont chargés avec pour origine l'angle situé en haut à gauche tandis que l'origine d'OpenGL est en bas à gauche. C'est la raison pour laquelle il faut faire 256 - (float16)y2D. RSTPour ce qui concerne le tag RST permettant d'apporter la correction de l'objet dans la scène, voici comment j'ai fait :
Je vous l'accorde, le sscanf n'est pas très propre. Tant pis. L'attribut listeRST à dû être ajouté. Dessin de l'objetPour dessiner, rien de plus simple, on mémorise le repère courant (la matrice), puis on dessine l'objet à sa place avec la correction RST, et on termine par une restauration du repère d'origine.
Test d'affichage de l'objetJ'ajoute un objet à ma scène que j'instancie à partir de mon fichier de skybox et je remplace l'affichage manuel de la skybox par un appel à ma méthode dessiner3D(). Visiblement rien de ne passe. Pas de panique, les choses fonctionnent rarement du premier coup. DébuggerPour débugger, chacun sa méthode. Personnellement je ne suis pas fan de débugger, je préfère écrire dans un fichier les actions qui s'exécutent et les analyser après. Je tiens à préciser qu'il s'agit d'un bug involontaire de ma part. Je pensais que ça fonctionnerait du premier coup. Vous assistez donc en live à un bug. C'est l'occasion pour moi de vous montrer comment je m'y prend pour le résoudre. Ce dont on est sûrOn voit que rien ne s'affiche. Nous somme pourtant sur que l'objet est bien instancié. Peut-être que les textures ne sont pas chargées correctement. Pourtant, si elles n'était pas chargées correctement et qu'on essayait de les afficher, on les verrait apparaître en blanc. La caméra étant correctement placée, à priori, les textures ne sont donc pas dessinées à l'écran. On peut donc se demander si les textures ont été correctement lues dans le fichiers O3S. On va donc vérifier que les tags image aient bien été détectés et créés.
Après exécution, dans le fichier stdout.txt (sortie standard de la SDL), j'obtient ceci :
A priori, les textures sont bien détectées et chargées. Nous allons vérifier la liste d'affichage en affichant chaque commande OpenGL à l'aide de printf. Par exemple :
Après exécution, je vois ceci :
La liste d'affichage me paraît correcte. Il n'y a donc aucune raison que la skybox ne soit pas dessinée. Si elle est bien dessiné, où est-elle dessiné ? Visiblement, on la dessine en (this->positionX;this->positionY;this->positionZ). Si elles sont bien initialisé à zéro, la skybox devrait apparaitre au centre de l'écran. En regardant le constructeur, on se rend compte que les variables initialisées ne sont pas les attributs. Après rectification, ça marche ! ![]() Modélisation de la skyboxNous ne voyons que 2 faces. Ceci est parfaitement normal, les faces "vers nous" sont regardées de derrière, elle ne sont donc pas dessinées. Pour vérifier les faces, nous devons soit déplacer la caméra, soit faire tourner la skybox. Le plus simple est de la faire tourner :
On remarque alors un "bug" au niveau de la face est. Je vous laisse faire la correction dans le fichier O3S. Vous devriez obtenir ceci : Je vous laisse également faire le bas, puis le haut. Pour le haut, vous devrez placer la caméra dans les Z négatifs.
Temps de construction de l'imageChez moi, le cube fait une tour complet en 20 secondes. Je m'interroge donc sur le temps de la boucle de construction de l'image. Un simple produit en croix me dit qu'en mettant 20 secondes à faire 360°, avec une rotation de 0.3° par image, j'obtiens un temps de construction d'image de 16ms, soit 60 images par seconde. Suis-je déjà arrivé à la limite ?Cela supposerait donc que le processeur consomme 100% du CPU, or ce n'est pas cas. Une pause serait donc faite quelque part ? En réalité, dans ma configuration graphique, j'ai validé l'option : "Synchronisation verticale". Cela a pour effet de bloquer l'affichage glFlush() jusqu'à l'heure de la prochaine image. Mon écran étant synchronisé à 60 images par seconde, ma boucle de création de l'image sera limité à 60 images par seconde. (60 FPS) Ne soyez donc pas surpris si votre programme se limite à 60 FPS, c'est tout à fait normal. Si la synchronisation verticale n'est pas activé, vous devriez mémoriser l'heure de la dernière boucle et faire tourner le cube de façon proportionnel au temps écoulé afin que la vitesse de rotation ne dépende pas de la machine qui exécute le programme. Agrandir la skybox, placer la camera en centrePour agrandir la skybox, rien de plus simple, il suffit de redimensionner l'objet directement dans l'O3S :
Maintenant, le cube est si grand que la camera est presque au centre du cube. Pour le moment, on se satisfera de ce résultat. Si vous agrandissez trop la skybox, vous risquez de voir du noir. La raison est très simple, votre skybox est en collision avec le plan de clipping du fond (réglé à 1000 pour le moment), ce qui a pour effet de ne pas la dessiner, on voit donc du noir. Entre les textures, des lignes apparaissentEn regardant bien, on peut voir un trait entre les textures. Pour remédier à ce problème, on peut croiser très légèrement les textures ou utiliser un mode de rendu différent. Dans le cadre de ce chapitre, je n'en parlerais pas. Vous trouverez des informations en tapant sur google les mots suivant : skybox arêtes opengl. Nous verrons plus tard comment remédier à ce problème. Nous savons maintenant comment modéliser un objet 3D et le manipuler. Souvenez-vous, lors de la création de la liste d'affichage, il nous manquait une information : la taille de la texture. Dans le prochain chapitre, nous allons organiser nos textures de façon à mémoriser ses informations. D'autre part, il y a un problème que j'ai passé sous silence, il s'agit de la charge des textures dans la carte graphique lorsqu'un objet et instancié plusieurs fois. Pourquoi recharger une texture qu'on a déjà chargée ? (Perte de temps, perte de place...) Nous mettrons donc au point un mécanisme permettant de ne charger que les textures utiles. Jusqu'à présent, nous ne faisons que des choses qui ne se voient pas, ce qui peut être assez décourageant. Ce qu'il faut bien garder à l'esprit, c'est que nous faisons tout cela pour faciliter le développement de la suite de notre jeu. Nous prendrons de la hauteur et il sera très facile ensuite d'ajouter des objets, sans se préoccuper des "couches basses". Pour repartir du bon pied, voici le projet actuel. J'ai fait un peu de mise au propre. ![]() Rédigé par David
Consulté 7601 fois |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hébergeur du site : 1and1.fr Site de création de Jeux Vidéo Apprenez à créer vos propres Jeux Video |
1389737 pages ont été consultées sur le site ! Dont 1629 pages pendant les 24 dernières heures. Page générée en 0.605 secondes Nos partenaires - Otium Production : Aide aux débutants à créer leurs jeux - Les bibliothèques de développement de jeux vidéo |