Basic javascript in VRML (part 1)
Introduction
This tutorial page explains basic vrmlscript in particular directOutput and array access methods.
Functions and eventIns
This code below shows the usage of functions and eventIns. The name right after "function" is either the same as an eventIn, any name if only called by other functions or a special name.
Any number of eventIns can be defined in a Script node. They are in the form of :
eventIn *SFxxx/MFxxx* *name*
The special names have specific meanings for the browser. There are three special names, initialize, shutdown, eventsProcessed. Unlike other functions these do not produce values or timestamps.
DEF AnyScript Script {
eventIn SFBool someFunction1
eventIn SFVec3f someFunction2
url "javascript:
function initialize () {
// put any scripting or calls to other functions
// which are run at startup of the world here
}
function shutdown () {
// put any scripting or calls to other functions
// which are run at shutdown of the world here
}
function eventsProcessed () {
// This function is called when events are produced
// this is used in Scripts that do not rely on the order
// of events received to generate fewer events than
// using function calls
// eventIns can be accessed using their names
// for example
var x=someFunction1;
}
function someFunction1 (val,ts) {
// val = the value ROUTEd to this event
// This is the same field type as the eventIn for the function
// ts = Timestamp. The time this event occured
// This is generally the current time
// but this may longer be the case in longer scripts
}
function someFunction2 (val,ts) {
// call to another function
someFunction3 (val,1,"test",ts);
// (a,b,c,d )
}
function someFunction3 (a,b,c,d) {
// This function has no declared eventIn
// but can have multiple fields in calls to it
// note: lack of ts or Timestamp.
}
"
}
Fields and directOutput
This code below shows the usage of fields and directOuput methods. Script nodes have two special fields. directOutput which needs to be set to TRUE in order to change nodes/fields within the world. It is only needed when using USE to link a script field to a scene Node. The second special field is mustEvaluate which when set to TRUE forces the running of the Script node code to take priority over other functions of the VRML browser like rendering, animations, ROUTEd events etc.
Any number of fields can be defined in a Script node. Like They are in the form of :
field *SFxxx/MFxxx* *name*
In addition SFNode and MFNode fields may contain USE and/or normal VRML nodes/scene graphs.
Empty field values
Often there is the need to set fields to empty or default values.
For all MFxxx nodes this is simply []
For other field this goes as follows :
SFVec2f 0 0
SFVec3f 0 0 0 (unless used for scale when it should be 1 1 1).
SFColor 0 0 0
SFTime -1
SFBool FALSE (usually!)
SFString ""
SFRotation 0 1 0 0
for other fields refer to the reference values for the Node the value is applied to.
DEF Move Transform {
translation 10 0 0
children [
# ....
]
}
DEF AnyScript Script {
# A standard SFVec3f field
field SFVec3f offset 0 20 0
# A SFNode field which adds USE in order to access an scene Node
field SFNode Move USE Move
directOutput TRUE
url "javascript:
function initialize () {
// use the print command to print the values to the
// browser debug/error console
// print the value of offset
print (offset);
// print the value in Move.translation
print (Move.translation);
//use the add command to add the offset to Move.translation
Move.translation=offset.add(Move.translation);
// print the value in Move.translation
print (Move.translation);
}
"
}
EventOuts
This code below shows the usage of eventOuts. These produced events can the be ROUTEd to other Nodes in the world. Setting any eventOut to a value produces the eventOut.
Any number of fields can be defined in a Script node. Like They are in the form of :
eventOut *SFxxx/MFxxx* *name*
DEF Move Transform {
translation 10 0 0
children [
# ....
]
}
DEF AnyScript Script {
# A standard SFVec3f field
field SFVec3f offset 0 20 0
# A SFVec3f eventOut
eventOut SFVec3f translation_changed
url "javascript:
function initialize () {
// set translation_changed to equal offset
translation_changed=offset;
}
"
}
ROUTE AnyScript.translation_changed TO Move.translation
Array access
Array access is the method by which individual numbers can be accessed from values containing multiple values. For example accessing the x (left--right) values of a translation field or the second keyValue "key" of a OrientationInterpolator.
Values which contain multiple values are:
All MFxxx type values.
SFVec2f contains two values
SFVec3f, SFColor, contains three values
SFRotation contains four values
SFString, SFImage contains any number of values
There are two methods of accessing values which contain multiple numbers. The first is to use fieldName[0] where 0 is the entry accessed.
The second way is to use special sub fields which are specific to certain SFxxx/MFxxx values. For example SFVec3f has .x .y .z so to access the second value (y) use fieldName.y
SFVec2f/MFVec2f .x .y
SFVec3f/MFVec3f .x .y .z
SFColor/MFColor .r .g .b (red, blue, green)
SFRotation/MFRotation .x .y .z .angle
Many MFxxx values contain multiple numbers of SFxxx values which themselves contain serval values. These are the MFxxx versions of the SFxxx types listed above. The method of accessing such values is fieldName[0][0] where the first [0] accesses the SFxxx value and the second a value within the SFxxx value.
MFxxx values which contain arrays of single numbers are accessed the same way as SFxxx values which contain several values.
Code to access SFVec3f values
DEF AnyScript Script {
# A standard SFVec3f field
field SFVec3f offset 0 20 0
url "javascript:
function initialize () {
// print the second (1) value of offset
print(offset[1]);
print(offset.y);
}
"
}
Code to access MFVec3f values
DEF AnyScript Script {
# A standard MFVec3f field
field SFVec3f offset [ 0 20 0, 0 0 0 ]
url "javascript:
function initialize () {
// print the first (0) entry's second (1) value of offset
print(offset[0][1]);
print(offset[0].y);
}
"
}
Node field access
Following on from array access we look at how to access values within nodes. Also MFxxx values within nodes, for example the children node of Group and Transform Nodes, are accessed using the same methods as array access.
Code to access the diffuseColor value of a Shape Material.
DEF Sphere Shape {
appearance Appearance {
material Material {
diffuseColor .1 .44 .22
shininess .1
specularColor .15 .15 .02
ambientIntensity 0
emissiveColor .04 .18 .09
}
}
geometry Sphere {
radius 2
}
}
DEF AnyScript Script {
# A SFNode field which adds USE in order to access an scene Node
field SFNode Sphere USE Sphere
directOutput TRUE
url "javascript:
function initialize () {
// print diffuseColor of Sphere
// note the multiple field accesses using the , method
// to move through the Shape node
print(Sphere.appearance.material.diffuseColor);
}
"
}
Basic maths
Here we look at basic maths in javscript.
*variable*++
example i++; -- increment i by one
*variable*--
example i--; -- decrement i by one
*resultvariable*=*variable1* + *variable1*
example a=x+y; -- add x to y and put the result in a
*resultvariable*=*variable1* - *variable1*
example a=x-y; -- subtract x from y and put the result in a
*resultvariable*=*variable1* / *variable1*
example a=x/y; -- divide x by y and put the result in a
*resultvariable*=*variable1* * *variable1*
example a=x*y; -- times x by y and put the result in a
*resultvariable*=*variable1* % *variable1*
example a=x%y; -- divide x by y and put the remainder of the division in a
Increment i by one example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 i 1
url "javascript:
function initialize () {
print (i);
//i = i + 1
i++;
print (i);
}
"
}
Decrement i by one example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 i 1
url "javascript:
function initialize () {
print (i);
//i = i - 1
i--;
print (i);
}
"
}
a=x+y example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 a 0
# A standard SFInt32 field
field SFInt32 x 5
# A standard SFInt32 field
field SFInt32 y 5
url "javascript:
function initialize () {
print (a);
//a = x + y
a=x+y;
print (a);
}
"
}
a=x-y example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 a 0
# A standard SFInt32 field
field SFInt32 x 5
# A standard SFInt32 field
field SFInt32 y 5
url "javascript:
function initialize () {
print (a);
//a = x - y
a=x-y;
print (a);
}
"
}
a=x/y example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 a 0
# A standard SFInt32 field
field SFInt32 x 15
# A standard SFInt32 field
field SFInt32 y 5
url "javascript:
function initialize () {
print (a);
//a = x - y
//3 = 15 - 5
a=x/y;
print (a);
}
"
}
a=x*y example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 a 0
# A standard SFInt32 field
field SFInt32 x 5
# A standard SFInt32 field
field SFInt32 y 5
url "javascript:
function initialize () {
print (a);
//a = x - y
//25 = 5 x 5
a=x*y;
print (a);
}
"
}
a=x%y example
DEF AnyScript Script {
# A standard SFInt32 field
field SFInt32 a 0
# A standard SFInt32 field
field SFInt32 x 3
# A standard SFInt32 field
field SFInt32 y 2
url "javascript:
function initialize () {
print (a);
//a = x - y
//1 = 3 % 2
a=x%y;
print (a);
}
"
}
Part 2
Part 2 of this tutorial
Examples
Notes
Recommended field/eventIn/EventOut names.
In order to follow the system allready used in VRML events I recommend using the following
EventIns have set_ added to the beginning of the name.
EventOuts have _changed added to the end of the name.
For example.
|
field
|
eventIn
|
eventOut
|
|
translation
|
set_translation
|
translation_changed
|
|
rotation
|
set_rotation
|
rotation_changed
|
|