On dispose de deux méthodes pour animer des objets:
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.
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 { ... }
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:
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 { 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 { 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 }
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
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