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