Commit a97b17e0 authored by Benjamin Castel's avatar Benjamin Castel
Browse files

edit: Corrected report

parent 71af0473
Loading
Loading
Loading
Loading
+22 −24
Changes for rapport/rapport.md: 22 added lines, 24 removed lines.
Original line number Diff line number Diff line
@@ -53,20 +53,17 @@ De plus, nous nous sommes fixé les contraintes suivantes pour ne pas nous épar
## Programmation

### Modifications apportées à *glitter*
<!-- TODO : Compléter -->

Nous avons dû modifier quelque peu glitter afin de permettre de mieux gérer certains éléments de notre projet. Nous avons notamment créé notre propre implémentation
Nous avons dû modifier quelque peu glitter afin de permettre de mieux gérer certains éléments de notre projet :

- Comme *glitter* est utilisé en tant que dépendance de notre projet actuel, certaines variables de *glitter* tel que *GLFW3_LIBAIRIES* étaient nécessaire pour le linking <!-- park --> de notre projet et n'étaient pas accessible. Nous avons donc ajouté des variables en *PARENT_SCOPE* dans le *external.cmake*.
- La touche *Q* (qwerty) ne ferme plus la fenêtre
- La touche *espace* ne bloque plus les update du jeu
- Possibilité d'envoyer des *boolean* aux *shaders* sous la forme d'*uniform*

- Comme *glitter* est utilisé en tant que dépendance de notre projet actuel, certaines variables de *glitter* telles que `GLFW3_LIBAIRIES` étaient nécessaire pour le linking de notre projet et n'étaient pas accessible. Nous avons donc ajouté des variables en `PARENT_SCOPE` dans le *external.cmake*.
- La touche `Q` (qwerty) ne ferme plus la fenêtre
- La touche `Space` ne bloque plus les updates du jeu
- Possibilité d'envoyer des *boléens* aux *shaders* sous la forme d'*uniforms*

### Système d'entités

