Actualités / Jeux

Roblox Physics: Construire un meilleur système de sommeil

Parlons du «sommeil» dans un moteur physique.

Le but d’un système de sommeil est d’arrêter de travailler sur des corps qui ne bougent pas et de commencer à travailler quand ils le seront. Le défi consiste à choisir la meilleure heuristique pour la transition entre ces états. Une approche courante dans d'autres moteurs consiste à surveiller la vitesse d'un corps, et lorsque la vitesse est inférieure à un seuil donné pendant plusieurs images, le corps est endormi. Il peut se réveiller en entrant en collision avec un corps éveillé, ou peut-être une poignée d'autres événements. Jusqu'à récemment, Roblox utilisait également une variante de cette méthode.

Certains problèmes connus avec cette méthode sont les interactions physiques où un corps peut avoir une vitesse proche de zéro pendant quelques images, mais n'a pas terminé sa trajectoire actuelle. Nous pouvons penser à un cas simple où une balle roule sur un plan incliné via son propre élan. Finalement, la balle manque d'énergie cinétique et atteint le sommet de sa trajectoire (après avoir tout converti en énergie potentielle en la poussant vers le haut de la pente), et roule sur la pente. Cependant, si elle est assez lente, la balle s'endormira simplement sur la pente au sommet de sa trajectoire avant de pouvoir rouler à nouveau.

Si un développeur rencontre ce type de cas de bord dans son jeu, le moteur fournit souvent une solution de contournement. Ils peuvent être en mesure d'ajuster les seuils de mise en veille, sacrifiant les performances de toutes les interactions. Ou peut-être qu'ils peuvent désactiver le sommeil sur un objet spécifique tous ensemble. Peut-être qu'ils veulent seulement désactiver le sommeil sur un objet pendant un certain temps. Dans tous les cas, il appartient au développeur de découvrir et de contourner tous les cas de pointe de sommeil rencontrés. Chez Roblox, nous voulions trouver un moyen d'éviter tous ces mauvais cas, en réduisant la charge de travail des développeurs. L'objectif est un système de veille dont le développeur ne devrait pas avoir à s'inquiéter.

Dans le moteur Roblox, les corps rigides sont appelés «assemblages». Il s’agit d’un ensemble d’un ou de plusieurs corps primitifs, ou «parties», rigidement connectés, mais c’est l’objet qui est soit éveillé, soit endormi.

https://blog.roblox.com/

Les assemblages peuvent être connectés à d’autres assemblages via des articulations simulées telles que des charnières ou des cordes, constituant ce que l’on appelle un «mécanisme». Ceci est important car les assemblys peuvent déduire leur état de veille en fonction de l'état d'autres assemblys dans leur mécanisme, que nous visiterons plus tard.

Comme d'autres moteurs, Roblox avait utilisé une heuristique traditionnelle pour déterminer quand les corps s'endorment. Chaque assemblage garde un «historique» de ses positions et orientations passées, et tant que l'écart par rapport à la position moyenne reste dans le seuil, l'assemblage reste éveillé. Essentiellement, si la vitesse est inférieure à une valeur définie pour quelques images, l'assemblage s'endort. J'appellerai cette valeur le seuil de vitesse.

https://blog.roblox.com/

Les assemblages Awake sont encadrés en rouge. Les ensembles de couchage sont encadrés en noir. Les assemblages statiques n'ont pas de contour.

L'exemple ci-dessus illustre la balle coincée sur une rampe comme décrit précédemment. Ici, une partie tournante pousse le cylindre vers le haut d'une colline, le gardant immobile pendant un certain temps. La vitesse du cylindre passe en dessous du seuil de vitesse pendant un temps suffisamment long pour s’endormir. Cela pourrait être illustré par une variété d'exemples, tels qu'une balle rebondissant en faible gravité, s'endormant dans les airs, ou un grand bloc basculant en place, s'endormant avant de rincer le sol.

Notre objectif était de voir s'il y avait de meilleures informations que le changement de position d'un assemblage au cours des dernières images pour déterminer s'il devait dormir. Pourquoi ne pas suivre l'une des lois les plus fondamentales du mouvement? «Un objet reste au repos ou continue de se déplacer à une vitesse constante, à moins qu'il ne soit agi par une force.» Nous savons que la gravité agit sur le cylindre et qu'elle devrait continuer à rouler. Nous voulons que l'objet soit éveillé lorsqu'il se déplace à une vitesse constante, ou qu'une force déséquilibrée agisse sur lui. Si l'un de ces cas est vrai, le corps doit rester éveillé. Nous pouvons récupérer les dernières valeurs d'impulsion sur un assemblage à partir du solveur physique et les vérifier par rapport à un autre seuil d'impulsion.

https://blog.roblox.com/

