|
Création du message
|
21-11-2010 10:04:49
|
Gehogor
|
"Re"-effectivement, je partage complètement l'avis de nabouill et Magnum. Cependant je me mets à ta place et je me dis que ce n'est pas évident de faire son wrapper tout seul. Et bien je te rassure, en fait, ça se fait très bien. J'en ai fait un entre Irrlicht et Newton 2.0 pour toute collision avec tous les paramètres physiques que le moteur physique met à disposition (par contre pas de ragdoll mais l'esprit est très clairement le même, désolé...) et c'est pas mal. Bon, tout n'est pas fonctionnel dans Newton 2.0, il faut laisser du temps mais ça le fait quand même. Ce n'est pas très bien documenté mais il y a des exemples. Pour finir, avoir un code qui distingue bien la partie physique de la partie graphique et bien plus propre à mon sens. En cas de gros bug "mystique venant de l'espace" c'est plus facile d'arrêter un des deux moteurs pour le corriger, enfin bon ... Je ne sais pas si ça peut t'aider, mais ci-dessous je te transmets trois méthodes qui utilisent Newton. Elles transforment un objet "GrPhysics3D" en objet "Newton" ou plutôt "NewtonBody". L'objet "GrPhysics3D" est un objet perso, tu peux utiliser le tien évidemment. Normalement il y a des commentaires pour suivre le déroulement, j'espère que ça pourra t'aider un peu, on ne sais jamais. Les méthodes a priori peuvent faire peur mais en fait non, si tu suis le déroulement, ça devrait le faire, ... Fonction d'initialisation: Code c++ :GrNewton::initialisation()
{
m_nWorld = NewtonCreate(); // Création du monde de Newton
float min[3];
float max[3];
min[0] = -50.0; // -x dans le vrai monde
min[1] = -2.0; // -z dans le vrai monde
min[2] = -50.0; // -y dans le vrai monde
max[0] = 50.0; // x dans le vrai monde
max[1] = 50.0; // z dans le vrai monde
max[2] = 50.0; // y dans le vrai monde
NewtonSetWorldSize(m_nWorld, min, max );
int materialID = NewtonMaterialGetDefaultGroupID(m_nWorld); // Récupération de la matière par défaut du monde "Newton"
NewtonMaterialSetDefaultFriction(m_nWorld, materialID, materialID, 0.8f, 0.4f); // Configuration de la friction de la matière par défaut
NewtonMaterialSetDefaultElasticity(m_nWorld, materialID, materialID, 0.8f); // Configuration de l'élasticité de la matière par défaut
NewtonMaterialSetDefaultSoftness(m_nWorld, materialID, materialID, 0.05f); // Configuration de la douceur de la matière par défaut
NewtonMaterialSetSurfaceThickness(m_nWorld, materialID, materialID,0.0f); // Ici, je ne sais pas trop... A voir !
// Association d'une méthode type "Callback" (ici: "ContactsProcess") à la matière par défaut, cette méthode est appellée par le moteur Newton
// lorsqu'il y a une collision entre de objet possédant cette même matière.
NewtonMaterialSetCollisionCallback(m_nWorld, materialID, materialID, NULL, OnAABBOverlap, ContactsProcess);
m_physicsActive = true; // Permission du thread de tourné
start(); // Lancement du thread
}
Transformation d'un objet "physics3D" en objet "Newton": Code c++ :QString GrNewton::p_loadPhysics3D(GrPhysics3D* physics3D)
{
if(physics3D->collisionType() == GrPhysics3D::NO_COLLISION) // Si l'objet "physics3D" autorise les collisions
return QObject::trUtf8("Objet [%1] -- partie physique [%2]: Mode de collision désactivé.\
").arg(physics3D->root()->name()).arg(physics3D->name());
QString tmpInfo = QObject::trUtf8("Objet [%1] -- partie physique [%2]: Mise à jour de la partie physique.\
").arg(physics3D->root()->name()).arg(physics3D->name());
NewtonCollision* listCollision[NB_MAX_PRIMITIVE]; // Déclaration d'un tableau de pointeur d'objet collision Newton
int materialID = NewtonMaterialGetDefaultGroupID(m_nWorld); // Récupération de l'identifiant de la matière par défaut du monde de Newton
QString material = physics3D->parameter("Material").toString(); // Récupération de l'identifiant de la matière de l'objet "physics3d" concerné
if(!material.isEmpty())
materialID = m_physicsMaterial->materialID(material); // On note le bon identifiant
int nbForm = 0;
for(int i=0;i<physics3D->childSize();i++) // Parcours de tous les enfants de l'objet "physics3D" pour les transformer en "forme primitive"
{
GrPrimitive3D* primitive3D = dynamic_cast<GrPrimitive3D*>(physics3D->child(i));
if(primitive3D != NULL)
tmpInfo += p_loadPrimitive3DRecursif(primitive3D,listCollision,materialID,nbForm); // Méthode de tranformtion ou "mini wrapper"
}
if(nbForm == 0)
return tmpInfo + QObject::trUtf8("Aucune forme primitive de créée.\
");
else
tmpInfo += QObject::trUtf8("Nombre total de primitives: %1.\
").arg(nbForm);
NewtonCollision* newColGroup = NewtonCreateCompoundCollision(m_nWorld,nbForm,listCollision,materialID); // Fusion des primitives de collision en une seule, maillage purement convex
NewtonBody* newBody = NewtonCreateBody(m_nWorld,newColGroup); // Création d'un "NewtonBody" // Création du corps Newton associé à son maillage de collision
//---------------------------------- Récupération du maillage --------------------------------// Partie en developpement, peut être non fonctionnel dans Newton 2.0 ?? Car buger ??
NewtonMesh* nMesh = NewtonMeshCreateFromCollision(newColGroup);
int faceCount = NewtonMeshGetTotalFaceCount(nMesh);
int indexCount = NewtonMeshGetTotalIndexCount(nMesh);
tmpInfo += QObject::trUtf8("Nombre total de face: %1 et d'index %2.\
").arg(faceCount).arg(indexCount);
/*int vertexStrideInByte,normalStrideInByte,uvStrideInByte0,uvStrideInByte1; // TODO_G: PAS FONCTIONNEL DANS NEWTON OU AUTRE CHOSE, A VOIR!
dFloat *vertex,*normal,*uv0,*uv1;
NewtonMeshGetVertexStreams(nMesh,vertexStrideInByte,vertex,normalStrideInByte,normal,uvStrideInByte0,uv0,uvStrideInByte1,uv1);
for(int i=0;i<vertexStrideInByte;i=i+3)
{
vertex[i];
vertex[i+1];
vertex[i+2];
}*/
NewtonMeshDestroy(nMesh);
//--------------------------------------------------------------------------------------------//
float mPos[16];
MMatrixToNewtonMatrix(mPos,physics3D->absolutePosition()); // Récupération du la position absolue de notre objet "physics3D"
NewtonBodySetMatrix(newBody,mPos); // On transmet cette position au corps rigide pour newton
NewtonBodySetMaterialGroupID(newBody,materialID); // On indique à Newton de quelle matière il est fait
NewtonBodySetUserData(newBody,physics3D); // Stockage de "GrPhysics3D*" pour son utilisation dans les méthode "CallBack"
physics3D->setUserData(0,reinterpret_cast<void*>(newBody)); // Stockage de "NewtonBody*" afin de pouvoir le réutiliser dans le "run()"
float inertia[3],origin[3];
if(physics3D->parameter("AutoInertialAndMass").toBool()) // Calcul automatique de l'inertie de Newton en fonction des formes de collisions
{
NewtonConvexCollisionCalculateInertialMatrix(newColGroup,inertia,origin);
physics3D->setParameter("Ix",inertia[0]); // On indique à l'objet "physics3D" son inertie
physics3D->setParameter("Iy",inertia[2]);
physics3D->setParameter("Iz",inertia[1]);
physics3D->setParameter("CenterMass_X",origin[0]); // On indique à l'objet "physics3D" son centre de masse
physics3D->setParameter("CenterMass_Y",origin[2]);
physics3D->setParameter("CenterMass_Z",origin[1]);
}
float mass = physics3D->parameter("Mass").toFloat();
NewtonBodySetMassMatrix(newBody,mass, // Configuration de la masse et inertie de notre objet Newton
physics3D->parameter("Ix").toFloat()*mass,
physics3D->parameter("Iy").toFloat()*mass,
physics3D->parameter("Iz").toFloat()*mass);
origin[0] = physics3D->parameter("CenterMass_X").toFloat();
origin[2] = physics3D->parameter("CenterMass_Y").toFloat();
origin[1] = physics3D->parameter("CenterMass_Z").toFloat();
NewtonBodySetCentreOfMass(newBody,origin); // Configuration du centre de masse et inertie de notre objet Newton
NewtonBodySetLinearDamping(newBody,physics3D->parameter("LinearDamping").toFloat()); // Configuration de l'amortissement linéaire de notre objet Newton
float angularDamping[3];
angularDamping[0] = physics3D->parameter("AngularDamping_Rx").toFloat();
angularDamping[1] = physics3D->parameter("AngularDamping_Ry").toFloat();
angularDamping[2] = physics3D->parameter("AngularDamping_Rz").toFloat();
NewtonBodySetAngularDamping(newBody,angularDamping); // Configuration de l'amortissement rotoïde de notre objet Newton
NewtonBodySetFreezeState(newBody,0);
NewtonBodySetAutoSleep(newBody,0);
// Association d'une "Callback" (ici:SetMeshTransformMesh) à l'objet Newton,
// elle sera appellée lorsque l'objet bougera selon le moteur Newton (il y a bcp d'exemple là dessus)
NewtonBodySetTransformCallback(newBody,SetMeshTransformMesh);
// Association d'une "Callback" (ici:ApplyForceAndTorqueEvent) à l'objet Newton,
// elle sera appellée lorsque l'objet devra subir une force (il y a bcp d'exemple là dessus)
NewtonBodySetForceAndTorqueCallback(newBody,ApplyForceAndTorqueEvent);
float pt0[3],pt1[3];
NewtonBodyGetAABB(newBody,pt0,pt1); // Calcul de l'enveloppe totale de l'objet Newton pour information
tmpInfo += QObject::trUtf8("Dimensions externes: %1 %2 %3.\
").arg(pt1[0]-pt0[0]).arg(pt1[1]-pt0[1]).arg(pt1[2]-pt0[2]);
for(int i=0;i<nbForm;i++) // Désallocation de la mémoire des primitives de collision
NewtonReleaseCollision(m_nWorld,listCollision[i]);
NewtonReleaseCollision(m_nWorld,newColGroup); // Désallocation de la mémoire de la primitive groupe de collision
return tmpInfo; // On retourne les informations de la méthodes
}
Fonction intermédiaire appellée dans "p_loadPhysics3D": Code c++ :QString GrNewton::p_loadPrimitive3DRecursif(GrPrimitive3D* primitive3D,NewtonCollision* listCollision[],int materialID,int& internalCounter)
{
QString tmpInfo;
float mPos[16];
float paramA = primitive3D->parameter("ScaleX").toFloat();
float paramB = primitive3D->parameter("ScaleY").toFloat();
float paramC = primitive3D->parameter("ScaleZ").toFloat();
// On récupère la position de la forme primitive du volume de collision par rapport à l'objet lui-même
MMatrixToNewtonMatrix(mPos,primitive3D->relativePosition());
NewtonCollision* newCol = NULL;
switch(primitive3D->primitiveForm())
{
case GrPrimitive3D::SPHERE:
newCol = NewtonCreateSphere(m_nWorld,paramA/2.0,paramC/2.0,paramB/2.0,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme SPHERE.");
break;
case GrPrimitive3D::BOX:
newCol = NewtonCreateBox(m_nWorld,paramA,paramC,paramB,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme BOX.");
break;
case GrPrimitive3D::CAPSULE:
newCol = NewtonCreateCapsule(m_nWorld,paramA/2.0,paramB*2.0,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme CAPSULE.");
break;
case GrPrimitive3D::CYLINDER:
newCol = NewtonCreateCylinder(m_nWorld,paramA/2.0,paramB,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme CYLINDER.");
break;
case GrPrimitive3D::CONE:
newCol = NewtonCreateCone(m_nWorld,paramA/2.0,paramB,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme CONE.");
break;
case GrPrimitive3D::CHAMFER_CYLINDER:
newCol = NewtonCreateChamferCylinder(m_nWorld,paramA/2.0,paramB,materialID,mPos);
tmpInfo = QObject::trUtf8("La primitive est de forme CHAMFER_CYLINDER.");
break;
case GrPrimitive3D::USER_PRIMITIVE:
irr::scene::IMesh* mesh = reinterpret_cast<irr::scene::IMesh*>(primitive3D->userData(3));
if(mesh != NULL)
{
float tolerance = primitive3D->parameter("MeshTolerance").toFloat();
if(mesh != NULL)
newCol = p_createCollisionFromMesh(m_nWorld,mesh,tolerance,paramA,paramB,paramC,materialID,mPos);
}
tmpInfo = QObject::trUtf8("La primitive est de forme USER_PRIMITIVE.");
break;
}
for(int i=0;i<primitive3D->childSize();i++) // Fonction récursive qui rappelle tous les enfant pour récupérer toutes les primitives
{
GrPrimitive3D* child = dynamic_cast<GrPrimitive3D*>(primitive3D->child(i));
if(child != NULL)
tmpInfo += p_loadPrimitive3DRecursif(child,listCollision,materialID,internalCounter);
}
if(newCol != NULL){
if(internalCounter<NB_MAX_PRIMITIVE){ // On limite le nombre de collision primitive total pour "UN" objet Newton
listCollision[internalCounter] = newCol;
internalCounter++;}
tmpInfo += QObject::trUtf8(" Création de la primitive réussie.\
");
}
return tmpInfo;
}
|