Jeu physique des tornades: comment l'aérodynamique est implémentée dans Just Cause 4 (trafic)

Jacques Kerner est ingénieur logiciel senior chez Avalanche Studios.


Comme si le jeu n'était pas assez fou avant

Présentation


Les séries de jeux Just Cause et Avalanche Studios sont connues pour leur technologie en monde ouvert, offrant un gameplay varié et passionnant. La dernière version du jeu - Just Cause 4 - a ajouté des catastrophes liées au vent et aux intempéries, qui sont devenues une nouveauté dans la pile de technologies qui approfondissent le gameplay. Mais les conditions environnementales extrêmes ont été conçues à l'origine non seulement comme un moyen de simuler un monde plus crédible. La fureur de la nature est contrôlée par les forces du mal qui s'opposent à Rico Rodriguez. Nous voulions rendre le vent plus manifeste et les conditions météorologiques extrêmes ne ressemblaient pas à des événements soudains étrangers à ce monde. Cet article présente les techniques développées par nous pour mettre en œuvre le vent dans toutes ses manifestations d'un point de vue physique, ainsi que la réaction de tous les objets à lui.

[Sous cat environ 120 Mo de fichiers GIF]


JC4 Tropical Storm - Early Concept (Volta)

Une offre que nous ne pouvions pas refuser


Alors que le développement de Just Cause 3 était presque terminé, la plupart de l'équipe est passée à la pré-production de Just Cause 4, et le minuscule noyau a dû travailler sur des correctifs pour JC3 et du contenu téléchargeable («DLC»). Hamish Young et moi, programmeur principal et concepteur principal de véhicules, nous sommes concentrés sur le DLC Mech Land Assault. Nous étions censés être le principal concepteur de physique (et la mécanique du joueur) et le principal programmeur de physique JC4, mais nous étions complètement absorbés par le DLC au moment où la conception de la nouvelle série de franchise était en cours de création, ses caractéristiques attrayantes et ses fonctions importantes étaient déterminées. Cette fois, un prototype à grande échelle a été créé pour tester la nouvelle mécanique de base et la réaction de Rico au vent. Un projet de l'intrigue a été écrit et l'éditeur Square Enix a approuvé la direction de développement initiale. Il ne restait plus qu'à maîtriser le concept. Mais comment faire cela sans compromettre les performances? Dès que nous avons commencé le projet, nous avons attaqué le problème sur deux fronts: 1. fixer de larges limites pour éviter les pires scénarios (spoiler: nous n’avons pas réussi) 2. gérer diverses manifestations de conditions météorologiques extrêmes, et en particulier des vents d’ouragan, créer un système qui offre un comportement réaliste, mais s'adapte bien au nombre et à la densité d'objets souhaités.


Sandstorm dans JC4 - Early Concept Art (Volta)

Contrôle des dommages


Le goulot d'étranglement dans la simulation en temps réel, et en particulier les jeux en monde ouvert, est le nombre de corps physiques en collision. Les principales dépenses résultent du calcul des collisions de nombreux corps en mouvement entrant en collision les uns avec les autres et avec un environnement statique (relief, bâtiments). C'est pourquoi les moteurs physiques comme Havok séparent les corps actifs et inactifs. Les corps actifs sont vérifiés pour les collisions avec d'autres corps et nécessitent un coût de calcul complet. Si le corps actif ne bouge pas pendant plusieurs images, le moteur physique le marque comme inactif, et à partir de ce moment, il peut être complètement ignoré jusqu'à ce qu'il soit «réveillé» par le corps actif qui approche. Ces corps inactifs reposent généralement sur le sol et les contrôles de collision entre eux et la terre ne sont plus effectués. Il est évident que la présence omniprésente du vent dans le monde ouvert deviendra une menace pour ce système, il était donc important pour nous de veiller à ce que le vent reste modéré et purement cosmétique lorsqu'il est exposé à de grandes surfaces, ou fort et physiquement activant lorsqu'il se produit dans de petits volumes et dans des endroits où la quantité les corps potentiellement actifs sont petits. J'ai parlé de ces limites à notre service de conception dans les premières étapes de développement afin qu'il ne soit pas piégé. Au début, il semblait que les concepteurs avaient écouté et décidé de limiter les trajectoires des événements météorologiques extrêmes à des itinéraires de destruction prédéterminés, dans lesquels des règles plus strictes pour la construction du monde devraient s'appliquer. Et ils ont respecté certaines de ces restrictions. Mais la tentation était trop grande, et la pression de collègues qui voulaient faire du jeu le meilleur possible s'est avérée insurmontable. A quoi je pensais juste? Immédiatement après cela, les concepteurs ont créé une tornade de plusieurs kilomètres de haut, traversant la capitale du pays - la partie la plus densément peuplée de l'île. Cette tornade a audacieusement non seulement la moitié de la capitale, mais aussi certains des programmeurs sans méfiance qui n'ont pas adhéré trop strictement à cette fonctionnalité de base du jeu.


Blizzard dans JC4 - Early Concept Art (Volta)

Approche générale


En général, la physique des conditions météorologiques extrêmes au JC4 nécessitait les ingrédients suivants:

  • Modèle de traînée aérodynamique appliqué à tous les objets dynamiques du monde, en tenant compte de leur forme et de leur taille
  • Des sources de vent dont la forme et la distribution correspondent à des conditions météorologiques extrêmes (tempête, tornade), mais qui fournissent également des schémas de propagation du vent dans le monde
  • Optimisation des systèmes ci-dessus pour que le jeu s'adapte au budget de charges de calcul

Ces trois problèmes devaient être résolus simultanément et dès que possible. De nombreuses décisions de conception dépendaient de la possibilité de mettre en œuvre les trois aspects, et au cours des premiers mois, nous étions insatisfaits des concepteurs qui attendaient patiemment l'occasion de jouer avec le système à grande échelle.

