Etude et intégration d'un système multi-utilisateurs dans la simulation comportementale



par Frédéric OURGAUD








Directeur de recherche : Pr Yves DUTHEN DEA en INFORMATIQUE : IHS2M

Responsable de stage : Mr Richard MOULI Laboratoire : IRIT/Toulouse


UNIVERSITE PAUL SABATIER & INPT Année 93/94

DEA en INFORMATIQUE : IHS2M

Intéraction Homme Système MultiModale

Responsable : R. CAUBET, Professeur


Laboratoire : IRIT




Etude et intégration d'un système multi-utilisateurs dans la simulation comportementale





par Frédéric OURGAUD





Directeur de recherche : Pr Yves DUTHEN

Responsable de stage : Mr Richard MOULI






Mots clés : simulation comportementale, images de synthèse, réalité virtuelle


Résumé : L'intégration d'utilisateurs dans une simulation comportementale leur permet d'avoir un rôle d'acteur. Ce rapport traite de cette mise en oeuvre sous la forme du clone de l'opérateur ; de plus, certaines extensions sont proposées (séquenceur temporel) afin de facilité l'écriture de comportements.


Abstract : Users' interaction in behavioural simulation gives them an actor's rôle. This document describes a design and implementation of an operator's clone concept. Some extensions are also proposed ("temporal sequencer") in order to write behaviours more easily.











Je tiens à remercier :


le professeur Jean Vignole pour m'avoir accueilli dans son laboratoire,


le professeur René Caubet pour m'avoir accueilli dans son équipe,


le professeur Yves Duthen pour le sujet qu'il m'a permis de traiter,


Richard Mouli pour m'avoir initié à in VITRAM et à la GLOO,


Frédéric Rubbio et Laurent Zuniga pour tous leurs conseils,

Nilo pour son enthousiasme,


Thierry, Jérome, Laurent et le reste de l'équipe, pour leur sympathie,


Et enfin Martine, pour m'avoir pardonné les quelques nuits et week-ends passés à l'IRIT.




SOMMAIRE




Introduction 2

I- Introduction 2

1- Cadre du projet 2

2- In VITRAM 3

2.1- Les animats 5

2.2- Algorithme de in VITRAM 6

2.3- Comportement des intelligents 7


Le clone de l'opérateur 9

II- Etudes préliminaires 9

1- Le clone 9

2- Comportement du clone 11

3- Liaison clients-serveur 12

4- Animat générique 13

5- Clone générique 13

5.1- Le débit réseau 14

5.2- Les capteurs/effecteurs 14

6- Les mondes 15

III- Système de transfert d'objets 17

1- Discussion 17

2- Autre technique de transmission 19

3- Notre choix 19

3.1- Problème de polymorphisme 20

3.2- Récursivité 20

4- Limite et extensions 21

IV- Le clone 22

1- Informations externes 22

1.1- Analyse 22

1.2- Ajout de variables 23

1.3- Intégration dans les bases de règles 24

2- Capteurs particuliers 26

3- Le squelette 27

4- Les déformations 28

V- Gestion client-serveur 29

1- Le client 29

1.1- Construction du clone 29

1.2- Distribution des périphériques 31

1.3- Algorithme du processus client 34

2- Processus fils 35

2.1- Analyse des arguments 35

2.2- Boucle de traitement 35

2.3- Un exemple 36

3- Le serveur 37

3.1- Introduction 37

3.2- Changement de monde 37

4- Protocole client-serveur 39

4.1- Introduction de personnages 39

4.2- Connexion privée 39


Extensions 40

VI- Séquenceur temporel 40

1- Recherche de solutions 41

2- Séquenceur temporel 42

3- Analyse du séquenceur 44

3.1- Arbre d'exécution 44

3.2- Correspondance avec le Grafcet 45

3.3- Comparaison de comportements 46

3.4- Utilisation de la récursivité 47

3.5- Mise en oeuvre 48

VII- Macro-animats 49

1- Les buts 50

2- Communication 52

3- Etudes des liaisons 53


Conclusion et perspectives 55


Exemples 56

Les robots bâtisseurs 56

La course à pied 61

Bibliographie 64










PREAMBULE




Ce mémoire est organisé en quatre parties. La première a pour but de présenter le cadre de ce DEA et de se familiariser avec in VITRAM.

La suivante constitue le premier but du DEA, c'est à dire l'étude et l'intégration des utilisateurs. Elle débute par une première approche, que l'on peut aussi qualifier de vue d'ensemble.

La troisième présente les extensions réalisées au cours de ce DEA afin d'améliorer la description des comportements, ce qui pourra se traduire par des animations de plus grande qualité.

Enfin, la dernière partie regroupe quelques exemples.




Partie 1





Introduction et cadre du projet




i- INTRODUCTION



1. En 1987, l'équipe images de synthèse de l'IRIT commença l'étude d'un nouveau projet : VOXAR (VOXel ARchitecture). Il s'agissait de concevoir et réaliser une machine parallèle dédiée aux calculs d'images de synthèse [DUTHEN 87], [CAUBET 88], [PITOT 91]. Son architecture est basée sur l'association entre l'espace, découpé en cubes (voxels), et les processeurs (transputers) connectés par un réseau hypertore. Aujourd'hui, VOXAR offre des performances appréciables et des travaux sont sans cesse en cours afin d'améliorer la qualité des images.


Parallèlement, in VITRAM [DUTHEN 93] a été développé dans le but de générer des animations qui seront visualisées sur VOXAR. Le choix de la méthode de calcul des trajectoires est alors décisive car elle détermine, entre autres, la qualité des animations et la souplesse de création.


Contexte des travaux


Pour réaliser des animations, une première méthode est l'interpolation de positions clés; néanmoins, son utilisation nécessite un animateur professionnel [BERGERON 85]. Une autre est liée à l'utilisation d'acteurs procéduraux [MAGNENAT 87].

Certaines de ces approches fournissent une aide "bas niveau" telle que la cinématique inverse [KOREIN 82], la satisfaction automatique de contraintes [REYNOLDS 87], la simulation physique [ISAACS 87], la détection de collision [HAHN 88].

Le problème du contrôle des déplacements de "haut niveau" a aussi été abordé. Les systèmes de contrôle hiérarchique sont une des principales approches [ZELTZER 82] [CHADWICK 89] qui concernent essentiellement le déplacement des corps articulés et le contrôle du comportement ou de la réponse aux stimuli [REYNOLDS 87] [WILHELMS 87b].

Certaines approches récentes se basent sur des principes de neurobiologie [RANDALL 91] pour implémenter un contrôle souple d'agents autonomes. L'approche Intelligence Artificielle Multi-Agents [FERBER 88] tend à placer au sein des acteurs animés de plus en plus d'intelligence, sous forme de raisonnement, raisonnement et apprentissage [PIERCE 91], apprentissage complet par algorithmes génétiques [KOZA 91].



L'approche retenue dans in VITRAM (in VITRo AniMats) est la simulation comportementale [REYNOLDS 87]. Elle consiste à créer un monde virtuel, dans lequel on introduit un ensemble d'objets et de personnages modélisés, dotés d'un comportement : les animats.

Enfin, il est intéressant que des utilisateurs, par l'intermédiaire d'interfaces issues de la réalité virtuelle, puissent participer à la simulation sous forme de clones. C'est le thème de ce DEA.


2. In VITRAM


Ce projet permet, dès à présent, de réaliser des simulations comportementales à travers les animats. Ceux-ci sont caractérisés par un corps (obtenu par un modeleur) et des données physiques (masse, ...). Certains sont munis de capteurs et d'un comportement qui peut être décrit dans un langage de type PROLOG (fig. 1.4).

In VITRAM réalise les simulations pas à pas. Un "top" représente un instant donné et, entre deux top consécutifs, il s'écoule un laps de temps invariable que l'on appelle le pas de la simulation. A chaque pas, tous les comportements des personnages sont exécutés, ce qui permet leur évolution et par là même, celle de l'animation.


Les figures 1.1 et 1.2 représentent des simulations que nous aimerions obtenir.




In VITRAM a été réalisé en langage objet EIFFEIL [MEYER 86] sur station Silicon Graphics 4D/35. Cette dernière assure une vitesse minimale d'exécution de la simulation, tout en permettant une visualisation 3D de grande qualité.

Le choix d'un langage objet permet, entre autres, une certaine souplesse de conception et d'extension. De plus, nous avons établi une hiérarchie des objets. La composition et le lien dynamique facilitent donc la mise en oeuvre du projet. Par exemple, considérons les capteurs des personnages; leurs liens peuvent se schématiser de la façon suivante :



On peut noter des arborescences similaires dans le moteur d'inférence PROLOG, dans les personnages, ...

Enfin, l'intérêt particulier d'EIFFEL est la possibilité de donner des pré-conditions aux paramètres des méthodes, ainsi que des post-conditions permettant la vérification de leur bon fonctionnement (programmation par contrat). Il est également possible de déclarer des invariants de boucles et de classes d'objets. Ceci permet une mise au point rapide.


2.1 - Les animats


Ils ont été repartis en trois catégories [MOULI 91], reliées par des liens d'héritage, afin de mieux correspondre à la réalité d'une part, et de mieux gérer les ressources informatiques (puissance, ...) d'autre part.


* Acomportementaux

Ils ne font que subir l'environnement. Ils permettent de modéliser les objets inertes, par exemple une table ou une carafe.


* Réflexes

Ils sont de conception généralement très simple : lampe, sonnette... Mais, comme leur "comportement" est codé dans le système (décrit par une méthode au sens EIFFEL), on peut les utiliser pour développer des personnages qui, soit nécessiteraient trop de calculs s'ils étaient de type intelligents, soit n'auraient pas besoin de la puissance de PROLOG. Ces personnages peuvent posséder divers capteurs (tels un oeil ou une oreille), ce qui leur permet d'avoir une perception de leur environnement.


* Intelligents

Ce sont les seuls munis d'un comportement régi par le moteur d'inférence de type PROLOG, et donc capables d'actions complexes liées à l'environnement. Tout comme les objets réflexes, les objets intelligents disposent de capteurs.


2.2 - Algorithme de in VITRAM


A chaque pas de simulation, in VITRAM suit l'algorithme suivant pour faire évoluer les personnages :


-- PHASE D'ACQUISITION

Pour tous les personnages

Si le personnage est un personnage réflexe

alors

le personnage scrute et filtre le monde;

le personnage mémorise les informations captées;

sinon

si le personnage est un personnage intelligent

alors

le personnage scrute et filtre le monde;

le personnage mémorise les informations captées;

le personnage produit les faits nécessaires à la réflexion

correspondant aux informations captées;

le personnage détermine par raisonnement les actions à réaliser;

FinSi

FinPour

-- PHASE D'EXECUTION

Pour tous les personnages

Si le personnage est un personnage réflexe

alors

le personnage exécute les actions automatiques (AA);

sinon

si le personnage est un personnage intelligent

alors

le personnage exécute les actions automatiques (AA);

le personnage exécute les actions déduites par le raisonnement (AD);

FinSi

le personnage se déplace (DE);

FinPour


Cet algorithme (schématisé en fig. 1.5) montre que la phase d'acquisition est isolée de celle de réflexion. Ainsi, les capteurs ne peuvent pas connaître les intentions des personnages (qui pourraient être déduites de leurs actions).



2.3 - Comportements des intelligents


Ils sont décrits par un ensemble de règles de type PROLOG appelé base de règles [RAINJONNEAU 92]. Le moteur d'inférence, écrit en EIFFEL afin d'accéder aux champs des objets, va opérer sur ces règles. La résolution débute en posant la question agir.

La base de travail d'un personnage est en fait la concaténation de trois bases. La première, la base d'action, contient l'ensemble des règles agir qui gouvernent les actions (prendre, aller vers, ...). La deuxième comprend des règles secondaires (calculs, ...), et la dernière les faits créés par les capteurs (les objets détectés, ...).


Une règle est définie par une suite de littéraux. Certains sont évaluables, c'est-à-dire qu'ils correspondent à des instructions du PROLOG. Par exemple le littéral imprime affiche chacun de ses arguments dans la sortie standard. Les actions (avancer, prendre, ...) sont aussi évaluables. Les autres littéraux (les non évaluables) doivent être unifiés à des règles. Le premier littéral de ce type utilisé dans l'exécution est agir.

Un littéral peut posséder des arguments; ils sont soit de type variable (leurs noms sont alors préfixés du caractère '*'), soit de type constante (nombre, objet de la simulation, ou chaîne de caractères).


