Projet HUMANS
Animation en VRML

Introduction

On dispose de deux méthodes pour animer des objets:

Mécanisme à base d'évènements

Un objet sera animé soit à l'aide d'une horloge (un type particulier de capteur) soit par la détection d'un évènement utilisateur (type clic de souris) que l'on récupèrera grâce à des capteurs. Les animations sont décrites par des suites de valeurs discrètes que l'on lisse grâce à des interpolateurs.

Evènements

Un évènement est un message envoyé d'un noeud vers un autre noeud selon une ROUTE. Il signale des stimuli externes, des changements de valeur des champs, des interactions entre noeuds. Un évènement est défini dans un noeud et consiste en une valeur temporelle (timestamp) qui marque le moment où il s'est produit et un champ de type:

Afin de pouvoir être référencés par une route, les noeuds évènements doivent être nommés en utilisant DEF, par exemple:

DEF name node {
...
}

Interpolateurs

Un noeud interpolateur définit une interpolation linéaire f sur un intervalle de valeurs clés t croissantes distinctes (key) auxquelles correspondent les valeurs f(t) (keyValue).

typeInterpolator {
    eventIn      SFFloat      set_fraction         # reçoit un évènement float
                                                     (fraction de temps générée
                                                     par un TimeSensor)
                                                     ce qui provoque l'évaluation
                                                     de l'interpolation et déclenche
                                                     l'émission de value_changed
    exposedField MFFloat      key           [...]  # paramètres
    exposedField MF<type>     keyValue      [...]  # valeurs
    eventOut     [S|M]F<type> value_changed        # contient la valeur interpolée
                                                     correspondant au paramètre
                                                     reçu dans set_fraction
}

Le type peut être:

Capteurs

Ce type de noeud permet à l'utilisateur d'interagir avec le graphe de scène. Il répond aux interactions utilisateur/objets géométriques, aux mouvements de l'utilisateur à l'intérieur du monde virtuel ou au défilement du temps. Ces noeuds capteurs (sensor nodes) sont des noeuds enfants et doivent être apparentés à des noeuds de groupement comme les Group nodes.
Chaque capteur définit quand un évènement est généré, et le traitement s'effectue dans l'ordre. Les différents type de capteurs (sensor nodes) sont:

TimeSensor

TimeSensor {
  exposedField SFTime cycleInterval 1.0  # durée d'un intervalle de temps en s
  exposedField SFBool enabled TRUE       # activation de l'horloge
  exposedField SFBool loop FALSE         # génération continuelle des évènements
  exposedField SFTime startTime 0.0      # date de début d'émission des évènements,
                                           en s à partir du début de la scène
  exposedField SFTime stopTime 0.0       # date de fin d'émission des évènements,
                                           en s à partir du début de la scène
  eventOut SFTime cycleTime              # évènements en sortie:
  eventOut SFFloat fraction_changed      # fraction_changed sera utilisé en entrée
                                           d'un interpolateur
  eventOut SFBool isActive              
  eventOut SFTime time
}

Rque: pour créer une animation en boucle infinie, il suffit de positionner loop sur TRUE, startTime et stopTime sur la même valeur, 0 si on veut que l'animation démarre dès l'ouverture de la scène.


TouchSensor

TouchSensor { 
  exposedField SFBool  enabled TRUE         # capteur valide ou non
  eventOut     SFVec3f hitNormal_changed    # émis lorsque isOver est vrai
                                              et que la souris bouge,
                                              contient la normale à la surface
                                              de la géométrie associée
  eventOut     SFVec3f hitPoint_changed     # idem, mais contient les coords du point
                                              de la géométrie associée
                                              pointé par la souris
  eventOut     SFVec2f hitTexCoord_changed  # idem, mais contient les coords de texture du point
                                              de la géométrie associée
                                              pointé par la souris
  eventOut     SFBool  isActive
  eventOut     SFBool  isOver               # vrai lorsque la souris passe sur la géométrie à associée
  eventOut     SFTime  touchTime            # émis lorsque isActive passe à TRUE
                                              ou à FALSE, et lorsque isOver est TRUE
}

Routes

