RaydiumWikiNi

TutorielUtiliserLaPhysique

PagePrincipale :: DerniersChangements :: ParametresUtilisateur :: Vous êtes ec2-18-191-189-119.us-east-2.compute.amazonaws.com
Ceci est une version archivée de TutorielUtiliserLaPhysique à 2006-11-26 21:41:34.

Écriture d'une application avec gestion de la physique


Ref: RaydiumTutoriels


Tutoriel3

Mise en place:



Notion de moteur physique:


Lors du développement d'un jeu vidéo, il arrive rapidement un moment où la facon de déplacer les différents objets dans la scène se pose. Pour reprendre l'exemple du tutoriel précédent (TutorielDeplacerDesObjets), nous avons été capables de déplacer la voiture dans la scène, mais sans grand réalisme: accélérations instannées, possibilités de tourner dans toute situation, pas de collisions possibles (que ce soit avec un mur ou un autre objet ou joueur), ...

Bien sur, il serait possible de programmer ces comportements, mais c'est une tâche terriblement ardue, et il est très dur d'obtenir un résultat réaliste.

Grace à une intégration d'ODE, Raydium offre la possibilité au programmeur de l'application d'obtenir des applications "physiquement réalistes": Il suffit de déclarer quelques propriétés pour les différents objets de la scène (masse / poids, taille, ...), pour que leurs déplacements soient automatiquements calculés.

Vocabulaire:


Raydium utilise la notion d' élément. Les différents éléments sont rassemblés au sein d'entités plus larges que sont les objets. Il est possible de relier les différents éléments entre eux grâce à des joints.

Objets:


Les objets sont des containeurs pour les éléments. "voiture" est par exemple un objet composé de différents éléments tels que les roues, le chassis, ...

Créer un objet est une opération très simple:

int raydium_ode_object_create(char *name);


Cette fonction créé un objet (et stocke son nom), et retourne un identifiant vers cet objet, qui n'est qu'optionnel. Il sera ensuite possible de rajouter des éléments à cet objet, grace à son nom ou son identifiant. Détruire un objet détruit aussi tout les éléments qui le compose.

Eléments:


Les éléments sont la base de la représentation visuelle de la physique: ce sont eux qui sont déplacés et affichés. En conséquence, la création d'un élément demande plus d'informations que celle d'un objet:

int raydium_ode_object_sphere_add(char *name, int group, dReal mass,
dReal radius, char type, int tag, char *mesh);
 
int raydium_ode_object_box_add(char *name, int group, dReal mass,
dReal tx, dReal ty, dReal tz, char type, int tag, char *mesh);



Il est bien sur possible d'effacer un élément à n'importe quel moment, ainsi que de le déplacer, de le pousser, et de régler beaucoup de paramètres plus ou moins avancés: friction, "type de matériau", viscosité, ...

Joints:


Les joints permettre de créer différents type de liaisons entre les éléments de la scène: attacher un bras à un torse, une roue au chassis, etc...
Raydium supporte différentes liaisons: rotule, charnière, suspension+arbre, et la construction de ces liens est spécifique à leur type: on ne construit pas un ensemble suspension + arbre de rotation de roue de la même manière qu'une charnière. Voici un exemple de fonction de construction de joint (type charnière ici):

int raydium_ode_joint_attach_hinge_name(char *name, char *elem1, char *elem2,
 dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z);


Cette version utilise les noms des éléments à attacher (elem1 et elem2), et non leurs identifiants. Les arguments suivants définissent le point (x,y,z) d'attache, et l'axe (x,y,z) de la charnière.

De manière générale, il est possible de préciser une force maximum au delà de laquelle le joint cède.

Agir sur la scène:


Moteurs:


Raydium permet la création de moteurs (au sens large) pour agir sur la scène


L'exemple de programme présent plus bas montre l'utilisation de plusieurs types de moteurs.

Forces:


Raydium dispose d'un certain nombre de fonction pour simuler différentes forces (pression de l'eau, vent, gravité déformée, ...). L'utilisation de ces fonction permet de répondre à des besoins avancés, qui ne sont solubles avec les autres outils cités plus haut.

Explosions:


Il existe deux types d'explosions, qui répondent à des besoins différents:


Mise en oeuvre: construction d'une voiture:


create_car(), avec commentaires :


