http://tecfa.unige.ch/ico/navi/tex2html/top.gifhttp://tecfa.unige.ch/ico/icons/vrml97-icon.gif next up previous contents index
Next: 5.3 Introduction to Scripting Up: 5. Introduction to moving, Previous: 5.1 The idea

Subsections


   
5.2 Introduction to Events, Routes, Sensors and Interpolators

The basis for animation is to dynamically change the values of a given object's fields. Lets imagine that you want to rotate an object and you that have a geometry node embedded in a Transform node like in the following example:

DEF Tecfa Transform {
   rotation  0 1 0  0
   children [
      Inline { url "inter-persons-2.wrl" }
     ]
}
In order to rotate the object, you want to able to change the value of the rotation field.

Events:

All exposed fields of a VRML node can be changed via incoming events. E.g. if you look at the definition of the Transform node, you can see that you can for example scale or rotate or translate and object, and even add or remove nodes from its children.

Transform {
  eventIn      MFNode      addChildren
  eventIn      MFNode      removeChildren
  exposedField SFVec3f     center           0 0 0
  exposedField MFNode      children         []
  exposedField SFRotation  rotation         0 0 1  0
  exposedField SFVec3f     scale            1 1 1
  exposedField SFRotation  scaleOrientation 0 0 1  0
  exposedField SFVec3f     translation      0 0 0
  field        SFVec3f     bboxCenter       0 0 0
  field        SFVec3f     bboxSize         -1 -1 -1
}
In addition to fields, most VRML nodes have so-called =>Events slots which are distinct from the ``fields'' you already encountered. There are two kinds of events:
1.
``eventIN'', i.e. incoming events that are messages sent by other nodes to change some state (field) within the receiving node.

2.
``eventOUT'', i.e. outgoining events used to send messages (events) to destination nodes. ``eventOUT'' slots are less frequent (mostly sensor nodes).

In addition to specific ``eventIN'' and ``eventOUT'' definitions, all the exposedFields implicitly define events too:

1.
You would use e.g. LIGHT.set_on to change the value of the ``on'' field in a PointLight node named ``LIGHT''

2.
and LIGHT.on_changed to propagate the state of the changed ``on'' field to other nodes (via a ROUTE statement).
See below for examples.

   
Routes:

In order to connect a node generating a message (event) with an other node receiving a message you must use a ``ROUTE'' statement. A node that produces events of a given type can be routed to a node that receives events of the same type with the following syntax:

      ROUTE NodeName.eventOutName TO NodeName.eventInName
Remember this: you can only connect fields of nodes that are exactly of the same type, else you will have to write a script in between as you will learn later.

Here are two examples of such a route statement:

  ROUTE LIGHT_CONTROL.isActive TO LIGHT.set_on
  ROUTE Random.feeling_changed TO Hasard.set_consequence
Since you can ONLY route messages that are exactly of the same data type, it might be a good idea now to start mastering all of VRML's data types (see section 8.4 on page [*]).

Sensors:

Usually Events are triggered by sensors. A variety of =>Sensor Nodes allow you to detect what and when something happens. We will discuss a few of them in the next sections. Now let's look at a simple TouchSensor example. The =>Touch Sensor node is defined as follows:  

TouchSensor
  exposedField SFBool  enabled TRUE
  eventOut     SFVec3f hitNormal_changed
  eventOut     SFVec3f hitPoint_changed
  eventOut     SFVec2f hitTexCoord_changed
  eventOut     SFBool  isActive
  eventOut     SFBool  isOver
  eventOut     SFTime  touchTime
The TouchSensor generates events as the pointing device ``passes over'' any geometry nodes that are descendants of the TouchSensor's parent group. In the code below we will make use of the ``isActive'' field which will change it's value from FALSE to TRUE whenever the user points to it (e.g. moves the mouse ``over'' it and holds down a button). As soon as the state of this field changes, the contents of the field (TRUE or FALSE) is ROUTEed to a PointLight node.

A simple sensor switches light example

Before reading further on, you might want to have a look at the example.

Example 5.2.1   A Simple Touchsensor Effect  

VRML: ../examples/anim/anim-touch-1.wrl
Source: ../examples/anim/anim-touch-1.text

Click on the ``switch'' and the blue sphere will be lit while you hold down the mouse. Holding down the mouse over the sensor means that the LIGHT_CONTROL.isActive is TRUE, releasing the mouse makes it FALSE again.

Here are the important parts of the code:

# A TouchSensor
#(in the same group as a geometry object so that it can be seen)
#
Transform {
   translation 0.5 1 5
   children [
      DEF LIGHT_CONTROL TouchSensor {
      }
      Inline { url ["light-switch.wrl"] }
     ]
}