Tout d'abord, nous avons créé un modèle de traînée aérodynamique. Après son achèvement, chaque objet a soudainement appris à réagir de manière assez réaliste au vent. Par exemple, si un objet tombe d'une falaise ou est projeté par une explosion, tous les objets ralentissent et tournent de manière réaliste dans l'air, ce qui en soi en valait déjà la peine. Mais en l'absence de sources de vent, il était difficile de dire comment elles se comporteraient dans des conditions de vent extrême. Bien que nous soyons fiers de nous-mêmes et du fait que l'expérience et l'intuition nous ont aidés à trouver rapidement une approche aux deux premiers problèmes qui répondaient aux exigences de performance, nous avons décidé que nous étions très chanceux lorsque la première version de la tornade a commencé à fonctionner exactement comme nous l'espérions. Elle a soulevé tous les objets dynamiques et les a tordus d'une manière plutôt réaliste, sans prendre tout le temps du processeur. Le directeur de JC4, Francesco Antollini, qui a très souvent posé des questions sur la situation de la tornade, est apparu juste à côté de mon lieu de travail et a exprimé son soulagement: je pense que j'ai raté l'occasion de lui faire honte de me mettre en doute; mais en fait je ressentais la même chose.

D'un point de vue physique, JC4 a été une percée par rapport à JC3: c'est un monde plus dense, rempli, vibrant et beau, qui est beaucoup plus intéressant à détruire. Et tout cela était possible sur les mêmes plateformes cibles (XBox One et PlayStation 4). Sans surprise, l'optimisation a pris beaucoup de temps. Notre directeur technique Dave Barrett a immédiatement profité de notre avantage: nous avions les indicateurs de performance nécessaires pour JC3, donc le chef du département de développement moteur, Daniel Pieroni, a été chargé de déterminer les coûts maximaux de performance et de mémoire pouvant être utilisés pour chaque aspect technique. La physique nous a donné une généreuse 8,5 ms sur 4 threads sur 33 ms de temps processeur, alloués pour créer une trame avec une fréquence de 30 fois par seconde. Havok a occupé une grande partie de ce budget pour reconnaître les collisions possibles entre les objets, calculer les contacts, résoudre les restrictions et «intégrer» le mouvement de tous les corps actifs pour déterminer leur position après 33 ms de temps simulé. J'ai calculé approximativement que notre budget pour tous les calculs liés à l'aérodynamique et au vent devrait être d'environ 1 ms sur 4 fils. Fondamentalement, nous avons réussi à respecter le budget, bien qu'il soit probablement préférable de demander à Daniel à ce sujet. La solution présentée ci-dessous est suffisamment rapide pour le temps réel lors du calcul de plusieurs centaines d'objets sur des processeurs modernes. Bien sûr, comme beaucoup plus, il peut être encore optimisé en l'adaptant pour fonctionner sur le GPU.

Dans la suite de l'article, je parlerai brièvement de la façon dont nous avons résolu chacun des problèmes, et pour ceux qui sont intéressés, je présenterai dans les applications des détails et des calculs mathématiques.


Wind in JC4 - Early Concept Art (Ironklad Studios)

Modèle de résistance


Notre objectif en créant le modèle de résistance était d'évaluer les forces de résistance et les couples, qui ressembleraient approximativement à ceux qui sont appliqués à un corps de forme arbitraire dans le monde réel. Remarquez à quel point nous n'étions pas ambitieux - personne n'exigeait un réalisme énorme. Cependant, nous avions certaines exigences. Premièrement, les forces de résistance doivent contrecarrer le mouvement du corps. Deuxièmement, la force doit être calculée à partir de l'équation de base de la traînée aérodynamique, c'est-à-dire varient en fonction de la surface de la figure et du carré de la vitesse de déplacement dans l'air. Enfin, d'une manière ou d'une autre, la forme et la taille du corps doivent être prises en compte pour que les objets ayant la même surface mais des formes très différentes se comportent différemment. J'ai été tenté d'approcher simplement la forme de chaque corps en fonction du parallélogramme qui le décrit, mais j'ai pensé que quelque chose de plus était nécessaire, car c'était évident - la forme de nombreux objets peut différer considérablement d'une boîte ou même d'un petit nombre de boîtes. Mon expérience précédente de travail avec des systèmes qui approximent approximativement le volume d'objets 3D à l'aide de voxels ou de sphères m'a fait chercher une meilleure solution. On m'a proposé de sélectionner manuellement les coefficients de résistance pour chaque objet, mais je voulais éviter une étape supplémentaire d'ajustement manuel dans un pipeline déjà compliqué. Par conséquent, j'ai continué à rechercher un moyen automatisé. Et je suis content de ne pas avoir reculé.

La façon la plus simple d'évaluer la pression du vent sur chaque surface de la forme de collision de nos objets est de ne prendre en compte que le vent entrant, en ignorant toute la circulation d'air autour des objets et la viscosité de l'air qui les entoure. Comme si la résistance à l'air ne consistait qu'à faire avancer la masse d'air devant l'objet ou son absorption par contre. Un premier prototype a montré que cette méthode était assez bonne pour nos besoins.

Le «seul» problème était que la somme des contributions de milliers de triangles pour chaque figure individuelle pendant l'exécution du jeu était d'un ordre de grandeur supérieur au niveau de coût requis. Dans les scènes "lourdes", nous pourrions facilement atteindre plus de 100 000 visages. Ce serait formidable si nous pouvions calculer les forces à l'avance. La première méthode de «force brute» a consisté en un calcul préliminaire des forces et couples aérodynamiques qui surviennent lorsqu'un corps se déplace à différentes vitesses dans plusieurs directions dans l'air calme lorsqu'il tourne à différentes vitesses angulaires dans différentes directions. Nous avons donc obtenu une table de recherche à partir de laquelle nous pouvions prendre des valeurs lors de l'exécution du jeu. Cela peut être imaginé comme une soufflerie virtuelle, incluse lors de la compilation de notre contenu, dans laquelle nous plaçons tous les objets tour à tour et les exposons à différentes vitesses de mouvement ou de rotation, en plaçant chaque objet sous différents angles, et à chaque fois en mesurant les forces et les couples.

