DrakkenRidge: Building an open-world adventure for mobile VR
Simeon Acker and Cyril Guichard - Garage Collective
GUEST BLOG
Made with Unity, DrakkenRidge est un RPG d'action en monde ouvert de Garage Collective, conçu et optimisé pour la VR mobile. Dans ce blog invité, l'équipe partage comment elle exploite diverses techniques de conception et de performance en utilisant le système d'entités et de composants d'Unity comme colonne vertébrale du rendu.

Présentation de DrakkenRidge VR
Nous sommes Garage Collective, l'équipe derrière DrakkenRidge, un RPG d'action en monde ouvert conçu pour la VR où vous pouvez visiter n'importe quel point que vous voyez à l'horizon. Endossez-vous dans le rôle d'un puissant Chasseur de Mages et explorez six îles magnifiquement artisanales – chacune totalement unique, avec ses propres personnages, quêtes, donjons et secrets.
Ce voyage vous emmènera des plages chaudes et confortables aux sommets enneigés à couper le souffle ; des forêts mystiques luxuriantes aux gouffres périlleux au plus profond de la terre. Créez de nouveaux objets, combattez des douzaines de créatures et d'ennemis artistiquement conçus, et débloquez de nouvelles écoles de magie qui peuvent transformer chaque rencontre en une expérience unique.
Construire un jeu de cette envergure en tant qu'équipe de deux personnes ne serait probablement pas possible sans le Système de Composants Entité. Dans ce billet, nous allons couvrir comment nous avons utilisé ces outils pour créer notre jeu d'aventure ambitieux.
Techniques de mélange pour un développement de jeu plus fluide
Il y a plusieurs avantages considérables à utiliser ECS pour créer un jeu, mais en tant que petit studio indépendant, nous avons dû prendre en compte d'autres facteurs lors de la décision de concevoir et d'ingénieriser DrakkenRidge pour la VR mobile.
Il y a deux défis principaux lors de l'utilisation d'ECS :
- La courbe d'apprentissage abrupte : Développer avec ECS nécessite un changement de paradigme complet par rapport à la logique orientée objet typique.
- La séparation des systèmes d'entités des systèmes d'objets de jeu traditionnels peut rendre leurs interactions difficiles.
Donc la question pour nous est devenue:
Quels objets et interactions devraient tirer parti de la puissance de l'ECS, et quels objets devraient rester des GameObjects et MonoBehaviours traditionnels ?
Entities dans DrakkenRidge
DrakkenRidge se compose d'environnements ouverts massifs, avec des dizaines de milliers d'objets dans un espace donné – potentiellement des milliers d'entre eux étant visibles par le joueur à tout moment.
Le rendu de ceux-ci en tant que GameObjects traditionnels nécessite une surcharge mémoire importante, le moteur devant évaluer l'intégralité de la hiérarchie de la scène et calculer les composants Transform pour chaque objet. Lors du rendu de milliers d'objets, surtout sur un appareil mobile, le GPU souffrira notablement.
Et si nous prenions ces objets et les rendions comme Entities ?

En tant qu'Entities, ils évitent une grande partie de la surcharge de rendu et de mémoire associée aux GameObjects et sont plutôt regroupés en morceaux de mémoire en utilisant le système Entities Graphics.
De plus, le pipeline artistique DrakkenRidge utilise intensivement la technique de Texture Atlassing, permettant aux environnements massifs d'utiliser moins de Matériaux au total (voir notre article de blog sur Texture Atlassing ici).
Entities Graphics peut regrouper et gérer tous les objets qui partagent un maillage et un matériau communs, et l'engine peut alors créer des appels de dessin étroitement empaquetés et rendre de nombreux objets en même temps.
Le résultat de ceci peut faire économiser des centaines de lots et d'appels SetPass.

Rendu de milliers d'objets – avec seulement huit appels SetPass
Systèmes d'entités personnalisés
DrakkenRidge utilise ECS pour rendre des milliers d'objets à la fois. Mais même avec les gains de performance massifs que cela débloque, il y a encore plus que nous pouvons faire pour améliorer l'expérience sur les plateformes VR mobiles.
Système d'auteur à distance
La première fonctionnalité que nous avons créée pour nos Entities DrakkenRidge est le système d'écriture de distance. Il prend en compte une variété de variables pour déterminer quand un objet doit être caché ou visible pour le joueur.
Parce que la vision du joueur s'étend très loin dans le monde ouvert, des milliers d'objets éloignés peuvent être visibles en même temps. Ce système priorise lequel de ceux-ci doit rester visible de manière proéminente et lequel doit s'estomper en arrière-plan. Des effets environnementaux, tels que le brouillard de distance, sont utilisés pour masquer la transition lorsque les objets éloignés s'estompent de la vue.

