Advanced javascript in VRML

Introduction

This tutorial page assumes a good understanding of vrmlscript in particular directOutput and array access methods.

Translation event and animation contol

This example uses a Script node to control the animation of a black ball across a surface. The source which produces the translation values (in this case a TouchSensor's hitPoint_changed event) produces occasional values and not a continious stream which is usual for animations.

In addition the Script stores in incoming values and moves smoothly from one point to the next at a constant movement rate of 10 meter per second. When the previous animation finishes it retrieves the next stored value and then beings a new animation after disgarding the last value.

DEF Ground Group {
 children [
  DEF Sensor TouchSensor {}
  Shape {
   appearance Appearance {
    material Material {
     diffuseColor .1 .44 .22
     shininess .1
     specularColor .15 .15 .02
     ambientIntensity 0
     emissiveColor .04 .18 .09
    }
   }
   geometry IndexedFaceSet {
    solid FALSE
    coord Coordinate {
     point [
      -10 0 -10, 10 0 -10, -10 0 10, 10 0 10,
     ]
    }
    coordIndex [ 2, 3, 1, 0, -1, ]
   }
  }
 ]
}

DEF MainTranform Transform {
 children [
  DEF Offset Transform {
   translation 0 0.5 0
   children [
    Shape{
     appearance Appearance {
      material Material {
       diffuseColor 0 0 0
       specularColor .5 .5 .5
       ambientIntensity 0
       emissiveColor .15 .15 .15
      }
     }
     geometry Sphere {
      radius 0.5
     }
    }
   ]
  }
  DEF Timer TimeSensor {
   cycleInterval 1
   startTime -1
  }
  DEF Move PositionInterpolator {
   key [ 0, 1 ]
   keyValue [ 0 0 0, 0 0 0 ]
  }
  DEF OffsetScript Script {
   eventIn SFVec3f set_translation
   eventIn SFBool timerIsActive
   eventOut SFTime startTime
   field SFNode Timer USE Timer
   field SFNode Move USE Move
   field MFVec3f storedValues []
   field SFBool timerActive FALSE
   field SFVec3f currentLocation 0 0 0
   field SFVec3f l_ 0 0 0
   field SFFloat distance 0
   url "javascript:
    function set_translation (val,ts) {
     if (timerActive) {
      // if timer is running add new value to the end of the stack
      storedValues[(storedValues.length)+1]=val;
     }
     else {
      // else calculate the distance between the current
      // location and the next next stored on then begin the animation
      l_[0]=currentLocation[0]-(val[0]);
      l_[1]=currentLocation[1]-(val[1]);
      l_[2]=currentLocation[2]-(val[2]);
      // the length of this vector is the distance between
      // the two points
      distance = l_.length();
      // animation interval = distance/10 meters per second movement rate
      Timer.cycleInterval=distance/10;
      // set animation keyValues
      Move.keyValue[0]=currentLocation;
      Move.keyValue[1]=new SFVec3f((val.x),(val.y),(val.z));
      //start Timer
      startTime=ts;
      currentLocation=val;
     }
    }
    function timerIsActive (val,ts) {
     timerActive=val;
     if ((!timerActive)&&((storedValues.length)>0)) {
     // if the timer is inactive and there are stored values
     // retrive the stored value and call the above function
      set_translation(storedValues[storedValues.length-1],ts);
     // decrease the number of stored values by one removing the
     // above used value
      storedValues.length=storedValues.length-1;
     }
    }
   "
  }
 ]
}
# route status of pointer and timer to Script
ROUTE Sensor.hitPoint_changed TO OffsetScript.set_translation
ROUTE Timer.isActive TO OffsetScript.timerIsActive

# animation routes
ROUTE OffsetScript.startTime TO Timer.startTime
ROUTE Timer.fraction_changed TO Move.set_fraction
ROUTE Move.value_changed TO MainTranform.translation

Examples

The above example in completed form Translation event and animation contol

Modified version of example with extra code explained in notes below added. Touchsensor fix

Notes

One know problem with the above example is the pointer is not over the Ground geometry the hitPoint_changed event reverts back to 0 0 0. This only effects the above example and I have chosen not to add the aditional code as it would complicate the example code.

A simple solution would be to use the isOver event produced by the TouchSensor the check if the 0 0 0 value is due to the pointer no longer being over the Ground geometry and ROUTEing this to a new function in the Script node which then keeps track.

If the source of the translations values is another source (for example a ProximitySensor or another Scipt) this additonal code would be unneeded.

The Graphics and 3D content of this site are the works of the author unless noted otherwise. The Unauthorized use of any of this site's content for commercial or other uses is strictly forebidden.