À quoi ressemblera cette table? Les valeurs connues à l'exécution sont la vitesse linéaire et angulaire du corps, donc S=5, c'est-à-dire seulement environ 300 Ko par objet. Et encore, c'est au moins un ordre de grandeur supérieur à la consommation de mémoire autorisée.

Pour réduire considérablement le nombre d'échantillons, j'ai utilisé deux techniques. Premièrement, j'ai converti le calcul sous une forme linéaire en une somme de contributions basée sur le calcul préliminaire des forces et des couples séparément pour seulement un corps en mouvement et seulement en rotation. Deuxièmement, j'ai approximé cela en une formule analytique pour extrapoler des valeurs à des vitesses arbitraires basées sur une réaction pré-calculée et seulement à une vitesse de 1 m / s et une vitesse de 1 rad / s. Cela a réduit la table précalculée à seulement 7 Ko par objet. Malheureusement, pour cela, j'ai dû effectuer plusieurs approximations. La raison du problème est que, même avec un modèle de résistance très simple, nous sommes confrontés au fait que les forces appliquées au corps, c'est-à-dire la rotation et le déplacement, ne sont pas seulement la somme des forces appliquées séparément pour la rotation et le déplacement. Même si je devais ajouter des approximations, j'ai réussi à enregistrer certains des termes causés par une combinaison de rotation lors du déplacement, similaire au composant Coriolis. La conclusion du libellé se trouve à l'annexe 1. Par conséquent, au lieu de stocker directement les forces et les couples pour chaque échantillon, nous stockons le vecteur de termes  mathcalA( hatu)utilisé dans les formules linéaires. Chaque échantillon correspond à une vitesse linéaire unitaire par rapport à l'air à 1 m / s ou à une vitesse angulaire unitaire par rapport à l'air à 1 rad / s, dans une certaine direction. Les composants de ce vecteur sont utilisés dans la formule, qui prend également en compte les vraies vitesses linéaires et angulaires de l'objet par rapport à l'air lors du calcul des forces et des couples qui doivent être appliqués à l'objet. L'annexe 1 explique comment cela se produit.

Pour stocker la table de recherche, nous avons utilisé une carte de cube, c'est-à-dire un cube dont les faces sont divisées en grilles de taille, disons 3x3 cellules, comme un cube de Rubik. Nous stockons des valeurs dans les coins des cellules, afin que chaque face puisse stocker des valeurs 4x4. Dans chaque coin de la cellule, nous calculons le vecteur allant du centre du cube au coin et normalisons ce vecteur pour obtenir la direction de l'unité. Nous utilisons ce vecteur de direction unitaire comme  mathcalA( hatu)pour le coin de la cellule. En conséquence, nous obtenons 6 tables (une par bord) de 16 éléments avec 19 valeurs flottantes chacune, ce qui est légèrement supérieur à 7 Ko, ce qui est très pratique. Il existe des moyens de réduire davantage le nombre d'échantillons, mais avec cette méthode, il est très facile d'interpoler la direction de la vitesse arbitraire: puisqu'elle tombe toujours dans la cellule, il est toujours possible d'utiliser les valeurs aux quatre coins de cette cellule pour effectuer une interpolation bilinéaire pour cette direction spécifique. La technique des cartes cubiques et de l'interpolation bilinéaire est très largement utilisée dans le rendu, il est donc très facile de trouver des informations à son sujet et le code correspondant.


Figure 1. Carte cubique des vitesses unitaires par rapport à l'air. Sur cette figure, j'ai mis en évidence en rouge une cellule séparée d'une carte cubique pour illustrer le principe. Avoir une vitesse linéaire  hat omegapar rapport à l'air, nous échantillonnons à nouveau la même carte cubique pour trouver la cellule bleue et utiliser les 4 coefficients stockés dans ses coins. Ensuite, nous mélangeons toutes les valeurs selon la formule de l'annexe 1.

Bien que cela ait fonctionné dans la plupart des cas, nous avons rencontré des difficultés pour changer le centre de masse ou l'échelle des objets lors de l'exécution. Nos solutions à ces problèmes se trouvent dans les annexes 2 et 3.

Lors du développement de ce modèle, je n'étais pas sûr du nombre d'échantillons suffisants pour obtenir un bon comportement des objets en mouvement et en rotation dans l'air, donc je ne savais pas avec certitude si j'avais suffisamment de mémoire sur le disque et au moment de l'exécution. En parallèle, nous avons commencé à créer de nouveaux actifs de destruction pour Havok, avec des centaines de fragments de différentes tailles, parfois plusieurs centaines de pièces pour un actif. Il m'est apparu que certains de ces actifs nécessiteraient la même quantité de mémoire, comme de nombreux autres actifs au total, si chaque fragment avait sa propre carte cubique. Le modèle général transmettait bien certaines caractéristiques uniques des objets complexes, mais était trop pour les petits fragments. De plus, je n'étais pas sûr du coût au moment de l'exécution, et pouvoir revenir à un modèle à moindre coût était un bon moyen de réduire les risques. Par conséquent, j'ai trouvé une formulation très compacte (faisant des approximations généreuses) basée uniquement sur des boîtes englobantes d'objets. Il se trouve à l'annexe 4.

Volume du vent


Nous avons introduit le concept de volumes de vent, soutenant l'idée qu'un vent d'objet puissant et physiquement activateur ne peut se produire que dans des espaces finis, et avons commencé à les classer en fonction de la forme et de la distribution du vent. Nous avons divisé les volumes de vent dans les principaux types suivants:

  • Volume de vent cylindrique utilisé pour les blizzards, les tempêtes de sable et les tempêtes tropicales
  • Volume de vent de tornade - un ensemble vertical de cylindres centrés par rapport à une spline verticale se déformant avec le temps
  • Souffleries composées de plusieurs figures connectées en forme de capsule (capsules dont les rayons diffèrent à différentes extrémités), formant quelque chose comme un «trou de ver»