Voici un exemple d'une base d'action ([MOULI 93a]) qui simule l'arrêt d'une voiture à un feu de signalisation (les commentaires sont précédés d'un point virgule) :



agir

- vitesse (Current, *vit) ; "Current" représente l'objet courant

; ici, c'est la voiture. La variable "vit"

; est instanciée par sa vitesse.

- sup (*vit, 0) ; Prédicat évaluable, vrai si "vit > 0"

- pres_feu ; Non évaluable : tête de clause

- freiner (20) . ; On freine de 20%


Un des littéraux évaluables, Récupère, permet de lire certains champs d'un objet (champs constants). Dans l'exemple suivant, une fourmi doit amener les grains qu'elle perçoit au centre de la fourmilière. Récupère est alors utilisé pour récupérer le champ grain d'une fourmi.


agir

- Récupère (Current, Grain, *g) ; Unifié si le grain existe

- CUT ; Ne pas exécuter les autres règles !

- RentrerMaison . ; Rentrer à la fourmilière

agir

- Voit (*g) ; La fourmi dispose d'un capteur 'oeil'

- EstUn (*g, GRAIN) ; Unifié si 'g' est un objet de GRAIN

- Prendre (*g) ; Prendre alors le grain

- CUT . ; Ne pas lire la suite

agir

- Avancer . ; On ne voit rien : on avance


Afin de simplifier l'emploi des bases de règles, des liens de dépendances peuvent être établis. De cette façon, une base est la concaténation de plusieurs autres. Elle est alors appelée "base liée".


Enfin, le lien dynamique du langage à objets peut permettre d'autres approches du comportement. Il est ainsi envisageable d'introduire des personnages intelligents raisonnant par algorithmes génétiques [LUGA 93] [DUMEUR 91] ou encore par réseaux de neurones [RANDALL 91].

Dans ces derniers cas, l'analyse directe du comportement est relativement difficile vu les structures de données utilisées (tableaux de booléens, ...).



Partie 2





Intégration du clone



II-ETUDES PRELIMINAIRES



1. Le clone


La participation des utilisateurs à des simulations comportementales leur permet d'avoir plus un rôle d'acteur que de spectateur. Elle peut être réalisée de diverses façons. Une première méthode consiste à construire une interface Homme - Machine, avec les boutons et menus déroulants classiques, permettant l'ajustement des déplacements, des positions, des comportements... Mais cette approche s'oriente davantage vers la supervision des animations, plutôt que vers la participation des utilisateurs.


Une autre méthode identifie l'utilisateur à un personnage de la simulation qui est alors appelé un clone d'utilisateur. Ses actions (mouvements, ...) sont alors reportées à son personnage qui agit en conséquence. Cette solution permet de garder l'intégrité de la simulation. En effet, l'utilisateur est un individu parmi d'autres du monde dans lequel il est plongé. De plus, il est perçu, par les autres animats de la simulation, par les effets qu'il occasionne au monde. Sa participation est donc limitée seulement par les capacités des animats, à savoir leurs capteurs (ouïe, odorat, ...), et leurs données physiques (masse, force, vitesse, ...).

Les domaines d'application sont variés et recoupent la réalité virtuelle. Par exemple, cette forme de participation est nécessaire à la téléprésence (patient virtuel pour l'entraînement de chirurgiens. Fig 2.1) et à la téléopération. Pour ces dernières applications, l'équipement minimal comprend un ou deux gants sensoriels, et une lunette stéréoscopique. Cependant, dans le cas général, le clone est une simplification de l'utilisateur.

Toutefois, si on ne dispose que de peu de moyens en interfaces de réalité virtuelle, il est toujours possible de recourir aux interfaces classiques de type souris, clavier, et écran auquel on peut ajouter des boutons et menus déroulants permettant de simuler nos mouvements (se diriger vers, saisir cela, ...).


Le clone introduit ci-dessus simule un utilisateur. Mais il peut aussi représenter toute sorte d'objet (une lampe ou un synthétiseur) : on parle alors de clone d'objets. De plus, si chaque animat représente un objet réel d'une pièce, la simulation relève du domaine de la téléopération .

Le clone a parfois une représentation différente de celle de l'utilisateur. Ce dernier peut alors s'insérer parmi des individus dont le comportement lui est totalement inconnu (composé de réseaux de neurones, ...). Eventuellement, en se déplaçant, il analyse comment les personnages réagissent à son attitude. Par ailleurs, si son clone commande un groupe d'animats, l'utilisateur peut diriger l'animation par ses gestes.

Enfin, il est possible que le clone représente un processus tel qu'un traitement de texte, un tableur ou un système d'exploitation. Cela permet de créer de nouvelles interfaces (projet AVIARY [SNOWDON 93] [WEST 92]).




Nous avons choisi, pour les avantages qu'elle procure, d'intégrer la méthode du clone dans in VITRAM; ce choix fut présenté dans [MOULI 93b] et [DUTHEN 93]. De cette façon, à chaque utilisateur ou objet réel ajouté à la simulation, correspond un clone.

A la mise en oeuvre, ce dernier pourrait être défini dans une classe EIFFEL. Mais cela interdirait la création de personnages, les mi-clones (qui englobent les clones d'opérateurs), dont le champ d'action dépasse le monde de la simulation, pour empiéter sur le monde réel.


Une solution à ce problème est l'utilisation conjointe de l'héritage multiple et du lien dynamique des langages à objets (Fig. 2.2).



Désormais, tout animat utilisant des données externes à son monde, entre dans la définition de clone.


2. Comportement du clone


Nous avons vu que le lien entre un animat et un clone est le comportement. Mais comment représenter le comportement d'un clone ? Pour cela, prenons l'exemple d'un clone copiant les mouvements d'une main. Son comportement, qu'il soit sous forme codée dans le cas d'une réalisation réflexe, ou sous forme d'une base de règles pour une implantation intelligent, peut être :


Si position(main) = (x, y, z) alors se déplacer en x, y, z

Si orientation(main) = (x, y, z) alors s'orienter vers x, y, z

Si position(doigt1) = (x, y, z) alors déplacer le doigt 1 en x, y, z

etc.


On voit ainsi que le problème du comportement du clone peut être résolu en effectuant une extension du langage (pour les intelligents) et des méthodes (au sens EIFFEL), afin de contenir des capteurs externes. Ces derniers clonent les capteurs électroniques placés sur le gant.

Si maintenant, l'utilisateur possède des lunettes stéréoscopiques ou tout simplement un écran sur lequel il désire visionner la scène, il ajoute un "oeil" au clone de sa main. L'oeil clone lui fournit alors la vision qu'il a du monde. Son comportement peut donc être le suivant :


Pour chacun des animats du monde

Si visible alors l'envoyer à l'utilisateur;

Fin.


A nouveau, on s'aperçoit qu'avec des extensions similaires à celles utilisées pour les capteurs, on peut obtenir des "sorties externes".


On est alors en droit de se demander si ces deux extensions sont suffisantes pour gérer toutes sortes de clones. Or, en résumant les dispositifs décrits (comportement, entrées externes et sorties externes), on peut modéliser tous les processus informatiques. En effet, ils sont (au moins à un certain niveau) de la forme Entrées - Comportement - Sorties.


3. Liaison clients-serveur


Si les clones sont regroupés avec les animats à l'intérieur d'une même simulation, se déroulant sur un site déterminé, il n'en est généralement pas de même pour les utilisateurs. En effet, deux personnes ne peuvent pas se partager les périphériques (souris, clavier, ...) d'une même machine.

Les utilisateurs sont donc distribués sur divers ordinateurs. Aussi, afin de leur laisser la liberté d'entrer ou de sortir du monde quand ils le désirent, la liaison utilisateurs - simulation est modélisée par une liaison de type clients - serveur.


Chaque utilisateur doit alors être rattaché à un processus client, lequel lui permet d'accéder au processus monde gérant la simulation (Fig. 2.2).



Les liaisons clients - serveur utilisent les moyens de communication pouvant exister entre la station de l'utilisateur, et celle de la simulation. On se place dans l'hypothèse qu'un réseau, utilisant le protocole INTERNET, existe entre les deux sites. En outre, on suppose que les systèmes sont des systèmes UNIX. La communication est alors réalisée par l'intermédiaire des sockets.


4. Animat générique


La distribution des utilisateurs pose problème pour la construction de nouveaux objets. Ceux-ci ne doivent pas être définis par des classes EIFFEL particulières. La raison en est simple : la simulation peut ne pas être bornée en temps (une simulation génétique a nécessité toute une année). Si l'un des utilisateurs souhaite y introduire un personnage décrit par une nouvelle classe, il ne peut pas l'envoyer directement au gestionnaire du monde car celui-ci ne la connaît pas. Il faut alors arrêter la simulation (avec les conséquences que cela implique), et recompiler le code du simulateur.

Plusieurs solutions peuvent être apportées pour les personnages intelligents. L'une consisterait à étendre la grammaire des bases de règles, de façon à autoriser la déclaration de nouvelles caractéristiques du personnage (amphibie, aérien...). Une autre, par la définition d'un langage restreint, permettrait l'héritage et la redéfinition de parties de bases de règles (le personnage chien hériterait de mammifère en redéfinissant la règle cri): l'emploi des bases liées serait simplifié, surtout lorsqu'elles sont en nombre.

Quant aux autres personnages de la simulation (objets et réflexes), ils peuvent toujours être transformés en intelligents.


5. Clone générique



Les utilisateurs étant distribués sur des sites différents, ils n'ont pas forcément les mêmes machines, ni donc les mêmes interfaces : certains n'ont que des tracés filaires du monde sur leur écran, tandis que d'autres sont vraiment projetés dans la simulation par des lunettes stéréoscopiques et des gants.

Cela influe sur la spécification du triplet Entrées externes - Comportement - Sorties externes mis en évidence au paragraphe sur le comportement. En effet, il faut éviter la spécialisation sur un ordinateur, et tenter de créer un clone générique capable de s'adapter à toutes les machines, avec un minimum de modifications du système. Dans ce but, citons les éléments dont les performances entre deux sites peuvent être très différentes : la carte réseau (débit plus ou moins élevé), la carte graphique, les unités de stockage, les différentes interfaces Homme-Machine et l'unité de traitement.


5.1- Le débit réseau

Pour les performances du réseau, le processus client décrit les différents transferts utiles à sa liaison avec le monde. En effet, implanté sur la machine de l'utilisateur, il en connaît les limites. Le taux d'occupation du réseau ainsi que la qualité de la visualisation dépendent alors directement du choix de ces transferts.

Ce dernier doit être fonction des différentes interfaces que possède l'utilisateur; il peut s'effectuer par l'intermédiaire d'un tableau de booléens représentant chacun un type de transfert. L'utilisation du lien dynamique des langages objets permet, éventuellement, la mise en oeuvre aisée d'un mécanisme plus puissant.

Malgré tout, certaines entrées-sorties, pourtant courantes, peuvent s'avérer très coûteuses en communication. Il s'agit par exemple du clone d'un oeil; celui-ci émet à l'utilisateur sa vision de la scène, à chaque pas de simulation. S'il perçoit de nombreux personnages, le transfert engorgera probablement le réseau. Pour ces cas particuliers, il est intéressant de construire une classe spécialisée qui minimisera les transmissions.


5.2 - Les capteurs/effecteurs

Nous l'avons vu, le clone (par exemple de l'utilisateur) repose sur un mécanisme de capteurs et d'effecteurs externes, en liaison avec une entité dans un autre monde. Il y a alors communication.

Celle-ci peut être réalisée avec une connexion : 1- par clone : la communication entre le clone et son hôte utilise une seule connexion que doivent emprunter tous les capteurs et effecteurs externes.

2- par capteur / effecteur externe : chacun d'eux possède sa propre connexion.

3- par périphérique : le périphérique (souris, gant, ..) est considéré comme l'élément de base du clone. Ses transmissions s'effectuent par une seule connexion.


On choisira la dernière solution qui a l'avantage de ne pas nécessiter de multiplexage ni de démultiplexage des données. De plus, les périphériques peuvent être souvent gérés de façon indépendante chez les processus clients. On peut, dans ce cas, associer à chacun d'eux un processus "fils dédié". Enfin, cette méthode constitue une généralisation de la deuxième solution qui nécessite trop de connexions.


6. Les mondes


Plusieurs machines peuvent réaliser des simulations en même temps; certaines sont à même d'en gérer plusieurs. De là peut découler un problème de changement de monde, un utilisateur pouvant demander le transfert de son clone vers une simulation qui l'intéresse davantage. Par exemple, des mondes décrivent un système sous différents points de vus; l'utilisateur, par le passage de l'un à l'autre, détermine le niveau d'abstraction qui lui est utile (niveau objet, niveau code, ...).

Ce problème est résolu par la parallélisation du simulateur (par exemple sur la machine VOXAR). En effet, il est possible de considérer qu'un ensemble de mondes fait partie d'un espace à quatre dimensions. Les trois premières sont représentées par les axes X, Y et Z. La quatrième définit le monde où se trouvent les animats. Le changement de monde se fait alors par déplacement sur cette dimension. Cependant, cette parallélisation n'est pas encore réalisée.

Il faut donc trouver un autre moyen pour "naviguer" entre les mondes. Une première idée consiste à demander à l'utilisateur de quitter son monde, puis de se connecter au nouveau. Mais dans ce cas, il doit reprendre le processus client et perd les caractéristiques actualisées de son clone.

Une autre idée est de transférer le clone directement dans le monde de destination. Mais, les capteurs et effecteurs externes sont reliés à leurs entités par des connexions statiques. Le changement de monde doit donc être transparent au niveau de ces connexions. Cela peut se faire de deux façons. Soit le processus monde crée un routeur de données au niveau de chaque communication permettant la continuité des données, soit il refait les connexions (Fig. 2.4).