# The light, off when the file is loaded
#
DEF LIGHT PointLight {
   on   FALSE
   location     -3 2 2
}

# The object to be lit in here:
#
 ......

ROUTE LIGHT_CONTROL.isActive TO LIGHT.set_on

As you can see in the following definition of the =>PointLight node, it has an exposedField (i.e. accessible field) called ``on''. All the ROUTE statement above does, is to define a connection between the sensor's isActive event to the PointLight's set_on event (i.e. to the value of the on field of PointLight. As in other GUIs it's the browser that will handle the routing of user actions (events) to sensors, i.e. they will become active. Below we give the complete definition of PointLight and you can see that there is indeed a exposedField ``on'' and therefore implictely a set_on event defined. [Yes I know, a section on lights is missing in this manual.]

PointLight {
  exposedField SFFloat ambientIntensity  0 
  exposedField SFVec3f attenuation       1 0 0
  exposedField SFColor color             1 1 1 
  exposedField SFFloat intensity         1
  exposedField SFVec3f location          0 0 0
  exposedField SFBool  on                TRUE 
  exposedField SFFloat radius            100
}

Of course you can also make light switches that will turn on some light permanently but (if I am not wrong) you have to do this with some scripting (see section 5.3.1 on page [*] that does exactly this). But before we look into scripting, let's learn a few more things about events.

   
5.2.1 TimeSensors and Rotations with Interpolators

[Warning, this section is difficult reading. Have to rewrite this at some point. Study the examples while you digest the text]

In this section you will meet first an other sensor, the TimeSensor which can be used for example to produce ``ticks'' that will get an animation going for a certain time and with a certain speed. Then we introduce the concept of an interpolator, i.e. a node that can generate numbers to producde an animation path.

Time Sensors:

The =>TimeSensor is a kind of =>Time Dependant Node. TimeSensors generate events as time passes. TimeSensors can be used to drive continuous simulations and animations, periodic activities (e.g., one per minute), and/or single occurrence events such as an alarm clock. Each Time Dependant Node contains the exposedFields: startTime, stopTime and loop and the eventOut isActive. Time dependant nodes are inactive until startTime is reached. Once active (isActive = TRUE), they will excute for 0 or more cycles until stopTime is reached or loop becomes FALSE. Note that they will ignore stopTIME if stopTime < startTime. To sum it up:

Here is the full definition of TimeSensor

TimeSensor {
  exposedField SFTime   cycleInterval 1
  exposedField SFBool   enabled       TRUE
  exposedField SFBool   loop          FALSE
  exposedField SFTime   startTime     0
  exposedField SFTime   stopTime      0
  eventOut     SFTime   cycleTime
  eventOut     SFFloat  fraction_changed
  eventOut     SFBool   isActive
  eventOut     SFTime   time
}
Note that VRML time is not human readable. =>SFTime are the number of seconds since Jan 1 1970. In the example that follows we will simply use it to get an animation going as soon as the user loads a world. I.e. the node below will just run eternally as soon as you load the file.

DEF TIME TimeSensor {
   cycleInterval        20
   startTime    0
   stopTime     -1
   loop         TRUE
}
When a TimeSensor becomes active it will generate an isActive = TRUE event and begin generating time, fraction_changed, and cycleTime events, which may be routed to other nodes to drive animation or simulated behaviors. The two most important output events are: We will discuss more about those events in the example further down.

We route the fraction_changed event to a so called OrientationInterpolator whose time-sensor triggered output is then sent to the object we are rotating. In order to guarantee a smooth animation, it will compute vaious orientation points as you will learn below.

   
The Orientation Interpolator

Let's look at the =>OrientationInterpolators which is one kind of VRML's =>Interpolators. In short, they allow you do simple animations (e.g.rotate objects, move objects around, change colors of things). An interpolator will generate values based on ``clues'' defined by a set of keys (received from the set_faction eventIn) and a set of corresponding keyValues. In other words, it will automatically compute intermediate positions for each time_fraction. You only have to specify a few to get it going like in the example below. Key Values are of a different type for each Interpolator. Here is the definition for the OrientationInterpolator:

OrientationInterpolator {
  eventIn      SFFloat    set_fraction
  exposedField MFFloat    key           []
  exposedField MFRotation keyValue         []
  eventOut     SFRotation value_changed
}

A simple Time Sensor/Orientation Interpolator example

You now can first look at the example before reading on.  

Example 5.2.2   A simple Timesensor Example  

VRML: ../examples/anim/anim-rotate-1.wrl
Source: ../examples/anim/anim-rotate-1.text

Below, you can see both the definition of the Orientation Interpolator and the ROUTE statements of the example world.

DEF Tecfa Transform {
   rotation  0 1 0  0
   children [ ..... ]
}

DEF TIME TimeSensor {
   cycleInterval        20
   ........
}


DEF OI_Tecfa OrientationInterpolator {
   key          [ 0 0.5 1 ]
   keyValue     [ 0 1 0  0, 0 1 0  3.1416, 0 1 0  6.2832]
}

ROUTE TIME.fraction_changed TO OI_Tecfa.set_fraction
ROUTE OI_Tecfa.value_changed TO Tecfa.rotation

The keyValue field is of type MFRotation, i.e. a comma separated set of orientation values that correspond to each element in the key field. In our example you can see that we rotate around the y axis (0 1 0) using orientations 0, 3.1416 and 6.2832. VRML now uses those positions to interpolate, i.e. to generate rotation values in between which are sent out with value_changed eventOUT each time the node receives a set_fraction eventIN.

The set_fraction event is of type SFFloat in the range of [0,1] and usually routed to from a TimeSensor's fraction_changed event. The fraction_changed event is an indicater in the range of [0,1] that tells how much of a complete cycle has elapsed so far. The duration of a cycle itself is defined in seconds by the cycleInterval field. E.g. in our example, the interval is 20 seconds.

DEF TIME TimeSensor {
   cycleInterval        20
    ......
}
Indeed, if you look again at this simple rotation example you can see that a full rotation lasts about 20 seconds. Rotation speed is constant, because we told the interpolator so with the key/keyValues.

To sum it up Interpolators:

The next example shows some more irregular rotation (randomly put together).

Example 5.2.3   A simple Timesensor Example II  

VRML: ../examples/anim/anim-rotate-2.wrl
Source: ../examples/anim/anim-rotate-2.text

Of course, eternal rotations can be annoying to the user and they certainly waste resources. Since (as far as I understand it) there is no way to start and stop animation at a given time after the scene has been loaded (time is in seconds starting some obscure date) you'd have to write a touchsensor that activates the rotation and do some Javascript for that.

   
5.2.2 More on Time Sensors and Interpolators

Let's see how to ``configure'' a TimeSensor according to your needs:

1.
Continously running:
   loop TRUE
   stopTime < startTime
2.
Runs one cycle and then stops:
   loop FALSE
   stopTime < startTime
3.
Runs until stopped, or after cycle is over:
   loop TRUE or FALSE
   stopTime >= startTime

The next example inspired from David Frerichs' exellent Creating Integrated Web Content with VRML 2.0 Tutorial In this example you can see something sliding forth and back once you click on the little red switch.

Example 5.2.4   A TouchSensor activating a Shuttle  

VRML: ../examples/anim/anim-shuttle-1.wrl
Source: ../examples/anim/anim-shuttle-1.text

Let's have a look at things that are new: When we load the file, the TimeSensor (called TimeSource here) has the loop = FALSE, so there will be no eventOUTs looping:

      DEF TimeSource TimeSensor { 
          cycleInterval 10
          loop FALSE
       }

Then we use a TouchSensor node (see section 5.2 on [*]) to activate the loop. More precisely, the Starter.isActive event (Touchsensor) is routed to TimeSource.set_loop (Timesensor). As soon as you click on the switch the loop will be turned on (and remain so). Here is the code of the switch and it's route:

     DEF Switch Transform {
         translation 2 -2 5
         children [
              DEF Starter TouchSensor { }
              Inline { url ["light-switch2.wrl"] }
              ]
     }
ROUTE Starter.isActive TO TimeSource.set_loop

  Finally, in order to move the object forth and back we use a =>PositionInterpolator that works more or less the same way as the OrientationInterpolator encountered in the previous section. The keyValue fields are the kinds of values (SFVec3f) that one uses in translation fields. Here is the other half of the code:

DEF TECFA Transform {
   translation 0 0 -50
   children [   
      DEF TimeSource TimeSensor { 
         cycleInterval 10
         loop FALSE
      }

      DEF Animation PositionInterpolator {
         key   [ 0, .50, 1.0 ]
         keyValue [ 0 0 -40, 0 0 6, 0 0 -40]
      }
      
      Inline { url "inter-persons-2.wrl" }
     ]
}
ROUTE TimeSource.fraction_changed TO Animation.set_fraction
ROUTE Animation.value_changed TO TECFA.translation


next up previous contents index http://tecfa.unige.ch/ico/navi/tex2html/top.gifhttp://tecfa.unige.ch/ico/icons/vrml97-icon.gif
Next: 5.3 Introduction to Scripting Up: 5. Introduction to moving, Previous: 5.1 The idea
D.K.S. - 1998-03-18