Cette restriction du vent par le volume final a été critiquée à plusieurs reprises, et au dernier moment ils l'ont presque abandonnée, la remplaçant par un «vent topographique». Partout, le vent était censé correspondre au mouvement des nuages ​​dans la haute atmosphère et fournir au joueur un flux d'air ascendant lorsqu'il rencontrait une pente croissante du terrain.Nous l'avons implémenté, mais l'absence d'un affichage graphique clair du vent nous a obligés à abandonner cette fonction. Les gars du département de rendu avaient déjà trop de tâches pour vendre des nuages, des rivières, des cascades, passer à DirectX 12 et bien plus encore.

Rétrospectivement, il s'est avéré que les tempêtes sont devenues les volumes de vent les plus simples, à la fois en termes de forme (cylindre) et de distribution du vent (presque unidirectionnel pour une tempête de sable, ou tournant autour d'un axe central pour un blizzard). En revanche, les tornades et les souffleries se sont avérées plus complexes et méritent une explication plus détaillée.

Tornade


Nous avions une idée claire et simple de la façon dont les objets devraient tourner autour d'une tornade, mais nous ne nous sommes pas mis d'accord sur la distribution des vents nécessaire pour atteindre ce résultat. Au lieu d'un débat sans fin, nous avons rendu les différents composants du champ de vent personnalisables au moment de l'exécution afin que Hamish puisse les expérimenter et trouver rapidement une option de travail. Une tornade est essentiellement un empilement de cylindres horizontaux dont les centres sont situés sur la cannelure centrale, qui se déforme avec le temps. Dans ces cylindres horizontaux, nous avons décomposé le champ de vent de tornade en coordonnées cylindriques avec une composante tangente, une composante radiale et une composante verticale. Chaque composant peut être ajusté à l'aide de courbes variables.


2. — . , , . . , .

Comme pour de nombreuses autres fonctionnalités, et comme c'est souvent le cas dans notre industrie, Hamish et moi sommes souvent passés de la configuration au code jusqu'à ce que le résultat soit assez bon. Hamish a modifié les courbes à son goût, jetant des dizaines de conteneurs de 12 mètres le long de la tornade pour observer leur comportement. Il a utilisé la vitesse maximale du vent enregistrée (environ 230 mph) pour la tornade. Après un certain temps, Hamish a découvert que sa configuration était compliquée car il fallait faire en sorte que le vent partout corresponde à un simple mouvement de rotation, mais en même temps attirait des objets au centre. La vitesse angulaire faisait déjà partie du champ, non seulement en poussant, mais aussi en faisant tourner des objets dans une tornade. Cela garantissait que, par exemple, les objets coincés au centre tourneraient en place, comme nous le voulions.Par conséquent, Hamish a demandé de commencer par le vent, correspondant partout à cette vitesse angulaire au centre, c'est-à-dire par le champ de vitesse d'un champ de rotation idéal, dans lequel un champ de vent personnalisé peut être ajouté. Après cette dernière configuration, les courbes ont commencé à se composer des composants suivants:

  • - facteur de la composante radiale (mouvement radial)R(d)
  • est le facteur de la composante tangente (mouvement radial)T(d)
  • - facteur de la composante verticale (mouvement radial)V(d)
  • - multiplicateur de composante horizontale (mouvement vertical)H(h)
  • - facteur de la composante verticale (mouvement vertical)Φ(h)

O Where est la hauteur au-dessus du bas de la tornade, eth est la distance du centre. La vitesse du vent de tornade est donnée par l'équation:d

V(d,h)=[VtT(d)H(h)+Ωd]t^+VrR(d)H(h)r^+VuV(d)Φ(h)up^


Lorsque les objets sont accélérés à la vitesse tangente de la tornade à une distance donnée, la composante tangente des forces de résistance de l'air est essentiellement nulle, car l'air et l'objet se déplacent à l'unisson le long de la tangente. Le reste de la vitesse du vent attire l'objet vers l'intérieur, car la planète attire des satellites pour plier sa trajectoire afin qu'il reste en orbite; De plus, les objets sont poussés vers le haut pour atteindre de plus grandes hauteurs. Pousser les objets vers le haut est l'optimisation des performances la plus importante, empêchant les calculs coûteux des contacts de centaines d'objets et de la terre. Il permet également qu'avec la hauteur de la tornade, il augmente le rayon en répartissant spatialement les objets pour réduire la probabilité de leur collision et de calcul de contact. Une tornade dans le monde réel est formée par l'échange d'air lorsqu'une couche d'air froid est au-dessus d'une couche d'air chaud.L'air chaud monte comme un tourbillon autour du centre d'une tornade, qui est de l'air froid qui descend. Par conséquent, en principe, au centre de l'entonnoir, la vitesse du vent doit être fortement dirigée vers le bas. Comme vous pouvez le voir, cela n'est pas mis en œuvre dans notre pays pour réduire la probabilité de pousser des objets vers le sol et de les entraîner dans une tornade, sinon cela augmenterait le calcul coûteux des collisions.


3. (), (). Ωdle champ tournant du vent avec lequel nous avons commencé, afin de mieux comprendre si un champ supplémentaire est nécessaire au bon fonctionnement de la tornade. Dans la version de droite, un champ tournant est ajouté. Au loin, nous voyons un vent très rapide, en tout point dirigé à environ 45 degrés du rayon. La section verticale sur la gauche montre combien la tornade doit tirer au centre. Ensuite, il y a un petit intervalle de transition dans lequel il n'y a presque pas de vent, et derrière lui il y a un fort champ tournant au centre. La force du champ de vent est indiquée en couleur, le plus rouge, le plus fort.