La première solution ne peut être utilisée en cas de changement fréquent de monde, car elle multiplie les connexions. C'est pourquoi on choisit la seconde.


Les mondes peuvent aussi apporter un degré supplémentaire d'intégrité des clones. En effet, si les périphériques d'une machine font partie d'un monde, le clone n'est alors qu'un animat particulier. Cependant, la machine nécessite une puissance de calcul supérieure à celle nécessaire à l'application, puisqu'elle doit gérer le monde des interfaces.

Afin d'éviter ce surcoût d'exécution, on prévoit un système secondaire qui prend le relais lorsque l'unité de traitement, où se trouve l'utilisateur, est peu puissante ou surchargée.




III-SYSTEME DE TRANSFERT

D'OBJETS



La distribution des utilisateurs nécessite la recherche d'un protocole adapté à la communication entre les processus clients et les clones de la simulation.

Ce projet étant réalisé avec un langage objets, on se propose de mettre au point des classes d'émission et de réception d'objets EIFFEL. Ainsi, le transfert d'un animat se fait par simple application d'une méthode. Le protocole est alors construit autour de certaines classes appellées messages.


1. Discussion


Le langage EIFFEL contient la classe STORABLE qui permet la sauvegarde d'un objet, soit dans un fichier de nom donné (méthode store_by_name), soit à travers une entité représentée par un descripteur de fichier UNIX (méthode store_by_descriptor).

Un socket pouvant être manipulé sous cette dernière forme, l'utilisation de cette classe est envisageable.

Les modifications à apporter à la classe STORABLE consistent principalement en ajouts de méthodes dédiées à la gestion du réseau : la fonction de demande de connexion à un site, celle de surveillance d'un port de connexion, ... (Fig. 3.1)



Cette méthode présente de grands avantages dont la simplicité et la rapidité de mise en oeuvre. De plus, elle est universelle et souple d'emploi. En effet, il suffit qu'une classe hérite d'EXPEDIABLE pour qu'elle puisse être sauvée dans son ensemble sur disque, ou transmise sur le réseau à un site distant.

Cependant, elle possède aussi des inconvénients :


* Un volume de données important

Un examen des données obtenues après sauvegarde d'un objet montre que de nombreux codes de contrôles sont émis afin de maîtriser la réception. Effectivement, la modification du code d'une classe altère généralement son format de sauvegarde.


* Aucun contrôle de la sauvegarde

Lors de la transmission d'une instance de classe, tous les champs, même ceux des classes parentes, sont transmis; ceci récursivement sur ses composants.


* Non portabilité

Les données émises sont liées au système sur lequel est implanté le compilateur. Par exemple, la description de réels, le nombre d'octets codant les entiers, l'ordre de compilation et de déclaration des champs, ... Ceci limite les échanges à des sites particuliers.



Ces différents points négatifs sont en contradiction avec nos objectifs initiaux qui, rappelons-le, sont la portabilité et un taux d'occupation du réseau configurable. On ne retiendra donc que la philosophie de la démarche.


2. Autre technique de transmission


Le paragraphe précédent a proposé une solution aux transferts d'objets EIFFEL relativement coûteuse et limitée aux communications entre machines quasi identiques. Mais nous avons besoin de faire le moins d'hypothèses possible sur les ordinateurs.

En 1990, Mattew Hillman a mis au point, lors d'un projet étudiant, certaines classes permettant le transfert de messages par objets, de façon à obtenir le maximun de portabilité (par exemple en veillant à la représentation des réels).

Le système proposé est articulé autour de la classe NET_CAPABLE. Cette dernière offre les méthodes class_code, transfer_to_net, transfer_from_net, send, et receive. La première de ces méthodes est un entier associé à la classe (celui du système dépend du compilateur); il permet de contrôler les réceptions. Les deux suivantes décrivent les émissions et réceptions à effectuer; elles sont définies à partir de fonctions de transmissions élémentaires (d'entiers, de caractères, ...). Enfin, les deux dernières émettent ou reçoivent l'objet courant à travers une connexion (classe NET_CONNECTION). La création d'une classe expédiable se fait donc par héritage de NET_CAPABLE et par redéfinition des trois premières méthodes susdites.

Ce système permet un vrai contrôle des transferts; néanmoins, le mode de réception implanté en limite l'utilisation. En effet, du fait que la réception s'effectue par application de receive, elle constitue une initialisation, par le réseau, de l'objet auquel est appliquée la méthode.


3. Notre Choix


Certains aspects de l'utilisation directe des classes de M. Hillman dans notre projet, sont discutables. Tout d'abord, nous avons vu qu'il est nécessaire de connaître à l'avance les classes des objets à recevoir, et d'en créer des instances (pour appliquer receive). Il en est de même lors de la réception des objets-fils d'un objet complexe tel qu'un personnage intelligent (capteurs, listes chaînées, ...).



Ces restrictions sont liées à deux problèmes, résolus dans les points suivants :


3.1 - Problème du polymorphisme


M. Hillman, lors de l'émission d'un objet, commence par transmettre un code caractérisant la classe parente. A la réception, il vérifie l'égalité avec celui de l'objet qui réalise le chargement. Si ces nombres diffèrent, une exception est levée.

Ces codes sont alors utilisés, non plus pour vérifier le "bon typage" des objets, mais pour générer directement une instance de la classe qu'ils caractérisent; ensuite la méthode receive est appelée. Pour cela, il faut préalablement, au lancement du programme par exemple, réaliser une association entre les codes et les noms des classes correspondants. Ces nombres ne doivent pas être affectés de façon automatique par l'instruction "UNIQUE" car, les constantes déclarées de cette façon ont une valeur dépendant du compilateur.

L'émission directe du nom de classe peut remplacer celle de son code en cas d'ajouts fréquents de nouvelles classes (elle prolonge alors à peine le transfert). En effet, si les codes sont placés dans une classe héritée par chaque objet expédiable, l'introduction d'un nouveau code provoque un changement de la spécification, et dès lors, une recompilation presque intégrale du programme.


Enfin, étant donné que les instances sont crées uniquement à partir du nom des classes, les expédiables ne doivent pas posséder de méthode de création avec paramètres.


3.2 - Récursivité


Le fait que les méthodes send et receive ne soient pas récursives empêche la transmission d'objets-fils. Il est alors nécessaire de modifier les fonctions de transferts de M. Hillman. Néanmoins, il faut considérer que les émissions se font objet par objet, et qu'un objet est conservé en mémoire tant qu'il n'est pas complètement décrit par les fonctions transfer_to_net. C'est pourquoi, on ajoute deux nouvelles méthodes, send et receive. Ces dernières font partie de la classe EXPEDIABLE et, étant récursives, elles permettent l'émission et la réception d'objets-fils. Les deux méthodes initiales de M. Hillman (renommées en SaveTo et LoadFrom) sont placées dans la classe COMMUNICATION, et émettent des objets à travers leur connexion; de plus, par l'intermédiaire d'une classe unique dans le système, elles contrôlent leur exclusion mutuelle. L'architecture du nouveau système est présentée en fig.3.2.



4. Limite et extensions


Les fonctions transfer_to_net ou transfer_from_net ne doivent pas s'appliquer à des objets cycliques pour ces méthodes. Ce problème ne se posant pas à l'intérieur de in VITRAM, aucune vérification de cycles n'est réalisée lors d'une transmission; cela doit donc être pris en charge par l'utilisateur en cas de besoin.


Dans le but d'être configurables, les connexions sont liées à un filtre de transmission. Ce dernier autorise ou interdit l'émission et la réception de certains champs; de cette façon le volume d'informations à transmettre reste minimum. Un filtre est constitué par un tableau de booléens, dont la fonction de décision de transmission est redéfinissable. Chaque objet, destiné à être modulable au niveau des transferts, déclare des booléens pour chacun de ses champs. La déclaration des booléens est faite dans le filtre de la communication. Les fonctions transfer_to_net et transfer_from_net appellent, pour un champ de données, la méthode de décision du filtre (qui initialement renvoie le booléen associé au champ). En fonction du résultat retourné, le champ est ou non transmis (et reçu).


Enfin, le filtre peut être modifié au cours d'une communication, ce qui permettrait des transferts dynamiques.


IV-LE CLONE


La classe CLONE contient les méthodes permettant d'accéder à des informations externes à travers un réseau. Il est intéressant que ces méthodes puissent gérer de nouvelles informations (demandées par un nouveau périphérique) sans avoir à modifier le code du programme.


L'étude porte essentiellement sur les personnages intelligents. En effet, les personnages réflexes n'ont guère d'intérêt : ils utilisent des méthodes comme comportement, et doivent alors être recompilés après chaque modification.


1. Informations externes


1.1 - Le principal problème dans l'intégration du clone est certainement la communication avec des données externes à la simulation (celles d'une interface). La méthode que nous avons employée pour accéder à de telles informations est inspirée des passages de paramètres dans les langages de programmation procéduraux. Ce choix est motivé par sa compatibilité avec les littéraux PROLOG de in VITRAM (forme f(x) ). En effet, les personnages intelligents doivent accéder aux capteurs et effecteurs externes au travers de leurs bases de règles.

Chaque capteur ou effecteur externe est désigné par un nom et peut être considéré alors comme une procédure. A ce nom correspond aussi une variable qui, selon les paramètres donnés, est lue ou écrite (elle est ainsi bidirectionelle). La classe CLONE formalise donc l'ensemble des capteurs et effecteurs externes par deux tableaux; le premier contient leurs noms, et le second leurs valeurs. Les valeurs, de type EXPEDIABLE, permettent, grâce à l'affectation inverse, d'utiliser des éléments de type CONSTANTE (arguments des littéraux), mais aussi de toute autre classe, ce qui sera certainement mis à profit dans les personnages réflexes.


Chaque dispositif externe est en liaison avec un site distant par une connexion. Cette dernière doit donc être scrutée, avant l'utilisation des données qui lui correspondent, afin de rechercher d'éventuelles mises à jour de valeurs. Les descendants de la classe CLONE peuvent alors consulter ces valeurs et obtiennent ainsi des capteurs externes. Ils peuvent également les modifier; les modifications sont émises au processus connecté et par ce biais les descendants ont à leur disposition des sorties externes (Fig. 4.1).



1.2 - Ajout de variables


Le comportement des intelligents est défini par des bases de règles de type PROLOG. L'apparition d'une nouvelle interface (gant, ...) est donc gérée par une de ces bases. Celle-ci doit s'appuyer sur les capacités de communication existant dans la classe CLONE, et ses données externes doivent être déclarées au préalable au personnage (pour être incluses dans la classe CLONE). A cette fin, chaque périphérique pourrait contenir son tableau de variables externes. Leur concaténation fournirait la table finale à placer dans l'animat. Cependant, cela engendrerait deux problèmes :


* Risque de collision de variables.

Il concerne en particulier les variables de nom "X" et "Y" qui sont très courantes pour les périphériques (souris, gants, ...). Il peut donc y avoir plusieurs noms identiques. Il est alors possible de préfixer ces noms par celui du périphérique. On obtient souris_x, clavier_y, ... Néanmoins, cette méthode interdit l'échange, dans une base, de deux périphériques dont les variables externes sont communes, à moins de la modifier.


* Echanges d'informations importants.

En effet, dans l'utilisation d'un périphérique, seule une partie des variables externes peut être connue de la base. Par exemple, lors de l'utilisation d'une souris, seul l'état des touches peut être pris en compte par la base; le mouvement, inutilisé, génère des échanges superflus.


Pour remédier à ces deux problèmes, les variables externes d'une base de règles sont locales, ce qui évite les collisions. De plus, seules les variables externes déclarées dans la base donnent lieu à des échanges d'informations.


1.2 - Intégration dans les bases de règles


Comme déjà mentionné, les capteurs et effecteurs externes prennent une forme de fonctionnelle à l'intérieur des bases de règles. Il aurait été possible de créer une classe CAPTEUR_EXTERNE héritant de CAPTEUR, et une autre, EFFECTEUR_EXTERNE héritant de ACTION. Les entrées seraient alors dissociées des sorties, interdisant de ce fait les variables bidirectionnelles. Nous avons préféré garder une cohésion des informations en unissant les entrées et les sorties dans la classe LITTERAL_EXTERNE. Les littéraux externes sont reconnus dans une base de règles par le caractère '#' qui les précède. Un littéral externe a donc la forme suivante :


#Nom (val)


"Nom" représente le nom du capteur ou effecteur choisi, et "val", sa valeur. A la lecture de la base de règles, "Nom" est placé dans un tableau, à un certain indice. Le littéral externe conserve cet index et l'utilise pour accéder à sa valeur. Ce procédé permet la localité des variables, ainsi que la rapidité d'exécution.


Si "val" est une constante, alors "Nom" est un effecteur (sortie externe), et il envoie sur sa connexion sa nouvelle valeur : "val". Si maintenant "val" est une variable, "Nom" est un capteur qui instancie "val" par sa valeur.

Les valeurs des littéraux externes sont conservées dans le temps, mais s'il n'y a pas eu d'initialisation, elles n'existent pas (void). Aussi, en cas de tentative de lecture d'une valeur inexistante, l'unification échoue (Fig. 4.2).




1/ X a une valeur inconnue sur les deux sites.