Le système d'entités est géré par la classe `model/Entity`. Cette classe a pour but de gérer une unité dans l'espace 3D, notamment de gérer sa position, sa rotation, son échelle (qui peuvent ensuite être transmis au `glapi` de glitter)
Le système d'entités est géré par la classe `model/Entity`. Cette classe a pour but de gérer une unité dans l'espace 3D, notamment de gérer sa position, sa rotation, son échelle (qui peuvent ensuite être transmis sous la forme d'une "model matrix" au `glapi` de glitter)

Nous avons décidé, de par notre nombre d'entités, de simplifier cette classe et de la séparer complètement de son fichier .obj. À la place, la classe `GlApplication`, qui hérite de la classe `glitter/Application`, gère elle-même le lien entre les entités et leurs modèles 3D (grâce à une `enum` appelée `modelKeys`).

@@ -74,17 +71,17 @@ Ce système permet de ne charger qu'une seule fois chaque modèle 3D, et donc de

### Gestion des collisions

Nous avons décidé, en accord avec nos objectifs, d'utiliser des **OBB** (*oriented bounding boxes*, boîtes d'encadrement orientées). Celles-ci ont divers avantages et inconvénients en comparaison des plus traditionnelles **AABB** (*axis-aligned bounding boxes*, boîtes d'encadrement alignés sur les axes).
Nous avons décidé, en accord avec nos objectifs, d'utiliser des **OBB** (*oriented bounding boxes*, boîtes d'encadrement orientées). Celles-ci ont divers avantages et inconvénients en comparaison des plus traditionnelles **AABB** (*axis-aligned bounding boxes*, boîtes d'encadrement alignées sur les axes).

Les **AABB** sont des boîtes qui encadrent un objet du mieux possible en étant alignés sur les axes de l'espaces 3D : Si l'objet se tourne, la boîte ne se tourne pas (elle reste alignée sur les 3 axes), mais elle est redimensionnée pour toujours encadrer l'objet. Ce fait a pour conséquence de mal représenter l'objet : un objet bien aligné sera bien encadré, mais une rotation sur les trois axes déformerait fortement la boîte à tel point qu'elle ne serait plus pertinente.
Les **AABB** sont des boîtes qui encadrent un objet du mieux possible en étant alignées sur les axes de l'espaces 3D : Si l'objet se tourne, la boîte ne se tourne pas (elle reste alignée sur les 3 axes), mais elle est redimensionnée pour toujours encadrer l'objet. Ce fait a pour conséquence de mal représenter l'objet : un objet bien aligné sera bien encadré, mais une rotation sur les trois axes déformerait fortement la boîte à tel point qu'elle ne serait plus pertinente.

Les **OBB**, elles, encadrent en permanence l'objet auquel elles sont attachées en suivant leur rotation.

Elles sont définies toutes deux en analysant le modèle 3D auquel elles sont attachées. On récupère les valeurs maximales des vertex sur chaque axe pour former les boîtes. Dans le cas des **OBB**, l'orientation et le dimensionnement des boîtes seront ensuite gérés par les entités pour former les boîtes.

La plus grande différence entre ces deux types de "boîtes de collision" est leurs manières de détecter les collisions. Les **AABB** fonctionnent simplement en comparant leurs valeurs minimales et maximales sur chaque axe du monde. Les **OBB** fonctionnent en cherchant un axe capable de séparer les deux boîtes interogées. Si aucun n'est trouvé, les boîtes entrent en collision.
La plus grande différence entre ces deux types de "boîtes de collision" est leurs manières de détecter les collisions. Les **AABB** fonctionnent simplement en comparant leurs valeurs minimales et maximales sur chaque axe du monde. Les **OBB** fonctionnent en cherchant un plan capable de séparer les deux boîtes interrogées. Si aucun n'est trouvé, les boîtes entrent en collision.

Cette dernière méthode a été implémentée par nos soins en nous basant sur le papier [*Dynamic Collision Detection using Oriented Bounding Boxes*, par David Eberly](https://www.geometrictools.com/Documentation/DynamicCollisionDetection.pdf). Notre version prends en compte la vélocité des objets comparés, ce qui nous permet de détecter les collisions entre les vaisseaux et entre missiles et vaisseaux. La gestion des collisions est générée par la classe `Entity`.
Cette dernière méthode a été implémentée par nos soins en nous basant sur le papier [*Dynamic Collision Detection using Oriented Bounding Boxes*, par David Eberly](https://www.geometrictools.com/Documentation/DynamicCollisionDetection.pdf). Notre version prend en compte la vélocité des objets comparés, ce qui nous permet de détecter les collisions entre les vaisseaux et entre missiles et vaisseaux. La gestion des collisions est gérée par la classe `Entity`.

### La *skybox*

@@ -92,7 +89,7 @@ La *skybox* désigne le "décor de fond" de notre jeu. Elle tire son nom du fait

### La gestion des rotation

notre gestion des rotations s'est d'abord basée sur les angles d'Euler. Cependant, nous avons rapidement remarqué que l'utilisation de ces angles comportait certains problèmes. Nous avons notamment été confronté au **Gimball Lock** (verrouillage de cadran). Ce problème intervient lorsque deux des axes de rotation d'Euleur se superposent, faisant alors perdre un degré de liberté à l'objet (deux angles de rotation deviennent similaires et évoluent de la même manière).
Notre gestion des rotations s'est d'abord basée sur les angles d'Euler. Cependant, nous avons rapidement remarqué que l'utilisation de ces angles comportait certains problèmes. Nous avons notamment été confrontés au **Gimball Lock** (verrouillage de cadran). Ce problème intervient lorsque deux des axes de rotation d'Euleur se superposent, faisant alors perdre un degré de liberté à l'objet (deux angles de rotation deviennent équivalents et évoluent de la même manière).

Pour éviter ce problème, nous avons décidé d'utiliser des **quaternions** pour gérer les rotations. Là ou les angles d'Euler se basent sur des axes de rotations, les quaternions définissent un vecteur servant d'axe de rotation, puis un angle représentant la rotation effective autour de cet axe.

@@ -100,15 +97,25 @@ Pour éviter ce problème, nous avons décidé d'utiliser des **quaternions** po

Le terrain est généré de sorte à ce que des obstacles (sous forme d'astéroïdes) soient générés aléatoirement, avec un tirage type monte-carlo : une zone de protection est définie autour des vaisseaux pour s'assurer que ceux-ci ne puissent pas apparaître en contact avec un astéroïde.

### Système de GUI

Le système de GUI passe par une classe `GuiElement` ainsi qu'un shader qui lui est spécialement réservé (disponible dans *shaders/gui.f.glsl* et *shaders/gui.v.glsl*). Il est extrêmement simple car il ne fait qu'afficher une texture sur un rectangle en 2D. L'espace de coordonnées a été quelque peu modifié afin que le coin en bas à gauche de la fenêtre corresponde aux coordonnées (0, 0) et que le coin en haut à droite de la fenêtre corresponde à (1, 1). Cette méthode nous permet d'avoir des dimension et une position relatives à la dimension de la fenêtre. À l'inverse, si nous avions utilisé un système basé sur le nombre de pixels disponible dans la fenêtre, il aurait fallut recalculer la taille et la position des différents éléments du GUI en fonction de comment la fenêtre se redimensionne. Notre méthode permet donc de gérer cela de manière bien plus simple puisque le placement et les dimensions des éléments sont relatifs aux dimensions de la fenêtre.

Comme pour les entités, les éléments du GUI sont ajoutés dans leur propre tableau (`std::vector<std::shared_ptr<GuiElement>>`) ce qui permet d'optimiser leur rendu en limitant les opération de *bind* notamment. Ils sont également séparés des entités puisqu'il faut au préalable désactiver les tests de 3D afin qu'OpenGL les "dessine" bien au dessus de ce qui à précédemment été dessiné.  

### *Split-screen* (écran partagé)

La gestion du *split-screen* est très simple. Il suffit de changer le viewport d'OpenGL (comprendre par là la zone de la fenêtre sur laquelle OpenGL va dessiner). On va d'abord définir le viewport comme faisant toute la largeur de la fenêtre et la moitié de sa hauteur totale avant de dessiner une première fois la scène en plaçant la caméra derrière le vaisseau du premier joueur. On définit ensuite la zone comme étant l'autre moitié de la fenêtre, on place la caméra derrière le vaisseau du le second joueur et on dessine une nouvelle fois la scène dans son intégralité.

## Règles du jeu

Le jeu est basé sur des règles simples : chaque joueur contrôle un vaisseau. Au début du jeu, ceux-ci apparaissent face-à-face à une certaine distance permettant le déplacement sans trop d'encombres.

Chaque vaisseau est enitèrement controlé par un joueur, les deux vaisseaux se contrôlent sur un même clavier.
Chaque vaisseau est entièrement contrôlé par un joueur, les deux vaisseaux se contrôlent sur un même clavier (en tirant parti du pavé numérique).

Chaque vaisseau peut tirer un missile à tout moment. Un projectile apparaît alors (de classe `model/Missile`), et le vaisseau ne peut plus tirer pendant une petite période de temps.

Chaque vaisseau dispose de 3 points de vie, et perds l'un d'eux à chaque tir reçu. Si l'un des joueurs voit les points de vie de son vaisseau réduits à zéro, il perd la partie. L'égalité est possible.
Chaque vaisseau dispose de 3 points de vie, et perd l'un d'eux à chaque tir reçu. Si l'un des joueurs voit les points de vie de son vaisseau réduits à zéro, il perd la partie. L'égalité est possible.

À la fin d'une partie, un écran de bilan est affiché, et appuyer sur la touche `Entrée` relance une nouvelle partie.

@@ -129,12 +136,3 @@ Le programme dans son état actuel possède plusieurs axes d'amélioration :
  - Animations pour les vaisseaux (réacteur par exemple). A priori, des modifications de glitter seraient nécessaire
  - Meilleur GUI (informations supplémentaire, meilleur "look", design plus attrayant...)
  - Possibilité d'ajouter des IA
### Système de GUI

Le système de GUI passe par une classe `GuiElement` ainsi qu'un shader qui lui est spécialement réservé (disponible dans *shaders/gui.f.glsl* et *shaders/gui.v.glsl*). Il est extrêmement simple car il ne fait que de d'afficher une texture sur un rectangle en 2D. L'espace de coordonné a été quelque peu modifié afin que le coin en bas à gauche de la fenêtre corresponde à la coordonnée (0, 0) et le coin en haut à droite de la fenêtre correspond à (1, 1). Cette méthode nous permet d'avoir des dimension et une position relative à la dimension de la fenêtre. A l'inverse, si nous avions utilisé un système basé sur le nombre de pixel disponible dans la fenêtre, il aurait fallut recalculer la taille et la position des différents éléments du GUI en fonction de comment la fenêtre se redimensionne. Notre méthode permet donc de gérer cela de manière bien plus simple puisque le placement et les dimensions sont relatifs aux dimensions de la fenêtre.

Comme pour les entités, les éléments du GUI sont ajoutés dans leur propre tableau (`std::vector<std::shared_ptr<GuiElement>>`) ce qui permet d'optimiser leur rendu en limitant les opération de *bind* notamment. Ils sont également séparés des entités puisqu'il faut au préalable désactiver les tests de 3D afin qu'OpenGL les "dessine" bien au dessus de ce qui à précédemment été dessiné.  

### Split-screen

La gestion du split-screen est très simple. Il suffit de changer le viewport d'OpenGL, comprendre par là la zone de la fenêtre sur laquelle OpenGL va dessiner. On va d'abort définir le viewport comme faisant toute la largeur de la fenêtre et la moitié de la hauteur totale de la fenêtre avant de dessiner une première fois la scène en placant la caméra derrière le premier joueur. On définit ensuite la zone comme étant l'autre moitié restante, on place la caméra derrière le second joueur et l'on dessine une nouvelle fois la scène dans son intégralité.