Figure 4. Lignes des chemins autour du champ de vent de tornade - la cannelure centrale de la ligne.

Une tornade directe semble ennuyeuse. Pour le déformer, nous avons utilisé 2 splines cubiques reliées par les extrémités, dont 3 points de contrôle sont en orbite et se déplacent à différentes vitesses autour d'une ligne verticale imaginaire. Le profil de tornade résultant change avec le temps, il passe donc lentement de la forme en S à la forme en C, et vice versa. L'annexe 5 explique comment nous avons créé des splines. Fait intéressant, la tornade en mode déformé ne fonctionnait pas aussi bien. Des objets encerclant l'orbite d'une tornade directe se sont maintenant dispersés dès que la fente centrale de la tornade s'est éloignée d'eux, et est malheureusement tombée au sol. Pour résoudre ce problème, nous avons ajouté un autre terme à la vitesse due à la déformation de la tornade elle-même. Au final, cette déformation devrait survenir principalement du fait du mouvement de l'air, et il nous a paru naturel d'ajouter cette composante. Cela a merveilleusement résolu le problème, nous donnant des lignes de chemin très similaires à l'image ci-dessous.


Figure 5. Lignes de trajectoires autour du champ de vents de tornade - la spline centrale se courbe au fil du temps


Figure 6. Exemple de tornade dans un jeu, elle détruit et absorbe tout sur son passage. Il s'agit du Havok Visual Debugger (VDB), un outil extrêmement utile qui nous permet d'observer des éléments simulés.

Souffleries


Les souffleries ont été conçues pour fournir un contrôle physique du vent dans certaines parties du monde, comme les canyons et les grottes, ainsi que des colonnes de fumée devant d'énormes ventilateurs industriels et des canons à vent. Ils peuvent être utilisés pour guider le joueur dans certains espaces ou missions. Nos premiers prototypes utilisaient un cylindre traditionnel avec un champ vectoriel uniforme de vitesse constante parallèle à l'axe de rotation du cylindre. Placer tous ces cylindres dans la scène a été une tâche minutieuse, nous avons donc utilisé une spline cubique de Bézier autour de laquelle un cercle de rayon variable est étiré. Cette forme est approximée en divisant la spline centrale en figures en forme de capsule, c'est-à-dire sur des capsules de rayons différents sur les bords. Le champ de vitesse en eux a également subi quelques changements. Initialement, le vent dans le tunnel était tangent à la cannelure centrale. Nous avons défini les vitesses du vent à chaque point de contrôle de la spline et elles ont été interpolées d'un point de contrôle à un autre le long d'un segment de spline. Cependant, Joshua Espinosa (le concepteur qui a travaillé sur les souffleries et les mouvements du joueur sur celles-ci) a vite découvert qu'il avait besoin de deux composants supplémentaires. L'un des composants est l'amont, donnant au joueur un ascenseur artificiel supplémentaire, toujours pointé vers le haut. Nous avons appelé l'autre composant «rétraction», il pousse le joueur vers la spline centrale, mais surtout aux bords du tunnel, tombant au centre à zéro. Enfin, la limite de réduction dans la partie extérieure du tunnel a assuré une transition en douceur de l'extérieur vers la partie extérieure du tunnel. L'épaisseur de cette limite est spécifiée en pourcentage du rayon; il agit tout le long de la soufflerie.


Figure 7. Soufflerie divisée en une séquence de figures en forme de capsule qui se chevauchent. La séparation se produit lorsque la direction de la spline change, ou lorsqu'il n'est plus possible d'effectuer une interpolation longitudinale linéaire du rayon (A) ou de la vitesse du vent (B). Nous avons calculé la dérivée seconde de ces variables le long de la spline pour déterminer le moment de la scission.


Figure 8. Souffleries modifiées dans le moteur Apex. La soufflerie est divisée en capsules de la bonne manière, en fonction de la spline, des changements de rayon et de vitesse du vent le long de la spline. Comme indiqué dans la section suivante, vous pouvez également voir la séparation spatiale qui trie les figures en forme de capsule en courbes de Morton. Ces calculs sont assez rapides pour les mises à jour en temps réel; en outre, vous pouvez rapidement interagir avec la soufflerie pour la tester. L'outil d'édition a été créé en retravaillant certaines parties de l'outil de création de rivière avec l'ajout du rendu de débogage.


Figure 9. Un exemple d'une longue soufflerie permettant à un joueur de se déplacer en amont vers une montagne. Le courant de la rivière pousse Rick à la mer, et le vent peut rapidement le renvoyer à l'intérieur de la terre au-dessus de la même rivière. Le département de mécanique du joueur a remarqué que les vents latéraux de Rico étaient trop forts, donc la principale influence du vent est d'accélérer le joueur (avec un vent arrière) ou de freiner (vent de face) et de lui donner une portance supplémentaire (composante amont).


Figure 10. Rico en wingsuit dans la même soufflerie. Ici, le joueur ne contrôlait pas la direction. Au début, Rico perd de l'altitude jusqu'à ce qu'il atteigne la partie extérieure de la soufflerie, ce qui ralentit progressivement son déclin. Ensuite, la partie centrale crée un écoulement ascendant suffisant pour surmonter la gravité et l'accélère rapidement dans le canyon. Le code JC3 Wingsuit pour une bonne interaction avec le vent a été développé par Joshua Espinosa, Hamish Young et Rickard Granfeld.

Optimisation des demandes de vent


Avec le potentiel de centaines de corps actifs, le calcul du vent local dans leur position devrait être un processus rapide. Nous avons commencé à optimiser les requêtes en calculant l'AABB (boîte de délimitation alignée sur l'axe) pour chaque volume de vent et en les stockant dans un tableau très compact. Cela permet un rejet par force brute car il est possible de vérifier rapidement la position par rapport à chaque AABB sans manquer de cache. Dans chaque trame AABB, les volumes de vent dans le réseau sont mis à jour pour préparer la demande.