'#X(125)' est évalué; l'argument étant constant, X est utilisé en sortie.

2/ '125' est placé dans le tableau des valeurs, et transmis au site distant.

3/ Aprés la réception sur ce dernier, la valeur de X peut être lue.


Ce fonctionnement a l'avantage d'être économique en informations, mais il peut paraître gênant car le sens des variables (entrée ou sortie) est défini dynamiquement, en fonction de l'instanciation ou non du paramètre. Mais en écrivant les règles d'un comportement, l'utilisateur connaît le rôle de chacune des variables; ainsi, et il devrait distinguer les entrées des sorties. Cependant, la comparaison entre une constante et la valeur d'un littéral externe peut prêter à confusion; en effet, le littéral est assimilé à une sortie, dans laquelle la constante est transmise.

Toutefois, si l'écriture s'avère gênante, il est possible d'ajouter un paramètre supplémentaire définissant le sens (entrée ou sortie) ou, par une lecture de la base de règles, de vérifier le sens de fonctionnement : un littéral externe de type entrée doit avoir en paramètre une variable n'apparaissant pas dans les littéraux précédents, contrairement à un littéral de type sortie.

L'exemple suivant représente le comportement du clone d'un oeil. Il contient sept littéraux externes : X, Y, Z décrivent le lieu de l'observateur, et DX, DY, DZ la direction du regard; VU sert à la transmission des objets détectés.


agir

- Position(current, *px, *py, *pz)

- #X(*px)

- #Y(*py)

- #Z(*pz)

- Direction(current, *dx, *dy, *dz)

- #DX(*dx)

- #DY(*dy)

- #DZ(*dz)

- Voit(*o) ; Capteur oeil

- #VU(*o) .


Certaines applications de capteurs externes requièrent la lecture des valeurs courantes; pour d'autres, seules les nouvelles valeurs sont nécessaires. Le fait qu'un littéral n'ait pas un nombre de paramètres fixé peut être utilisé pour résoudre cette difficulté. Par exemple, si un littéral externe n'a aucun paramètre, l'utilisateur demande l'annulation de la valeur courante. Ainsi, tant qu'une nouvelle valeur n'est pas reçue, l'unification en lecture de ce littéral échoue.


Pour conclure, signalons une retombée intéressante de cette mise en oeuvre : la réalisation de variables internes partageables dans une base de règles. Pour cela, il suffit de ne pas leur relier de connexions. Ainsi ces variables conservent uniquement les valeurs qui leur sont affectées. Actuellement, une base ne peut pas contenir à la fois des variables et des littéraux externes (car ils ont la même syntaxe).


2. Capteurs particuliers


Le problème traité ici est celui des capteurs de type oeil qui doivent transmettre de nombreuses d'informations à chaque cycle du monde. Plusieurs choix sont possibles pour leur fonctionnement :


* Les capteurs transfèrent tout ce qui est perçu à chaque top de simulation. Cette méthode utilise uniquement les littéraux externes. Mais elle est très coûteuse communication réseau.


* Le processus monde emet l'intégralité de ses animats au client en début de connexion, puis effectue une mise à jour régulière des coordonnées, de la forme et des couleurs. Les capteurs n'envoient alors que les références des personnages repérés. Cette méthode, contrairement à la précédente, est très économique en ce qui concerne l'occupation du réseau. Cependant, elle devient gênante avec la croissance de la population du monde. En effet, du fait que chaque client possède l'ensemble du monde, des problèmes de mémoire peuvent apparaître. De plus, le volume de transfert augmente afin d'assurer les mises à jour de chacun des personnages.


* Dans l'hypothèse où les clients et le serveur sont reliés par un réseau "en bus", les capteurs peuvent, comme dans le cas précédent, n'envoyer qu'une référence sur les objets détectés. A la fin du pas de simulation, le serveur transmet en mode "diffusion" tous les animats, et chaque client conserve ceux qui lui sont nécessaires. Pour un nombre fixé de personnages, les performances augmentent avec le nombre d'utilisateurs, ce qui rend cette solution très intéressante pour certaines applications.


* On définit une distance entre deux objets. Les capteurs utilisent alors un seuil, préalablement choisi sur cette distance et, en fonction du résultat (distance conséquente ou peu importante), ils envoient ou non l'objet. Cette méthode, par utilisation de littéraux évaluables, peut être réalisée avec peu de modifications; elle permet aussi le contrôle des transferts à l'intérieur même des bases.


* Chaque personnage est affecté d'une règle permettant d'extrapoler ses mouvements, ses déformations, ... Le client, dans l'attente de mises à jour, utilise ces règles pour faire progresser les animats. Des fonctions d'interpolation de trajectoire font l'objet d'une étude [ZUNIGA 94], et peuvent être utilisées, avec une certaine précision, afin d'extrapoler les positions. Le serveur effectue des mises à jour si les différences entre les objets prédits et les objet réels sont trop importantes.


