Des bases mathématiques du développement à la création de mon propre moteur de jeu 3D
Les bases mathématiques des jeux vidéo
Dans cet article, Nicolas Fraysse, développeur, nous explique pourquoi il s’est lancé dans sa propre création de moteur de jeu 3D et explicite les difficultés rencontrées.
Introduction
Tous les jeux vidéo en 3D et en temps réel ont une base mathématique, directement ou indirectement incluse dans le jeu.
Les jeux de Valve (Portal, Half life 2, Dota) sont autant d’ exemples de créations réussies grâce aux formules mathématiques. Bien que tous les jeux vidéo (2D & 3D) aient une base mathématique, ces dernières ne sont pas forcément identiques selon la technologie utilisée.
Il est possible pourtant d’observer le fait qu’un moteur 3D peut servir à faire de la 2D (sans utiliser toutes les fonctionnalités de la 3D). La 2D est seulement un cas particulier de 3D si on part du principe qu’elle ne possède qu’une seule dimension en moins. Par exemple : il est possible de faire des rotations en 2D avec des Quaternions mais cela n’aurait aucune utilité particulière dans la fluidité du jeu.
Les mathématiques de base et la physique
Il est primordial, et ce avant tout exemple, de bien comprendre que la réalisation complète d’un jeu vidéo résulte d’une savante connaissance des mathématiques de rendu nécessaires à la réalisation d’infographies comme dans ce projet Epitech réalisé il y a quelques années.
Les mathématiques sont une science utilisée dans de nombreux domaines. Dans celui de la programmation informatique, il prend aujourd’hui l’une des places prépondérantes dans la maintenabilité et la jouabilité des différents supports.
Quelques explications supplémentaires peuvent s’avérer utiles quant à l’utilisation de tel ou tel type de mathématiques. Ainsi, si les mathématiques de rendu sont essentielles à la programmation d’un jeu vidéo, les mathématiques liées à la physique en sont elles majoritairement exclues.
Pourquoi ? Tandis que les mathématiques sont une science absolue, l’infographie et la physique dans les jeux vidéos font toujours appel à des approximations. Ainsi, si la physique est représentée par des approximations, que les infographies sont représentées par des approximations ; alors, la physique dans jeu vidéo implique un risque encore plus grand en termes d’approximations et donc de problèmes engendrés lors du développement ou à réception du projet.
Le jeu vidéo en temps réel est un problème car il faudrait calculer chaque image (contraintes) ce qui rend le calcul extrêmement lourd pour la machine. Le but est donc de rendre plus léger le programme pour qu’il soit accessible pour la majorité des machines.
Comment en suis-je venu à créer mon propre moteur de jeu 3D
Et en premier lieu vint la raison.
Je me suis vite rendu compte qu’il n’existait pas de moteurs gratuits avec la capacité de supporter la modabilité. Par ailleurs, la seule envie de coder en jouant (façon Garrys-mod) a bien vite été dépassée et j’ai souhaité aller encore plus loin.
Je souhaitais une solution qui ne nécessite pas de rechargement du jeu pour rajouter une asset (possibilité de le faire) avec – bien évidemment – un aspect réseau (multijoueurs).
Bien qu’il existait certains moteurs intéressants, aucun ne répondait alors à mes besoins tout en étant full/cross-plateforme (Linux, Windows, Apple).
Le choix de la solution à adopter
Je suis partie du constat qu’il existait, certes certains moteurs intéressants, mais qu’aucun ne répondait alors à mes besoins tout en étant full/cross-plateforme (Linux, Windows, Apple). Ajouter à cela le fait que des moteurs tels que les UE4 interdisent l’injection des fichiers assets en run time. Et, vous obtenez les raisons premières qui m’ont poussé à me lancer en totale indépendance.
J’ai décidé d’axer mes recherches sur les solutions non payantes. Exit donc Source Engine et Unity. Si la première est une solution entièrement payante, la seconde n’accepte que le C# et ne permet de programmer en C++ que moyennant finance.
Vinrent ensuite les options Open-Source comme Ogre 3D qui, bien que prometteur, oblige à installer de nombreux autres outils et plugins afin de fonctionner correctement. Son second problème majeur ? Il nécessite de le combiner soi-même puisque le binaire n’est pas générer ce qui pose un problème sur le facteur temps.
Dans l’équation argent – temps – valeur ajoutée, la seule et unique solution qui apparaissait alors était de réaliser moi-même mon moteur de jeu.
Le choix du dépôt moteur
Lors de mes études, j’ai créé un dépôt sur Epitech (sans savoir qu’ils en gardaient les droits) avant de finalement pratiquer la « Grande Purge »‘ sur Git.
Le projet est ensuite passé sur Visual Studio Team Services (Azure DevOps / Visual Studio Online) durant un temps avant de pratiquer une nouvelle purge. Premier problème : le compte utilisé était répertorié Epitech (fin de 5° année, perte de droit moteur).
Second problème : le prix de la collaboration (5 collaborateurs maximum en version free) et donc pas ou peu de scalabilité*.
Résultat : moins d’une année d’ancienneté.
*
Les fonctionnalités OpenSource aujourd’hui gratuites n’étaient pas proposées à l’époque.
Après VSTS, le projet arrive sur GITEA (Github gratuit) avec ses avantages d’être Open Source et la possibilité de l’installer sur nos propres serveurs.
Pourquoi ? Après de nombreuses conversations avec les autres collaborateurs du projet, il est apparu qu’il était possible de rendre l’OpenSource lucratif ce qui a forcément ravivé l’envie de tenter de nouveau l’aventure. Cependant, l’obligation d’ajout d’un VPN rendait le serveur trop lent et donc – à contrecoeur – m’a pousé à sacrifier mon serveur GITEA.
Résultat : quelques mois de tests infructueux.
Suite à des problèmes d’architecture, de maintenabilité, de formules mathématiques (emmagasinés entre tech 1 et tech 3), nous avons dû tout mettre en pause l’espace de quelques semaines.
Pour la petite histoire, je me rappelle m’être dit à l’époque : » le moteur marche sur Mac et Linux mais la gestion des fichiers est très compliquée sous Mac (ce qui était étonnant). Il faut que l’on arrive à le faire marcher sous Windows via le téléchargement de Visual Studio et des outils de développement en C++ ».
Et pourtant, en compilant mon projet, des centaines d’erreurs de compilations sont apparues et la maintenabilité est devenue elle aussi complexe.
Architecture du projet
Pour ce projet, il a évidemment fallu mélanger du framework et du Engine. Finalement, et comme vous en vous en doutez, ça a planté. Chaque fois que je changeais une API du Framework, il fallait changer tout le moteur : inmaintenable et surtout très frustrant.
Il a donc été nécessaire de reboot le framework et, d’emblée, le faire marcher sur l’ensemble des plateformes. Nous avons donc réalisé un passage sur Github Public qui dispose du full Open-Source.
Le système comprenant les tests unitaires et la compilation automatisée a été réalisée sur le service d’intégration continue TRAVIS (Build). Il compile ainsi sur les trois OS (Mac, Windows, Linux). Le framework a été rendu fonctionnel de la même manière sur les trois systèmes d’exploitation grâce à l’acquisition des méthodes de Clean Code.
La question qui vous vient est certainement la suivante : pourquoi ne pas avoir commencé la partie Engine ?!
Cela nécessite forcément une phase de réflexion antérieure et l’obligation de séparer le rendu de la partie purement fonctionnelle du jeu. Il est donc obligatoire de posséder un serveur qui n’a pas besoin d’éléments de rendu mais des éléments propres aux différents jeux ; il a besoin de « jouer au jeu sans l’afficher » (NDLR).
Le moteur a ainsi demandé une reconstruction complète du framework. Vous pouvez d’ailleurs partager vos idées et participer à sa reconstruction ici.
Comment régler le problème
Séparer le rendu du fonctionnel est la priorité. L’Engine ne doit pas être dépendant d’API de rendu comme Open GL ou Direct X. En effet, si dépendance il y a, tous les serveurs sans carte graphique ne peuvent lancer l’Engine. Le moteur est ainsi programmé pour forcer l’utilisation du mode accéléré (hardware accelerated). L’utilisation de ce mode permet d’utiliser des fonctionnalités GPU (Graphics Processing Unit) avancées.
Par conséquent, sur une carte graphique ne supportant pas les fonctions comme les shaders, l’application ne pourra se lancer.
Afin d’y parvenir, plusieurs solutions existent pourtant :
- Créer des interfaces pour le rendu qui n’auraient que des implémentations vides sur un serveur. Puis, créer des implémentations dans des modules différents pour chaque API de rendu (Direct X, OpenGL, etc.)
- Créer des interfaces pour le rendu dans une bibliothèque header only avec, de nouveau, des modules différents pour chaque API de rendu.Pour régler les soucis liés à la gestion des fenêtres / contexte de rendu/input :
- Créer une abstraction pour représenter la classe maître du jeu vidéo avec une implémentation différente sur serveur et sur client.
- Créer deux classes différentes : une pour le client, une pour le serveur. L’inconvénient majeur est qu’il faut alors instaurer une implémentation différente du module du jeu en serveur ainsi qu’en client.