Si la position est à l'intérieur du volume de la tempête, nous calculons directement l'effet du vent en utilisant une forme cylindrique. Pour une tornade, vous devez faire plus de calculs, car en haut, elle est beaucoup plus large qu'en bas, tandis que la densité d'objets la plus élevée est en bas. La solution AABB ne coupe pas très bien les objets près de la tornade, nous avons donc utilisé des cylindres empilés les uns sur les autres. Ils transmettent la forme de tornade beaucoup plus près et sont utilisés pour couper des objets avant de calculer le vent. La dernière optimisation de tornade a été d'éviter de projeter la position de la requête sur la spline centrale. Cela était possible car bien que la tornade spline soit interpolée en points 3D, et donc qu'il s'agisse d'une courbe 3D paramétrique, en pratique les points de contrôle interpolés par elle sont uniformément et séquentiellement répartis le long de la verticale, ce qui nous donne une courbe assez simple. En général, la projection d'un point sur une spline 3D ou la recherche d'un point sur cette spline avec la même hauteur nécessite une recherche le long de cette spline. Mais à la place, nous avons décidé de changer la façon dont la spline est échantillonnée en utilisant la hauteur au-dessus du bas de la tornade comme paramètre d'échantillonnage pour la spline elle-même. Cela modifie légèrement la forme de la spline, mais la spline passe toujours par les points d'interpolation. Mais en même temps, pour trouver un point sur la spline à la même hauteur, cela revient à lui transférer la hauteur de la position de la requête, puis à fixer la hauteur du point dans la hauteur de la requête. Pour les points de contrôle situés de manière inégale le long de l'axe vertical, la différence est notable, mais lorsqu'ils sont uniformément situés, elle est à peine visible. Nous pourrions également changer la façon dont la courbe centrale est construite en utilisant la fonction de hauteur cubique au lieu de la courbe paramétrique, mais, comme beaucoup d'autres optimisations, celle-ci est apparue trop tard.

Les souffleries nécessitaient également une optimisation, car la projection de chaque point d'interrogation sur la spline centrale de chaque soufflerie n'était même pas prise en compte. Heureusement, nous avons réussi à profiter de la technologie mise en œuvre simultanément pour les rivières par Engin Silasun: une base de données spatiale clairsemée. Nous divisons l'espace en 32 O( log(n)). Si la cellule n'est pas dans la base de données spatiale, il n'y a pas de vent au point d'interrogation provoqué par les souffleries. Si la cellule est trouvée, vous devez effectuer une vérification plus coûteuse. De plus, cette vérification devrait être assez rapide, et nous avons donc coupé les souffleries en figures en forme de capsule. Dans le cas général, les capsules sont utilisées car il est possible de calculer la distance à leur segment central à faible coût. Les figurines en forme de capsule sont un peu plus chères, mais toujours plus rapides que de trouver la distance la plus courte à une spline cubique. Une autre propriété d'un système spatialement holistique de souffleries est que nous pouvons nous souvenir de l'index de cellule d'un certain objet situé dans la trame précédente et l'utiliser comme un indice pour accélérer la requête dans la trame suivante, car il est très probable qu'il se trouve déjà dans ce ou dans un voisin cellule.


Figure 11. Les figures en forme de capsule des souffleries sont entrées dans une base de données spatiale clairsemée en fonction des cellules qu'elles traversent. Le résultat est un réseau de 9 cellules, dont chacune n'a que quelques figures en forme de capsule.

En conclusion


La combinaison des techniques que nous avons utilisées s'est avérée très efficace. En soi, ces techniques sont activement utilisées dans la programmation. L'essentiel du travail réside dans leur sélection et leur bonne collaboration pour résoudre le problème actuel. C'est typique de la programmation de jeux vidéo: elle est pleine de petits problèmes qui nécessitent des solutions simples mais fiables.

Le modèle de résistance à l'air est extrêmement simplifié et ne reflète pas certaines propriétés importantes de l'écoulement réel du fluide. Par exemple, une feuille à un angle de 45 degrés générera plus de portance que dans notre modèle brut. Mais la bonne chose à ce sujet est que les forces et les couples ne sont pas calculés lors de l'exécution, et une solution avec une carte cubique évite une simulation plus détaillée. En fait, nous avons vérifié les calculs des forces et des couples générés sur l'ensemble de la carte cubique de l'objet à tester (une voiture ancienne de JC4) à l'aide d'un logiciel open source de dynamique des fluides computationnelle (OpenFOAM). La comparaison a montré que nous n'étions pas trop éloignés des résultats corrects, mais la «forme» des cartes cubiques était différente, et je m'attends à ce qu'elle diffère encore plus pour les objets en forme d'aile. Cependant, il a fallu plusieurs heures pour calculer le logiciel, il est donc évident qu'une telle solution n'est pas adaptée à une utilisation sur tous les objets. Notre méthode a pris moins d'une seconde par objet. Mais je pense qu'il serait très intéressant pour les jeux basés sur la physique d'avoir des coefficients aérodynamiques rapides mais réalistes pour tous les objets. Supposons que Rico puisse collecter des objets dans d'énormes boomerangs. J'ai brièvement joué avec cette idée, en regardant la chute et la rotation rapides des graines d'hélicoptère d'érable, et j'ai créé un modèle à Maya pour voir ce qui se passe. Le résultat s'est avéré meilleur que prévu et l'objet a vraiment tourné lentement lorsqu'il est tombé. Mais il me semble que pour une rotation plus rapide il faudra améliorer significativement le modèle de résistance à l'air. Comme cela arrive souvent, nous n'avons tout simplement pas eu assez de temps.


