cliquer - PAGE D`accueil
Transcription
cliquer - PAGE D`accueil
0.1 Il nous a paru nécessaire d'écrire une petite introduction à DirectX ainsi qu'à ses composantes DirectDraw et Direct3D. En effet, nous allons employer de nombreux termes relatifs à ces 3 Direct. De plus, de part la nature de notre projet, il nous à semblé indispensable de vous faire une courte introduction sur les jeux vidéos de rôle (« RPG » : rôle playing game), qui permettra - par comparaison - de mieux définir nos objectifs. 1. DIRECTX DirectX est une bibliothèque de fonctions créée par Microsoft pour permettre aux développeurs de jeux de ne plus se soucier du matériel utilisé. Ainsi un programme écrit pour un certain type de machine doit théoriquement pouvoir marcher sur tout autre configuration (malgré le fait, par exemple, qu'il n'y ait pas la même carte vidéo, ni la même carte son…). L'idée de départ venait du fait que dans le monde DOS, les jeux requérant des accélérations matérielles devaient être réécrits pour chacune des cartes du marché (carte son et 3D). Microsoft avec Windows95 eu besoin d’unifier ces bibliothèques pour enfin pouvoir programmer des jeux en étant indépendant du matériel. Dans la plupart des cas ceci est vérifié, même si bien des fonctions spécifiques ne sont pas implémentées de la même manière (même parfois pas du tout) suivant les constructeurs. Car c’est à la charge du fabriquant d’écrire les pilotes pour assurer la compatibilité de son matériel avec DirectX : il ne reste plus qu’à espérer pour le programmeur de jeux vidéo, que ce lien à été réalisé de façon correcte ! DirectX est fourni sous la forme d'un SDK (Software Development Kit). Dans lequel se trouve les librairies appropriées aux principaux compilateurs (C++, Java, VB), de nombreux exemples de codes, une aide en ligne volumineuse ainsi que des applications qui permettent de tester le matériel. DirectX se compose de DirectDraw pour l'affichage 2D, Direct3D pour l'affichage de scène en 3D, de DirectInput pour la gestion des périphériques d'entrée (clavier, souris, manettes de jeux…), de DirectSound qui gère toute la partie son, de DirectMusic qui s'occupe de la musique de fond (pour pouvoir rendre une musique dynamique), de DirectShow qui permet l'affichage de vidéo et la lecture de mp3 et enfin de DirectPlay qui permet de jouer en réseau. Actuellement, nous en sommes à la version 8 de DirectX. Dans cette version, DirectDraw et Direct3D sont regroupés dans DirectGraphics ainsi que DirectSound et DirectMusic dans DirectMusic. Figure 1 : organisation de DirectX 0.2 DirectX possède une compatibilité descendante c'est à dire qu’un programme écrit avec une version X sera compatible avec les librairies X et ultérieures. Ceci est dû au fait que DirectX est construit sur le modèle COM : au fur et à mesure des versions, les fonctions ne sont qu’ajoutées et non remplacées. Toutes les composantes utilisent des "buffers" autrement dit des tampons de données contenant diverses informations, et cela en fonction de la nature de la composante (DirectDraw gère des images, Direct3D des textures, DirectSound des Waves…). 2. DIRECTDRAW DirectDraw est la composante de DirectX la plus importante, du moment où il est nécessaire d’afficher des graphismes en plein écran. En effet : elle gère exclusivement l'affichage 2D des surfaces et les autres modules graphiques (Direct3D, DirectShow…) doivent obligatoirement dialoguer avec elle pour pouvoir accéder à la surface écran. Ici nous ne travaillons qu'avec des morceaux d’images appelées « surfaces ». Les opérations possibles avec ces tampons se limitent à : - Copies d’images ou morceaux d’images. Les fonctions employées sont dites de « Blitting » : elles ne peuvent faire que des transferts simples, tout mélange de couleur ou transformation géométrique est soit impossible, soit bien trop lent du fait de la prise en charge logicielle des opérations (DirectDraw n’utilise que très peu les fonctions 2D des GPU). De plus, dans notre jeu nous n’utilisons pas ces fonctions, car elles posent des problèmes de compatibilité avec les fonctions Direct3D. - Accès directs en lecture / écriture. DirectDraw nous permet de travailler dans les surfaces comme dans n’importe quelle zone mémoire. Pour cela il faut auparavant bloquer la surface avec la fonction « Lock », celle ci retourne un pointeur sur le début de l’image. Le point délicat réside dans le fait que ces surfaces ont différents formats de pixels : il peut être de 16, 24 ou 32 bits, puis dans ce total on peut répartir différemment les bits pour chaque composante R, G, B et canal Alpha (A Æ transparence du pixel). De plus, l’organisation des lignes peut être non linéaire (pour une surface écran de 800x600, la carte vidéo stocke souvent les lignes sur 1024 pixels pour faciliter ses calculs). Malgré cela, nous utilisons la fonction « Lock » lors du chargement des textures (Disque dur vers surface), et pour lire des pixels sur l’écran. Figure 2 : les composantes de couleur. 0.3 - La gestion du « double-buffering », Pour l’affichage à proprement parler, nous utilisons deux types de surfaces : primaire (« FrontBuffer ») et secondaire (« BackBuffer »). Chaque application écrite avec DirectDraw ne possède normalement qu’une seule surface primaire. En effet, celle-ci correspond au contenu de l’écran : donc cette surface est directement visible par l’utilisateur. Pour éviter que la construction de l’image ne soit visible (scintillement), les opérations graphiques se déroulent exclusivement dans la surface secondaire. Une fois le rendu de l’image terminé, le programme appelle une fonction DirectDraw : le « Flip » qui permet d’intervertir la surface primaire avec la surface secondaire donc de l’afficher à l’écran. Enfin, toutes les surfaces qui ne participent pas directement à l’affichage (autre que primaire et secondaire) sont appelées surfaces hors-écran (« Off-screen »). Elles servent à stocker les textures dans notre cas, ou les sprites 2D en général. Figure 3 : utilisation de DirectDraw, gestion du double-buffering. 3. DIRECT3D Direct3D est la couche de DirectX permettant de gérer l’affichage de primitives 3D. Tout d’abord il nous semble important de définir ce que fait réellement Direct3D et ce qui reste à la charge du programmeur. Premièrement Direct3D ne possède pas de notions de primitives 3D (Boites, sphères, objets…), c’était vrai jusqu'à la version 6 si le « mode retenu » était utilisé : mais ce type de fonctionnement était loin d’être exempt de problèmes (compatibilité, rapidité…), et il à été abandonné à partir de DirectX version 7. Ceci précisé, nous pouvons considérer que Direct3D ne sait tracer que des triangles ! Même les polygones à 4 côtés doivent êtres divisés (« Splités ») pour pouvoir être assimilés (Au contraire de l’OpenGL). 0.4 A partir de ces triangles représentés dans un espace de dimension 3, Direct3D les rends en effectuant ce panel d’opérations possibles : - transformations dans l’espace : en premier lieu il faut passer de la dimension 3 à la dimension 2 caractérisant l’écran : pour cela, lors du rendu, Direct3D effectue la projection des points. Dans notre cas, s’agissant d’un jeu 2D, nous avons décidé d’oublier la coordonnée Z des points. L’initialisation du « Viewport » (fenêtre de visualisation) à donc été faîte pour que les coordonnées (X,Y) des points correspondent aux coordonnées (x,y) de l’écran (projection orthogonale). Figure 4 : illustration de la projection orthogonale. - « Lighting » (illumination) : ceci consiste à calculer (hardware avec les G-Forces, software sinon) la valeur d’illumination des points des triangles suivant sa normale, sa position et les caractéristiques des sources lumineuses définies auparavant dans la scène (Objets « Light »). Cette possibilité est importante pour le réalisme des scènes 3D. Mais, encore une fois, dans le cadre d’une utilisation 2D nous désactiverons cette fonction (pour chaque tracé de primitive, il est nécessaire de préciser à Direct3D de désactiver le «Lighting »). Nous aurons aussi des lampes dynamiques, mais elles seront simulées par des textures. - Application de texture: Ce qui va suivre explique en grande partie notre choix de développer notre moteur en utilisant Direct3D. En effet, au contraire de DirectDraw, il est possible de rendre une surface 2D en l’étirant suivant les points extérieurs. De plus nous pouvons indiquer à Direct3D d’effectuer un filtrage linéaire des pixels, pour éviter les effets d’escalier en cas de déformations ou changements d’échelle. Figure 5 : différence de qualité entre le filtrage linéaire et le « pixel voisin ». 0.5 Les textures elles-mêmes sont des surfaces DirectDraw possédant une interface adéquate. Comme elles résident le plus souvent en mémoire vidéo et sont directement utilisées par la carte graphique, les contraintes techniques sont nombreuses. Notamment la taille (largeur et hauteur) doit être obligatoirement une puissance de deux. De plus, la mémoire vidéo est limitée (suivant la carte graphique, la présence de l’AGP ou non…), donc nous avons été obligé d’utiliser, pour les textures, un format de pixel sur 16 bits (le 1-5-5-5 avec un bit pour le canal alpha) qui ne permet pas de restituer toutes les nuances de couleur. - Gouraud : Utilisé pour adoucir les transitions des facettes d’objets 3D et pour l’éclairage, le modèle d’illumination de Gouraud est en fait une interpolation 2D des indices de couleurs situés aux extrémités du triangle. Nous allons utiliser cette fonction pour simuler l’éclairement de nos sprites. Figure 6 : illustration de l’interpolation de couleur qu’effectue le Gouraud entre trois points d’un triangle possédant des indices de couleurs différents. Ceci sans et avec texture. - Mélange de couleurs (« Alpha-Blending ») : Cette technique consiste à mélanger la couleur du nouveau pixel (source) avec le précédant (destinataire) situé sur la surface de rendu. Ceci en fonction de leurs valeurs RGB et/ou de leurs canaux alpha. Il existe une multitude de paramètres permettant au programmeur de réaliser la plupart des effets de transparence, mais aussi de masque et de combinaison. Pour s’en donner une idée veuillez vous reporter à l’annexe X où un tableau récapitule toutes les combinaisons possibles. Figure 7 : Un exemple de mélange possible : l’alpha-blending additif , qui est la combinaison la plus courante : c’est une addition saturée (donc pas d’overflow) entre chaque composante de couleur. 0.6 - L’alpha-testing : Un cas particulier de l’alpha-blending qui permet d’afficher que certains pixels lors de l’application d’une texture, et cela suivant son canal alpha. Nous utiliserons très souvent cette possibilité car nos sprites n’occupent pas tout un rectangle mais possèdent un découpage complexe. Figure 8 : affichage d’un sprite en utilisant l’alpha-testing qui se sert du canal alpha de la texture source : le pixel est affiché que si son alpha est au-dessus d’un certain seuil. Comme c’est un choix binaire nous avons choisi de mettre le canal alpha de toutes les textures sur 1 seul bit. Bien-sûr, Direct3D propose bien d’autres possibilités (Z-buffer, brouillard…). Mais elles ne seront pas exposées ici, étant - de part sa nature - totalement ignorées par notre moteur 2D. Il faut préciser que le moteur 2D, utilisant toutes les techniques décrites ci-dessus, aurait pu en théorie être directement implémenté de façon logicielle. Mais dans ce cas, malgré une optimisation parfaite, nous aurions jamais atteint les 30 images par secondes obligatoires pour une animation fluide des objets à l’écran. En effet la plupart des opérations Direct3D sont directement prises en charge par la carte graphique dédiée, le processeur ne pouvant avoir une telle rapidité de traitement pour ces calculs massifs et spécifiques. Figure 9 : deux screenshots d’une scène du jeu vidéo « Unreal Tournament ». L’un montre le rendu via Direct3D, l’autre avec uniquement le processeur. Malgré la qualité du rendu logiciel (le meilleur de sa catégorie), on peut constater que les textures ne sont pas filtrées, les effets de transparence sont réduits ou supprimés (flare des lampes). De plus, le rendu D3D est extrêmement plus rapide… En définitive, la plupart des effets de notre jeu, notamment l’alpha-blending, doivent leur présence à Direct3D (pour son exploitation directe du matériel 3D), dans ce but nous avons construit, dès le départ, notre moteur 2D autour de cette bibliothèque. 0.7 4. RPG Le RPG (« Rôle Playing Game ») est une catégorie de jeu à part, au même titre que les quakes-likes (jeux de tir en vue subjective) ou les simulations de courses… Le principe est assez simple : vous contrôlez un personnage central, qui évolue à travers un monde immense. Le but est d’achever des quêtes (tuer dragon, libérer princesse…) tout en faisant évoluer les caractéristiques de votre personnage : son endurance, force physique, niveau de magie, dextérité, nouveaux sort et armement… Un aspect intéressant de ce type de jeu est l’IA : des personnages « intelligents » contribuent à donner du réalisme et de l’intérêt au jeu. Et cela pour les ennemis, comme pour les autres protagonistes (marchands, simples passants, compagnons de route…). A ce propos, la référence en matière de RPG sur ordinateur : « Baldur’s Gate », utilise un système d’IA sophistiqué appelé « Bioware system », il gère, entre autres, la notion de réputation du personnage et les réactions complexes de ses compagnons de route… Mais pour quoi s’être fixé sur ce type de jeu ? Avant de pouvoir répondre, il faut savoir que la tendance générale dans l’industrie du jeu vidéo est de passer à la « tout 3D ». Mêmes les types de jeux qui semblaient très bien fonctionner en 2D avec des sprites (comme les jeux de stratégies) suivent cette tendance (avec des résultats mitigés). Mais heureusement, la plupart du temps, les jeux de type RPG restent encore en 2D : ceci vient principalement du « gameplay » (façon de jouer) particulier, qui est plutôt adapté à une vue isométrique lointaine. De plus, encore très peu de titres utilisent l’accélération 3D des cartes vidéos pour améliorer les effets 2D et proposer un éclairage dynamique. C’est un challenge qui nous à semblé intéressant de relever… Maintenant que nous avons définit le principe du RPG, nous pouvons commencer à énumérer les principales caractéristiques et les choix effectués dans le cadre de notre jeu : La vue isométrique : la « caméra » est placée tel que le personnage principal soit toujours centré à l’écran. On simule en fait une vue de dessus avec un angle de 30° par rapport à l’horizontale du terrain. Cet angle n’est pas choisi au hasard : 30° permet d’avoir des cases deux fois plus large que hautes, donc simplifie les calculs par la suite. En effet dans un soucis d’optimisation nous utiliserons le plus possible des puissance de deux (8 ,16, 32, 64, 128…), avec lesquelles toutes les multiplications (très coûteuses en temps processeur) pourront êtres remplacées par des décalages de bits. Par exemple la taille de nos dalles est de 64x32… - Cases en diamant : pour apporter plus de réalisme, et essayer de camoufler l’utilisation des cases, nous ne projetons pas directement le terrain parallèlement à x ou y, mais on le tourne de 45° - 0.8