Contenu du renducontact(at)guillaumelevieux.com :: « Home

Vincent Stehly-calisto

Programmeur Enjmin



*-- Liens --*

Lien Github : https://github.com/Aredhele/Cardinal-Engine
Lien build : https://github.com/Aredhele/Cardinal-Engine/releases
Lien trailer complet (1080p30) : https://www.youtube.com/watch?v=wQ5CTL_yWNI
Lien démonstration technique (1080p60) : https://www.youtube.com/watch?v=B6xjwc-0cTM

*-- Préface --*

Mon rendu est essentiellement contenu dans la vidéo "démonstration technique" (voir le lien ci-dessus).
La vidéo aborde presque l'ensemble des fonctionnalités implémentées dans le moteur et offre une présentation
de l'API utilisateur du moteur (en début de vidéo).

Le moteur est fonctionnel et stable dans sa dernière release. Il a été utilisé tout au long de son
dévellopement par Darenn et Ervan. Le moteur est CMake based par souçis de compatiblité et de souplesse de développement.

J'aborderai uniquement ce que j'ai réalisé personnellement dans le projet.

*-- Le projet --*

Cardinal Engine (nom inspiré du Système Cardinal dans Sword Art Online) est un moteur programmé entièrement en C++ avec OpenGL 3 sur une période
d'environ 1 mois. Le moteur est compatible avec plusieurs IDE donc CLion (testé) et Microsoft Visual Studio 2017 (testé) ainsi que tous les autres
IDE supportant CMake. Le moteur n'est pas spécialisé pour les mondes en voxel mais est générique. Dès le début, la partie moteur et la partie jeu
ont été séparé et sont devenues indépendantes. Le moteur utilise 8 bibliothèques third party, toutes sous support CMake et intégrées très simplement
grâce à CMake :

° Glew
° Glfw
° Glm
° OpenAL
° OpenVR
° Bullet3
° ImGui
° Google Test

Cardinal Engine compile sous MinGW x64 g++ 6.1.0 et avec Visual C++ 2017. Il est aussi possible de compiler le projet normalement en demandant à CMake
de générer un projet pour l'IDE souhaité (par défaut une solution Visual Studio classique). Le projet est théoriquement cross-platforme.
Il faudrait retirer un include de Windows.h qui a été fait en fin de projet pour récupérer l'état de la mémoire et ajouter les dépendances
liées à la platforme (comme X11 sous Debian) et cela devrait fonctionner.

L'archive zip contient tous les shaders ainsi que les sources du projet (sans les third party et les ressources). Pour récupérer le projet complet, il
faut cloner le dépôt git. La build est aussi sur git dans la section "Release" avec normalement toutes les dlls nécessaires.


*-- Les objectifs du projets --*

N'ayant jamais fait d'OpenGL et étant très intéréssé par la programmation moteur, j'ai décidé d'en apprendre un maximum dans le cadre du projet et d'aller
le plus loin possible. C'est pour cela que j'ai tout refait par moi même, pour être sûr d'avoir compris du chargement de la ressource à sa modification en post-processing.

De plus, comme ce projet comptait 3 personnes, j'ai dû dévelloper le moteur tout en faisant attention à ne pas modifier l'interface utilisateur.


*-- Et après ? --*

Pour la suite, j'aimerai apprendre à utiliser Vulkan et faire mon mémoire de M1 sur une thématique de la programmation moteur en rendu.


*-- Les fonctionnalités --*

*-- CMake --*

Tout d'abords, Cardinal Engine est un projet CMake. Bien que souvent utilisé pour le logiciel libre, l'open source et les projets communautaires, CMake
est aussi utilisé dans certains studios de jeu vidéo ayant leur propre moteur comme le studio Shine Research. Pour ce projet, CMake m'a permis :

° Intégrer les third party en une seule ligne à chaque fois (exemple : ADD_SUBDIRECTORY(OpenVR))
° Gérer précisement les dépendances du projet ainsi que les flags de compilation
° Pouvoir gérer facilement plusieurs éxécutables dans le même projet (comme les plugins et les tests)
° Générer un dossier de build propre à chaque build du projet (Avec les ressources, les dlls etc..)
° Uniformiser les différences entre les IDE

*-- Support de la réalité virtuelle --*

Le moteur supporte OpenVR et implémente de quoi faire du rendu stéréoscopique avec le HTC Vive (testé). La VR s'active en une ligne
de code dans le moteur (CF le readme du projet Git). De plus, lorsque le rendu stéréoscopique est activé, le moteur affiche les frames
envoyées au casque avant la passe du Compositor (OpenVR).

*-- Support d'OpenAL --*

OpenAL est intégré est fonctionnel. Il est possible de charger des sons au format WAV dans des buffers et de jouer ces sons. Cela
fonctionne exactement comme dans toutes les bibliothèques (SDL, SFML).

*-- Système de particules --*

Il est aussi possible de créer des systèmes de particules. Les sytèmes de particules sont optimisés avec l'instanciation GPU
et peuvent être paramétrés selon différents critères :

° Emission shape (Cone, Plane)
° Gravity
° Speed
° Max amount
° Emission rate
° Size, color

*-- Indexing des vbos --*

Bien que ce ne soit pas une optimisation en terme de vitesse d'éxécution (CPU ou GPU), le moteur permet d'indexer les vbos.
Cela permet tout de même de stocker plus de sommets sur la carte. J'ai pu grâce à ça afficher 30 000 chunks (faces non visibles retirées, sans frustrum culling)
plus de 16 millions de triangles) à 45 FPS (GTX 1080) car l'indexing me faisait économiser de 30 à 80 % en mémoire par chunk.

