Ue4

Analyse du module physique UE4

Ue4 Physical Module Analysis



1. La relation entre les composants du maillage et la physique




À propos de l'utilisation de base de la physique UE, les documents officiels et mes documents précédents ont été présentés plus en détail. ( Lien vers le document officiel Analyse de détection de collision de plan UE4Règles de collision UE4 détaillées (mise à jour 2016.7.12)



Ici, principalement du point de vue du code, analysez simplement comment la physique dans UE4 est utilisée et efficace, et comment la physique correspondant à StaticMesh et SkeletalMesh est générée et fonctionne. La troisième partie impliquera du contenu du moteur PhyX, parlera brièvement de l'interaction entre UE et PhysX.



Tout d'abord, il existe généralement 5 types d'objets avec de la physique qui sont communs dans les jeux, tels que les capsules, les maillages statiques StaticMesh, les maillages squelettiques SkeletalMesh, Landscape terrain et PhysicsVolume (BrushComponent). Ces cinq types ont essentiellement les mêmes règles physiques. Pour plus de commodité, nous résumons uniquement StaticMesh et SkeletalMesh.

Pour les pierres placées directement sur la scène, etc., des actifs qui sont généralement importés dans le moteur via un logiciel de modélisation 3D. Après l'importation dans le dossier de ressources du moteur, le modèle de pierre existe dans le moteur en tant que classe UStaticMesh. Après avoir fait glisser du dossier de ressources vers la scène, l'objet de la scène devient StaticMeshActor. Pour le modèle de joueur avec animation, c'est un atout avec des informations osseuses importées via un logiciel de modélisation 3D. Après avoir été importée dans le dossier de ressources du moteur, la classe USkeletalMesh existe dans le moteur. Après avoir fait glisser du dossier de ressources vers la scène, l'objet de la scène devient SkeletalMeshActor. Bien sûr, mettre le SkeletalMeshActor sans aucun traitement dans la scène ressemble à un StaticMeshActor, sans aucune animation, et peut-être sans aucune physique.

Étant donné que UE4 favorise le développement basé sur les composants, de nombreuses fonctionnalités d'Actor sont fournies via des composants, de sorte que les données physiques sont accrochées aux composants plutôt qu'à Actor. Plus de N composants peuvent être attachés à n'importe quel acteur, de sorte qu'un joueur peut avoir plusieurs UStaticMeshCompnent et USkeletalMeshCompnent (généralement il y a aussi un corps de capsule comme composant racine). À titre d'exemple simple, le propre modèle du joueur est un USkeletalMeshCompnent, puis les vêtements et l'équipement sur le corps peuvent être représentés par un UStaticMeshCompnent. La plus grande différence entre les deux est que SkeletalMesh peut générer des animations. Afin de fonctionner avec plus de précision, chacun de ses os peut générer une physique correspondante, et à mesure que l'animation change, chacune de ses propres physiques osseuses doit également suivre l'animation pour changer, donc c'est beaucoup plus compliqué que StaticMesh.



Pour un maillage statique StaticMesh, sa physique doit généralement être créée dans le logiciel de modélisation. Lors de l'importation dans l'éditeur, l'UE créera des informations physiques basées sur les données importées. Bien entendu, UE4 lui-même fournit également la création de collisions physiques, comme le montre la figure 1-1. Dans tous les cas, construisez essentiellement un UBodySetup pour UStaticMeshComponent dans l'éditeur et créez les données physiques de base UBodyInstance au moment de l'exécution lors du démarrage du jeu.


Figure 1-1 L'éditeur UE ajoute une collision