Une route définit la connexion entre un noeud qui génère un évènement et un noeud qui reçoit cet évènement. Les routes ne sont pas des noeuds mais de simples déclarations, qui doivent apparaître après la définition des noeuds auxquels elles font référence.

L'exemple suivant montre comment définir des routes pour faire sauter un personnage sur place continuellement:

DEF Avatar Transform {
  children [
    Shape {
      ...
    }
  ]
}

DEF Animation Group {
  children [
	  DEF Jump PositionInterpolator {
	    key [ 0, 0.5, 1 ]
	    keyValue [ 0 0 0, 0 1 0, 0 0 0 ]
	  }
	  DEF Time TimeSensor {
	    cycleInterval 1
	    startTime 0
	    stopTime 0
	    loop TRUE
	  }
  ]
}

ROUTE Time.fraction_changed TO Position.set_fraction
ROUTE Position.value_changed TO Avatar.translation

Exemple

L'exemple suivant permet de faire faire des battements de jambes à un personnage h-anim:

#VRML V2.0 utf8

# PROTOs h-anim .....

DEF BIP Humanoid {
  # description h-anim ...
}

DEF Ground Transform {
  # description du sol
}

WorldInfo {
  title "Bip L0"
  info ""
}
NavigationInfo {
  avatarSize [ 0.56, 1.85, 0.43 ]
  headlight TRUE
  speed 1
  type "EXAMINE"
}

# decription de l'animation Battement:
DEF Battement Group {
  children [
    # Interpolateurs de rotation sur les hanches et chevilles
    DEF r_ankleRotInterp_Battement OrientationInterpolator {
      key [ 0, 0.1, 0.25, 0.4, 0.5, 0.75, 1 ]
      keyValue [ 0 0 1 0, 0 0 1 0, 1 0 0 0.785, 0 0 1 0, 0 0 1 0, 0 0 1 0, 0 0 1 0 ]
    }
    DEF r_hipRotInterp_Battement OrientationInterpolator {
      key [ 0, 0.25, 0.5, 0.75, 1 ]
      keyValue [ 0 0 1 0, 0 0 1 -0.785, 0 0 1 0, 0 0 1 0, 0 0 1 0 ]
    }
    DEF l_ankleRotInterp_Battement OrientationInterpolator {
      key [ 0, 0.25, 0.5, 0.6, 0.75, 0.9, 1 ]
      keyValue [ 0 0 1 0, 0 0 1 0, 0 0 1 0, 0 0 1 0, 1 0 0 0.785, 0 0 1 0, 0 0 1 0 ]
    }
    DEF l_hipRotInterp_Battement OrientationInterpolator {
      key [ 0, 0.25, 0.5, 0.75, 1 ]
      keyValue [ 0 0 1 0, 0 0 1 0, 0 0 1 0, 0 0 1 0.785, 0 0 1 0 ]
    }
    # Horloge associée
    DEF Time_Battement TimeSensor {
      cycleInterval 4
      startTime 0
      stopTime 0
      loop TRUE
	  }
  ]
}

# définition des routes

# les changements de temps de l'horloge sont envoyés aux différents 
# interpolateurs
ROUTE Time_Battement.fraction_changed TO r_ankleRotInterp_Battement.set_fraction
ROUTE Time_Battement.fraction_changed TO r_hipRotInterp_Battement.set_fraction
ROUTE Time_Battement.fraction_changed TO l_ankleRotInterp_Battement.set_fraction
ROUTE Time_Battement.fraction_changed TO l_hipRotInterp_Battement.set_fraction

# les valeurs interpolées à chaque pas de temps sont envoyées
# comme valeurs d'entrée aux transformations des joints correspondants
ROUTE r_ankleRotInterp_Battement.value_changed TO hanim_r_ankle.set_rotation
ROUTE r_hipRotInterp_Battement.value_changed TO hanim_r_hip.set_rotation
ROUTE l_ankleRotInterp_Battement.value_changed TO hanim_l_ankle.set_rotation
ROUTE l_hipRotInterp_Battement.value_changed TO hanim_l_hip.set_rotation

Fichier complet pour tester/visualiser: BipHigh_h-anim_battement.wrl

Liens utiles