Académique Documents
Professionnel Documents
Culture Documents
1
par Thibaut Cuvelier (site Web) (Blog)
Date de publication : 18/10/2011 Dernire mise jour : 07/11/2011
PhysX est un moteur de physique dvelopp par NVIDIA et qui, dans sa troisime version, permet d'utiliser la puissance des GPU pour acclrer les simulations physiques. Il est aussi fort populaire parmi les dveloppeurs de jeux vido.
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
I - PhysX...................................................................................................................................................................... 3 I-A - Petit historique............................................................................................................................................... 3 I-B - La concurrence sur l'acclration matrielle................................................................................................. 4 I-C - Succs de PhysX.......................................................................................................................................... 4 II - Obtenir le PhysX SDK........................................................................................................................................... 5 II-A - Compiler les exemples..................................................................................................................................6 II-B - Prparer l'environnement.............................................................................................................................. 6 III - Utiliser le PhysX SDK........................................................................................................................................... 7 III-A - Initialisation du SDK.....................................................................................................................................7 III-B - Rappel d'allocation....................................................................................................................................... 8 III-C - Rappel d'erreur............................................................................................................................................ 9 III-D - Extensions et cooking..................................................................................................................................9 IV - Une scne...........................................................................................................................................................12 V - Premiers acteurs..................................................................................................................................................13 VI - Rcuprer les donnes de la simulation............................................................................................................15 VII - Affichage des donnes...................................................................................................................................... 19 VIII - Redistribution.................................................................................................................................................... 22 IX - Conclusions.........................................................................................................................................................22
-2Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
I - PhysX
PhysX est un moteur physique prvu pour des jeux vido. Il permet de grer en temps rel des collisions et des processus physiques plus complexes. Sa rputation n'est plus faire dans le monde du jeu vido : il est notamment intgr dans les moteurs de jeu UnrealEngine 3, Unity 3D, Gamebryo, Torque, etc. Notamment, c'est lui l'uvre dans l'UDK, une version grand public de l'Unreal Engine 3, prvue pour des utilisations non commerciales ou ducatives (il est possible, videmment, de vendre des produits utilisant l'UDK, voir conditions sur le site). La suite de l'article supposera que vous tes sur une plateforme Windows 64 bits. Cependant, je tenterai d'expliciter autant que possible les diffrences par rapport des plateformes 32 bits (gnralement, un rpertoire diffrent) ; par contre, pour les autres plateformes, je ne m'avancerai pas, ne pouvant tester confortablement (avec les exceptions des chemins et de la configuration de l'environnement de compilation, rien ne devrait changer).
-3Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
Les ventes ne seront pas suffisantes non plus pour permettre Ageia de vivre de belles annes ; cependant, la mode de l'acclration physique tait lance. En 2008, Ageia est rachet par NVIDIA. L'utilit d'un PPU va mincir, vu l'activit de NVIDIA dans le GPGPU. Finalement, ds 2010, PhysX n'a plus support les PPU, seulement les GPU NVIDIA, grce CUDA. Il ne s'agit que de l'acclration, les simulations peuvent toujours se faire sur le CPU. En 2011, le moteur a t presque compltement rcrit pour la troisime version, en repensant compltement l'architecture vieillissante de la srie 2. On dispose alors d'un multithreading amlior, d'une base de code unifie pour toutes les plateformes (ce qui permettra un support de plateformes mergentes, comme Android) et d'autres.
-4Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
-5Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
Dans le SDK pour Windows, la documentation est exclusivement disponible sous la forme d'un fichier CHM, elle n'est pas disponible en ligne, dans le dossier $physx$\SDKs\Docs \PhysXSDK.chm, avec $physx$ le dossier d'installation de PhysX (cette convention sera garde tout au long du tutoriel).
PxTask et PxFoundation ont chang de rpertoire depuis la version 3.0. Il faudra aussi lier une srie de bibliothques, dfinir par projet (les fichiers d'import sont disponibles dans $physx $\SDKs\lib\win[32|64]\, il faut aussi l'indiquer l'EDI, dans la mme fentre que les fichiers d'en-tte, sous Library Directories). Voici les bibliothques disponibles dans PhysX :
Foundation PhysX3Common PhysX3CharacterDynamic PhysX3CharacterKinematic PhysX3Vehicle PhysX3Cooking PhysX3 PhysX3Extensions LowLevel GeomUtils SceneQuery SimulationController PvdRuntime RepX3
Il est aussi possible d'utiliser des #pragma pour dfinir les bibliothques lier, cette mthode sera prfre par la suite, tant donn qu'elle dispense de fournir un fichier de projet et qu'elle explicite, depuis les sources, les bibliothques
-6Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
externes utiliser. Cependant, il faudra adapter ces lignes pour correspondre l'environnement de compilation le cas chant (notamment pour d'autres plateformes). videmment, tout ceci n'est ncessaire que pour une utilisation complte de PhysX.
Des rappels par dfaut sont fournis ; une macro donne la version des en-ttes de PhysX ; finalement, des paramtres par dfaut sont galement fournis pour les tolrances. On peut donc initialiser le SDK trs rapidement en utilisant ses paramtres par dfaut, sans oublier de librer les objets crs :
#include #include #include #include <iostream> <PxPhysicsAPI.h> <PxDefaultErrorCallback.h> <PxDefaultAllocator.h>
using namespace physx; // Pour #pragma #pragma #pragma // Pour #pragma #pragma Windows 32 bits : #pragma comment(lib, "PhysX3_x86.lib") comment(lib, "PhysX3_x64.lib") comment(lib, "Foundation.lib") comment(lib, "PhysX3Extensions.lib") Windows 32 bits : #pragma comment(lib, "PhysX3Cooking_x86.lib") comment(lib, "PhysX3Cooking_x64.lib") comment(lib, "PxTask.lib")
bool recordMemoryAllocations = true; PxPhysics * mSDK = NULL; PxDefaultErrorCallback pDefaultErrorCallback; PxDefaultAllocator pDefaultAllocatorCallback; int main() { mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, pDefaultAllocatorCallback, pDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations); if(mSDK == NULL) { std::cerr << "An error has happened." << std::endl; exit(1); } } mSDK->release();
La version 3.0 du SDK n'obligeait pas utiliser l'espace de noms physx, du moins avec Visual Studio 2010 ; avec la version 3.1, ne pas inclure la ligne using namespace physx; donnera un bon nombre d'erreurs de symboles non dfinis.
-7Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
Et en 64 bits, o l'on peut avoir de la mmoire aligne sur seize bits sans plus chipoter (de mme que pour PlayStation 3 et XBox) :
class PxDefaultAllocator : public PxAllocatorCallback { void* allocate(size_t size, const char*, const char*, int) { void *ptr = ::malloc(size); PX_ASSERT((reinterpret_cast<size_t>(ptr) & 15)==0); return ptr; } void deallocate(void* ptr) { ::free(ptr); } };
Ce bout de code est extrait des extensions PhysX, disponible dans le fichier $physx$ \SDKs\PhysXAPI\extensions\PxDefaultAllocator.h, ct des implmentations par dfaut pour d'autres plateformes. Pour vrifier l'utilisation de mmoire dynamique du SDK, on peut changer cette implmentation pour correspondre aux besoins. Cette fonction ne devrait jamais retourner NULL. S'il n'y a plus de mmoire disponible ou que l'allocation n'est pas possible pour une autre raison, il faut agir en consquence (arrter proprement l'application, par exemple). Les trois derniers paramtres dterminent le nom du type de donnes en cours d'allocation, ainsi que l'endroit o l'allocation a t demande (les valeurs des macros __FILE__ et __LINE__), afin d'allouer, au besoin, la mmoire d'un tas spcifique. L'tat du SDK ne devrait pas tre modifi par une (ds)allocation mmoire ; ces deux fonctions doivent tre thread-safe (elles peuvent tre appeles depuis le thread utilisateur ou un thread de simulation physique).
-8Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
void PxDefaultErrorCallback::reportError(PxErrorCode::Enum e, const char* message, const char* file, int line) { const char* errorCode = NULL; switch (e) { case PxErrorCode::eINVALID_PARAMETER: errorCode = "invalid parameter"; break; case PxErrorCode::eINVALID_OPERATION: errorCode = "invalid operation"; break; case PxErrorCode::eOUT_OF_MEMORY: errorCode = "out of memory"; break; case PxErrorCode::eDEBUG_INFO: errorCode = "info"; break; case PxErrorCode::eDEBUG_WARNING: errorCode = "warning"; break; default: errorCode = "unknown error"; break; } printf("%s (%d) :", file, line); printf("%s", errorCode); printf(" : %s\n", message);
Ces deux rappels (d'allocation et d'erreur) par dfaut sont dfinis dans les extensions de PhysX.
-9Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) PxCooking * mCooking = PxCreateCooking(PX_PHYSICS_VERSION, & mSDK->getFoundation(), PxCookingParams()); if (!mCooking) { std::cerr << "An error has happened." << std::endl; exit(1); }
Pour initialiser les extensions, il est ncessaire d'inclure, en plus de PxPhysicsAPI.h, PxExtensionsAPI.h. Initialiser les extensions n'est requis qu'en cas d'utilisation de fonctions ncessitant des allocations. Sinon, cela n'est pas ncessaire (si la seule partie utilise des extensions est les rappels par dfaut, cela n'est pas utile). Il est prfrable galement de les fermer la fin de l'application (ce n'est pas encore requis) :
PxCloseExtensions(); mCooking->release();
Pour le cooking, veillez bien passer un objet de fondations venant de l'objet SDK, car ces fondations sont prvues comme un singleton (cela permet aussi de s'assurer que la gestion de la mmoire sera correcte pour les objets passant du cooking au SDK). On a donc une initialisation et une fermeture propre des trois parties comme ceci :
#include #include #include #include #include <iostream> <PxPhysicsAPI.h> <PxDefaultErrorCallback.h> <PxDefaultAllocator.h> <PxExtensionsAPI.h>
using namespace physx; #pragma #pragma #pragma #pragma #pragma #pragma comment(lib, comment(lib, comment(lib, comment(lib, comment(lib, comment(lib,
"Foundation.lib") "PhysX3_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3_x86.lib") "PhysX3Extensions.lib") "PhysX3Cooking_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3Cooking_x86.li "GeomUtils.lib") "PxTask.lib")
bool recordMemoryAllocations = true; PxPhysics * mSDK = NULL; PxCooking * mCooking = NULL; PxDefaultErrorCallback pDefaultErrorCallback; PxDefaultAllocator pDefaultAllocatorCallback; int main() { mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, pDefaultAllocatorCallback, pDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations); if(! mSDK) { std::cerr << "An error has happened." << std::endl; exit(1); } if (! PxInitExtensions(*mSDK)) { std::cerr << "An error has happened." << std::endl; exit(1); } mCooking = PxCreateCooking(PX_PHYSICS_VERSION, & mSDK->getFoundation(), PxCookingParams()); if (! mCooking) { std::cerr << "An error has happened." << std::endl; - 10 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) exit(1);
Tout ceci ne doit tre fait qu'une fois par excution du programme (mme si, dans cet exemple minimaliste, c'est tout ce qui est fait). On peut cependant commencer amliorer cet exemple, en sparant main() des initialisations. On peut simplement dplacer le code dans des fonctions auxiliaires, tant donn que tous les objets sont dclars dans l'espace global (pour faciliter le code, cela n'est pas le meilleur exemple reproduire, il vaudrait mieux tout placer dans un objet, par exemple) :
#include #include #include #include #include <iostream> <PxPhysicsAPI.h> <PxDefaultErrorCallback.h> <PxDefaultAllocator.h> <PxExtensionsAPI.h>
using namespace physx; #pragma #pragma #pragma #pragma #pragma #pragma comment(lib, comment(lib, comment(lib, comment(lib, comment(lib, comment(lib,
"Foundation.lib") "PhysX3_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3_x86.lib") "PhysX3Extensions.lib") "PhysX3Cooking_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3Cooking_x86.li "GeomUtils.lib") "PxTask.lib")
bool recordMemoryAllocations = true; PxPhysics * mSDK = NULL; PxCooking * mCooking = NULL; PxDefaultErrorCallback pDefaultErrorCallback; PxDefaultAllocator pDefaultAllocatorCallback; void initPhysX(); void releasePhysX(); int main() { initPhysX(); releasePhysX(); } void initPhysX() { mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, pDefaultAllocatorCallback, pDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations); if(! mSDK) { std::cerr << "An error has happened." << std::endl; exit(1); } if (! PxInitExtensions(*mSDK)) { std::cerr << "An error has happened." << std::endl; exit(1); } mCooking = PxCreateCooking(PX_PHYSICS_VERSION, & mSDK->getFoundation(), PxCookingParams()); if (! mCooking) { std::cerr << "An error has happened." << std::endl; exit(1); }
- 11 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
Pour la suite, on ne prsentera plus que le code de main(), tant donn qu'il est maintenant trs concis.
IV - Une scne
Il faut commencer par crer un monde pour lancer la moindre simulation. En terminologie PhysX, c'est une scne PxScene qu'il faut instancier.
PxScene * mScene;
Chaque plante du systme solaire est diffrente, au moins en termes de gravit. Il faut donc prvoir un set de paramtres pour grer ces disparits. On peut commencer par dfinir la gravit, dans la direction souhaite :
PxSceneDesc sceneDesc(mSDK->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
On donne un vecteur pour la gravit, avec ses trois composantes : abscisse x, ordonne y, cote z. Le plan XZ est celui du sol, les ordonnes sont donc perpendiculaires au sol, d'o la composante ngative du vecteur. Ceci n'est jamais que pure convention, on pourrait dcider de faire tout autrement sans que le moteur n'en soit affect, il suffit de changer l'interprtation des donnes. On peut galement dfinir des retours lors d'vnements lors de la simulation, des limites et des bordures, un seuil minimal de vitesse pour les rebondissements et bien d'autres, la rfrence est alors extrmement utile. Cependant, ces valeurs sont donnes ou calcules partir des tolrances passes en paramtre, il vaut donc mieux, autant que possible, les dfinir dans l'objet SDK plutt que dans la scne (voir la documentation). Il faut encore dfinir un mcanisme de filtrage des collisions. On peut utiliser celui par dfaut de PhysX (toujours dfini dans les extensions) :
PxSimulationFilterShader gDefaultFilterShader = PxDefaultSimulationFilterShader; // ... sceneDesc.filterShader = & gDefaultFilterShader;
On peut ici le dfinir directement, car on est sr qu'il n'a pas pu tre install autre part. Par contre, dans les exemples de SDK, une vrification est d'abord excute, car une fonction (dpendante de l'exemple) est d'abord appele sur ces descriptions de scne et cette fonction peut dfinir des paramtres sa guise (c'est une des complexits ajoutes par le framework des exemples). Finalement, il faut dfinir des objets qui vont grer la rpartition des tches de simulation sur les threads (tant sur CPU que sur GPU, le GPU n'tant support que sous Windows). On dfinit ici le nombre de threads utiliser 1, d'autres valeurs permettront d'utiliser le multithreading par PhysX.
mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); if(!mCpuDispatcher) std::cerr << "PxDefaultCpuDispatcherCreate failed!"; sceneDesc.cpuDispatcher = mCpuDispatcher;
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) mScene = mSDK->createScene(sceneDesc); if (!mScene) std::cerr << "createScene failed!";
Avant de conclure sur les scnes, sachez qu'il est possible de faire varier la gravit de la scne aprs sa cration. void PxScene::setGravity(const PxVec3 &) change cette gravit, tandis que PxVec3 getGravity() const la rcupre. Il reste important de regarder les indications de la documentation sur l'utilisation de ces fonctions. Il est difficile de ne pas remarquer que PhysX est prvu pour tre personnalis autant que possible pour une parfaite intgration avec l'existant, sans que les performances ne puissent en ptir. Remarquons aussi que toutes les mthodes de PxScene sont virtuelles, permettant ainsi d'hriter et de redfinir des mthodes au besoin. On a donc ce code (en se basant sur le code complet disponible prcdemment) :
PxSimulationFilterShader pDefaultFilterShader = PxDefaultSimulationFilterShader; PxDefaultCpuDispatcher * mCpuDispatcher; PxScene * mScene; int main() { initPhysX(); PxSceneDesc sceneDesc(mSDK->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); sceneDesc.filterShader = pDefaultFilterShader; mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); if(!mCpuDispatcher) std::cerr << "PxDefaultCpuDispatcherCreate failed!"; sceneDesc.cpuDispatcher = mCpuDispatcher; PxScene * mScene = mSDK->createScene(sceneDesc); if (!mScene) std::cerr << "createScene failed!"; } releasePhysX();
On peut galement dplacer ce nouveau code dans une fonction auxiliaire, afin de toujours garder une fonction main() bien lisible, PhysX ayant besoin de beaucoup de dclarations. En appelant la mthode release() de la scne, on supprime automatiquement tous les objets lis (acteurs, formes, etc.), qui seront vus plus tard.
V - Premiers acteurs Au commencement, Dieu cra les cieux et la terre. La terre tait informe et vide : il y avait des tnbres la surface de l'abme et l'esprit de Dieu se mouvait au-dessus des eaux. (Ge, I, 1-2).
Il faut donc crer quelque chose dans ce monde vide. Premire constatation : toute chose est faite d'une matire, au moins. On doit donc crer un matriau avant toute chose :
PxMaterial * mMaterial; mMaterial = mSDK->createMaterial(0.5f, 0.5f, 0.1f); if(!mMaterial) std::cerr << "createMaterial failed!";
Les trois paramtres du matriau sont : la friction statique, la friction dynamique et la restitution. Les frictions dterminent les forces de frottement exerces par cet objet ; la restitution, l'nergie conserve aprs un choc. On
- 13 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
peut pousser le vice : une friction anisotropique est un frottement dont le coefficient varie en fonction de la direction du corps en contact. La documentation donne les mthodes appeler pour cela. Il faut bien rappeler que PhysX est un moteur physique en temps rel, on n'a donc en pratique jamais le temps de rsoudre exactement tous les systmes en jeu dans une simulation pour chaque image. On doit donc effectuer des approximations, chaque tape, ce qui fait qu'une bote pourrait glisser sur une pente, alors qu'elle ne devrait pas, cause de ces erreurs. Il faut toujours garder cela en tte : non, les simulations ne seront pas exactes, mais suffisamment prcises pour les besoins d'un jeu (en rgle gnrale). Dans une utilisation relle, crer autant de matriaux que ncessaire serait plus qu'une plaie. On voudrait donc externaliser toutes ces donnes en dehors du code source : c'est pour a qu'il est possible de srialiser ces objets (la scne ou le SDK entier). Cela sort cependant du cadre de cette introduction. On veut ensuite poser un objet sur un plan. L'axe Y reprsentant la verticale (par convention, comme expliqu plus haut), le plan devra donc tre parallle XZ. En effet, prenant la gravit telle que dfinie prcdemment, un objet ne pourra tre stable que sur un tel plan. On commence par en dfinir l'orientation.
PxReal d = 0.0f; PxTransform pose = PxTransform(PxVec3(0.0f, d, 0.0f), PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));
On cre ensuite le plan et on l'ajoute la scne. Il s'agit d'un objet rigide et statique, d'o l'utilisation de la classe PxRigidStatic ; sa forme est, par dfinition, planaire ; on utilisera le matriau dfini prcdemment. Il faut cependant l'expliciter au moteur, il n'est pas capable de comprendre les intentions du dveloppeur sans cela.
PxRigid* plane = mSDK->createRigidStatic(pose); if (! plane) std::cerr << "create plane failed!"; PxShape * shape = plane->createShape(PxPlaneGeometry(), * mMaterial); if (! shape) std::cerr << "create shape failed!"; mScene->addActor(* plane);
On peut galement se simplifier un peu la vie en utilisant les fonctions auxiliaires disponibles dans les extensions de PhysX :
PxReal density = 1.0f; PxTransform(PxVec3(0.0f, 5.0f, 0.0f), PxQuat::createIdentity()); PxVec3 dimensions(1.0f, 1.0f, 1.0f); PxBoxGeometry geometry(dimensions); PxRigidDynamic * actor = PxCreateDynamic(* mSDK, transform, geometry, * mMaterial, density); if (!actor) std::cerr << "create actor failed!"; mScene->addActor(* actor);
Ceci cre un cube (tant acteur que forme), avec une certaine densit donne, ce qui permet de calculer la masse et le tenseur d'inertie. En rsum, voici ce que l'on vient de faire :
PxMaterial * mMaterial; - 14 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) PxRigid* plane; PxShape * shape; PxRigidDynamic * actor; int main() { initPhysX(); initScene(); initActors(); releasePhysX(); } void initActors() { // Material mMaterial = mSDK->createMaterial(0.5f, 0.5f, 0.1f); if(! mMaterial) std::cerr << "createMaterial failed!"; PxReal d = 0.0f; PxTransform pose = PxTransform(PxVec3(0.0f, d, 0.0f), PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f))); // Plane plane = mSDK->createRigidStatic(pose); if (! plane) std::cerr << "create plane failed!"; shape = plane->createShape(PxPlaneGeometry(), * mMaterial); if (! shape) std::cerr << "create shape failed!"; mScene->addActor(* plane); // Cube PxReal density = 1.0f; PxTransform(PxVec3(0.0f, 5.0f, 0.0f), PxQuat::createIdentity()); PxVec3 dimensions(1.0f, 1.0f, 1.0f); PxBoxGeometry geometry(dimensions); actor = PxCreateDynamic(* mSDK, transform, geometry, * mMaterial, density); if (! actor) std::cerr << "create actor failed!"; mScene->addActor(* actor);
La scne est cre, les objets sont en place mais, pour le moment, ils ne font rien.
Cette fonction simulate() est excute de manire asynchrone, en gnral (en fonction de l'implmentation du gestionnaire de tches) : la simulation aura dbut dans un thread spar. On a cependant besoin des rsultats de la simulation : comment savoir quand ils sont disponibles ? On peut appeler PxScene::fetchResults(), qui renvoie un boolen indiquant si les rsultats de la simulation sont disponibles ou non. On peut lui passer un boolen en paramtre : PxScene::fetchResults(true) ne va retourner que quand les rsultats seront disponibles, pas avant.
mScene->fetchResults(true);
- 15 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
Dernire tape pour chaque itration : rcuprer les donnes et les passer qui de droit (gnralement, le moteur 3D, pour qu'il affiche les changements calculs par le moteur physique). On doit pour cela les demander forme par forme PhysX, grce la mthode statique inline PxTransform PxShapeExt::getGlobalPose(const PxShape & shape).
PxTransform np = PxShapeExt::getGlobalPose(* shape);
Se pose quand mme un problme : on n'a pas de forme pour le cube ! Petite astuce :
PxU32 nShapes = actor->getNbShapes(); PxShape** shapes = new PxShape*[nShapes]; actor->getShapes(shapes, nShapes); while (nShapes--) foo(shapes[nShapes]); // on s'occupe de la forme courante delete [] shapes;
tant donn qu'il n'y a rien pour visualiser graphiquement les translations imposes par la physique, on va simplement afficher les vecteurs de transformation. Ceci tant le dernier exemple, on va le montrer en entier.
#include #include #include #include #include #include <iostream> <PxPhysicsAPI.h> <PxDefaultErrorCallback.h> <PxDefaultAllocator.h> <PxExtensionsAPI.h> <PxTask.h>
using namespace physx; #pragma #pragma #pragma #pragma #pragma comment(lib, comment(lib, comment(lib, comment(lib, comment(lib, "Foundation.lib") "PhysX3_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3_x86.lib") "PhysX3Extensions.lib") "GeomUtils.lib") "PxTask.lib")
bool recordMemoryAllocations = true; PxPhysics * mSDK = NULL; PxCooking * mCooking = NULL; PxDefaultErrorCallback pDefaultErrorCallback; PxDefaultAllocator pDefaultAllocatorCallback; PxSimulationFilterShader pDefaultFilterShader = PxDefaultSimulationFilterShader; PxDefaultCpuDispatcher * mCpuDispatcher; PxScene * mScene; PxMaterial * mMaterial; PxRigidStatic * plane; PxShape * shape; PxRigidDynamic * actor; float mStepSize = 1.0f / 42.0f; void void void bool void void void initPhysX(); initScene(); initActors(); PhysXLoop(); ShowTransformations(); TransformPrint(PxShape*); releasePhysX();
int main() { std::cout << "Starting..." << std::endl; initPhysX(); initScene(); initActors(); std::cout << "Warmed up; looping" << std::endl; while(PhysXLoop()) ; std::cout << "\nLooping ended" << std::endl; - 16 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
releasePhysX(); std::cout << "Closed" << std::endl; int foo; std::cin >> foo;
void initPhysX() { mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, pDefaultAllocatorCallback, pDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations); if(! mSDK) { std::cerr << "An error has happened." << std::endl; exit(1); } if (! PxInitExtensions(*mSDK)) { std::cerr << "An error has happened." << std::endl; exit(1); }
} void initScene() { PxSceneDesc sceneDesc(mSDK->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); sceneDesc.filterShader = pDefaultFilterShader;
mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); if(!mCpuDispatcher) std::cerr << "PxDefaultCpuDispatcherCreate failed!"; sceneDesc.cpuDispatcher = mCpuDispatcher; mScene = mSDK->createScene(sceneDesc); if (!mScene) std::cerr << "createScene failed!";
} void initActors() { // Material mMaterial = mSDK->createMaterial(0.5f, 0.5f, 0.1f); if(! mMaterial) std::cerr << "createMaterial failed!"; PxReal d = 0.0f; PxTransform pose = PxTransform(PxVec3(0.0f, d, 0.0f), PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f))); // Plane plane = mSDK->createRigidStatic(pose); if (! plane) std::cerr << "create plane failed!"; shape = plane->createShape(PxPlaneGeometry(), * mMaterial); if (! shape) std::cerr << "create shape failed!"; mScene->addActor(* plane); // Cube PxReal density = 1.0f; PxTransform transform = PxTransform(PxVec3(0.0f, 5.0f, 0.0f), PxQuat::createIdentity()); PxVec3 dimensions(1.0f, 1.0f, 1.0f); PxBoxGeometry geometry(dimensions); actor = PxCreateDynamic(* mSDK, transform, geometry, * mMaterial, density); if (! actor) std::cerr << "create actor failed!"; mScene->addActor(* actor);
} bool PhysXLoop() {
- 17 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) static int i = 0; std::cout << "\n\t" << i << "\n" << std::endl; mScene->simulate(mStepSize); mScene->fetchResults(true); ShowTransformations(); ++i; if(i == 42) return false; else return true;
} void ShowTransformations() { std::cout << "\tplane" << std::endl; TransformPrint(shape); std::cout << "\tcube" << std::endl; PxU32 nShapes = actor->getNbShapes(); PxShape** shapes = new PxShape*[nShapes]; actor->getShapes(shapes, nShapes); while (nShapes--) TransformPrint(shapes[nShapes]); delete [] shapes; } void TransformPrint(PxShape * s) { PxTransform np = PxShapeExt::getGlobalPose(* s); std::cout << "\t( " << np.p.x << " ; " << np.p.y << " ; " << np.p.z << " )" << std::endl; } void releasePhysX() { PxCloseExtensions(); mScene->release(); mSDK->release(); }
On peut ensuite s'amuser changer quelques paramtres, voir si tout s'adapte bien. Par exemple, si on multiplie certains moments la gravit par deux, on obtient cette fonction de boucle :
bool PhysXLoop() { static int i = 0; std::cout << "\n\t" << i << "\n" << std::endl; mScene->simulate(mStepSize); mScene->fetchResults(true); ShowTransformations(); if(i % 4) mScene->setGravity(2 * mScene->getGravity()); ++i; if(i == 42) return false; else return true;
Les rsultats obtenus vont bien varier fortement (les vecteurs de dplacement vont sans cesse augmenter en norme, puisque la gravit devient plus forte et que le cube est en chute libre). De mme, si on oriente la gravit diffremment
- 18 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
en changeant son vecteur dans l'initialisation de la scne, les rsultats vont varier, la composante Z de la chute du vecteur augmentant :
void initScene() { PxSceneDesc sceneDesc(mSDK->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 2.0f); sceneDesc.filterShader = pDefaultFilterShader; mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); if(!mCpuDispatcher) std::cerr << "PxDefaultCpuDispatcherCreate failed!"; sceneDesc.cpuDispatcher = mCpuDispatcher; mScene = mSDK->createScene(sceneDesc); if (!mScene) std::cerr << "createScene failed!";
Tout ceci pour vous convaincre que la simulation a bien lieu, mme si tout se passe trs vite.
using namespace physx; #pragma #pragma #pragma #pragma #pragma comment(lib, comment(lib, comment(lib, comment(lib, comment(lib, "Foundation.lib") "PhysX3_x64.lib") // Pour Windows 32 bits : #pragma comment(lib, "PhysX3_x86.lib") "PhysX3Extensions.lib") "GeomUtils.lib") "PxTask.lib")
bool recordMemoryAllocations = true; PxPhysics * mSDK = NULL; PxCooking * mCooking = NULL; PxDefaultErrorCallback pDefaultErrorCallback; PxDefaultAllocator pDefaultAllocatorCallback; PxSimulationFilterShader pDefaultFilterShader = PxDefaultSimulationFilterShader; PxDefaultCpuDispatcher * mCpuDispatcher; PxScene * mScene; PxMaterial * mMaterial; PxRigidStatic * plane; PxShape * shape; PxRigidDynamic * actor; float mStepSize = 1.0f / 42.0f; void void void bool void void initPhysX(); initScene(); initActors(); PhysXLoop(); ShowTransformations(int); TransformPrint(PxShape*, int);
- 19 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog) void releasePhysX(); int main() { initPhysX(); initScene(); initActors(); while(PhysXLoop()) ; releasePhysX(); int foo; std::cin >> foo;
void initPhysX() { mSDK = PxCreatePhysics(PX_PHYSICS_VERSION, pDefaultAllocatorCallback, pDefaultErrorCallback, PxTolerancesScale(), recordMemoryAllocations); if(! mSDK) { std::cerr << "An error has happened." << std::endl; exit(1); } if (! PxInitExtensions(*mSDK)) { std::cerr << "An error has happened." << std::endl; exit(1); }
} void initScene() { PxSceneDesc sceneDesc(mSDK->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f); sceneDesc.filterShader = pDefaultFilterShader;
mCpuDispatcher = PxDefaultCpuDispatcherCreate(1); if(!mCpuDispatcher) std::cerr << "PxDefaultCpuDispatcherCreate failed!"; sceneDesc.cpuDispatcher = mCpuDispatcher; mScene = mSDK->createScene(sceneDesc); if (!mScene) std::cerr << "createScene failed!";
} void initActors() { // Material mMaterial = mSDK->createMaterial(0.5f, 0.5f, 0.1f); if(! mMaterial) std::cerr << "createMaterial failed!"; PxReal d = 0.0f; PxTransform pose = PxTransform(PxVec3(0.0f, d, 0.0f), PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f))); // Plane plane = mSDK->createRigidStatic(pose); if (! plane) std::cerr << "create plane failed!"; shape = plane->createShape(PxPlaneGeometry(), * mMaterial); if (! shape) std::cerr << "create shape failed!"; mScene->addActor(* plane); // Cube PxReal density = 1.0f; PxTransform transform = PxTransform(PxVec3(0.0f, 5.0f, 0.0f), PxQuat::createIdentity()); PxVec3 dimensions(1.0f, 1.0f, 1.0f); PxBoxGeometry geometry(dimensions); - 20 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
actor = PxCreateDynamic(* mSDK, transform, geometry, * mMaterial, density); if (! actor) std::cerr << "create actor failed!"; mScene->addActor(* actor);
mScene->simulate(mStepSize); mScene->fetchResults(true); ShowTransformations(i); ++i; if(i == 42 * 42) return false; else return true;
} void ShowTransformations(int step) { PxU32 nShapes = actor->getNbShapes(); PxShape** shapes = new PxShape*[nShapes]; actor->getShapes(shapes, nShapes); while (nShapes--) TransformPrint(shapes[nShapes], step); delete [] shapes; } void TransformPrint(PxShape * s, int step) { PxTransform np = PxShapeExt::getGlobalPose(* s); std::cout << "x(" << step + 1 << ") = " << np.p.x << "; " << std::endl; std::cout << "y(" << step + 1 << ") = " << np.p.y << "; " << std::endl; std::cout << "z(" << step + 1 << ") = " << np.p.z << "; " << std::endl; } void releasePhysX() { PxCloseExtensions(); mScene->release(); mSDK->release(); }
Une fois compil, il suffit d'excuter ce code comme ceci pour en rcuprer les donnes :
physx.exe > data
Dans MATLAB, une fois toutes les instructions de data excutes, on peut lancer l'affichage du graphe :
plot3(x,y,z) xlabel('X') ylabel('Y') zlabel('Z') grid on
- 21 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
VIII - Redistribution
Depuis PhysX 2.8.4, il n'est plus ncessaire que le client installe un SystemSoftware pour le support de PhysX. Il est donc ncessaire de distribuer les bonnes DLL (sous Windows) avec l'application pour qu'elle puisse s'excuter sans encombre. Dans la suite, * remplacera x86 ou x64, en fonction de la plateforme vise (32 ou 64 bits). Trois DLL au plus seront ncessaires : PhysX3_*.dll, toujours requise, elle contient le cur du moteur ; PhysX3Cooking_*.dll, uniquement en cas d'utilisation du module de cooking (prparation des meshes avant utilisation) ; PhysX3GPU_*.dll, uniquement si l'application est prvue pour lancer des simulations sur le GPU.
IX - Conclusions
L'utilisation de PhysX semble naturelle tout qui connat au moins un peu les principes physiques et gomtriques sous-jacents. Merci Alexandre Laurent pour ses commentaires lors de la rdaction ! Merci Claude Leloup et Mahefasoa pour leur relecture orthographique !
- 22 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/
Premiers pas avec PhysX 3.1 par Thibaut Cuvelier (site Web) (Blog)
1 : Certains font remarquer que, malgr la grande qualit du SDK, sa distribution est mdiocre : notamment, une documentation pas entirement mise jour, les difficults d'intgration Visual Studio 2010, des exemples sans fichier de projet. 2 : Pour rappel, les indices en MATLAB commencent 1, non 0, ce qui oblige faire un step + 1 dans l'affichage.
- 23 Copyright 2011 - Thibaut Cuvelier. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://tcuvelier.developpez.com/tutoriels/jeux/physx/3.1/premiers-pas/