Composant de création de distance avec valeurs personnalisées pour le filtrage d'entités en temps d'exécution
Des valeurs de sélection uniques sont générées dans l'éditeur pour chaque Entité en fonction d'une variété de paramètres. Ces données sont ensuite transmises, au moment de la création de l'Entity, aux systèmes qui utilisent ces données précalculées pour prendre des décisions en temps d'exécution sur le moment où les Entities doivent être rendues ou éliminées.
Groupes d'entités personnalisés
En utilisant le système d'authoring de distance DrakkenRidge, les Entities peuvent être assignées à des groupes avec une gestion de décision partagée, afin de permettre, par exemple, qu'une section de la ville soit rapidement rendue ou éliminée en fonction de divers facteurs du jeu, au lieu que chaque entité de la ville décide individuellement.

Entities regroupées avec gestion de décision partagée
Niveaux de détail des entités
La troisième fonctionnalité du système d'authoring de distance DrakkenRidge permet de remplacer les Entities à la volée par une autre Entity qui serait encore moins coûteuse à rendre. Cette technique a été initialement rédigée pour résoudre le problème des shaders et des matériaux plus coûteux.
Bien que les modèles d'environnement dans DrakkenRidge soient déjà hautement optimisés, certains shaders ajoutent un coût perceptible. Ce système d'Entities LOD (Level of Detail) permet de rendre des « versions d'entities avec des shaders à coût plus élevé » uniquement lorsque cela est nécessaire.
/// If using a simplified LOD object, see if we are in its range
if (inDistanceReturn.useLOD)
{
if (inDistanceReturn.isInDistanceLOD)
{
ecbParallel.SetEnabled(unfilteredChunkIndex, inDistanceReturn.lodEntity, true);
if (ChildLookup.TryGetBuffer(inDistanceReturn.lodEntity, out lodChildBufferData))
{
var newParent = inDistanceReturn.lodEntity;
SetEnableChildren(
entityCanBeReEnabledComponentLookup: entityCanBeReEnabledComponentLookup,
unfilteredChunkIndex: unfilteredChunkIndex,
parentEntity: newParent,
enabled: true,
childBufferData: lodChildBufferData,
ChildLookup: ChildLookup,
ecbParallel: ecbParallel);
}Lorsque les conditions sont remplies, utilisez un LOD simplifié pour l'Entité.
Optimisations du CPU
Les calculs d'auteur de distance de DrakkenRidge s'exécutent à travers des Jobs compilés en Burst pour une performance CPU maximale.
Unity Jobs sont des fonctions qui peuvent être planifiées comme des tâches asynchrones pour s'exécuter en arrière-plan, et le Burst Compiler accélère les tâches gourmandes en CPU en les traduisant en code machine natif hautement optimisé.
[BurstCompile]
public partial struct ProcessBufferJob : IJobChunk
{
internal EntityCommandBuffer.ParallelWriter ecbParallel;
public EntityTypeHandle entityTypeHandle;
[ReadOnly] public BufferTypeHandle<Child> childTypeHandle;
[ReadOnly] public ComponentTypeHandle<DistanceCompData> distanceCompDataTypeHandle;
// A BufferLookup for random access to Child buffers.
[ReadOnly] public BufferLookup<Child> childLookup;
[ReadOnly] public ComponentLookup<Disabled> disabledComponentLookup;
public PlayerDesignatorCompData targetDesignator;
public HelperStructToUpdateEnabledEntities addToBufferStruct;
public Entity playerEnt;
public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
{
var entities = chunk.GetNativeArray(entityTypeHandle);
var childAccessor = chunk.GetBufferAccessor(ref childTypeHandle);
var distanceCompData = chunk.GetNativeArray(ref distanceCompDataTypeHandle);
bool hasChildBuffer = chunk.Has(ref childTypeHandle);
DynamicBuffer<Child> lodChildBufferData;
for (int i = 0; i < chunk.Count; i++)
{
Entity currentEntity = entities[i];Conseil: Une optimisation pour DynamicBuffer est de le caster en NativeArray avant l'itération : « var lodChildNativeArray = lodChildBufferData.AsNativeArray(); »
GameObjects et physique dans DrakkenRidge
Dans DrakkenRidge, 90% du monde est rendu en utilisant ECS, exécutant ses propres tâches en arrière-plan pour maintenir l'environnement visible dans un état beau et optimisé.
Mais pour notre petite équipe de développement composée d'un programmeur et d'un artiste, nous avons décidé de construire beaucoup de nos interactions VR rapprochées en utilisant des GameObjects et des MonoBehaviors traditionnels. Cela a permis un temps d'itération plus rapide dans un environnement de tests rapides et de cycles de conception fréquents.
Interactions physiques et combat
Les interactions VR dans DrakkenRidge sont largement pilotées par des simulations physiques. Cela inclut tout, de la prise et de la manipulation d'objets, à l'escalade et au parkour du joueur, en passant par le lancer de sorts et le combat au corps à corps.
Les joueurs peuvent interagir avec des défis d'escalade basés sur la physique.
Exécuter des simulations de physique dans le monde ouvert
Le combat dans DrakkenRidge est piloté par un système qui mélange des animations uniques avec des comportements physiques par articulation. Chaque IA décide comment faire en sorte que sa mort soit réactive et gratifiante en fonction de la situation.
Combiner la physique par articulation avec des animations scénarisées pour créer des réactions uniques
De nombreux objets et sorts dans DrakkenRidge permettent au joueur de infliger des dégâts à plusieurs ennemis à la fois, ce qui entraîne souvent l'exécution de simulations physiques sur de nombreux rigs de personnages simultanément.
Appliquer la physique des explosions à des groupes d'IA
Optimisations physiques
Les simulations physiques en temps réel peuvent être coûteuses, surtout sur les plateformes mobiles. Pour aider à atténuer cela, chaque objet physique dans le monde suit l'emplacement du joueur, et si le joueur est en position d'interagir avec la simulation ou non.
Par exemple, le joueur peut grimper sur de longues chaînes construites à partir de maillons pilotés par la physique qui interagissent entre eux et avec le monde qui les entoure. Ces collisionneurs, articulations et corps rigides de physique sont activés/désactivés dynamiquement en fonction de la manipulation directe par le joueur ou de la vue de la chaîne.
En règle générale, nous rendons les objets à grande distance, mais nous n'autorisons les interactions physiques qu'avec les objets proches. Dans un jeu en VR, où l'action se passe de près, cela correspond à ce à quoi le joueur s'attend.
Optimisations supplémentaires
Lors de la décision sur la manière d'optimiser notre rendu pour la VR mobile, nous avons considéré comment chaque environnement était construit et avons choisi la solution qui correspondait le mieux à nos besoins.
En plus de l'ECS, nous avons considéré une variété de techniques, y compris les LOD et impostors.
LOD des objets
Le rendu des GameObjects avec LODs consiste à avoir plusieurs versions d'un objet donné à afficher à différentes distances du joueur. Par exemple, un modèle de maison très détaillé est remplacé par une version très simplifiée en faible polygone, ce qui permet d'économiser du temps de rendu lorsque le joueur est loin de l'objet.
Dans DrakkenRidge, chaque objet est déjà modélisé dans un style artistique rétro low-poly hautement optimisé, et la grande majorité du monde est gérée via ECS, donc les LOD 3D traditionnels n'apporteraient aucun avantage réel.
Cependant, le système d'écriture de distance que nous avons créé a été conçu pour gérer le rendu des LOD pour les Entities distantes, lorsque cela est nécessaire.
Imposteurs
Un système d'imposteur prend des GameObjects 3D et les convertit en billboards 2D lorsque le joueur est à une certaine distance d'eux. Ceci fonctionne mieux pour les objets d'arrière-plan denses et éloignés tels que les forêts. DrakkenRidge utilise des imposteurs dans certaines situations.

Les imposteurs correctement implémentés sont indiscernables de leurs homologues 3D.
Dans DrakkenRidge nous avons testé une variété de techniques d'optimisation, choisissant soigneusement lesquelles implémenter. Unity ECS a fourni de loin les plus grands gains de performance, rendant notre monde entier à une fraction du coût de l'utilisation du pipeline GameObject traditionnel.
Pensées finales
Pour DrakkenRidge, notre combinaison de techniques de conception et d'optimisation s'est avérée être la recette parfaite, nous permettant de construire une aventure VR unique. Le monde ouvert est alimenté par ECS pour Unity, et nos interactions rapprochées sont conçues avec le flux de travail familier GameObject et physique, permettant à l'équipe de concevoir, tester et itérer rapidement.
Les RPG en monde ouvert pour la VR mobile ne sont pas hors de portée, et nous sommes impatients de voir davantage de développeurs relever ce défi !

DrakkenRidge VR est disponible maintenant. Découvrez plus de jeux Made with Unity sur notre page Steam Curator, et consultez d'autres histoires des développeurs Unity sur le Blog Unity et le Resource Hub.