void create_car(void)
{


Pour commencer, déclarons une variable entière, qui contiendra l'identifiant de l'objet "voiture" que nous allons créer.

int a;


Ces quelques constantes déterminent respectivement la force maximum au delà de laquelle les essieux céderont, la "friction à l'air" des roues, et les paramètres des suspensions.

#define BREAK_FORCE     130
#define ROTFRICTION     0.0005
#define ERP_CFM         0.3,0.8 
 


Ensuite, on efface un éventuel objet qui porte déjà le nom "WATURE" (cette fonction va en général générer une erreur non fatale). Il ne reste plus ensuite qu'a créer notre objet "WATURE", et a affecter le retour de la fonction à la variable "a".

raydium_ode_object_delete_name("WATURE");
 
a=raydium_ode_object_create("WATURE");


L'objet est créé, il est maintenant possible d'y ajouter les différents éléments qui vont le composer: une boite (corps de la voiture) et 4 sphères (roues). Chacune des roues se verra attachée au corps par un "hinge2". Le hinge2 est une liaison "suspension" qui offre 2 axes de rotation : l'un pour tourner la roue à droite ou à gauche (axe 0), et l'autre pour permettre à la roue de tourner autour de l'essieu (axe 1), ajouté à un degré de liberté en translation le long du premier axe, qui va jouer le rôle de suspension. Même si l'expliquation peut sembler complexe, c'est une opération simple, encapsulée dans un seul appel de fonction.

Dans un premier temps, il faut donc créer la boite "corps" : (ne tenez pas compte de l'instruction suivante)

raydium_ode_object_box_add("corps",a,1,1.2,0.6,0.4,RAYDIUM_ODE_STANDARD,0,"clio.tri");
raydium_ode_element_slip_name("corps",RAYDIUM_ODE_SLIP_ICE);

Ensuite, il est possible de créer une première roue (avant gauche) :

raydium_ode_object_sphere_add("pneu_ag",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_ag",ROTFRICTION);

... et de la placer correctement par rapport à la caisse, qui est centrée en 0,0,0 :

raydium_ode_element_move_name_3f("pneu_ag",0.42,0.253,-0.180);

Il ne reste plus qu'a construire et pramètrer la suspension "hinge2" :

raydium_ode_joint_attach_hinge2_name("suspet_ag","corps","pneu_ag",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_break_force_name("suspet_ag",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_ag",ERP_CFM);

Il reste à répéter l'opération pour les 3 autres roues :

raydium_ode_object_sphere_add("pneu_ad",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_ad",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_ad",0.42,-0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_ad","corps","pneu_ad",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_break_force_name("suspet_ad",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_ad",ERP_CFM);
 
raydium_ode_object_sphere_add("pneu_rg",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_rg",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_rg",-0.444,0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_rg","corps","pneu_rg",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_hinge2_block_name("suspet_rg",1);
raydium_ode_joint_break_force_name("suspet_rg",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_rg",ERP_CFM);
 
raydium_ode_object_sphere_add("pneu_rd",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_rd",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_rd",-0.444,-0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_rd","corps","pneu_rd",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_hinge2_block_name("suspet_rd",1);
raydium_ode_joint_break_force_name("suspet_rd",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_rd",ERP_CFM);

... et la voiture est construite ! Pour pouvoir conduire cette voiture, nous allons mettre en place 2 entités de contrôle: l'une pour permettre à la voiture d'avancer, et la seconde pour la diriger :

Moteur de la voiture (relié à l'axe 1 des deux liaisons avant) :

raydium_ode_motor_create("moteur",a,RAYDIUM_ODE_MOTOR_ENGINE);
raydium_ode_motor_attach_name("moteur","suspet_ag",1);
raydium_ode_motor_attach_name("moteur","suspet_ad",1);
raydium_ode_motor_power_max_name("moteur",0.2);

"Volant", reliè à l'axe 0 de ces même liaisons :

raydium_ode_motor_create("direction",a,RAYDIUM_ODE_MOTOR_ANGULAR);
raydium_ode_motor_attach_name("direction","suspet_ag",0);
raydium_ode_motor_attach_name("direction","suspet_ad",0);
raydium_ode_motor_power_max_name("direction",0.2);

La force maximum de ces moteurs est fixée à 0.2 unités, valeur déterminée après différents tests de conduite. La voiture est maintenant prête à rouler, nous avons juste à donner des ordres aux 2 moteurs et à placer la caméra au bon endroit à l'intérieur pour vivre de grands frissons ;)

code source complet : (les parties importantes sont données en gras)


#include "raydium/index.c"
 
GLfloat sun[]={1.0,0.9,0.5,1.0};
 
void create_car(void)
{
int a;
 
#define BREAK_FORCE     130
#define ROTFRICTION     0.0005
#define ERP_CFM         0.3,0.8
 
raydium_ode_object_delete_name("WATURE");
 
a=raydium_ode_object_create("WATURE");
raydium_ode_object_box_add("corps",a,1,1.2,0.6,0.4,RAYDIUM_ODE_STANDARD,0,"clio.tri");
raydium_ode_element_slip_name("corps",RAYDIUM_ODE_SLIP_ICE);
 
raydium_ode_object_sphere_add("pneu_ag",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_ag",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_ag",0.42,0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_ag","corps","pneu_ag",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_break_force_name("suspet_ag",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_ag",ERP_CFM);
raydium_ode_object_sphere_add("pneu_ad",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_ad",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_ad",0.42,-0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_ad","corps","pneu_ad",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_break_force_name("suspet_ad",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_ad",ERP_CFM);
raydium_ode_object_sphere_add("pneu_rg",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_rg",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_rg",-0.444,0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_rg","corps","pneu_rg",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_hinge2_block_name("suspet_rg",1);
raydium_ode_joint_break_force_name("suspet_rg",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_rg",ERP_CFM);
 
raydium_ode_object_sphere_add("pneu_rd",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"roue5.tri");
raydium_ode_element_rotfriction_name("pneu_rd",ROTFRICTION);
raydium_ode_element_move_name_3f("pneu_rd",-0.444,-0.253,-0.180);
raydium_ode_joint_attach_hinge2_name("suspet_rd","corps","pneu_rd",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
raydium_ode_joint_hinge2_block_name("suspet_rd",1);
raydium_ode_joint_break_force_name("suspet_rd",BREAK_FORCE);
raydium_ode_joint_suspension_name("suspet_rd",ERP_CFM);
 
raydium_ode_motor_create("moteur",a,RAYDIUM_ODE_MOTOR_ENGINE);
raydium_ode_motor_attach_name("moteur","suspet_ag",1);
raydium_ode_motor_attach_name("moteur","suspet_ad",1);
raydium_ode_motor_power_max_name("moteur",0.2);
 
raydium_ode_motor_create("direction",a,RAYDIUM_ODE_MOTOR_ANGULAR);
raydium_ode_motor_attach_name("direction","suspet_ag",0);
raydium_ode_motor_attach_name("direction","suspet_ad",0);
raydium_ode_motor_power_max_name("direction",0.2);
}
 
void display(void)
{
float speed,direct;
 
raydium_joy_key_emul();
 
direct=raydium_joy_x*0.3;
speed=raydium_joy_y*55;
 
raydium_ode_motor_speed_name("moteur",-speed);
raydium_ode_motor_angle_name("direction",direct);
 
if(raydium_key_last==1027) exit(0);
 
raydium_clear_frame();
raydium_ode_element_camera_inboard_name("corps",0.2,0,0.1,2,0,0);
 
raydium_ode_draw_all(0);
if(raydium_key[GLUT_KEY_F1]) raydium_ode_draw_all(1);
 
raydium_rendering_finish();
}
 
int main(int argc, char **argv)
{
raydium_init_args(argc,argv);
raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Physics test");
raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_TRILINEAR);
raydium_projection_near=0.01;
raydium_projection_far=1000;
raydium_projection_fov=60;
raydium_window_view_update();
raydium_light_on(0);
memcpy(raydium_light_color[0],sun,raydium_internal_size_vector_float_4);
raydium_light_intensity[0]=1000000;
 
raydium_light_position[0][0]=50;
raydium_light_position[0][1]=150;
raydium_light_position[0][2]=200;
 
raydium_light_update_all(0);
raydium_background_color_change(sun[0],sun[1],sun[2],sun[3]);
raydium_fog_disable();
 
raydium_ode_ground_set_name("cocorobix.tri");
create_car();
 
raydium_callback(&display);
 
return 0;
}


Ce tutoriel ne montre qu'une toute petite partie de ce qu'il est possible de faire avec RayODE. Vous pouvez tenter de rajouter une boite de vitesses, des explosions, d'autres vues, un joueur extérieur à la voiture, etc. N'hésitez pas à consulter la documentation, et surtout les applications Raydium telles que "test6.c". Un autre tutoriel dédié à l'aspect réseau est disponible, et un autre s'intéresse a la gestion du son (avec RayODE en particulier).



Tutoriel 4: TutorielUtiliserPhp