(UBodySetup et UBodyInstance: je comprends personnellement que UBodySetup est une donnée physique statique, qui est généralement construite avant le lancement du jeu [bien sûr, vous pouvez la créer lorsque le jeu s'exécute sans aucun problème]. Vous pouvez la comprendre en tant que classe, après compilation Il existe. Et UBodyInstance est une donnée physique qui joue vraiment dans le jeu. On comprend que les objets créés par cette classe n'apparaissent qu'au moment de l'exécution. Plusieurs UBodyInstances peuvent être créées via un UBodySetup)

Pour SkeletalMesh, en raison de la grande quantité de données, ses données physiques sont stockées dans PhysicsAsset. Lorsque le jeu est en cours d'exécution, SkeletalMeshComponent lira les données UBodySetup dans l'actif physique, puis créera les données physiques de base correspondantes UBodyInstance pour le personnage via UBodySetup. Pour aller plus loin, le moteur physique PhysX de NVIDA (bien sûr vous pouvez également utiliser le moteur physique BOX2D), il y aura une explication simple plus loin dans ce document.

(En plus de SkeletalMeshComponent.cpp, il existe SkeletalMeshComponentPhysics.cpp dans UE4, et PhysAnim.cpp est utilisé pour traiter spécifiquement la logique de la physique SkeletalMeshComponent)


Figure 1-2 Actifs physiques


L'image suivante décrit la relation de base entre les cours de maillage, de composant et de physique de base


Figure 1-3 Diagramme de classe lié à la physique


Si vous ne vous sentez toujours pas familier avec BodyInstance, vous voudrez peut-être le comprendre en conjonction avec le diagramme de classe familier ci-dessous. Nous savons que lors de la configuration de la physique pour Mesh, vous devez configurer des canaux de collision précis pour effectuer des collisions entre différentes physiques. Si vous regardez de plus près, CollisionResponses et ObejctType sont en fait membres de FBodyInstance. Ces propriétés que nous définissons dans l'éditeur sont en fait définies pour BodyInstance (suite à PxRigidActor dans PhysX, qui sera décrit plus tard).

Figure 1-4


Si nous voulons voir visuellement dans l'éditeur si la physique a été créée, nous pouvons appeler la commande de console Show Collision. La figure ci-dessous montre la collision de la capsule du personnage et la collision physique osseuse correspondante (combinaison de plusieurs capsules).


Figure 1-5


2. Processus de création physique


Ce qui précède décrit grossièrement la relation logique entre les composants de base de l'UE4 et la physique. Nous voyons que s'il s'agit de Staticmesh ou SkeletalMesh ci-dessus, cela créera de la physique via BodySetup, et BodySetup appellera finalement BodyInstance pour générer de la physique réelle. Ci-dessous, nous analysons le processus d'initialisation physique spécifique dans le jeu.


2.1 Création physique de UStaticMeshComponent


Le premier est UStaticMeshComponent. Vous pouvez voir que lorsque l'acteur est chargé dans la scène et que l'UActorComponent est enregistré, les informations physiques de l'UPrimitiveComponent sont créées. En fait, à l'exception de UStaticMeshComponent, tous les composants hérités de UPrimitiveComponent (les cinq mentionnés dans la première partie le sont tous) créeront des données physiques après enregistrement (pour les composants directement hérités d'UActorComponent, tels que les composants mobiles, cette opération ne sera pas effectuée). Par conséquent, à l'exception de SkeletalMeshComponent (qui sera analysé plus tard), le moment de la création physique des autres composants hérités de UPrimitiveComponent est très clair, c'est-à-dire que la physique est créée lorsque l'UActorComponent est enregistré. (Bien sûr, certaines circonstances particulières doivent également mettre à jour la physique, comme lors du changement de modèle)

Figure 2-1 Scène de chargement de la pile de création physique StaticMesh



Figure 2-2 Le diagramme de pile de la création physique de la capsule à la naissance du joueur


Voulez-vous créer des données physiques lors de l'enregistrement des composants? Vous pouvez vous référer au code ci-dessous. En fait, il y a évidemment trois conditions,

1. A-t-il été créé?

deux. Si la scène physique actuelle peut être obtenue (les variables de la scène physique sontFPhysScene* PhysicsScene, compris comme un monde physique qui coexiste avec le monde du jeu. Cette PhysicsScene initialise généralement les informations du monde, c'est-à-direannulerInitWorld (constInitializationValuesIVS=InitializationValues()) lors de sa création

3. Si ShouldCreatePhysicsState doit être créé. De toute évidence, je souhaite contrôler la création ou non des données physiques correspondantes pour le composant. Il est plus approprié d'écrire ici. Par exemple, tous les composants qui héritent de UActorComponent et ne réécrivent pas la fonction renverront directement false et UPrimitiveComponent réécrit cette fonction.


Figure 2-3 Capture d'écran indiquant s'il faut créer des codes de condition physique lors de l'enregistrement


2.2 Création physique de USkeletalMeshComponent


USkeletalMeshComponent est différent des autres composants physiques. Parce que sa physique est plus compliquée et implique PhysicsAsset, il doit réécrire le processus de création physique de la classe de base. De plus, de manière générale, nous ne voulons pas que la physique osseuse du joueur soit toujours présente. La raison est simple, juste pour améliorer les performances. Pour les composants généraux avec la physique, il suffit de le configurer avec un simple corps de collision (PhysX comprend Sphere, Box, Capsule). Le coût d'un composant physique aussi simple lorsque le jeu est en cours d'exécution est très faible. Cependant, pour un USkeletalMeshComponent, nous devons créer une unité physique de base pour presque tous les os pour plus de précision. Une fois que le joueur ou le PNJ est trop, cette consommation est très impressionnante. Cependant, nous ne pouvons pas renoncer à utiliser la physique de USkeletalMeshComponent, car une fois que notre jeu veut réaliser des frappes précises, lorsque l'effet d'attaquer différentes positions est différent, nous devons utiliser la physique des os. Par conséquent, une solution courante consiste à créer de la physique lorsque cela est nécessaire et à la supprimer lorsqu'elle n'est pas nécessaire. (La physique SkeletalMesh du moteur par défaut existera toujours. Reportez-vous à la Figure 1-5, et nous devons nous en occuper nous-mêmes. Une solution sera donnée plus tard.)

Commençons par l'enregistrement des composants. L'initialisation physique de USkeletalMeshComponent est différente des composants précédents. Il a d'abord rechargéannulerUSkeletalMeshComponent:: Fonction CreatePhysicsState (). Et en appelant la fonction InitArticulated pour initialiser physiquement tous les os, c'est le code logique lorsque le composant est initialisé. Analysons brièvement,


Figure 2-4 Capture d'écran du code CreatePhysicsState surchargé


Vous pouvez voir que USkeletalMeshComponent a deux chemins d'exécution pour créer de la physique. L'un consiste à utiliser la méthode de classe de base UPrimitiveComponent pour créer des données physiques comme les autres composants, et l'autre consiste à utiliser les données PhyiscsAsset dans USkinnedMeshComponent. (La variable bEnablePerPolyCollision est 0 par défaut, et le moteur n'a pas été modifié) Par conséquent, on peut voir que l'USkeletalMeshComponent normal initialise la physique via la fonctionannulerInitArticulé(FPhysScene*PhysScene,booléenbForceOnDedicatedServer=faux) pour initialiser le physique de chaque os (Articulate signifie articulé). Si le développeur ne fait rien, les données physiques de USkeletalMeshComponent seront créées lors de l'inscription et existeront toujours pendant le jeu.

De manière générale, USkeletalMeshComponent est appelé à chaque fois que TickComponentUSkeletalMeshComponent:: La fonction RefreshBoneTransforms, comme son nom l'indique, consiste à mettre à jour la rotation des coordonnées de l'os et ainsi de suite.


Figure 2-5 Diagramme de pile de transformation osseuse de mise à jour de tick


Dans la fonction RefreshBoneTransforms, vous pouvez décider d'ouvrir un thread pour mettre à jour l'animation et les données physiques associées séparément (en fonction de l'appel finalInitArticuléPhysique de création de fonction).


Figure 2-6 Ouvrez un thread séparé pour traiter les données physiques de l'animation


Le diagramme de pile suivant montre que le moteur gère les données physiques en ouvrant un thread distinct.


Figure 2-7 Un thread distinct pour traiter la pile d'appels de données physiques d'animation


Nous avons mentionné plus tôt que nous devons choisir de laisser la physique être générée lorsque cela est nécessaire, mais d'être supprimée dans des conditions normales. Comment est-ce arrivé? En fait, nous pouvonsUSkeletalMeshComponent:: UpdateKinematicBonesToAnim pour traiter, cette fonctionLe sens est de mettre à jour les données physiques actuelles en fonction de la transformation de l'animation, et chaque image doit être exécutée.L'idée de base est que chaque cadre vérifie si des données physiques osseuses sont nécessaires et, si nécessaire, nous créons les données physiques correspondantes (retournées directement après leur création). S'il est détecté qu'il n'est plus nécessaire de mettre à jour la physique, appelezUSkeletalMeshComponent:: TermArticulated () supprime les données physiques. Nous savons déjà que toutes les données physiques en fonctionnement sont stockées dans BodyInstance, et cette fonction effacera toutes les données BodyInstance que nous stockons actuellement dans Bodies. Les amis qui oublient Bodies peuvent regarder en arrière le diagramme de classe de USkeletalMeshComponent.

Dans le même temps, il y a une note ici pour référence:

// Ce code ci-dessous produit un résultat intéressant ici

// - les codes ci-dessous mettent à jour les données physiques, donc si vous ne mettez pas à jour la pose, la physique n'aura pas le bon résultat

// - mais si nous mettons simplement à jour l'os physique sans mettre à jour la pose actuelle, il aura des données périmées

// Si vous le souhaitez, transmettez les données d'animation aux articulations physiques afin qu'elles puissent être utilisées par les moteurs.

// Voir si nous allons avoir besoin de mettre à jour la cinématique

const bool bUpdateKinematics = (KinematicBonesUpdateType! = EKinematicBonesUpdateToPhysics :: SkipAllBones) Vous pouvez mettre la physique mise à jour dans cette position à traiter.

En outre, pour USkeletalMeshComponent, il existe des attributs tels que bPhysicsRequiredOnDediServer lors de l'initialisation de la physique pour contrôler si les données physiques sont créées en mode serveur.


3. Moteur physique BodyInstance et PhysX


Nous avons appris précédemment que BodyInstance est une unité de base de la physique d'exécution dans la logique UE. En fait, dans le moteur PhysX, il existe également une unité physique de base. Cette unité physique est PxRigidActor. Un BodyInstance correspond à un PxRigidActor (en fait, un PxRigidActor correspondant est créé lorsque BodyInstance :: InitBody), afin que nous puissions combiner le moteur UE avec le moteur PhysX.
A ce moment, je pose une autre question, comment une vraie collision physique est-elle détectée?
Cette question mérite en effet notre attention, et la méthode de détection est différente selon les situations. Par exemple, si vous voulez savoir si deux balles entrent en collision, il vous suffit de juger de la distance entre les centres des deux balles. La collision de deux modèles complexes peut devoir être jugée en jugeant si les deux faces triangulaires ont une intersection. Je pose cette question ici, juste pour rappeler à tout le monde que l'acteur du moteur physique doit également connaître sa propre forme, puis traiter davantage la logique de collision. Par conséquent, après avoir créé une unité physique de base PxRigidActor, nous devons également créer une géométrie de base (appelée Shape dans le moteur), ce traitement logique se trouve dans la fonction UBodySetup :: AddShapesToRigidActor_AssumesLocked. En voyant cette fonction, nous savons que Shape est créé par UBodySetup, et les données de géométrie sont également stockées dans UBodySetup.

Les types fournis dans PhysX sont les suivants:

1.PxSphereGeometry sphérique

deux.PxBoxGéométrie boîte

3.PxCapsuleGéométrie Corps de capsuleSquelettiqueMailleFréquemment utilisé)

Quatre.PxConvexMeshGeometry Corps convexe

5.PxTriangleMeshGeometryFace triangulaire

De ces 5 types, les 4 premiers types de données sont stockés dans UBodySetupFKAggregateGeomAggGeom à l'intérieur.

Les données physiques du dernier triangle sont stockées dans TriMesh et TriMeshNegX de UBodySetup.

Les données physiques du corps convexe et de la surface triangulaire sont spéciales. Il doit passer par un processus de cuisson physique. Ce processus est similaire au rendu. Les informations sur les sommets et l'index de toutes les surfaces triangulaires sont fournis au moteur PhysX. Puis PhysX utilise ces données pour cuire une collision complète. Model, mais ce processus prend un certain temps à s'exécuter (lorsque nous créons une boîte de collision convexe ou définissons une collision simple sur une collision complexe). Par conséquent, si vous souhaitez adopter la cinquième méthode pour votre propre ACtor spécial, vous devriez également préférer terminer le processus de cuisson avant le début du jeu, afin que cela n'affecte pas les performances et l'expérience du jeu.

De plus, lorsque nous créons de la physique, nous la divisons également en statique et dynamique. Ils passent OwnerComponent-> Mobility! = EComponentMobility sur les composants ::MobileContrôller. De toute évidence, le coût de la collision statique et de la collision dynamique est différent.

//Créer statiquePxRigidActor

GPhysXSDK-> createRigidStatic (PTransform)

//Créer une activitéPxRigidActor

GPhysXSDK-> createRigidDynamic (PTransform)

À partir de là, nous avons essentiellement terminé l'initialisation des données physiques. Cependant, nous savons que dans le jeu, il existe de nombreux paramètres détaillés, tels que le canal de collision, le type de collision, etc. Ces données doivent également être mises à jour et traitées en temps opportun. Le traitement de cette logique et des balises associéesFBodyInstance:: UpdatePhysicsFilterData->FBodyInstance:: UpdatePhysicsShapeFilterData. UpdatePhysicsFilterData est le traitement des données physiques totales (car il peut y avoir d'autres moteurs physiques, tels que Box2D, etc.). Et UpdatePhysicsShapeFilterData est l'endroit où la logique UE réelle interagit avec la logique PhysX. En fait, le paramètre de collision CollisionEnabled que nous faisons habituellement correspond à Physx. Ce sont les deux opérations. PShape-> setFlag (PxShapeFlag::eSCENE_QUERY_SHAPE,vrai) PShape-> setFlag (PxShapeFlag::eSIMULATION_SHAPE,faux) (reportez-vous à la structure ci-dessous).

Ci-dessous la marque de forme dans PhysX

structPxShapeFlag

{

énumérationEnum

{

eSIMULATION_SHAPE= (1<<0),

eSCENE_QUERY_SHAPE= (1<<1),

eTRIGGER_SHAPE= (1<<2),

VISUALISATION= (1<<3),

ePARTICLE_DRAIN= (1<<4)

}

}

À propos deUEcontrePhysXL'interaction entre eux est brièvement présentée ici. Pour ce qui est du contenu plus détaillé, si vous êtes intéressé, accédez au code source pour en savoir plus.

Enfin, je recommande un autre document lié à la physique UE Analyse du module du moteur physique UE4


Lien original (veuillez indiquer s'il est réimprimé):http://blog.csdn.net/u012999985/article/details/78242493