En visitant à nouveau le même exemple, nous voyons le cylindre rouler correctement sur la pente. Désormais, il est impossible pour une assemblée de dormir si elle est agitée par une force déséquilibrée. Pour qu'un assemblage s'endorme, il doit être en dessous du seuil de vitesse ainsi que du seuil d'impulsion.

En essayant d'utiliser cette même logique pour provoquer le réveil des assemblys, nous rencontrons un petit problème. Nous ne pouvons pas vérifier la dernière valeur d’impulsion d’un assemblage endormi, car l’intérêt d’un élément d’endormissement est qu’il n’est pas dans le solveur. Pour cela, nous devons toujours nous fier aux contacts et aux événements de changement de propriété. Cependant, la relation de mécanisme peut aider dans une variété de cas. En fait, l'historique d'un assemblage est également utilisé pour aider à déterminer quand autre les assemblages dans le même mécanisme devraient se réveiller.

Lorsqu'un mécanisme a un assemblage éveillé, tous les voisins immédiats de cet assemblage sont mis dans un état de «vérification» (s'ils ne sont pas également éveillés). Les assemblages en état de «vérification» sont toujours en veille, mais vérifiez l'historique de l'assemblage éveillé à chaque image, et si son écart est supérieur à un autre seuil plus grand, nous décidons simplement que l'assemblage de «vérification» devrait également être éveillé. C'est ce qu'on appelle le seuil de vitesse voisin.

https://blog.roblox.com/

Nous supposons que si l'un de ces assemblages est soumis à beaucoup de mouvement, les autres assemblages doivent également être éveillés et en mouvement. Ce n'est pas toujours vrai, donc cela finit par être un peu plus agressif que nécessaire. Par exemple, disons que vous avez un moulin à vent composé de deux assemblages: les pales en rotation et la base. Idéalement, les lames en rotation devraient être éveillées tandis que la base reste endormie car elle ne bouge pas. Cependant, tant que les lames en rotation se déplacent à une vitesse supérieure au seuil de vitesse voisin, la base restera éveillée de manière incorrecte.

Ce comportement idéal peut causer des problèmes avec d'autres types de mécanismes. Vous pouvez faire en sorte qu'un assemblage se déplace juste assez vite pour rester éveillé, mais assez lentement pour que ses voisins restent en état de vérification de veille. Si l'assemblage éveillé se déplace à un point qui nécessiterait que le voisin endormi se déplace également, ils restent tous les deux bloqués et finissent par s'endormir.

Voici une démonstration de ce cas. Nous avons deux blocs reliés par une corde en apesanteur. Le grand bloc est éveillé et en mouvement, tandis que la partie stationnaire est en train de «vérifier le sommeil». C’est exact, jusqu’à ce que le gros bloc se déplace suffisamment loin pour que la corde soit apprise.

https://blog.roblox.com/

Les assemblages «Sleeping Check» sont encadrés en orange.

Il n’ya aucun moyen pour l’assemblage de contrôle du sommeil de savoir que la corde a été apprise, en ce qui le concerne, le voisin se déplace encore assez lentement pour rester endormi en toute sécurité. Le bloc mobile tire sur la corde mais ne peut plus bouger, il s’arrête et s’endort.

Comme vous vous en doutez déjà, un nouveau seuil d'impulsion voisin pourrait également être utilisé pour réveiller les voisins endormis. Dans ce cas de corde, on sait que le bloc subit une grande variation de la force du filet dès que la corde est apprise. Nous utilisons ce changement de force comme un événement pour réveiller l'assemblage de «vérification». Dans l'exemple, nous voyons qu'une fois la corde apprise, la partie endormie se réveille. Le tout sans exécuter de calculs supplémentaires sur la partie dormante elle-même.

https://blog.roblox.com/

Cela peut non seulement être utilisé pour réveiller les assemblages endormis, mais cela peut également les maintenir endormis plus longtemps. Nous n'avons plus besoin de supposer qu'un assemblage a besoin de se réveiller simplement parce que son voisin éveillé se déplace assez rapidement.

En fin de compte, avec seulement quelques petits changements, nous améliorons considérablement le système de veille du moteur. Plutôt que d’utiliser des seuils de vitesse soigneusement réglés, la première loi de Newton s’applique directement. Nous regardons maintenant plutôt les forces, endormant les corps lorsqu'ils sont vraiment au repos. Des tonnes de cas extrêmes sont désormais gérés correctement par le moteur, évitant ainsi aux développeurs de les trouver et de les corriger de manière indépendante. Parfois, aborder les problèmes de physique en revenant aux fondamentaux de la physique peut finalement fonctionner.


Ni Roblox Corporation ni ce blog n'approuvent ou ne soutiennent aucune entreprise ou service. De plus, aucune garantie ou promesse n'est faite concernant l'exactitude, la fiabilité ou l'exhaustivité des informations contenues dans ce blog.

Cet article de blog a été initialement publié sur le blog Roblox Tech.