Les méthodes peuvent se compléter en fonction du problème à traiter (nombre d'utilisateurs, de personnages, ...). Pour ces cas particuliers, il est nécessaire de définir les classes supportant leur mise en oeuvre.


3. Le squelette


Le squelette des personnages fait aussi partie des problèmes de transmissions. Effectivement, un squelette peut contenir des milliers de facettes, et il est utile d'en limiter les transferts.

Une solution consiste à créer une librairie de corps prédéfinis. Ainsi, il suffit de donner le nom du squelette plutôt que d'envoyer l'ensemble de ses facettes. Cependant, un utilisateur peut désirer un squelette non répertorié, ou ne pas posséder la même librairie que le serveur (problème d'unités de stockage). On utilise alors des bibliothèques momentanées limitées sur une session client-serveur.

Les émissions se résument au nom du squelette. Tout nom inconnu donne lieu à un message de demande de description dudit squelette. La description, une fois reçue, est stockée dans la bibliothèque temporaire. Lorsque celle-ci est pleine, certains squelettes sont effacés en suivant, par exemple, les algorithmes utilisés dans les mémoires caches : destruction des moins fréquemment ou récemment utilisés, ...


4. Les déformations


En général, les déformations d'un squelette ne le modifient pas en profondeur; seules certaines parties peuvent être affectées. Ainsi, il suffit de considérer uniquement celles-ci. On peut aussi prévoir un système similaire à ceux décrits pour les trajectoires. En outre, ces déformations sont souvent obtenues par application d'opérateurs (effilement, torsion, ...) [JESSEL 92]. Dans de tels cas, on transmet la combinaison de fonctions employée avec leurs caractéristiques (points d'application, intensité, ...). Si les opérateurs sont inconnus, un message de demande de description de squelette est envoyé (l'opérateur étant une méthode, il ne peut être transmis, à moins de définir des macro-commandes).


V-GESTION CLIENT-SERVEUR



1. Le client


Le processus client a pour but de construire le clone de l'utilisateur, en fonction du matériel et des préférences de ce dernier; le clone est alors transmis au monde afin de participer à une simulation.


Les grammaires utilisées dans ce chapitre comportent les signes suivants :

- X + Le nombre de X est supérieur ou égal à un

- X * Le nombre de X est quelconque

- { X1 X2 ... XN } L'intérieur de l'accolade est considéré comme une unité

- X1 | X2 Choix : soit X1, soit X2


Dans ces diverses règles, X et Xi représentent des unités syntaxiques.


1.1 - Construction du clone


A défaut d'une interface graphique interactive, elle se fait par succession de questions-réponses. Le processus client demande à l'utilisateur le monde où il veut aller, ainsi que la forme de son clone, ses capacités, et son comportement. Ce dernier étant défini par une base de règles, l'utilisateur, qui pourrait l'avoir construite et sauvegardée au préalable, n'aurait alors qu'à donner son nom. Mais la création d'un nouveau clone demanderait un programme spécial.


Une autre solution s'appuie sur la correspondance de chaque périphérique accessible au clone avec une base de règles qui en permet la gestion. Le comportement est alors décrit par la liste des bases utilisées; il peut donc être vu comme une base liée. Toutefois, deux périphériques ayant les mêmes variables externes ne pourraient pas être échangés. C'est pourquoi chaque base est décrite avec son périphérique associé, selon la forme :


NomBase (NomPeriph)


Par exemple, si les deux périphériques souris et gant possèdent les données X, Y, Z (en utilisant un artifice pour calculer la profondeur avec la souris), et si les bases de règles mouvement et position décrivent respectivement les données externes X Y Z par macro-commandes (de type à gauche, à droite, ...), ou par coordonnées, on peut écrire :


Mouvement (gant) : Décrit à partir du gant les mouvements : en haut, ...

Mouvement (souris) : Idem à partir de la souris.

Position (gant) : Donne les coordonnées du gant.

Position (souris) : Donne les coordonnées de la souris.


Si une base de règles n'est pas associée à un périphérique, elle ne doit pas contenir de littéraux externes; elle est alors utilisée pour obtenir un degré d'abstraction plus élevé dans les commandes ou, pour posséder des comportements indépendants (utilisés dans les mi-clones) ou enfin, pour offrir des têtes de règles indispensables aux autres bases (par exemple, avec une librairie mathématique).

La grammaire <L> obtenue est :


<L> = { NomBase | NomBase (NomPériph) }+


Ainsi est-on capable de définir correctement notre clone. Pourtant la description obtenue, si elle est modifiée régulièrement, s'avère encore lourde d'utilisation. En effet, l'utilisateur ne doit pas omettre une base-librairie (abstraction, mathématique, ...), ou un périphérique peu utilisé, ... ce qui implique une documentation sur les périphériques utilisés.

De ce fait, on introduit un niveau supplémentaire dans la description du comportement du clone. Dans ce niveau, nous appelons ressource, un ensemble de bases défini par la grammaire précédente. Plus exactement, une ressource est décrite dans un fichier (avec l'extension .DCE) dont le contenu suit la grammaire <R> ci-dessous :


<R> = ANIMAT ( <L> ).


De plus, le fichier peut contenir des commentaires qui, pour garder une cohérence avec la grammaire des bases, sont marqués par le caractère ';' et s'étendent jusqu'à la fin de la ligne.

Le comportement du clone est ainsi décrit par la liste des ressources dont il a besoin. Cependant, la gestion des périphériques sur la machine de l'utilisateur est distribuée (voir point suivant) et, comme certains regroupements de périphériques peuvent être réalisés sur un même processus, cette déclaration est étendue par un parenthésage. A l'intérieur d'une parenthèse, les périphériques des ressources peuvent être rassemblés; il en est de même pour ceux dont les ressources sont en dehors de parenthèses.

La grammaire <C> demandée pour la déclaration du comportement est :


<LR> = Ressource +

<C> = { Ressource | ( <LR> ) }*


A partir de ces informations, le processus client construit l'ensemble des bases de règles régissant le comportement du clone. Mais, en règle générale, les bases nécessitent des capteurs. C'est pourquoi, chaque base est liée à un fichier de même nom (mais d'extension .CPT) contenant la liste des capteurs utilisés.

Un problème similaire se pose avec les périphériques pour le filtre de la communication. En effet, c'est lors de la conception des périphériques que l'on planifie les émissions-réceptions, ainsi que la quantité d'informations nécessaire sur les objets. A chaque périphérique on associe alors un fichier contenant son filtre (extension .FTR).


Un clone, possédant deux capteurs ou deux bases identiques, exécute un travail dont une partie est en double. Il faut donc éviter ce genre de duplication. Pour les bases, on considère qu'il y a équivalence si les règles sont les mêmes et qu'elles ne contiennent aucun littéraux externes. Pour les capteurs, une comparaison sur les noms est faite.


Enfin, un clone, une fois défini, peut être nommé puis sauvegardé sur disque. Dès lors, seul son nom et celui du monde de destination sont nécessaires au processus client pour effectuer son travail.

En plaçant ces deux noms en paramètres du client à l'intérieur des fichiers systèmes ".login" ou ".cshrc", le clone est automatiquement activé.


1.2 - Distribution des périphériques


Le comportement d'un clone, décrit par des bases de règles, nécessite certaines informations externes à la simulation. Ces informations se trouvent sur la machine de l'utilisateur, et peuvent se composer en groupes indépendants les uns des autres. Par exemple, un groupe rassemble les informations sur la souris de l'utilisateur, un autre, sur son gant.

Toutes ces informations peuvent être gérées par le processus client; néanmoins, afin de le laisser à sa tâche première, il est préférable de les distribuer sur plusieurs processus. La distribution peut être réalisée par groupes, lequels représentent normalement des périphériques. Ainsi un processus gère la souris, un autre une fenêtre, ...

Toutefois, remarquons que la gestion de la souris peut être incluse dans celle de la fenêtre dans les systèmes courants, tel que X-Window. On applique donc ce dernier genre de regroupement, afin de réduire le nombre de processus en activité, et de simplifier la tâche de l'utilisateur (cela le dispense d'avoir une fenêtre pour la gestion du clavier, une autre pour la souris, ...) (Fig. 5.1).



Pour réaliser les regroupements, il est indispensable de connaître les programmes disponibles, et les différents périphériques qu'ils sont capables de gérer. Dans ce but, il est possible d'instaurer, pour chacun des programmes, un fichier de description (d'extension .DES) de ses capacités. Mais pour permettre un contrôle plus pointu de l'exclusion mutuelle, que peuvent demander certains périphériques ou certaines ressources, cette description est déportée au niveau de chaque périphérique. Ceci entraîne une certaine redondance limitée par des liens entre fichiers.

La grammaire <P> correspondante est :


<P> = { Periph (Lettre) }+ > NomPrg


Cette grammaire peut être étendue pour autoriser un programme à gérer plusieurs périphériques identiques. Cela peut se traduire par un signe '+' situé après "Periph".



La lettre, associée à chaque périphérique, est utilisée comme option au lancement du programme pour lui indiquer les différents périphériques qui lui sont connectés. En outre, les processus ainsi créés doivent connaître les numéros de sockets avec lesquels communiquer. C'est pourquoi, chaque option est suivie de ce nombre.

Enfin, lors de son exécution, le programme ignore les diverses variables externes utilisées, ainsi que les diverses caractéristiques des communications. La solution adoptée consiste à créer un tube de communication avant le dédoublement du client. Un des deux processus obtenus est remplacé par le programme; l'autre, par l'intermédiaire du tube créé, envoit la table des noms, ainsi que le descriptif des communications (filtres, ...).

La commande qu'exécute le processus-fils, prend la forme suivante :


Programme -Lettre1 socket1 -Lettre2 socket2 ... > Tube


Après avoir décrit la méthode de distribution, voyons comment s'effectuent les regroupements : le comportement du clone, défini par l'utilisateur sous forme d'une liste de ressources (grammaire <R>), est compilé afin d'en séparer les ressources concentrées par l'utilisation des parenthèses. Pour chacune des listes obtenues, l'algorithme ci-dessous est appliqué :


Pour chaque ressource de la liste

Lire le descriptif de ressource (.DCE) :

Charger les bases en isolant les périphériques demandés;

Charger les capteurs (.CPT);

Fin

FinPour

Tant qu' il reste des périphériques

En prendre un au hasard;

Ouvrir son fichier de description de programme (.DES);

Pour chacune des options présentes

Rechercher un périphérique qui corresponde;

Le marquer;

FinPour

Lancer le programme avec les périphériques marqués;

Détruire ces périphériques;

FinPour


Cet algorithme a été simplifié pour des raisons de compréhension. Il ne tient pas compte de l'unicité des capteurs et des bases de règles, ni de la gestion des connexions. Cette dernière est réalisée au niveau du chargement des bases; lorsque l'une contient des littéraux externes, on demande une connexion au monde.


1.3 Algorithme du processus client


Dans cet algorithme, on utilise les abbréviations : * U: utilisateur * M: monde

* P: processus


Demander M à U;

Demander une connexion au PM associé à M;

Demander les interfaces disponibles pour U;

Pour chacun des périphériques s'y trouvant

Demander une nouvelle connexion à PM : NC;

Rechercher la base de règles gérant le périphérique;

Associer NC aux capteurs et effecteurs de cette base;

Créer un processus fils du PCG, que l'on dédie au périphérique;

Donner à ce processus fils NC;

FinPour;

Demander à U le corps de son personnage, ...

Envoyer l'animat ainsi formé, à travers la première connexion;

Refermer celle-ci;


Bien sûr, le personnage créé peut être sauvegardé, de sorte qu'à la session suivante, le processus client fasse la correspondance entre un utilisateur et son clone.


2. Processus fils


Les processus fils, lancés par le processus client, sont construits à partir d'une classe mère (FILS) afin d'en simplifier l'écriture. Cette classe est chargée de l'analyse des arguments passés en paramètres, puis de la réception de la table des variables et de celle des connexions. Cette classe permet aussi la gestion de l'ensemble des périphériques.


2.1 - Analyse des arguments


Pour chacune des options données, on applique une première méthode (virtuelle) dont le rôle est d'associer à une option, le périphérique correspondant. La description du périphérique est réalisée par l'intermédiaire d'une classe héritière de FILS_ACT. Après cette association, une deuxième méthode déclare au périphérique, l'ensemble des variables demandées par la base de règles. Pour cela, elle parcourt le sous-tableau des variables correspondant au numéro de connexion donné à la suite de l'option. De cette façon, chacun des périphériques connaît celles à mettre à jour, et limite ainsi ses transmissions.


2.2 - Boucle de traitement


Après la phase d'analyse, une fonction de la classe FILS réalise la gestion des périphériques recensés. Cette gestion est faite par une suite d'instructions qui est répétée, tant qu'un booléen (fin) reste à faux.

Voici le contenu de cette boucle :


Pré-Action;

Réceptionne;

Post-Action;

Traite Fonctions;


"Pré-Action" et "Post-Action" doivent être définies dans les classes descendantes de FILS. Elles autorisent des actions globales avant, et après la réception d'informations externes, par exemple pour placer le booléen fin à vrai. La réception de données par les connexions se fait par examen de ces dernières. Lors de la réception d'un objet, on appelle une méthode du périphérique auquel il appartient.

Enfin, l'appel de "TraiteFonctions" permet aux périphériques d'émettre des messages s'ils le souhaitent.


2.3 - Un exemple


La figure 5.2 montre l'architecture de la classe FENETRE qui permet la gestion des périphériques souris, clavier et fenêtre.

Cette classe fait correspondre à l'option 'S' une instance de PERIPH_SOURIS, à l'option 'C' une instance de PERIPH_CLAVIER, et à l'option 'F' une instance de PERIPH_FENETRE. En action initiale (avant d'entamer la boucle de traitement), elle demande au système (code en langage C) l'ouverture d'une fenêtre et la prise en compte des événements clavier et souris. La pré-action est constituée de l'analyse des événements reçus.

L'implantation sur une nouvelle station nécessite l'adaptation du source C (moins de cent lignes) où se trouvent les primitives pour afficher une fenêtre, mémoriser les événements, ...



3. Le serveur



3.1- Le serveur représente en fait un monde, et une terminologie plus exacte serait le "serveur de la simulation". Son travail consiste à faire évoluer la population d'animats de son monde, et à recevoir des personnages supplémentaires par l'intermédiaire de connexions.

Pour cela, le serveur dispose d'un "port" de communication sur lequel chaque client doit demander une connexion. Il existe deux sortes de connexions; la première est utilisée pour transmettre des personnages, dans le but de les inclure dans la simulation. La deuxième est dédiée à des fins privées; il s'agit là de connexions nécessaires aux littéraux externes, et dont les objets transmis ne doivent pas entrer dans la simulation.

Le serveur est aussi capable de transférer des objets vers un autre monde, sur leur demande ou sur celle d'un hôte.


3.2- Changement de monde


Si ce changement, pour un personnage, est simple en général, il n'en n'est pas de même pour l'affectation d'un personnage clone à un autre monde. En effet, un clone est relié par un certain nombre de connexions à son propriétaire. Il faut donc reconstruire ce maillage avec le monde de destination, avant de le transférer. Cette reconstruction utilise un certain protocole constitué de quatre fonctions. Ce chiffre s'explique par la volonté de limiter les blocages dans la simulation. Voici la description de ces fonctions et du protocole choisi (voir aussi Fig. 5.3) :


* Etape 1


Le serveur demande à l'objet expédiable de se préparer à son changement de monde, ceci à l'aide de la méthode ChangeWorld (NouveauMonde), où "NouveauMonde" correspond au nom du futur monde, ou à son numéro INET.

L'objet itère cette fonction sur chacun de ses champs expédiables. En effet, certains capteurs spéciaux peuvent gérer directement des connexions (par exemple une classe de capteurs externes réduisant les transmissions par extrapolation).

Si la fonction "ChangeWorld" est appliquée à un objet ayant des connexions, elle génère pour chacune un message de demande de changement de monde. Les processus recevant ce message demandent alors une connexion vers le nouveau monde, puis ils envoient le résultat de cette demande .


* Etape 2


Le serveur, après le temps nécessaire à ces transmissions, fait appel à la fonction LiaisonOk, laquelle renvoie un booléen indiquant l'acceptation ou non du transfert. Cette fonction se contente de scruter les connexions de l'objet, afin d'attendre les réponses des processus connectés. Elle fait un ET logique entre toutes ces réponses, et celles de la même méthode appliquée aux divers champs expédiables de l'objet.


* Etape 3


Si le serveur reçoit une réponse positive de "LiaisonOk", toutes les liaisons ont pu être reconstruites. Il applique alors la méthode ConfirmeChange de l'objet, ce qui permet de fermer les connexions devenues inutiles, et de valider les nouvelles. Dans le cas contraire, il applique la méthode AnnuleChange, qui ramène les connexions à l'état précédant la demande de changement de monde .

Ces deux dernières fonctions, comme les précédentes, sont appliquées récursivement sur chaque champ expédiable, et génèrent pour chaque connexion un message.


* Etape 4


Si la méthode "ConfirmeChange" a été appelée, il suffit au serveur de transférer l'objet par une connexion vers son nouveau monde, et de l'enlever de la simulation courante.



1/ Le clone de l'utilisateur (client) se trouve sur 'Monde1'. Le clone demande son changement de monde. Il envoie alors sur chacune de ses connexions le message correspondant.

2/ Le client reconstruit chacune des connexions sur 'Monde2'. Puis, il avertit le clone du succès de l'opération.

3/ Le clone confirme le transfert; le client remplace les connexions du 'Monde1' par celles sur le 'Monde2'.

4/ 'Monde1' envoie alors le clone par une connexion temporaire.


4. Protocole Client-Serveur


Afin de communiquer, les processus client et serveur doivent suivre un protocole commun .

Tout d'abord, le client doit connaître les numéros des sockets du serveur qui correspondent aux siens. En effet, lors de l'assemblage de bases de règles contenant des littéraux externes, une connexion est créée et répertoriée avec les autres connexions. C'est la description de ces connexions qui est transmise avec l'animat, et qui lui permet de communiquer avec l'extérieur. Les connexions doivent donc utiliser les numéros de sockets du serveur.

C'est pourquoi, dès qu'une connexion est acceptée par le serveur, celui-ci y envoie son numéro de descripteur de fichier. Le processus client peut alors l'utiliser.


Le reste du protocole est en fait très simple, étant donné qu'il est réalisé par émission d'instances de classes, lesquelles peuvent être complexes. Ce protocole est résumé dans les lignes qui suivent.


4.1 - Introduction de personnages


Pour introduire un nouveau personnage dans un monde, après connexion sur celui-ci, il faut émettre le filtre de la communication, suivi de l'animat à l'intérieur d'un message issu de la classe MES_ANIMAT. Lorsque l'on ne désire plus transmettre d'objets, ni continuer la communication, on émet un objet de la classe MES_STOP.


4.2 - Connexion privée


Suite à la demande de connexion, on envoie une instance de la classe MES_PRIVE. A partir de ce moment, le serveur ignore la connexion, ce qui permet la réalisation de protocoles privés. Il est inutile de transmettre un filtre pour cette opération.





Partie 3





Extensions


VI-SEQUENCEUR TEMPOREL



Comme on a pu le remarquer dans le chapitre consacré à in VITRAM, les personnages intelligents réfléchissent uniquement sur l'instant présent. En effet, un moteur d'inférence exécute la base de règles globale de chaque INTELLIGENT, mais ne permet aucune conservation d'informations, que ce soit par des instanciations ou par des faits.

Ce problème se fait donc ressentir au niveau de la description des comportements. Certaines méthodes ont déjà été utilisées afin de donner de la mémoire aux personnages. Elles consistent à définir des champs particuliers dans la description des classes des objets. Puis on ajoute des littéraux évaluables permettant d'accéder à ces champs.


Par exemple, si on veut qu'un animat puisse faire le tour d'une maison définie au sol par un polygone, on crée la classe RODEUR héritant de INTELLIGENT, puis on ajoute le champ "ButCourant" qui est un point de l'espace. Ensuite, on écrit le littéral évaluable "ButSuivant" qui, à partir de du but courant, place le nouveau point à atteindre (en suivant la description du polygone).


Le comportement PROLOG peut être alors :


agir

- Récupère (Current, ButCourant, *point) ; But courant

- PresDe (Current, *point, 0.5) ; On est arrivé

- ButSuivant . ; On en change

agir

- Récupère (Current, ButCourant, *point) ; But courant

- AllerVers (*point) . ; On avance

AllerVers (*point)

- ... ; Suivant le personnage : évite obstacle, ...


Cet animat, bien que de comportement très simple, est relativement long et pénible à créer. On peut alors imaginer ce qu'est la conception d'un personnage plus complexe.

Nous voulons aussi éviter les recompilations du système, afin de permettre des simulations relativement longues, dans lesquelles il est toujours possible d'inclure de nouveaux personnages. Or la méthode décrite ne correspond qu'imparfaitement à ces objectifs.


1. Recherche de solutions


Pour remédier à ce problème, on peut profiter de l'avantage inattendu des capteurs et effecteurs externes; en effet, si un littéral externe n'est pas relié à une connexion, il est assimilable à une variable interne (voir chapitre sur les clones). Aussi, étant partagé par la base entière, un tel littéral peut servir de mémoire.

Une autre méthode consiste à conserver certains faits. La mémorisation de ceux-ci peut être faite soit par littéraux spéciaux, soit par un algorithme ne conservant que les plus utilisés, ce qui correspond bien à notre perception de la mémoire.


En utilisant l'une ou l'autre de ces méthodes, notre problème principal, qui est la limitation des recompilations, serait résolu. Cependant, le second persisterait : la complexité. Afin de mieux la mettre en évidence, considérons l'exemple qui suit :


Un utilisateur désire créer une animation dans laquelle une abeille s'envole de sa ruche à la recherche de pollen. Elle passe par un point A, puis par un point B. De là, elle rentre chez elle, et montre le chemin du point le plus intéressant à ses camarades.


Soit "Mémo" la fonction de mémorisation d'un fait, quelles que soient les méthodes employées. Considérons que son premier paramètre est IN pour introduire une valeur, OUT dans le cas contraire. Le nom de la variable à laquelle on accède est contenu dans l'argument suivant, et la valeur, dans le dernier. Aussi, on suppose "Quantité", "PointA" et "PointB" définies dans la base.

On obtient :


agir

- Mémo (OUT, Etape, Début) ; Unifié au lancement

- Position (Current, *point) ; Point de départ

- Mémo (IN, Ruche, *point) ; A conserver pour le retour

- Mémo (IN, Etape, A) . ; Passage à l'étape suivante

agir

- Mémo (OUT, Etape, A) ; On va vers le point A

- AllerVers (PointA) ; On avance; réussi si arrivé

- Quantite (*poll) ; Repère le pollen

- Mémo (IN, Poll, *poll) ; Mémorise la quantité

- Mémo (IN, Etape, B) . ; On passe à la suite

agir

- Mémo (OUT, Etape, B) ; On va vers le point B

- AllerVers (PointB) ; On avance; réussi si arrivé

- Quantite (*pollB) ; Repère le pollen

- Mémo (IN, PointMax, PointA) ; Par défaut on ira en A

- Mémo (IN, Etape, Retour) ; On rentre à la ruche

- Mémo (OUT, Poll, *pollA) ; On compare les quantités

- Sup (*pollB, pollA) ; On reviendra en B

- Mémo (IN, Poll, *polBl) ; Mémorise la quantité max.

- Mémo (IN, PointMax, PointB) . ; Et du point B

agir

- Mémo (OUT, Etape, Retour) ; On rentre à la ruche

- Mémo (OUT, Ruche, *point)

- AllerVers (*point)

...

AllerVers (*point)

- ...


On remarque que la base est un ensemble de clauses agir en début desquelles est vérifié l'état de l'objet (si va vers A, de retour, ...); ce fonctionnement est assimilable à l'instruction CASE des langages classiques. De plus, de nombreuses lignes sont quasi identiques (les mémorisations, les tests, ...). Cette présentation, bien qu'acceptable, n'en est donc pas moins lourde dans sa réalisation, ce qui pose des problèmes pour une simulation plus longue ou plus compliquée.


2. Séquenceur temporel


Les problèmes qui ont été soulignés tout au long des paragraphes précédents viennent du fait que in VITRAM, de par ces règles PROLOG, ne gère pas la dimension temporelle des simulations. Une autre façon de raisonner dans la recherche de solutions, est donc d'essayer de donner cette dimension à l'intérieur des bases.

Etant donné que nous nous limitons à des simulations comportementales, la partie "passée" de cette dimension ne nous intéresse pas. Par contre, la branche du futur est attrayante. C'est dans cette partie que l'on va pouvoir planifier les animations des objets, en fonction de leurs connaissances actuelles (qui peuvent regrouper aussi des informations du passé) (Fig. 6.1).



Il est alors tentant de remplacer la logique des prédicats utilisée dans PROLOG, par une logique temporelle [AUDUREAU 90]. Cependant, ces dernières sont plus adaptées à la démonstration de la validité de programmes parallèles, qu'à leur utilisation dans le comportement de personnages.


Nous avons donc choisi une extension que nous jugeons facile à manier, qui est appelée "séquenceur temporel". Cette extension permet de découper le temps à venir en intervalles, pendant lesquels s'exécutent des clauses PROLOG. Ce séquenceur prend la forme "THEN" à l'intérieur des bases de règles. En voici sa forme générale ("C1" et "C2" sont des suites de littéraux) :

C1 THEN C2


Le fonctionnement de cette nouvelle instruction est, de façon simplifiée, le suivant: "C1" a le contrôle au début, et le garde dans les pas de simulation suivants, tant qu'une unification n'a pas complètement réussi. Dès qu'une unification a éliminé tous les littéraux de "C1", le contrôle sera donné à "C2" au prochain pas (Fig. 6.2).

On appelle clause temporelle, une clause contenant un séquenceur temporel. Une clause peut contenir plusieurs séquenceurs; le temps est alors découpé en autant d'intervalles. De plus, certains littéraux, non évaluables, peuvent être unifiés avec des clauses temporelles. Enfin, une clause temporelle peut être récursive.


De tout ceci, retenons que désormais, l'utilisateur peut décrire les comportements de personnages presque comme s'il parlait : "Fais cela, puis telle action, suivie de telle autre, ...". Mais aussi, mesurons les risques d'erreurs : récursivité, cycles, ..., qui feront stopper la simulation par manque de mémoire.



Enfin, si cette description semble intéressante, il lui manque cependant la mémoire des faits. En effet, si "C1" a réalisé une action que la clause "C2" doit continuer, celle-ci aura certainement besoin de divers paramètres pour faire son travail. Ces passages de valeurs peuvent se faire, comme dans le premier point, par une mémoire commune, mais l'écriture s'en trouverait alourdie. La solution retenue est, lors du passage du contrôle d'un groupe de littéraux à un autre, d'instancier ce nouveau groupe par l'unifieur du premier.


3. Analyse du séquenceur


Etudions maintenant plus en détails le séquenceur. Comme il a été dit, le groupe de littéraux précédant un séquenceur est exécuté à chaque pas du monde, tant qu'il n'y a pas d'unification totale. Cependant, un littéral peut s'unifier de plusieurs façons, et un autre, dans son évaluation, peut faire apparaître des séquenceurs. Dans un tel cas, répéter, au top suivant, le premier groupe de littéraux serait une erreur, car elle casserait l'action de certains séquenceurs apparus dans les unifications. Cette erreur vient du fait que l'on raisonne comme dans un PROLOG habituel où, une clause est soit vraie, soit fausse. Mais, dans les deux cas, son exécution est terminée. L'ajout de séquenceurs introduit un nouvel état des clauses que l'on peut définir comme "en cours de résolution" (Fig. 6.2).

On reprend donc les littéraux initiaux si l'état de la clause formée par le groupe de littéraux est "échec". Si l'état est "succès", il y a passage du contrôle au groupe suivant avec l'unifieur trouvé. Enfin, si l'état est "en cours", la tâche continue.


3.1 - Arbre d'exécution


L'enchaînement successif de séquenceurs avec, pour certains littéraux, plusieurs unifications possibles de clauses temporelles, conduit à un arbre d'exécution. On va donc conserver de pas en pas cet arbre. Son évolution entraîne celle du comportement du personnage. Aussi, comme le CUT dans l'arbre de résolution PROLOG, on peut prévoir un BREAK dans l'arbre du comportement, celui-ci permettant de reprendre des mauvais choix effectués dans le passé. Malheureusement, l'espace de ce DEA n'était pas suffisant à son développement.

Exemple du break :


agir

- Voit(*o) ; Recherche de nourriture

- SeMange(*o)

then

- Attraper(*o) ; Poursuite de la même proie pour la fatiguer

then

- Dormir.

Attraper(*o)

- Voit(*o) ; Elle a été plus rapide que nous ?

- Cut

- AllerVers(*o) ; Non ... on la rattrape ...

- Manger(*o). ; Puis on la mange.

Attraper(*o) ; Perdue de vue : on casse le séquenceur

- Break. ; pour faire un retour arrière (prendre une nouvelle cible)


L'évolution d'un noeud de l'arbre de comportement est fonction de celle de ses fils. Chacun d'eux est exécuté, l'un après l'autre (à moins qu'il y ait activation d'un CUT). Ces exécutions simulent le parallélisme du comportement mais, ne l'oublions pas, sont aussi réinitialisées pour chaque fils dans l'état "échec". Ce qui peut correspondre à une désynchronisation entre les fils issus d'une même unification (Fig. 6.3).



3.2 - Correspondance avec le GRAFCET


En permettant aux règles de se synchroniser en fin d'exécution (par exemple avec une instruction WAIT en fin de règle), il est possible d'avoir un algorithme transformant un GRAFCET (Fig. 6.4-abc) en bases de règles. Ce qui permet de mesurer la puissance du séquenceur, et les nouvelles applications possibles.





3.3 - Comparaison de comportements


Afin de donner une idée de la facilité d'écriture, voici l'exemple de l'abeille, repris ici avec le séquenceur.


agir

- Position (Current, *ruche)

then

- AllerVers (PointA)

- Quantité (*PollA)

then

- AllerVers (PointB)

- Quantité (*PollB)

- Choix (*PollA, *PollB, *Poll, *Point)

then

- AllerVers (*ruche) ; Le premier comportement

then ; se finissait ici.

- AlerterCamarades (*Poll) ; Mais on continue jusqu'au bout !

- AllerVers (*Point)

then

- Butiner

then

- AllerVers (*ruche) .

Choix (*PollA, *PollB, *PollA, PointA)

- SupEg (*PollA, *PollB)

- CUT .

Choix (*PollA, *PollB, *PollB, PointB) .


3.4 - Utilisation de la récursivité


L'utilisation de la récursivité dans des règles temporelles va faciliter certaines animations. Par exemple, pour définir un personnage qui joue à la tour d'Hanoï, il suffit d'ajouter un séquenceur dans une des règles formant le jeu. Alliée au BREAK, elle devrait résoudre des problèmes d'intelligence artificielle dans le temps.

La tour d'Hanoï avec séquenceur :


hanoi (1, *x, *y, *z)

- Imprime(*x, *z) ; Imprime peut être remplacé par

- Cut ; 'PoseSur' afin d'animer un personnage.. hanoi (*n, *x, *y, *z)

- Moins (*n, 1, *n1)

- hanoi (*n1, *x, *z, *y)

then

- Imprime (*x, *z)

then

- hanoi (*n1, *y, *x, *z).

3.5 - Mise en oeuvre



L'implantation du séquenceur a nécessité l'intégration du moteur d'inférence dans les clauses. On ne retrouve donc plus la classe MOTEUR. Aussi, la gestion des "règles filles" est assurée par la classe CELL_ARBRE. Le lien entre cette dernière et la classe CLAUSE est la classe QUESTION dont toutes deux héritent. En effet, toute clause est une question potentielle.

La résolution d'un objet QUESTION débute par application de la méthode Résoudre, laquelle retourne la nouvelle question. Le graphe de conception est présenté en figure 6.5.



Pour conclure, signalons que, malgré le séquenceur temporel, l'utilisation des mémoires décrites en début de chapitre reste indispensable dans certains cas. Aussi, les actions, de par leur gestion interne, peuvent s'exécuter dans un ordre différent de celui défini.


VII-MACRO-ANIMATS



La simulation comportementale peut être réalisée avec des individus monoblocs, c'est à dire possédant un corps unique et figé. En effet, l'aspect visuel d'une simulation n'a encore que peu d'importance dans le comportement d'un personnage. Cependant, le projet in VITRAM a pour finalité la construction de films vidéo de qualité en images de synthèse. Or la qualité des animations est liée, entre autres, à trois faits :


* La facilité d'écriture des personnages car, plus leur écriture est aisée, plus les comportements peuvent être complexes.

* L'impression de mouvements. Une fourmi qui se déplace en ne modifiant ni la position de ses pattes, ni celle de sa tête ou de son corps attire très rapidement le regard des spectateurs.

* L'obéissance à des lois. Pour la simulation d'un être quelconque, les lois sont celles qui gouvernent son monde. Pour un chat ou un chien, c'est par exemple la conservation de l'énergie, la gravitation, ...


Ce chapitre est centré sur la deuxième observation. Effectivement, la première est déjà supportée par les règles PROLOG et le séquenceur temporel; quant à la dernière, si elle n'est pas encore totalement intégrée à l'intérieur de in VITRAM, elle peut tout de même y être simulée grâce à des règles supplémentaires dans le comportement.

L'idée qui est développée est celle des macro-animats. Il s'agit d'objets liés à d'autres par l'intermédiaire d'articulations caractérisant leur type de liaison (rotule, glissière, ...). Chacune des parties filles d'un macro-animat est alors appelée micro-animat, et chacun de ces derniers a son propre comportement (Fig. 7.1). Le comportement d'un macro-animat est donc distribué sur ses micro-animats, ce qui facilite la création de comportements par encapsulation de ces derniers.


L'orientation prise tout au long de ce chapitre, est la réutilisation du code existant afin de permettre rapidement des mouvements plus réalistes. L'objectif n'est pas de construire un système complet de micro-comportements tel qu'on peut en découvrir dans [McKENNA 90] ou [ISAACS 87], mais seulement, par certains artifices, de donner plus de vie aux animations.




1. Les buts


L'évaluation et le déclenchement de comportements élémentaires (aller vers, attraper cela, ...) indépendants, bien que pouvant être décrits par les règles PROLOG actuelles, manquent de souplesse et surtout d'une dynamique d'exécution. Cela se remarque davantage à l'intérieur d'un macro-animat où une multitude d'actions peut être demandée à tout moment.

Pour remédier à ce nouveau problème, le modèle actuel du comportement est étendu par la conjecture suivante :


L'exécution d'un personnage se réduit à la

réalisation d'un ensemble de buts.


L'ensemble de buts peut être complété ou réduit en fonction du comportement.

L'hypothèse faite ici apparaît dans [MAES 91]. Désormais, les clauses agir ne forment qu'un but particulier. Chacun des buts (que Maes appelle comportements) doit posséder sa priorité, laquelle est utilisée pour déterminer leur ordre d'évaluation. En effet, lors de l'exécution d'un personnage intelligent, les buts sont évalués par ordre de priorité jusqu'à ce qu'il y en ait un qui déclenche un CUT ou qui se retrouve sous le contrôle d'un séquenceur. Cette dernière solution a été adoptée car le CUT n'était pas suffisant pour éviter l'évaluation de buts moins importants que le courant.


La création, la modification et la suppression d'un but sont assurées par le littéral évaluable "But(objet, nom, priorité)". Le premier argument est l'objet à évaluer; le deuxième représente le nom du but, et le dernier sa priorité. Suivant le type ou la valeur de ce dernier, l'action est différente :


* Type Variable : dans ce cas, le littéral but retourne la priorité du but dont le nom est donné. Si il n'en existe aucun possédant ce nom, l'unification échoue.

* Type Constante positive ou nulle : si un but, dont le nom correspond au premier argument, existe, alors il y a modification de sa priorité (elle prend la valeur de la constante). Dans le cas contraire, il y a création d'un nouveau but.

* Type Constante négative : si le but existe, il est supprimé, sinon l'unification échoue.


Exemple (simple) d'utilisation du littéral but :


but

- Maj. ; Mise à jour des priorités des buts

but

- Manger.

but

- Boire.

but

- Dormir.

Manger

- Voit(*o) ; Recherche de la nourriture

- SeMange(*o)

- AllerVers(*o) ; Attrape la proie

- Manger(*o)

- But(manger, 0). ; Le but manger est placé au minimun : on n'a plus faim

; Idem pour Boire et dormir

Maj

- But(manger, *m) ; A chaque pas de simulation, la faim augmente

- Plus(*m, 1, *m2)

- But(manger, *m2)

- ... ; Idem pour les autres buts


L'intégration des buts à l'intérieur d'IN VITRAM permet désormais de lire les pensées d'animats. En effet, en plaçant un personnage intelligent en premier argument de But, ses buts ou intentions deviennent accessibles.


Le nom d'un but est une chaîne alphanumérique, ce qui est très limitatif. Effectivement, considérons un macro-animat désirant attraper un objet à l'aide de son bras. Il ne peut pas générer directement ce but car il contient un argument, il doit donc passer par une règle supplémentaire dédiée ainsi que par une variable interne pour le passage de l'objet à saisir.

Cette restriction est due au fait que les fonctions PROLOG, bien qu'ayant été spécifiées dans in VITRAM, n'ont pas été encore intégrées.


La mise en ouvre des buts est réalisée par modification du code de CELL_ARBRE.


* Le littéral raconte


Afin de simplifier la compréhension de scènes, les intelligents peuvent utiliser le litteral raconte. Ce dernier ajoute des faits décrivant la nature de l'objet passé en paramètre. Par exemple, le "robot bâtisseur" (voir annexe) doit poser une brique sur un mur. Afin qu'il sache où la placer, il applique raconte(*mur); dès lors, il possède de nouveaux faits décrivant l'ensemble des places disponibles. L'action de raconte aurait pu être réalisée par des règles PROLOG à partir des coordonnées des briques positionnées, mais elle aurait nécessité de nombreux calculs.


2. Communication


La distribution du comportement sur les micro-animats nécessite une communication entre les objets d'un même macro-animat. Celle-ci est réalisée par l'intermédiaire de littéraux spéciaux, et elle ne peut se faire qu'entre deux objets liés, par exemple le bras et l'avant bras, ...

Un objet de type macro-animat doit pouvoir accéder à ses micro-animats (ses fils). Aussi, il peut avoir besoin de communiquer avec son père. Mais les fonctions PROLOG n'étant pas encore disponibles, il ne peut le faire qu'en appelant des littéraux du père. Voici la syntaxe utilisée pour chacun des cas :


* Acces à un fils :

NomLitteral/NomFils(<arguments>)


* Acces à son père :

NomLitteral/FATHER(<arguments>)


Si le littéral demandé n'existe pas chez le fils ou le père, la recherche se poursuit sur l'objet suivant (en appliquant à nouveau l'indexation) jusqu'à ce qu'il n'y en ait plus; dans ce dernier cas, l'unification échoue.

Si un micro-animat dispose de la règle "Chercher(*objet)" qui le fait se déplacer vers l'"objet", un macro-animat le comportant peut le commander de la façon suivante :


action

- #MonBut(*o) ; Variable interne contenant l'objet à attraper

- Chercher/Bras(*o) ; Réussie si sur l'objet. Le fils s'appelle 'Bras'

- Prendre(*o)

-#MonBut. ; L'objet est pris : attend le prochain


L'intégration de la communication dans in VITRAM est réalisée par la classe CELL_EXTERNE qui hérite de CELL_ARBRE.


3. Etude des liaisons


Une articulation est un objet qui permet de rattacher deux autres objets par une certaine liaison. Par exemple un bras est lié au corps par une liaison rotule.

Les articulations sont définies dans in VITRAM par héritage de la classe OBJET. Chaque articulation contient trois matrices. La première est la matrice de changement de repère entre les deux objets attachés. Les deux autres contiennent les différentes bornes inférieures et supérieures correspondant aux diverses translations et rotations.


Les mouvements des articulations sont générés par leurs comportements. Pour ce faire, l'utilisation de la cinétique inverse serait la bienvenue. Néanmoins celle-ci nécessite la résolution d'un système d'équations dont la dimension augmente de façon exponentielle avec le nombre de liaisons. Bien que des algorithmes récursifs aient été mis au point, réduisant le temps de calcul, leur mise en oeuvre EIFFEL demanderait encore trop d'opérations. C'est pourquoi une solution relativement simple a été recherchée. Cette méthode porte le nom de force virtuelle.

La demande de déplacement est considérée comme une force virtuelle appliquée à l'objet à déplacer. L'articulation, sur laquelle il est lié, apporte une certaine contribution à ce déplacement, en fonction de ses degrés de liberté et de ses capacités. Puis, elle passe le vecteur mouvement restant (après soustraction et modification du repère) à l'objet suivant, et ainsi de suite (Fig. 7.2). Les contributions peuvent modifier certaines coordonnées correctement placées; afin de garder les mouvements cohérents, on peut alors utiliser la méthode des moindres carrés appliquées aux participations.



Cette méthode ne propose pas une solution optimale comme dans le cas de la cinétique inverse, mais elle a l'avantage d'être simple et rapide.

L'objet suivant dépend du sens de parcours des objets : il peut être dans le sens macro-animatðfils, ou filsðmacro-animats. La dernière solution devrait donner de meilleurs résultats. Enfin, il est possible de relancer le vecteur résultant d'un parcours, afin d'obtenir lors de sa stabilisation, les commandes optimales. L'itération peut se faire par enchaînement d'indexations.




VIII-Conclusion et perspectives



L'intégration des clones au projet in VITRAM permet de définir des simulations où se mèlent utilisateurs, animats et processus informatiques. Par actions sur les personnages, les clones d'opérateurs peuvent modifier l'animation, jusqu'à la diriger.

Le séquenceur temporel et les variables internes simplifient l'écriture des comportements. Il est alors possible d'obtenir des simulations difficilement réalisables auparavant. De plus l'existance d'un algorithme permettant la transcription d'un grafcet en base de règles donne une idée des ressources contenues dans le langage de description.

Bien que les articulations n'aient pas été implantées, les macro-animats peuvent être utilisés en association avec des animats afin d'obtenir des micro-animations simples; par exemple, une liaison glissière ou le mouvement d'une roue de voiture sont facilement réalisables par l'indexation de littéraux, avec passage de paramètres (angle de rotation, ...). De cette façon , les personnages paraissent plus vivants.


La mise en oeuvre complète des macro-animats devrait ouvrir un espace d'animation beaucoup plus étendu. L'encapsulation des comportements qui en découlera facilitera l'écriture de personnages complexes.

La réalisation de littéraux évaluables autorisant la destruction de certains personnages ou le changement de paramètres innés (squelette, masse, ...) permettrait, par l'intermédiaire de clones superviseurs, un système intègre de simulation : un utilisateur s'assimilant à un réalisateur. Aussi, le système pourrait obtenir une puissance équivalente à celle donnée par l'interface graphique (GLOO 1) de in VITRAM.

A cette fin, il faudrait paralléliser le simulateur (ou le coder dans un langage plus rapide); en effet, la vitesse d'exécution est insuffisante pour permettre une réelle intégration d'utilisateurs. Toutefois, l'évaluation des clones doit se poursuivre pour en dégager de nouvelles applications.

Enfin l'intégration de personnages intelligents commandés par réseaux de neurones ou algorithmes génétiques rendra l'interaction et la simulation plus attrayante, puisque ces derniers ont un comportement adaptatif.



1GLOO : The Graphic Library Object Oriented

Bibliothèque mise à la disposition de l'ANL (Agence Nationale du Logiciel) 1992




Partie 4





Exemples



Les robots bâtisseurs

(construction d'un mur)



L'objectif de cette simulation est la construction d'un mur par l'intermédiaire de plusieurs animats. Le comportement proposé est divisé en trois buts. Les deux premiers sont la recherche de la prochaine brique à prendre et du lieu où la poser (le plus proche); le dernier est la construction du mur.


;********************************************************************

;* Les variables internes :

;* - *Maison : Vecteur donnant le lieu d'origine du robot

;* - *Mur : Vecteur donnant le lieu du mur

;* - *Brique : Brique a aller chercher

;* - *Lieu : Vecteur ou poser la brique

*

;* Le robot doit voir le mur dans son etat initial, et au moins une brique

;********************************************************************



;********************************************************************

;* COMPORTEMENT GENERAL DU ROBOT

;********************************************************************


; Memorisation de l'etat initial :

but

- MemoMaison.

; Recherche de la future brique :

but

- MemoBrique.

; Recherche du futur lieu :

but

- MemoLieu.

; Construction du mur a partir de ces 2 informations :

but

- Construire.


;********************************************************************

;* MEMORISATION DE DONNEES INITIALES

;********************************************************************


; 1/Memorisation de sa 'maison' = lieu initial.

; Si le robot ne trouve pas de brique, il y retourne pour en prendre.

; C'est en quelque sorte son lieu d'approvisionnement priviligie.

; 2/Memorisation du lieu du mur : le robot doit le voir de sa position

; initiale

; 3/Initialise la recherche de brique sur la maison, et le lieu au mur


MemoMaison

- *Maison (Current)

- BriqueMaison

- Voit (*o)

- Type (*o, MUR)

- *Mur (*o)

- LieuMur

- Set_But (Current, MemoMaison, -1).


;********************************************************************

; Place la maison comme le lieu ou chercher les briques


BriqueMaison

- *Maison (*o)

- *Brique (*o) .


;********************************************************************

; Place le mur comme lieu ou poser les briques


LieuMur

- *Mur (*o)

- *Lieu (*o) .


;********************************************************************

;* MEMORISATION DE LA DERNIERE ET PLUS PROCHE BRIQUE

;********************************************************************


MemoBrique

- MajBCourante

- Voit (*b)

- Type (*b, BRIQUE)

- Libre (*b, Current, 0.0)

- GardeBProche (*b).


; Mise a jour de la brique memorisee : existe elle encore, pour longtemps ?

; Si plus de brique en vue => on place la maison en memoire

; 'BRIQUE' peut contenir une brique, et dans ce cas on fait les tests,

; ou elle peut contenir le robot (pour la position initiale) : on ne

; fait alors rien.


MajBCourante

- *Brique (*b)

- Type (*b, BRIQUE)

- ExisteB (*b)

- Cut.

MajBCourante.


; On a une brique, on verifie si elle peut toujours nous etre accessible


ExisteB (*b)

- Voit (*b)

- Cut

- BriqueMaison

- Libre (*b, Current, 0.0)

- *Brique (*b).

ExisteB (*b)

- PeutVoir (Current, *b)

- BriqueMaison.


; Garde la brique la plus proche (ou celle qui n'est pas le lieu d'origine)


GardeBProche (*b)

- *Brique (*v)

- Type (*v, BRIQUE)

- Cut

- PlusProche (Current, *b, *v)

- *Brique (*b).

GardeBProche (*b)

- *Brique (*b).


;********************************************************************

; Dit si un animat est plus proche d'un objet (o1) que d'un autre (o2)


PlusProche (*an, *o1, *o2)

- Distance (*an, *o1, *d1)

- Distance (*an, *o2, *d2)

- SupEg (*d2, *d1).


;********************************************************************

; Dit si un objet est libre (si personne ne s'y dirige)

; 'br' si a 1 indique que l'on s'interresse aux personnes

; possedant une brique


Libre (*o, *nous, *br)

- Voit (*an)

- GestionPossede (*an, *br)

- Neg (*an, *o)

- Collision (*an, *o, *d, 3)

- PlusVieux (*an, *nous)

- Cut

- Impasse.

Libre (*o, *nous, *br).


; Si 'b' = 1, 'a' doit avoir une brique

; Si 'b' = 0, 'a' ne doit pas en avoir


GestionPossede (*a, *b)

- Possede (*a, BRIQUE)

- Cut

- Sup (*b, 0.5).

GestionPossede (*a, *b)

- Sup (0.5, *b).


;********************************************************************

;* RECHERCHE UN LIEU OU POSER LA BRIQUE

;********************************************************************


; S'inspire de MemoBrique


MemoLieu

- Voit (*m)

- Type (*m, MUR)

- Raconte (Current, *m)

- MajLCourant

- Place (*x, *y, *z)

- Vecteur (*l, *x, *y, *z)

- Libre (*l, Current, 1.0)

- GardeLProche (*l).


; Mise a jour du lieu memorise : existe il encore, pour longtemps ?

; Si plus de place en vue => on place le mur en memoire.

; 'LIEU' peut contenir un lieu, et dans ce cas on fait les tests,

; ou il peut contenir le mur (pour la position initiale) : on ne

; fait alors rien.


MajLCourant

- *Lieu (*b)

- Type (*b, VECTEUR)

- ExisteL (*b)

- Cut.

MajLCourant.


; On a un lieu, on verifie si il peut toujours nous etre accessible


ExisteL (*b)

- Libre (*b, Current, 1.0)

- Position (*b, *x, *y, *z)

- Place (*x, *y, *z)

- Cut.

ExisteL (*b)

- LieuMur.


; Garde le lieu le plus proche (ou celui qui n'est pas le mur)


GardeLProche (*l2)

- *Lieu (*l)

- Type (*l, VECTEUR)

- Cut

- PlusProche (Current, *l2, *l)

- *Lieu (*l2).

GardeLProche (*l2)

- *Lieu (*l2).


;********************************************************************

; CONSTRUCTION

;********************************************************************


Construire

- PrendreBrique

then

- PoserBrique.


; On va chercher une brique


PrendreBrique

- *Brique (*b)

- Aller (Current, *b)

then

- Prendre (Current, *b).


; On la pose sur le mur


PoserBrique

- *Lieu (*l)

- Aller (Current, *l)

then

- *Mur (*m)

- Poser (Current, NUL, *m, *l).


;********************************************************************

; Se deplace jusqu'a arriver au but


Aller (*o, *l)

- Trajet (*o, *l, 2.0, *dir, *acc, *ok)

- Position (*dir, *x, *y, *z)

- SeDiriger (*x, *y, *z)

- Va

- GereAcc (*acc)

- Sup (*ok, 0.5)

- Stop.


; L'acceleration est incluse dans 'AllerVers'


GereAcc (*acc)

- Sup (*acc, 0.0)

- Cut.

GereAcc (*acc)

- Stop.


La course à pied






La simulation proposée permet à un personnage (par exemple le clone de l'utilisateur) de diriger une course entre animats. Pour cela, il doit disposer d'un bras; lorsqu'il le lève, les animats se regroupent sur la ligne de départ, et quand il le baisse, ils se dirigent vers l'arrivée.



; Partie : COMPORTEMENT DES SPORTIFS


;********************************************************************

; AGIR

; On se repose jusqu'a ce que l'on apercoive l'arbitre lever le bras.

; On va alors se placer sur la ligne de depart, et on se met en position.

; Des que l'arbitre baisse le bras, on court jusqu'a l'arrivee. Puis

; on se repose a nouveau, etc...


agir

- se_promener ; Repos

- voit(bras)

- annonce(bras, 1) ; Bras a l'horizontal

then

- s_orienter_vers(depart)

- avance

- sur(depart)

then

- s_orienter_vers(bras)

- annonce(bras, 2) ; Bras en l'air

then

- s_orienter_vers(arrivee)

- voit(bras)

- annonce(bras, 0) ; Bras baisse

then

- courir .


;********************************************************************

; SE_PROMENER

; Tant que l'on ne depasse pas une certaine distance / au centre du

; jeu, on continue a avancer dans la direction courante .

; Des que l'on depasse cette limite, on se tourne vers l'arbitre et on prend

; une autre direction.


se_promener

- distance_ok

- avance .

se_promener

- s'orienter_vers(bras)

- rnd(*a) ; Angle alpha de 0 a 1

- mult(*a, 20, *i) ; Nbre intermediaire de 0 a 20

- moins(*i, 10, *b) ; Angle beta de -10 a +10 degres

- tourne(*b) .


;********************************************************************

; DISTANCE_OK

; Calcul la distance du sportif au centre du jeu. On obtient

; un succes tant que cette distance n'est pas trop importante.

; On pourrait par ex. prendre comme critere : "distance < distance

; de vue".


DistanceOk

- position(current, *x, *y, *z)

- direction(current, *dx, *dy, *dz)

- mult(*dx, 5, *ddx)

- mult(*dy, 5, *ddy) ; Tient compte de l'orientation

- mult(*dz, 5, *ddz)

- plus(*x, *ddx, *rx)

- plus(*y, *ddy, *ry)

- plus(*z, *ddz, *rz)

- carre(*rx, *rx, *cx)

- carre(*ry, *ry, *cy)

- carre(*rz, *rz, *cz)

- plus(*cx, *cy, *r1)

- plus(*cz, *r1, *r2)

- racine(*r2, *r) ²; Pour lisibilite

- inf(*r, 200) .


;********************************************************************

; ANNONCE

; Un objet n'a que quelques directions privilegiees :

; Vers le bas (0), a l'horizontal (1) ou vers le haut (2)

; Les autres dependent de notre orientation.

; On renvoie alors 0, 1 ou 2 suivant la position de l'objet.


annonce(*o, *r)

- direction(*o, *x, *y, *z)

- angle(*x, *y, *z, 0, 0, -1, *a) ; Angle des 2 vecteurs

- abs(*a, *b)

- ann_aux(*b, *r) .


ann_aux(*a, *r)

- inf(*a, 45)

- cut

- eg(*r, 0) . ; Vers le bas


ann_aux(*a, *r)

- inf(*a, 135) ; 90+45

- cut

- eg(*r, 1) . ; A l'horizontal


ann_aux(*a, *r)

- eg(*r, 2) . ; Sinon, vers le haut


;********************************************************************

; S_ORIENTER_VERS


s_orienter_vers(*o)

- voit(*o)

- cut .

s_orienter_vers(*o)

- tourne(10)

- impasse .


;********************************************************************

; SUR

; Succes si on se trouve sur l'objet


sur(*o)

- position(current, *x, *y, *z)

- PresDe(*o, *x, *y, *z, 5) .


;********************************************************************

; COURIR


courir

- s_orienter_vers(arrivee)

- accelerer(20) ; Accelere de 20%

- avance

- sur(arrivee)

then

- AnnulAcc

- freiner(20) ; Freine de 20%

- vitesse(*v)

- inf(*v, 5) .




Bibliographie



[AUDUREAU 90] E. Audureau, P. Enjalbert, L. Farinas del Cerro

"Logique temporelle"

Ed. Masson


[BERGERON 85] P. Bergeron, P. La Chapelle

"Tony de Peltrie".

Film, SIGGRAPH'85 Film Show, San Francisco, 85.


[CAUBET 88] R. Caubet, Y. Duthen, V. Gaildrat

"VOXAR : A tridimensional Architecture for Fast Realistic Image

Synthesis".

Proceedings of CGI'88 pp.135-149, Springer-Verlag, Genève, Mai


[DUMEUR 91] Renaud Dumeur

"Extended classifiers for simulation of adaptative behavior"

Proceedings of the First International Conference On Simulation

Behavior

From Animals to Animats. The MIT Press. pp 58-63


[DUTHEN 87] Y. Duthen

"Présentation du projet VOXAR".

Rapport interne L.S.I. N°280bis. Mars 87


[DUTHEN 93] Y. Duthen

"Les projets VOXAR et in VITRAM".

Habilitation à diriger des recherches, UPS Toulouse, mars 93


[FERBER 88] J. Ferber, M. Ghallab

"Problématiques des univers Multi-agents intelligents"

Journées Nationales du PRC IA, Toulouse, mars 88


[HAHN 88] J. Hahn

"Realistic Animation of Rigid Bodies".

SIGGRAPH'88 Conference Proceedings, Vol 22 n°4, pp 199-208


[ISAACS 87] P. Isaacs, M. Cohen

"Controlling Dynamic Simulation with Kinetic Constraints".

SIGGRAPH'87 Conference Proceedings; juillet


[JESSEL 92] J.P. Jessel

"Modélisation par réseau d'atome pour la représentation d'objets et

pour l'illumination globale".

Thèse de doctorat de l'université Paul Sabatier; Janvier 91


[KENNA 90] M. Mc Kenna and David Zelter

"Dynamic Simulation of Autonomous Legged Locomotion"

Computer Graphics, Vol 24, n°4, août


[KOREIN 82] J. Korein, N. Badler

"Techniques for Generating the Goal-Directed Motion of

Articulated Structures".

IEEE Computer Graphics and Applications, Vol 2 n°9, pp 71-81


[KOZA 91] J. Koza

"Evolution and Co-Evolution of Computer Programs to Control

Independently-Acting Agents".

Proceedings of the First International Conference On Simulation

Behavior

From Animals to Animats. The MIT Press. pp 366-375


[LUGA 93] H. Luga

"Etude des algorithmes génétiques et conception d'un système

génétique multi-représentations".

Rapport de stage de D.E.A.. Juin 93


[MAES 91] Pattie Maes

"A bottom-up mechanism for behavior selection in an artificial

creature"

Proceedings of the First International Conference On Simulation

Behavior

From Animals to Animats. The MIT Press. pp 238-246


[MAGNENAT 87] Magnenat-N. Thalmann, D. Thalmann

"The direction of Synthetic Actors in the film "Rendez-vous à

Montréal".

IEEE Computer Graphics and Applications, Vol 12, pp 9-19

[MEYER 86] B. Meyer

"Eiffel : Programming for Reusability and Extensibility".

Technical report TR-EI-4/IN, Version 1.2

Interactive Software Enginering Inc (novembre 86)


[MOULI 91] R. Mouli

"Système orienté objet pour la simulation comportementale".

Rapport de stage de D.E.A.. Juin 91


[MOULI 93a] R. Mouli, Y. Duthen, R. Caubet

"Un système de simulation comportementale orienté objet pour

l'animation intelligente".

Interface to real & virtual worlds 92, pp 111-121, Montpellier.


[MOULI 93b] R. Mouli, Y. Duthen, R. Caubet

"In VITRo AniMats, a behavioural simulation model".

IEEE International Workshop on Robot and Human

Communication


[PIERCE 91] D. Pierce, B. Kuipers

"Learning Hill-Climbing Functions as a Strategie for Generating

Behaviors in a Mobile Robot"

Proceedings of the First International Conference On Simulation

Behavior

From Animals to Animats. The MIT Press. pp 327-336


[PITOT 91] P. Pitot

"Conception et réalisation d'une machine parallèle dédiée à la

synthèse d'images réalistes : la machine VOXAR".

Thèse de doctorat de l'université Paul Sabatier; Janvier 91


[RAINJONNEAU 92] S. Rainjonneau

"Un modèle Orienté-Objet pour la simulation comportementale".

Thèse de doctorat de l'université Paul Sabatier; 92


[RANDALL 91] Randal D. Beer and Hillel J. Chiel

"The Neural Basis of Behavioral Choice in an Artificial Insect"

Proceedings of the First International Conference On Simulation

Behavior

From Animals to Animats. The MIT Press. pp 247-254


[REYNOLDS 87] C. Reynolds

"Flocks, Herds and Schools : A Distributed Behavioral Model".

SIGGRAPH'87 Conference proceedings, Vol 21, n°4, pp 25-34


[SNOWDON 93] D. N. Snowdon, Adrian J. West, Toby L.J. Howard "Towards the next generation of Human-Computer interface"

Interface to Real & Virtual Worlds, pp 399-408, Montpellier


[WEST 92] A.J. West, Howard, Hubbold, Murta, Snowdon, Butler

"AVIARY : A Generic Virtual Reality Interface for Real

Applications"

Virtual Reality Systems, Londres, mai 92.


[WILHELMS 87] J. Wilhelms

"Towards Automatic Motion Control".

IEEE Computer Graphics and Applications, Vol 7 n°4, pp 11-22


[ZELTZER 82] Zelter

"Motor Control Techniques for Figure Animation".

IEEE Computer Graphics and Applications, Vol 2 n°9, pp 53-60


[ZUNIGA 94] L. Zuniga

Rapport de stage de GNAM - A paraître.



Pour nous contacter : siteclic.aro.microclic.com en remplaçant '.aro.' par @
3 requêtes