Sensors

In order to implement the behaviour of a virtual world, we need to pass events between nodes. In VRML, data (events) flow from the eventOut field of one node to an eventIn field of the same datatype of another node. The receiving node may respond to the event by processing it, and generating further events, and/or use it to update one of it's fields.

For example:

  • A set of events of type SFBool (a boolean value) could be passed to a script node that performs a logical AND operation. If all of the SFBool values are true, then the script would generate an SFBool event with the value TRUE, otherwise it would generate an SFBool event with the value FALSE. The node processes the incoming event and outputs an event.
  • A TimeSensor node could be activated by routing an SFBool value from a script node (e.g. the AND node mentioned above) to it's 'enabled' field, thus updating the value of that field and controlling the TimeSensor.

However, events need to come from somewhere, and this is where sensors come in. Sensors generate events. The TimeSensor, which is commonly used to control animations (see the Animation module of this course) generates fraction values that can be passed to an interpolator. Most of the other VRML sensors generate events as the result of a user action (e.g. clicking on an object) or user proximity:

The standard VRML97 sensors are:

  • TouchSensor
  • TimeSensor
  • CylinderSensor
  • PlaneSensor
  • SphereSensor
  • ProximitySensor
  • VisibilitySensor

In addition to these, the Collision group node and the Anchor node can also be used to detect user interaction and generate events.

TouchSensor

