The object must first exist before it can be moved. Once it is defined, it must be placed inside a Transform node. The Transform node is a grouping node which means it can contain many nodes. This allows the VRML designer to move several objects at once. The Transform node can also contain other Transform nodes that already move an object. So if a designer wanted to create a human form, an arm object would be placed inside one Transform node, the other arm would be inside another Transform node and the whole body would be placed under a single third Transform node. Each arm could swing at different time rates and in different directions - the Transform node containing the arm would be manipulated. To move the whole body, manipulate the third Transform node; as the body moves forward, the arms would swing at their assigned rates, yet they would also move with the body.
The Transform node can also rotate objects, so the previous human object can sway while it moves forward. VRML uses the right-hand rule in determing rotation angles. The field type SFRotation ( 0 1 0 0 ) describes the angle the object will face. The first three numbers correspond to the three axis in the coordinate grid ( X Y Z 0 ). The fourth number is the angle in radians.
Degrees to Radians: 0 = 0; 45 = .78; 90 = 1.57; 135 = 2.35; 180 = 3.14; 225 = 3.92; 270 = 4.71; 315 = 5.48; 360 = 6.28.
Defining this field can get complicated. It is best to keep the values either zero or one; one refers to the axis of rotation, zero means ignore that axis. So a field definition of 0 1 0 .78 means rotate about the Y axis .78 radians. Using the right hand rule, wrap your right hand around the axis of rotation with your thumb pointing in the positive direction and rotate in the direction of your fingers. This example rotates a box 45 degrees:
Transform
{ rotation 0 1 0 .78
children Shape
{ appearance Appearance
{ material Material
{ diffuseColor 0 0 1 }
} # end Appearance node
geometry Box {size 4 2 5 }
} # end of Shape node
} # end Transform node
To move the box, define the translation field of the transform node. This will center the box around the point defined in the translation field. This won't cause the box to move while it's being viewed - it will be in the new position when the scene is rendered. To animate the box, the TimeSensor node is required. This node acts like a separate clock and can be used to start or stop a movement, either a translation or a rotation or both.
Interpolator nodes compute the values between a starting and ending value. The designer sets the main values so the interpolators do most of the work. There are 6 interpolator nodes; ColorInterpolator, CoordinateInterpolator, NormalInterpolator, OrientationInterpolator, PositionInterpolator, ScalarInterpolator. The PositionInterpolator is for movement while the OrientationInterpolator is for rotations. All interpolators have a key field, which ranges from 0 to 1. The designer can define intervals between these values to vary the amount of manipulation over time. All interpolators have a keyValue field which defines the value the object changes to.The interpolator computes the logical values between each keyValue value and each userdefined value must match up with a user defined Key value; there should be the same number of items in each field.
To complete the puzzle, these nodes need to be connected. Routes are used to essentially plug one field in a node to a field in another node. The only stipulation is that both fields must be the same type. So you route the TimeSensor fraction_changed node to the interpolator's set_fraction field. That's an eventOut field to an eventIn field. You can't route eventIns to eventIn or eventOuts to eventOuts. ( exposedFields have both eventIn and eventOut capabilities )
Next you route the interpolator's value_changed field to the Transform node's translation or rotation field. You don't have to worry about the Shape node itself, the Transform node controls the movement. To establish a route, the node has to be named. The DEF and USE features define a node and refer to a previously defined node. Put the userdefined name after the DEF or USE keyword and then continue on with the node definition. Once everything is all wired together, the object will perform the movement when the browser loads the scene - maybe.
The TimeSensor node determines when the manipulation will begin. As long as the stopTime value is less than the startTime value, the manipulation will occur. The cycleInterval field sets the time the manipulation will occur ( in seconds), the loop field determines if the manipulation will repeat itself, and the enabled field determines if the node will work at all ( TRUE means it will work ). This example will move the box from left to right:
DEF BlueBox Transform
{ rotation 0 1 0 .78
children Shape
{ appearance Appearance
{ material Material
{ diffuseColor 0 0 1 }
} # end Appearance node
geometry Box {size 2 3 5}
} # end of Shape node
} # end Transform BlueBoxDEF BoxTime TimeSensor
{ cycleInterval 4
loop TRUE
stopTime -1
} # end TimeSensor BoxTime DEF BoxMovement PositionInterpolator
{ key [ 0, .5, .6, 1]
keyValue [0 0 0, 10 0 0, 10 0 0, 0 0 0]
} # end PositionInterpolator BoxMovement ROUTE BoxTime.fraction TO BoxMovement.fraction
ROUTE BoxMovement.value TO BlueBox.translation
Notice that the two middle values in the key field of the PositionInterpolator node are close to each other in value. This causes the box to pause at the far right. Notice that there are 4 items in both the key and the keyValue fields - there must be a 1:1 correlation between the two fields. Notice that ROUTE and TO are capitalized - this is mandatory. Notice that there are no 'set' or 'changed' attachments to the route 'fraction' or 'value' tags: the browser knows what to do. Finally, notice that the box is still angled 45 degrees. This would change if the OrientationInterpolator was used and routed to the rotation field.
DEF BoxRotate OrientationInterpolator
{ key [ 0, .5, .9, 1]
keyValue [0 1 0 0, 0 1 0 3.13, 0 1 0 6, 0 1 0 6.28]
} # end PositionInterpolator BoxMovementROUTE BoxTime.fraction TO BoxRotate.fraction
ROUTE BoxRotate.value TO BlueBox.rotation
When rotating, VRML rotates to the desired angle via the shortest route. So if you were at .78 radians (45 degrees) and wanted to go to -.78 radians (315 degrees or -45 degrees), if you set the start value at .78 and the end value at -.78, the OrientationInterpolator would compute a path which would resemble a pendulum swinging back and forth. But if you wanted the object to rotate from .78 around to the -.78 angle, then you need to insert a middle value, like 3.14, midway between the two values.
DEF BoxRotate OrientationInterpolator
{ # rotates all the way around
key [ 0, .5, 1]
keyValue [0 1 0 .78, 0 1 0 3.14, 0 1 0 -.78]
} # end PositionInterpolator BoxMovementDEF BoxRotate OrientationInterpolator
{ # swings back
key [ 0, 1]
keyValue [0 1 0 .78, 0 1 0 -.78]
} # end PositionInterpolator BoxMovementDEF BoxRotate OrientationInterpolator
{ # swings back and forth
key [ 0, .2, .25, .6, .65, 1]
keyValue [ 0 1 0 0, 0 1 0 .78, 0 1 0 .78, 0 1 0 -.78,
0 1 0 -.78, 0 1 0 0 ]
} # end PositionInterpolator BoxMovement
Movement seems complicated but if you keep it simple, it is a straightforward exercise. Remember, once the movement starts, the object will take on the values of the keyValue field in the interpolator. So if it's original location is 0 0 0 and the starting value of the keyValue field is 0 2 0, the object will jump to the starting value once the TimeSensor node begins the manipulation. A VRML designer can move an object all over the world, stop it, start it again, and/or spin it around; whatever one can imagine!