This chapter will discuss a two examples in detail to illustrate the use of net nodes and SharedObjects.
The example shows a green sphere which rotates 360 degrees when clicked. This is not very interesting in a single world alone, but because we use a net node to transmit the starting event, other users sharing this world with you will see it rotate and can also start it. Here is a link to the example world.
Now we take a look at the source code.
#VRML V2.0 utf8 # the PROTO of the NetworkSFBool node for transmitting SFBool events PROTO NetworkSFBool [ eventIn SFBool set_value eventOut SFBool value_changed eventIn SFBool value_fromnet eventOut SFBool value_tonet exposedField SFString tag "" exposedField SFBool pilotOnly TRUE field SFBool localCopy TRUE exposedField SFBool echo TRUE exposedField SFBool cont FALSE ] { Script { eventIn SFBool InSc IS set_value eventOut SFBool OutSc IS value_changed eventIn SFBool netInSc IS value_fromnet eventOut SFBool netOutSc IS value_tonet field SFBool local IS localCopy directOutput TRUE mustEvaluate TRUE url "javascript: function InSc(value) { netOutSc = value; if( local == true ) OutSc = value; } function netInSc(value) { OutSc = value; } " } }
First we have the PROTO node defining the net node NetworkSFBool used for transmitting SFBool events. It is taken from the matrix_protos.wrl file defining all net nodes implemented yet.
# the central Group node holding all information for the Matrix System DEF MATRIX_CORE Group { children [ DEF MATRIX_TRACKER ProximitySensor { size 100000 100000 100000 }, Viewpoint { position 0 1 10 }, DEF NET NetworkSFBool { tag "bool" }, NavigationInfo { speed 5 }, Background { skyColor [ 0.9 0.9 0.9 ] groundColor [ 0.1 0.1 0.6 ] }, ] }
Then there is the Group node MATRIX_CORE with a number of child nodes. First the ProximitySensor node used to track the users position and orientation. Then a Viewpoint, NavigationInfo and Background node setting some properties of the world. And finally an instantiation of the net node NetworkSFBool. It sends its events to any node named bool, in this case to all copies of itself.
DEF GREENBALL Transform { translation 0 0 0 children [ DEF TOUCH TouchSensor{}, DEF TIMER TimeSensor { loop FALSE cycleInterval 5 }, DEF ENGINE OrientationInterpolator { key [ 0, .5, 1] keyValue [ 0 1 0 0, 0 1 0 3.14, 0 1 0 6.28] }, Shape { appearance Appearance { material Material { diffuseColor 0 1 0 } } geometry Sphere { radius 1.5 } } ] } DEF CONTROLLER Script { eventIn SFBool start eventOut SFTime startTime url ["javascript: function start( value, time ){ if( value == TRUE ) startTime = time; } "] }
Then there is some geometry defining a green sphere and a TouchSensor. Finally we have a simple script node which takes a SFBool event and puts out the events time stamp as a SFTime event.
ROUTE TOUCH.isActive TO NET.set_value ROUTE NET.value_changed TO CONTROLLER.start ROUTE CONTROLLER.startTime TO TIMER.set_startTime ROUTE TIMER.fraction_changed TO ENGINE.set_fraction ROUTE ENGINE.value_changed TO GREENBALL.set_rotation
All these nodes are connected with these ROUTEs. If a user clicks on the green sphere an SFBool event is send from the TouchSensor to the net node. The net node sends it to the controller script which generates an SFTime node with the time stamp of the SFBool event and sends it to the startTime exposedField of the TimeSensor node. This starts the TimeSensor which generates fraction_changed events turning the sphere with the help of an orientationInterpolator node. this is basic VRML stuff.
But the net node also transmits an event to other client applets running the same world. There the copies of this node generate also SFBool events to the controller script, thus starting the animation in all copies simultaneously.
This example describes a little SharedObject acts like a simple whiteboard displaying three different textures. The displayed texture can be selected by clicking on one of three buttons below the board. This object can be loaded into any DeepMatrix world by a user and all users can then work with it and change the texture by clicking the buttons.
The following VRML file defines the SharedObject. You can find this file here board.wrl.
#VRML V2.0 utf8 PROTO NetworkSFInt32 [ eventIn SFInt32 set_value eventOut SFInt32 value_changed eventIn SFInt32 value_fromnet eventOut SFInt32 value_tonet exposedField SFString tag "" exposedField SFBool pilotOnly TRUE field SFBool localCopy TRUE exposedField SFBool echo TRUE exposedField SFBool cont FALSE ] { ... } # SharedObject PROTO PROTO SharedObject [ exposedField SFBool isPilot TRUE exposedField SFString name "" exposedField MFNode children [] exposedField SFVec3f position 0 0 0 exposedField SFRotation orientation 0 0 1 0 eventIn SFBool set_isVisible eventOut SFBool isVisible_changed exposedField MFString url [] exposedField SFBool isAvatar FALSE exposedField MFNode states [] ] { ... }
First we define all the PROTOs that we need. In this case this is the NetworkSFInt32 NetworkState to share the value of a whichChoice field in a switch node. And the SharedObject PROTO for the object definition itself. Then we start with the object definition.
SharedObject { children [ # Here goes the geometry DEF SW Switch { whichChoice 0 choice [ Transform { children Shape { appearance Appearance { texture ImageTexture { repeatS TRUE repeatT TRUE url "grass0.jpg" } } geometry Box { size 2 2 0.1 } } translation 0 2 0 }, Transform { children Shape { appearance Appearance { texture ImageTexture { repeatS TRUE repeatT TRUE url "leaf0.gif" } } geometry Box { size 2 2 0.1 } } translation 0 2 0 }, Transform { children Shape { appearance Appearance { texture ImageTexture { repeatS TRUE repeatT TRUE url "sky0.gif" } } geometry Box { size 2 2 0.1 } } translation 0 2 0 } ] } # switch end Transform { children [ Shape { appearance Appearance { material Material { specularColor 0.9 0.9 0.9 emissiveColor 1 0 0 } } geometry Box { size 0.5 0.5 0.1 } }, DEF Button1 TouchSensor {} ] translation -0.75 0.467181 0 } Transform { children [ Shape { appearance Appearance { material Material { specularColor 0.31 0.77 0.8 emissiveColor 0 0.87 0 shininess 0.03 } } geometry Box { size 0.5 0.5 0.1 } }, DEF Button2 TouchSensor {} ] translation 0 0.45306 1.3411e-007 } Transform { children [ Shape { appearance Appearance { material Material { specularColor 0.8 0.78 0.77 emissiveColor 0.74 1 0.09 shininess 0.05 } } geometry Box { size 0.5 0.5 0.1 } }, DEF Button3 TouchSensor {} ] translation 0.75 0.471992 -2.86847e-007 }, DEF Control Script { eventIn SFBool b1 eventIn SFBool b2 eventIn SFBool b3 eventOut SFInt32 choice url "javascript: function b1( value ){ if( value == true ){ choice = 0; } } function b2( value ){ if( value == true ){ choice = 1; } } function b3( value ){ if( value == true ){ choice = 2; } }" } # This is the NetworkState node we use DEF Net NetworkSFInt32 { tag "choice" echo FALSE localCopy TRUE } ] # end children
The definition of the SharedObject is in children. Here is all the geometry and the script we need to control the texture switching defined. Furthermore the NetworkState node is defined here. Following that we put the ROUTEs we need to make it work.
ROUTE Button1.isActive TO Control.b1 ROUTE Button2.isActive TO Control.b2 ROUTE Button3.isActive TO Control.b3 ROUTE Control.choice TO Net.set_value ROUTE Net.value_changed TO SW.whichChoice
Finally we reuse the NetworkState node to fill the states field of the SharedObject node. This way the DeepMatrix system can access the NetworkState node and transmit its value to the other clients.
states [ USE Net ] }
The Shout3D version is very similar, besides the changes to the geometry. The script is replaced by a custom node called Control. The source of this node can be found in the custom_nodes directory in the source tree.