Sémiotisation des univers 3D et architecture Unreal Engine :
création d’une Debug Room
Un outil parfois utilisé dans le développement de jeux vidéo, et très intéressant sur le plan sémiotique et informatique, est la Debug Room.
Il s’agit d’un endroit isolé du reste d’un monde virtuel, une sorte de laboratoire où l’on peut tester toutes les interactions et les fonctionnalités d’un jeu 3D.
Et, à partir de mon jeu Goldanniyatech, je vais analyser les spécificités de la Debug Room sous un double angle sémiotique et informatique, car celle-ci présente une particularité extrêmement intéressante.
En effet, cet endroit unique produit paradoxalement une rupture sémiotique de l’expérience virtuelle du joueur et une perte de la multiplicité des signes tout en permettant in fine d’améliorer la sémiotisation d’un univers virtuel, et d’enrichir l’expérience du jeu.
Mon analyse va s’opérer à partir d’une double grille de lecture, à la fois sémiotique et informatique, notamment via l’analyse des principes du paradigme orienté objet et de l’architecture du moteur Unreal Engine 5.
La problématique qui existe ici correspond à l’intérêt même des Debug Rooms :
Comment la Debug Room, lieu par excellence de la rupture sémiotique où l’illusion est vidée de sa sémiotique, devient-elle le catalyseur d’une resémiotisation plus solide ?
0. Introduction
L’univers virtuel, particulièrement dans sa forme en monde ouvert, fascine par sa richesse gargantuesque, faussement illimitée.
Pour autant, n’importe quel simulacre virtuel possède, comme je l’ai indiqué dans ma thèse doctorale, une double lecture des signes, inspirée de celle de Hjelmslev.
Pour rappel, selon Hjelmslev, un signe unit un plan de l’expression (la forme) et un plan du contenu (le sens).
Il y a d’abord une première lecture, proche du joueur, qui voit, par exemple, pour chaque véhicule, un autre moyen de locomotion ou d’interaction.
Ensuite, il y a une seconde lecture, beaucoup plus technique, qui s’occupe de l’interaction brute.
Par exemple, 50 voitures différentes peuvent être représentées par une seule et même classe C++ Unreal Engine dont on dérivera toutes les variantes.
Cela peut être une classe AWheeledVehiclePawn , complète mais assez rigide au regard de , ou simplement sa classe parent APawn avec un code intégralement custom (ce qui est mon cas pour mon jeu)
Sur le plan de la programmation, il n’existe qu’une seule voiture, mais avec des paramètres (on parle de membres ou de propriétés en orienté objet) qui permettent de fabriquer une illusion de multiplicité.
Cela repose sur l’un des piliers de l’orienté objet : l’héritage. Néanmoins, on évoquera également les limites de cet héritage et la composition,
pour éventuellement faire echo à Unreal Engine 6, et comment cela va modifier les choses sur le plan sémiotique.
1. L’illusion d’un héritage composé
Afin d’entrer au coeur du processus de (dé)sémiotisation, analysons l’architecture du moteur Unreal Engine 5.
Celle-ci est basée sur deux concepts phares du paradigme orienté objet : l’héritage et la composition.
Ainsi, Unreal 5 est actuellement plutôt différent du moteur Unity, qui est beaucoup plus proche d’un modèle ECS (Entity-Component-System) où les entités sont vides et possèdent exclusivement des composants.
Je précise toutefois que, d’une part, Unreal Engine 5 possède une portion purement ECS, notamment le Mass Entity, et que la prochaine verison, Unreal Engine 6, va adopter une architecture beaucoup plus proche du modèle ECS, notamment avec un Scene Graph. UEFN intègre d’ailleurs déjà ces éléments.
La classe de base UObject est utilisé pour instancier la plupart des classes appartenant à Unreal, sauf certaines structures qui contiennent uniquement des données (notamment FText ou FVector, par exemple).
Toutefois, les classes héritant de UObject permettent d’intégrer les aspects générés par le UHT (réflexion, sérialisation, Garbage Collector, etc.), autrement dit les facéties qui n’existent pas en C++ standard, contrairement au C# par exemple (d’où la réflexion native sur Unity 😅).
Certes, la réflection statique sera intégrée dans le C++ 26, mais elle ne pourra nullement remplacer celle du moteur Unreal, qui est encore en C++ 20 et qui, de toute façon, va drastiquement changer d’architecture pour Unreal Engine 6 pour passer sur un véritable ECS.
1.1. Les AActors
Pour avoir un objet qu’il est possible de placer dans un niveau (.umap), qu’il s’agisse d’un niveau normal ou d’un monde ouvert (World Partition), nous avons besoin d’une classe AActor ou d’une sous-classe de celle-ci.
Cette classe est composé d’un élément essentiel, à savoir un système de Transforms, qui intègre 3 vecteurs d’un objet tridimensionnel : la position (FVector), la rotation (FRotator) et l’échelle (FVector).
Attention, le système de Transforms sur Unreal est très différent du moteur Unity, où un GameObject, l’équivalent de notre AActor, possède un Transform qui ne peut pas être détaché, et beaucoup plus simple. (Unity Manual, Transform Class).
Toutefois, et si on est attentif au terme que j’ai utilisé, l’ingéniosité sur Unreal est d’utiliser la composition :
plutôt que de coder en dur (hard-code) le Transform directement dans un AActor via des membres (propriétés et méthodes en OO moderne), il est compsé grâce à une autre classe : une USceneComponent, une sous-classe du UActorComponent qui possède un Transform. Celle-ci dérive bien de UObject lorsqu’on regarde le header (Unreal 5.7) :
Engine/Source/Runtime/Engine/Classes/Components/SceneComponent.h
UCLASS(ClassGroup=(Utility, Common), BlueprintType, hideCategories=(Trigger, PhysicsVolume), meta=(BlueprintSpawnableComponent, IgnoreCategoryKeywordsInSubclasses, ShortTooltip="..."), MinimalAPI)
class USceneComponent : public UActorComponent
{
// La suite du code du moteur
};
Le mode de pensé sur Unreal Engine 5 est donc bien spécifique : on démarre avec un AActor plutôt complet mais générique, auquel on va intégrer des composants pour qu’il puisse répondre à des besoins spécifiques.
Héritage multiple… Ou pas
Toutefois, il est d’usage de considérer que l’équipe d’Unreal Engine favorise le design pattern Composition Over Inheritance, ce qui signifie de préférer des classes qu’on intègre dans d’autres classes. plutôt que des héritages.
Et, le langage C++ permettant l’héritage multiple
2. (Dé)sémiotisation qualitative
La création de nouveaux AActors sur Unreal repose donc sur une compréhension rigoureuse des fondamentaux en programmation, mais également une intuition de la sémiotisation d’un univers virtuel.
Et je peux préciser que l’absence d’une séparation entre la classe (programmation d’un objet) et les variantes (interactions) peut créer des problématiques importantes, notamment une dette technique (debugger plusieurs classes similaires, absence de respect des principes comme le DRY, le SOLID, etc.).
Je rappelle surtout, du moins sur Unreal Engine 5, que les deux langages, Blueprints et Unreal C++, fonctionnent sur Unreal conjointement, et ne sont pas deux langages séparés ou au choix, contrairement aux langages Boo, JavaScript et C# sur les anciennes version de Unity (Unity Blog 2018), supprimées au profit du C# uniquement et d’un langage visuel (Visual Script).
De surcroît, l’architecture du moteur Unreal, intégrant l’héritage (UObject, AActor, etc.) et la composition (), possède une sémiotisation différente.
En effet, il est plus d’usage d’avoir une classe de base plus importante et fonctionnelle en C++, non seulement à cause de la nature intrinsèquement plus bas-niveau que le C# de Unity, par exemple, mais également parce que, sur le plan pratique, le développement sur Unreal est plus lourd (compilation et UBT) et le danger d’un bug peut faire crasher UnrealEd.
Cela signifie aussi que
2.1 Illustration par les trésors
Dans mon jeu, il est possible de découvrir des trésors disséminés dans la ville. Chaque trésor peut apparaître ou non, en fonction d’une probabilité.
Toutefois, si les trésors sont différents, ma classe TreasureChest est la même pour tous.
CDO et Sémiotisation
Cette conscience de sémiotisation et désémiotisation permet de mieux appréhender les besoins pour le constructeur d’un AActor.
En effet, si ma classe TreasureChest n’est qu’une représentation désémiotisé d’un coffre, et non pas une véritable représentation, elle doit donc être réalisée de manière différente;
2.2. La fragilité du signe
On peut donc observer une désémiotisation complète du signe trésor et, in fine, de
La Debug Room représente, par excellence, une sorte de fragilité sémiotique du monde ouvert, où l’illusion d’un simulacre est totalement désémiotisée par la pure technicité des Debug Rooms.
| Plan |
Jeu vidéo (lecture joueur) |
Jeu vidéo (lecture technique) |
| Expression (forme) |
50 voitures visuellement distinctes |
1 classe Vehicle en C++ |
| Contenu (sens) |
Vitesse, puissance, style |
Membres de données : speed,model… |
2.3. Resémiotisation
Ce qui est fascinant, c’est que ce processus de désémiotisation permet justement de s’assurer que la sémiotisation fonctionne, qu’elle est opérante et qu’elle n’est pas avec des bugs qui peuvent justement mettre à mal cette sémiotique.
Les bugs, justement, peuvent mettre à mal le processus de sémiotisation, et fournir une désémiotisation non-voulue, qui in fine gêne l’expérience du joueur.
Le logiciel interactif 3D (ici le jeu vidéo) est bien un élément expérientiel, et c’est justement ce processus de sémiotisation, de donner du sens, ou d’une manière plus poétique, d’insuffler une âme à un univers, qui permet justement de créer une véritable expérience.
C’est ce qui sépare les “jeux” des oeuvres.
3. Conclusion
La Debug Room est bien un lieu qui opère une désémiotisation : plutôt que de tester toutes les variantes visuelles et que de rester dans le domaine expérientiel, on s’occupe simplement de vérifier les éléments uniques. Sur Unreal Engine, les classes de base de chaque objet, et les classes dérivées si elles sont en C++ et rajoutent des membres sbustantiels, sont les seuls présents dnas ce processus de désémiotisation.
Ainsi, de par la nature intrinsèquement expérientielle des jeux 3D en monde ouvert, la désémiotisation dans une Debug Room n’a de sens que d’un point de vue interactif, c’est-à-dire avec l’analyse aussi bien, pour Unreal, que des scripts haut-niveau (en Blueprints) que des systèmes bas-niveau (en C++).
Si la désémiotisation n’est que rarement visuelle dans une Debug Room, c’est bien parce qu’il est relativement aisé de voir des erreurs sur les assets 3D.
En effet, un Static Mesh avec des faces manquantes (peut-être à cause d’un problème d’orientation des faces) ou encore des textures PBR ayant des artefacts, ces phénomènes peuvent s’observer directement dans un monde ouvert. Il n’est donc nullement nécessaire d’isoler des meshes 3D, sauf dans des cas précis ou pour des modèles complets.
Elle est donc opérante dans le coeur de ce que signifie l’interaction dans un jeu vidéo : la programmation.
Et la plus grande force de la sémiotique, c’est justement d’offrir des outils pour formaliser et normer la sémiotisation d’un univers en monde ouvert.
Cela permet in fine de mieux appréhender la composition, et de séparer non pas subrepticement mais clairement le point de vue du joueur de notre point de vue du développeur
Naturellement, ce n’est pas indispensable, et les préceptes en programmation sont déjà suivi par la plupart des bons programmeurs.
Mais c’est ce qui risque de faire la différence entre un univers créé directement et un univers avec une méta-réflexion substantielle.
Le passage à Unreal Engine 6 permettra, grâce à une architecture plus proche d’un ECS, de mieux désémiotiser encore.