*-- Outils de debug --*

Depuis le début, le moteur possède un système de gizmos comme celui d'Unity. Il possible de dessiner des lignes, des rayons, des boîtes,
où les gizmos des lights, les axes ou la grille.

*-- Lighting --*

Les point lights et les directional lights sont disponibles. Cependant, le lighting est en forward rendering et donc pas très optimisé
surtout pour les point lights.

*-- Post-processing --*

Le moteur à la possibilité de faire du post-processing via une post-processing stack (inspiré d'Unity, CF démo).
Les effets disponibles :

° Identity (Ne fait rien, pour débug)
° Light scattering (Passe pour récupérer la diffusion de la lumière en prenant en compte l'occlusion du décors)
° Depth buffer (Afficher le depth buffer)
° Shadow map (Affiche la shadow map, ne marche pas encore)
° Mirror (Mirroir selon X et Y)
° Fog (Fog exponentiel utilisant le depth buffer)
° Negative (Inverse les couleurs)
° Sepia (Applique une teinte sepia)
° Box blur (Blur box avec kernel paramétrable)
° Gaussian blur (Gaussian blur avec kernel paramétrable)
° Sharpen (Rend les edges plus distincts)
° Edge detection (met en avant les edges)
° God ray (affiche les god rays depuis la lampe directionnelle, utilise la passe de light scattering)
° Bloom (Bloom low cost)
° Vignette (Vignette autour de l'image, paramétrable)
° Depth of field (Profondeur de champ basé sur le depth buffer et utilisant un plan de profondeur)
° Fast Aproximate Anti-Aliasing (FXAA - Utilise un petit kernel pour détecter les edges et les blender)

Le post-processing marche en "ping-pong texturing". C'est à dire qu'à l'application des post-effects, la texture
source deviendra la texture destination et inversement à chaque itération.

*-- ImGui --*

Le moteur utilise ImGui pour afficher des interfaces graphiques in game et permettre la modification des objets
du moteur en temps réel. J'ai dû créer une méthode OnGUI() dans le moteur pour que l'utilisateur sache où et quand rendre
l'interface graphique. Cela permet d'éviter les problèmes liés au cycle de vie d'ImGui.

*-- Génération infinie --*

Bien qu'absent dans le rendu final, j'avais fait de la génération infinie au début du projet (basé sur un bruit de perlin 3D).
Je détectais la position du joueur en nombre de chunk, et lorsque qu'il changeait de chunk, un événement était généré et le moteur
translatait une matrice. Les chunks dans le dos du joueur étaient enlevés puis regénérés et remis devant le joueur. Cette technique
permet d'avoir une variable "Far" exprimée en nombre de chunks qui correspond en fait à la taille de la matrice de chunks.

De plus, après avoir expérimenté de gros ralentissements à la regénération en temps réel, j'ai threadé la génération. Je n'avais pas de
picking et de physique à ce moment donc la génération était "simple".

En preuves pour la génération threadée, des gifs ont été mis dans le rendu.

*-- Hiérarchie et Inspector --*

Grâce à ImGui, j'ai pu créer assez facilement de la GUI pour faire une hiérarchie et un inspector.
N'ayant pas de pattern composite, la hiérarchie montre tous les composants instanciés et non pas des game objects.
Pour ce faire, chaque objet hérite d'une classe Inspector et implémente comme dans Unity une méthode OnInspectorGUI()
qui sera appelée lorsque l'utilisateur cliquera sur un objet. L'objet affichera à son tour ses attributs.

Cette feature est 100% fonctionnelle dans la dernière build et permet par exemple de tweaker le système de particule en temps réel.

*-- Custom mip mapping & texturing --*

Par défaut, lorsqu'une texture est chargée dans le moteur à l'aide d'un utilitaire, un mip mapping automatique est appliqué.
Le moteur permet d'éviter ça et de faire passer une liste de textures qui servira de mip maps. Le moteur supporte les fichiers
BMP et DDS.

*-- Les interfaces du moteur --*

Le moteur possède des interfaces dont il est possible d'hériter pour créer
des classes personnalisées compatibles et enregistrables dans le moteur depuis
la partie utilisateur.

Le moteur peut aussi afficher du texte nativement sans passer par ImGui.

° IRenderer (MeshRenderer, TextRenderer, ParticleRenderer, LineRenderer)
° IShader (UnlitColorShader, UnlitTextureShader, StandardShader etc...)
° IPostEffect (FXAA, Bloom, God ray, Sepia etc...)
° IEmissionShape (Cone, Plane)

*-- Autres --*

J'ai fais pas mal de recherches pendant le projet. Par exemple, le buffer mapping.
C'est une technique qui permet de demander à OpenGL de mapper des vbos dans la mémoire RAM pour les consulters / modifier.
Il est possible de passer des flags pour qu'il soit persistent. Pour optimiser les updates de vbos
il est possible de faire du triple buffering et de mettre à jour des buffer créés avec glMapBuffer de façon asynchrone
en faisant passer les bons flags.

° J'ai ajouté un stack allocator au moteur pour optimiser certaines allocations
° Le moteur à un système de plugin pour gérer le code utilisateur
° Le moteur possède sa propre lib. d'assertion (ASSERT_NOT_NULL, ASSERT_GT etc..)
° Le moteur peut faire de la projection orthographique (CF screenshots)
° J'ai commencé à faire les shadows mais ce n'est pas encore dans le rendu car incomplet
° J'ai aussi pris le temps de soigner le projet sur Git et de mettre des extraits de code en guise de tutoriels.

Merci de votre lecture !