Figure 12. À gauche: toutes les orientations d'une voiture à pétrole d'époque de Just Cause 4, placée dans une soufflerie virtuelle pour remplir une carte cubique avec une grille 5x5 sur chaque face. À droite: Paraview a visualisé les résultats pour deux orientations - sous un angle au-dessus (au-dessus) et derrière (au-dessous). Le rouge indique la haute pression, le bleu indique la basse pression, les lignes indiquent les débits.

Les tornades et les tempêtes ont fonctionné très efficacement. La déformation de la tornade peut encore être améliorée. Si nous y consacrions plus de temps, nous pourrions probablement faire des tornades d'eau (bien sûr, avec des requins au lieu de vaches), des tourbillons ou des tornades de feu. Nous avons eu une autre idée - développer un canon qui crée une mini-tornade.

Les souffleries ont été utilisées dans différentes parties du monde pour contrôler le vent sur une île, comme les canyons, les missions, autour de certaines bases militaires. Ils aident le joueur à traverser les vastes étendues de notre monde ouvert avec des vents ascendants stratégiquement situés. Mais je pense qu'il vaudrait mieux utiliser l'idée du vent topographique, que nous n'avons pas eu le temps de mettre en œuvre. Il serait plus rationnel de le mettre en œuvre en premier, cela nous donnerait un vent omniprésent systématique qui ne nécessite presque aucun ajustement, et les souffleries fourniraient un contrôle local sur les écarts par rapport à celui-ci.

Et, finalement, c'était une idée logique d'utiliser des pare-vent comme mécanique de jeu. Nous avons implémenté un prototype d'obstacles jouable, qui a été montré à l'intérieur de l'équipe, mais l'avons abandonné par manque de temps pour la mise en œuvre correcte. Sa physique n'était qu'une partie du coût total de cette fonctionnalité, qui était censée être prise en charge par la plupart de l'équipe de développement.

Mais rien ne peut me distraire de la fierté que je suis de ce que nous avons réussi à faire dans JC4. Notre visualisation des conditions météorologiques extrêmes et en particulier des tornades, combinée à la capacité de Rico à se déplacer dans l'espace, a permis de créer un gameplay absolument unique et exceptionnel. J'espère que vous avez aimé jouer à JC4 autant que nous l'avons fait lors de sa création.


Annexe 1: Modèle de résistance à l'air


Nous regardons le corps  mathcalBdéfini par le maillage Ti,i in[0,N1].


Figure 13. Le corps i in[0,N1].

Considérons un triangle  vecVi:

 vecVi= vecV+ vec Omega times vecOCi=Vi  hatvi



Figure 14. Triangle et vitesse en son centre.

Maintenant, nous devons écrire la force élémentaire  vecFiagissant sur ce triangle. C'est ici que nous devons tenir compte de nos exigences:

 vecFi=Ai Vi ( vecVi cdot hatni)  hatni


Cela correspond bien aux exigences, car la force est presque toujours dirigée vers le côté contre la direction du mouvement, est proportionnelle à la surface du triangle et proportionnelle au carré de la vitesse du triangle par rapport à l'air. Pour que la force agisse sur tout le corps, il nous suffit de résumer ces forces:

 vecF= sum vecFi= sumAi Vi ( vecVi cdot hatni)  hatni


Alors que nous nous efforçons de tout réduire à 1 m / s et 1 rad / s, réécrivons avec  hat omega:

 vecF= sumAi  |V hatv+ Omega hat omega times vecOCi |(V hatv+ Omega hat omega times vecOCi) cdot hatni  hatni


Et maintenant la première grosse approximation:

 |V hatv+ Omega hat omega times vecOCi | environV+ Omega | hat omega times vecOCi |


Cela équivaut à approximer la longueur de l'hypoténuse d'un triangle par la somme des longueurs de ses deux côtés. Cette approximation est également connue sous le nom de «distance d'un pâté de maisons» (distance de Manhattan). Quand je travaillais sur cette tâche, j'étais juste à Manhattan, il serait donc stupide de ne pas l'utiliser. Nous avons donc les éléments suivants:

 vecF= sumAi (V+ Omega | hat omega times vecOCi |)(V hatv+ Omega hat omega times vecOCi) cdot hatni  hatni


Nous décomposons:

 vecF=V2 sumAi hatv cdot hatni hatni+ Omega2 sumAi | hat omega times vecOCi |( hat omega times vecOCi) cdot hatni hatni+V Omega sumAi( hat omega times vecOCi) cdot hatni hatni+ OmegaV sumAi | hat omega times vecOCi |( hatv cdot hatni) hatni


Au début, cela peut sembler intimidant. Mais alors vous remarquez que c'est ce que nous recherchions. Notez que seuls les montants sont trouvés  | hat omega times vecOCi |avec sa valeur moyenne parmi tous les triangles:

 | hat omega times vecOCi | approxMoy( | hat omega times vecOCi |)i in[0,N1]


Notons-le par  hat omega. Maintenant, nous pouvons enfin écrire:

 vecF=V(V+ Omega  overlinevr( hat omega)) vecFt( hatv)+ Omega2 vecFr( hat omega)+V Omega vecFc( hat omega)


où:

\ begin {align *} \ vec {F} _t (\ hat {v}) & = \ sum {-A_i \ hat {v} \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ vec {F} _r (\ hat {\ omega}) & = \ sum {-A_i \ | \ hat {\ omega} \ times \ vec {OC_i} \ | (\ hat {\ omega} \ times \ vec { OC_i}) \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ vec {F} _c (\ hat {\ omega}) & = \ sum {-A_i (\ hat {\ omega} \ times \ vec {OC_i}) \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ overline {v_r} (\ hat {\ omega}) & = {1 \ over N} \ sum {\ | \ hat {\ omega} \ times \ vec {OC_i} \ | } \ end {align *}


Moment de ces forces par rapport au point Oopeut être obtenu d'une manière similaire. Et en conséquence, nous obtenons ce qui suit:

 left. vecM right|O( hatv, hatw)=V(V+ Omega  overlinevr( hat omega)) vecMt( hatv)+ Omega2 vecMr( hat omega)+V Omega vecMc( hat omega)


où:

\ begin {align *} \ vec {M} _t (\ hat {v}) & = \ sum {-A_i \ hat {v} \ cdot \ hat {n} _i \ (\ vec {OC_i} \ times \ hat {n} _i)} \\ \ vec {M} _r (\ hat {\ omega}) & = \ sum {-A_i \ | \ hat {\ omega} \ times \ vec {OC_i} \ | (\ hat {\ omega} \ times \ vec {OC_i}) \ cdot \ hat {n} _i \ (\ vec {OC_i} \ times \ hat {n} _i)} \\ \ vec {M} _c (\ hat {\ omega}) & = \ sum {-A_i (\ hat {\ omega} \ times \ vec {OC_i}) \ cdot \ hat {n} _i \ (\ vec {OC_i} \ times \ hat {n} _i)} \ end {align *}


Compte tenu des définitions ci-dessus, nous pouvons maintenant former un vecteur  mathcalA( hatu):

 mathcalA( hatu)= beginbmatrix vecFt( hatu) vecFr( hatu) vecFc( hatu) vecMt( hatu) vecMr( hatu) vecMc( hatu) overlinevr( hatu) endbmatrix


Ceci est un vecteur de 19 valeurs et nous nous référons au tableau d'échantillons  chapeauw, mais nous pouvons trouver des valeurs assez proches, puis les utiliser directement ou les utiliser pour interpoler la sortie. Et à ce stade, la carte cubique décrite dans l'article entre en jeu.

Annexe 2: centre de masse


Vous pouvez remarquer que les valeurs indiquées ci-dessus sont calculées par rapport à un point arbitraire Pi. La force totale agissant sur le corps est simplement la somme de toutes les forces:

 vecF= sum vecfi



Moments Osont définis comme:

 left. vecmi right|O= vecOPi times vecfi


et le moment total de ces forces par rapport au point Oest égal à:

M|O=mi|O=OPi×fi


Maintenant c'est juste une définition mathématique, une formule qui ne peut pas être utilisée directement pour changer le mouvement du corps, parce que le centre de gravité dans cette formule par le théorème de Schal est égal à:G

M|O=(OG+GPi)×fi=OG×fi+GPi×fi


Nous reconnaissons le moment des forces concernant , donc:F

M|O=OG×F+M|G


Et c'est très utile pour nous si nous calculons la force totale inchangé et appliqué le couple suivant au centre de masse:F

M|G=M|O+GO×F


Au début, j'ai décidé de prendre comme point de départ l'origine du corps au centre du parallélogramme de délimitation du corps, qui doit toujours être proche du centre de masse et localiser l'échantillonnage du vent à l'endroit le plus logique par rapport au corps.O

Annexe 3: Mise à l'échelle


Un autre défaut est apparu lorsque des ballons ont été introduits dans le jeu. Ces billes sont des corps sphériques dont la taille peut varier d'un facteur 5 ou 10. Comme dans le cas du centre de masse, il était trop coûteux de recalculer les propriétés aérodynamiques à l'exécution. Est-il possible de dériver une formule analytique?


Figure 15 Corps OsCsi=s OCi

Considérons à nouveau le corps , mais maintenant pour un objet à l'échelle. Nous obtenons:F

Fs=V2Aiv^n^in^i+Ω2Aiω^×OCsi(ω^×OCsi)n^in^i+VΩAi(ω^×OCsi)n^in^i+ΩVAiω^×OCsi(v^n^i)n^i


En utilisant les mêmes approximations que la première fois et en remplaçant , on obtient:s OCi

Fs=V(Vs2+Ωs3 vr¯(ω^))Ft(v^)+Ω2s4Fr(ω^)+VΩs3Fc(ω^)


Pour le centre de masse du corps écaillé Gs.

Annexe 4: Modèle de résistance simplifié pour le parallélogramme


Il existe de nombreuses façons d'approximer les forces et les couples pour un parallélogramme, et différentes formules peuvent être obtenues. Assez compact, facile à implémenter dans le code et les calculs lors de l'exécution, il peut être déduit en ignorant l'effet du mouvement angulaire sur la force linéaire et l'effet de la vitesse linéaire sur le couple. Prendre la taille du parallélogramme englobant , on peut arriver aux formules compactes suivantes:ez

F=ρV2eyez,exez,exeyv^


M=ρ6Ω2exeyezw^ey2+ez2,ex2+ez2,ex2+ey2


Annexe 5: cannelure du centre Tornado


La tornade est centrée autour d'une courbe centrale dont la forme change lentement. Nous l'avons implémenté en utilisant deux splines cubiques de Bézier consécutives: pour le fond etC0 pour le haut. SplineC1 a des points de contrôleC0P0 , P1, P2et etP3 contrôlé par des pointsC1P4 , P5, P6et P7. La position de la tornade elle-même est à un point au sol et point le plus hautP0 commence juste au-dessus de la couche nuageuse, mais tarde, suivant lentement la position au sol. Étant donné que les courbes sont connectées à une extrémité,P7P3 et coïncident dans l'espace. Nous avons également utilisé 3 orbites de référence horizontales pour les pointsP4P1 , P2et P5. Enfin était situé exactement à mi-chemin entreP3P2 et etP5 à mi-chemin entreP6P5 et P7.

Création d'une spline centrale de tornadeÉvolution de la spline centrale de la tornade dans le temps

Les références


  1. Juste cause 4
  2. Havok
  3. Fondements des structures de données multidimensionnelles et métriques . Hanan samet
  4. Courbe d'ordre Z
  5. Cartographie des cubes
  6. Mousse ouverte
  7. Volta
  8. Ironklad studios

Source: https://habr.com/ru/post/fr441678/


All Articles