A TouchSensor detects a mouse (actually, any pointing device) event over any of the shapes in the same group (including the group's children) as the sensor.

The TouchSensor has six eventOut fields that generate events depending on what user actions are sensed. The most commonly used of these are:

  • isActive - Generates TRUE (SFBool) when the mouse button is pressed on a sensed shape and FALSE when it is released
  • isOver - Generates TRUE (SFBool) when the cursor is over a sensed shape and FALSE when the user moves the cursor off the sensed shape
  • touchTime - When the user releases the mouse button (ie when isActive generates a FALSE event), an SFTime event is generated containing the absolute time.

In addition to the eventOut fields above, the TouchSensor has an 'exposedField' called 'enabled' which can be set to TRUE or FALSE. This can be used to turn the sensor on/off by routing SFBool events to it. The default value is TRUE so to create an active TouchSensor, you just need to add DEF a_name TouchSensor{} to a Group's children in order to add an active sensor to the group. Note that you need to name the sensor, otherwise you will not be able to route events to or from it.

For example (to use a TouchSensor to activate a TimeSensor using the TouchSensor's touchTime):

DEF Clock TimeSensor {
   enabled FALSE
   cycleInterval 5.0
}
DEF Touch TouchSensor {}

ROUTE Touch.touchTime TO Clock.set_startTime

Route diagram for the code above:

TimeSensor

The TimeSensor is a clock that generates events.

The node's exposed fields are:

  • enabled - if this SFBool value is true then the sensor generates events, otherwise it is inactive
  • startTime - the absolute time at which the clock should start generating events (if it is enabled)
  • stopTime - the absolute time at which the clock should stop generating events
  • cycleInterval - the length of time the sensor takes to vary it's fractional time output between 0.0 and 1.0
  • loop - this SFBool value specifies whether the clock should loop or not.
    • If the value is FALSE then the sensor plays up to one cycle only. If stopTime has not been specified then it (stopTime) is set to startTime + cycleInterval.
    • If the value is TRUE then the sensor loops continously. If stopTime has been specified then it will stop looping at the specified time, otherwise it will loop forever.

The fields above are used to configure the TimeSensor, to determine when events should be generated. The TimeSensor's eventOut fields are used to route events from the TimeSensor to other nodes.

  • isActive - generates a TRUE event when the sensor becomes active and starts to output events, and FALSE when it stops
  • cycleTime - generates the absolute time value each time a cycle starts over
  • time - generates an absolute time value continuously, as long as the sensor is generating fraction_changed events
  • fraction_changed - generates an SFFloat value between 0.0 and 1.0 as the clock progresses through the cycle.

We can build on the previous example by routing the fraction_changed value of the TimeSensor to an interpolator, which in turn outputs values that are routed to a Transform group, thus playing the animation every time the TouchSensor detects a mouse click.

A complete VRML example of how to start an animation when the user touches a shape:

#VRML V2.0 utf8
Group {
  children [
    DEF GreenBox Transform {
      children [
        Shape {
          appearance Appearance {
            material Material {
              diffuseColor 0.0 1.0 0.0
            }
          }
          geometry Box {}
        }
      ]
    },
    DEF Touch TouchSensor {},
    DEF Clock TimeSensor {
      cycleInterval 2.0
    },
    DEF Path OrientationInterpolator {
      key [ 0.0 0.5 1.0 ]
      keyValue [
        0.0 1.0 1.0 0.0,
        0.0 1.0 1.0 3.14,
        0.0 1.0 1.0 6.28
      ]
    }
  ]
}

ROUTE Touch.touchTime        TO Clock.set_startTime
ROUTE Clock.fraction_changed TO Path.set_fraction
ROUTE Path.value_changed     TO GreenBox.set_rotation

Route diagram for the code above:

Advanced interactive simulations can be created using a combination of TouchSensors (to generate initial events), Scripts (to determine what to do with them) and TimeSensors to play resulting animations. For example, to create an interactive door, you could attach a TouchSensor to a door shape and route the touchTime to a Script so that the Script generates an event to start an animation to either open or close the door depending on whether the door was open or closed when it was clicked on.

We will look at how scripts can be used to do this a little later in this module.

CylinderSensor, PlaneSensor, and SphereSensor

These sensors are are used to detect mouse drag motion that can (for example) be used to translate objects depending on user actions.

The CylinderSensor generates SFRotation values around the Y axis, as if the user is rotating a cylinder.

The SphereSensor generates SFRotation values, as if the user is rotating a ball.

The PlaneSensor outputs values in the XY plane of the sensor's parent coordinate system when the sensor is active.

The values outputed from these sensors can be routed directly to a Transform group, enabling the user to drag the sensed shape around (PlaneSensor), rotate it freely (SphereSensor) or rotate it around the Y axis (CylinderSensor).

CylinderSensor VRML Example:

#VRML V2.0 utf8
Group {
  children [
    DEF GreenBox Transform {
      children [
        Shape {
          appearance Appearance {
            material Material {
              diffuseColor 0.0 1.0 0.0
            }
          }
          geometry Box {
          }
        }
      ]
    },
    DEF Drag CylinderSensor { }
  ]
}

ROUTE Drag.rotation_changed TO GreenBox.rotation
A PlanseSensor can be used to translate a Transform group in planes other than XY by rotating the coordinate system of a group containing the sensor and the Transform group, and rotating the Transform group to compensate for the previous rotation.

Using PlaneSensor to move objects in XZ plane VRML Example:

#VRML V2.0 utf8
Group {
  children [
    Transform {
      # rotate coord system around X-axis so XY is in parents XZ
      rotation 1.0 0.0 0.0 1.57
      children [
        DEF TheObject Transform {
          # rotate back around X-axis to compensate for rotated
          # coord system of parent group
          rotation 1.0 0.0 0.0 -1.57
          children [
            Shape {
              geometry Box {}
              appearance Appearance {
                material Material {
                  diffuseColor  1 0 0
                }
              }
            }
          ]
        },
        DEF TheSensor PlaneSensor {}
      ]
    }
  ]
}

ROUTE TheSensor.translation_changed TO TheObject.set_translation

These sensors have a number of exposedFields that can be used to set constraints, which we will come back to in the next section of this module.

ProximitySensor, VisibilitySensor, and Collision

These sensor nodes generate events based on the user's location in the virtual environment as opposed to mouse clicks or mouse drag motion.

The Proximity sensor generates events if the user is within a user defined distance from a sensed group. It's eventOut fields include isActive, enterTime, exitTime, position_changed, and orientation_changed. The position and orientation changed values are positions within the sensed region, in the coordinate system of the ProximitySensor.

The VisiblitySensor senses whether a boxed shape area is visible to the user. EventOut fields are isActive, enterTime, and exitTime.

The Collision node is a group node that generates a collideTime event when the user collides with any shape within the group.




Michael Louka, October 31, 2001