X3D example showing a flying model using Follower animation techniques
under development, instantReality works but BS Contact fails silently
Vrml97ToX3dNist, http://ovrt.nist.gov/v2_x3d.html
X3D-Edit 3.3, https://www.web3d.org/x3d/tools/X3D-Edit
"Roller Coaster with Twin Motion Trails" "Developed by Tom Kaye (tomk@sgi.com)" "Silicon Graphics Inc, 1997" "Created in CosmoWorlds" "Packaged by CosmoPackage" "PositionDamper and OrientationDamper nodes added by Herbert Stocker, www.hersto.com"
"Sky.x3d" "https://www.web3d.org/x3d/content/examples/Basic/Followers/Sky.x3d" "Sky.wrl" "https://www.web3d.org/x3d/content/examples/Basic/Followers/Sky.wrl"
"grass4.jpg" "https://www.web3d.org/x3d/content/examples/Basic/Followers/grass4.jpg"
ecmascript: function initialize() { if( Browser.getName() == 'blaxxunCC3D' // This also covers BS Contact VRML. || Browser.getName() == 'bsContactMP4' ) { AppFromBelow.texture= TexGrass; AppFromBelow.textureTransform= TexTransGrass; MatFromBelow.transparency= .6; MatFromBelow.emissiveColor= new SFColor(1, 1, 1); } }
ecmascript: function triggerIn(value, time) { // fire off a single round startTime = value; firstTime = false; }
ecmascript: function rawCoordinateIn(value, time) { offsetCoordinateOut = value.add(offsetFactor); }
ecmascript: ////////////////////////////////////////////////////////////////////// // author: -Tom Kaye, Silicon Graphics Inc, 1997 (tomk@sgi.com) // purpose: -Generate a polyline tail from a series of coordinates // passed into the script (one per clock-tick). // Lots of useful auxilliary info is returned as well. // input: -a series of position values // output: -a polyline consisting of the last maxPoints coordinates // passed into the script. // - position, orientation and speed of the head // of the motion path ////////////////////////////////////////////////////////////////////// function initialize() { position[0] = 0; position[1] = 0; position[2] = 0; last_position = position; direction = position; distance = 0; rotation = new SFRotation(initial_direction, direction); speed = 0; last_time = 0; current_time = 0; pointCount = 0; stepCount = stepSize; currentIndex = 0; coord.length = maxPoints; coordIndex.length = maxPoints + 3; for ( i = 0; i < coordIndex.length; ++i) { coordIndex[i] = -1; } } function reset(value, time) { position[0] = 0; position[1] = 0; position[2] = 0; last_position = position; direction = position; distance = 0; rotation = new SFRotation(initial_direction, direction); speed = 0; last_time = 0; current_time = 0; pointCount = 0; stepCount = stepSize; currentIndex = 0; coord.length = maxPoints; coordIndex.length = maxPoints + 3; for ( i = 0; i < coordIndex.length; ++i) { coordIndex[i] = -1; } } function set_isVisible(value, time) { isVisible = value; isVisible_changed = isVisible; } function set_isActive(value, time) { if (value != isActive) { isActive = value; isActive_changed = isActive; if (isActive == true) { reset_trigger = time; } } } function set_position(value, time) { last_position = value; // a bogus assignment if ( isActive ) { // skip every stepSize points if ( stepCount >= stepSize ) { stepCount = 0; // update the coordIndex with as few operations as possible if ( pointCount <= maxPoints ) { // first pass as tail grows from 0 to maxPoints in length // and coordIndex consists of only one polyline if ( pointCount < maxPoints ) { coordIndex[currentIndex + 1] = currentIndex; coordIndex[currentIndex + 2] = -1; } else { // occurs once: currentIndex == pointCount == maxPoints coordIndex[currentIndex + 1] = 0; coordIndex[currentIndex + 2] = -1; currentIndex = 0; coordIndex[currentIndex ] = currentIndex; coordIndex[currentIndex + 1] = -1; } } else { // subsequent passes when tail is a constant length of maxPoints // and coordIndex consists of two polylines if ( currentIndex < maxPoints ) { coordIndex[currentIndex] = currentIndex; coordIndex[currentIndex + 1] = -1; } else { // occurs once each cycle when currentIndex == maxPoints coordIndex[currentIndex ] = 0; coordIndex[currentIndex + 1] = -1; currentIndex = 0; coordIndex[currentIndex ] = currentIndex; coordIndex[currentIndex + 1] = -1; } } // save last position and time to later compute direction and speed last_position = position; position = value; last_time = current_time; current_time = time; // add the new position to the coordinate array ring-buffer coord[currentIndex] = position; position_changed = position; // echo position value as an output // compute direction based on last two points passed in direction = position.subtract(last_position); distance = direction.length(); // compute a new rotation only if there has been some finite movement if ( distance >= 0.00001 ) { rotation = new SFRotation(initial_direction, direction); } // Compute speed and output results only if two or more points have been // passed in since initialization or last reset if ( pointCount >= 1 ) { // compute speed speed = distance / (current_time - last_time); rotation_changed = rotation; speed_changed = speed; // outpout the coord and coordIndex arrays only when appropriate if (isVisible ) { coord_changed = coord; coordIndex_changed = coordIndex; } else { coordIndex_changed = nullcoordIndex; } } // increment the appropriate counters currentIndex += 1; // cycles between 0 and maxPoints (length of tail) pointCount += 1; // total number of points processed since reset } // end stepCount block stepCount += 1; } }
ecmascript: ////////////////////////////////////////////////////////////////////// // author: Tom Kaye, Silicon Graphics Inc, 1997 (tomk@sgi.com) // purpose: Generate absolute WingTip coordinates from a single // position and rotation value. // input: position and rotation of a vehicle // output: absolute coordinates of left and right wingtips ////////////////////////////////////////////////////////////////////// function set_vehiclePosition(value, time) { vehiclePosition = value; rightWingtipCoordinate_changed = vehiclePosition.add( vehicleRotation.multVec(rightOffsetVector) ); leftWingtipCoordinate_changed = vehiclePosition.add( vehicleRotation.multVec(leftOffsetVector) ); } function set_vehicleRotation(value, time) { vehicleRotation = value; }