Ygdrasil is a framework created for developing networked virtual environments. It is focused on building the behaviors of virtual objects from re-usable components, and on sharing the state of an environment through a distributed scene graph mechanism. It has been used in the construction of numerous artistic and educational applications.
Ygdrasil is built in C++, around SGI's OpenGL Performer visual simulation toolkit and the CAVERNsoft QUANTA networking library. Performer provides a hierarchical representation of the virtual world database, called a scene graph. The scene graph is a tree that encodes the grouping of objects and nesting of 3D transformations, and provides tools for operations such as switching elements on or off.
Ygdrasil focuses on the rapid construction of dynamic, interactive virtual worlds, so in addition to the basic graphical data as used in Performer, its scene graph nodes can have behaviors (i.e. functions to update the state of nodes) attached to them. The system includes a number of nodes that implement common virtual world components - sounds, user avatars, navigation controls, timers, triggers that detect when a user enters an area, etc. An event based message passing facility allows nodes to be tied together to assemble large complex worlds from simple components. Nodes in the virtual world, such as triggers, can generate events to initiate the passing of messages to other nodes (i.e. when(enter,myLight.on)).
Although the included nodes will accomodate a great number of interactions, it may be desirable to create new nodes to modify the existing behavior or bring in external data such as web-based content. Individual nodes are derived from a common class and use a plugin facility based on Dynamic Shared Objects (DSO's) to allow for the rapid modification or the addition of new nodes. New components can be easily added by taking one of the classes, such as a transformation node, and deriving a subclass with the new features.
The Ygdrasil framework is unique in that it seamlessly extends the scene graph to be shared across the network. In a shared system, each participant has his own local copy of the common scene graph. Node data, such as lists of nodes' children, transformation matrices, and model information, are automatically distributed among these participants as the data changes or when participants first join the shared world. Each particular node is considered to be owned by the host that creates it. As a result, specialized node behaviors can be calculated by the owning host and clients can join a world without needing anything beyond the standard, core node types.
Ygdrasil runs on Linux and IRIX unix based systems. A windows based version is in development. The following installation instructions apply to both IRIX and Linux based systems. Ygdrasil relies on users having the directory /usr/local/bin in their path. The bash shell usually includes this directory in the path of each user.
Performer
Ygdrasil uses SGI's OpenGL Performer simulation library. The software with a
permanent demo license can be downloaded from www.sgi.com.
Follow the installation instructions provided by SGI. The RPM based installation
is recommended over using tar files. Once installed, the installation can be
verified by typing
perfly
at the command prompt. If the Performer logo appears to move slowly, you may
not be running with hardware acceleration. Type
glxinfo
and look for the phrase "direct rendering". If "no" is indicated then you may
need to update your graphics card drive of XWindows configuration.
Bergen
Ygdrasil requires the Bergen Sound Server for playing sample files and other
sound related functions. Download the latest version of Bergen from the downloads
section. Login as root, and place the tar file in the installation location,
usually /usr/local. Untar the file:
tar -xvzf bergen_0.6.X.tar.gz
Change directory into the directory created by the tar file. If installing in
a location other than the default, then edit the Makefile to change the variable
BERGEN_DIR. Execute the following:
make install
A symbolic link named bergen will be created at /usr/local
pointing to the installation directory. And, symbolic links will be placed in
/usr/local/bin that point to a number of Bergen executables.
Ygdrasil
Download the latest version of Ygdrasil from the downloads
section. Login as root, and place the tar file in the installation location,
usually /usr/local. Untar the file
tar -xvzf ygdrasil_0.4.X.tar.gz
Change directory into the directory created by the tar file. If installing in
a location other than the default, then edit the Makefile to change the variable
YG_DIR. Execute the following:
make install
A symbolic link named yg will be created at /usr/local
pointing to the installation directory. And, symbolic links will be placed in
/usr/local/bin that point to the Ydrasil executables.
Versions of Ygdrasil distributed to the public require a valid CAVElib license
to operate. In order to customize the simulator interface for use with the Ygdrasil
graphical interface, a number of configuration lines are added to the default
cave.config file located in /usr/local/CAVE/etc.
Some prior versions of Ygdrasil were installed directly into the /usr/local/yg directory. If you want to retain your prior version then move it to a version specific directory before starting the installation (i.e. mv /usr/local/yg /usr/local/yg_0.1.X). For installation on the IRIX operating system, add a line in etc/yg.config to set the ARCHITECTURE variable to sgi.
For the Windows version, login as administrator and extract the zip file to the C: drive. This will a create directory under Program Files called Ygdrasil with the yg_0.4.X directory below it. Browse to the win32 directory and double click on the the vcredist_x86.exe executable. For each user, login and browse to the win32 directory and double click on the install.bat batch file. This will create a My Ygdrasil directory under the My Documents directory of the current user.
Ygdrasil creates virtual worlds by interpreting scripts stored in text files.
A number of example scripts, known as scene files, are included with the system.
You can execute the example scene file named example1.yg by typing
yg example1.yg
at the command prompt. This example file creates a terrain, a spinning banana,
and another banana that prints a message to the shell window when you point
at it.
The window that appears is called the simulation window and allows you to interact with the world using the mouse and keyboard. Pressing the TAB key alternates between controlling the user hand and the user viewpoint with the mouse. The arrow keys turn the user left and right and move the user forwards and backwards. Pressing the F5 key on the keyboard prints out a list of simulator commands in the shell window.
The application can be quit by pressing the esc key while focused on the simulation window. In addition, a number of commands can be entered directly into the shell window during runtime. Typing graph and hitting return lists the contents of the current scene and typing quit also quits the application.
Ygdrasil also comes with a graphical development environment for creating scene
files. The Ygdrasil GUI can be started by typing
yg
without a scene file at the command prompt. Interaction with the interface uses
standard point and click mouse interaction. Right clicking brings up a context
sensitive menu. There is an interactive tutorial that will walk you through the basic functions of the graphical interface.
Ygdrasil scenes are created by defining any number of nodes in a scene file.
The following script
ygEnvironment( skycolor(0.1 0.2 0.7) )
ygLight sun()
ygObject( file(ground.pfb) )
creates three nodes; a ygEnvironment
node, a ygLight node named
sun, and a ygObject
node. In this example, skycolor and file
are messages that initialize the properties of the environment and object nodes
respectively. The three float values (0.1 0.2 0.7)
and the string ground.pfb are arguments that set
the red, green, and blue of the skycolor and the name of the model file to load
respectively.
Nodes within scene files can be arranged in a tree structure with each node
having a single parent and any number of children nodes. Replacing the last
line of the previous example with the following lines
ygTransform( position(0 5 0) )
{
ygObject( file(ground.pfb) )
ygObject( file(tree.pfb) )
}
adds a ygTransform node
with two object nodes as its children. Like many nodes in Ygdrasil, only the
children of a transform are affected by its transformation. As a result, the
ground.pfb and tree.pfb
models are positioned 5 units down the Y axis from the origin of the world.
Syntax
Each node type created (i.e. environment, light, object, etc.) must be followed
by an open parenthesis and a closed parenthesis. The following example creates
a transform node:
ygTransform ( )
Each node can optionally be given a name by inserting it between the node type
and the parenthesis as follows:
ygTransform myTransform( )
And, optionally, any number of messages can be given to the node by enclosing
them within the parenthesis and separating them with commas as follows:
ygTransform myTransform( position(0 5 0), size(2) )
Finally, any number of node definitions such as above can be enclosed in braces
to indicate that they are children of the node:
ygTransform myTransform( position(0 5 0), size(2) )
{
ygObject( file(ground.pfb) )
ygObject( file(tree.pfb) )
}
Throughout this documentation the following notation with be used:
( ) | parenthesis | groups objects |
, | comma | indicates an AND relationship between objects |
| | vertical bar | indicates an OR relationship between objects |
[ ] | sqaure brackets | indicates objects are optional |
{ } | braces | indicates objects are optional and may be repeated 0 or more times |
' ' | single quotes | indicates that the actual character should be used |
Scene file syntax is formally represented as follows:
node_type [node_name] '(' [message] [,message] ')' [ '{'
{node_definition} '}' ]
When 2 nodes are given the same node name within a scene file, Ygdrasil will
attempt to rename the second occurance by incrementing an integer value at the
end of the node name. For example, a second occurance of myObject
will be named myObject1 while a second occurance
of myObject1 will be renamed myObject2.
Comments can be placed anywhere in the scene file by using either C++ style comments or standard C style comments. The C++ style comment indicator (//) can be placed anywhere in a line and will comment out the remainder of that line. All C++ style comments included in a scene file will be preserved when saving the scene from Ygdrasil. The C style comment indicator (/*) and terminator (*/) must be placed on separate lines, and C style comments will not be preserved when the scene file is saved. In addition, C style include directives (i.e. #include "file.yg") and macro substitution can be used within scene files.
Messages
Messages given to nodes usually consist of a message type followed by any number
of arguments inside parenthesis. In the following example
ygEnvironment myEnvironment( skycolor(0.1 0.2 0.7), fog(off),clip
)
the skycolor message type is given 3 floating point
arguments, the fog message type is given a single
string argument, and the clip message has no arguments.
Individual message arguments can be separated by either a space or a comma.
Each argument in a message has default values which will be used when the full
number of arguments are not given. For example, the following message:
skycolor(0.1 0.2)
will set the skycolor to (0.1,0.2,0.0) because the default skycolor values are
(0.0,0.0,0.0). The clip message actually takes 2
floats, but calling it without any arguments merely sets the values to the default.
The documentation for the ygEnvironment
node gives the following description:
fog | (off | lin | linear | exp | exp2), three floats, float, float | set the fog properties (type, color, onset, opaque) |
Messages place directly between the parenthesis of a node definition are called
initial messages because they set the initial properties
of the node when the world is created. By default, messages are directed to
the node within which they are placed, but they can optionally be preceded by
the name of another node
myEnvironment.skycolor(0.1 0.2 0.7)
in order to direct them to another named node within the scene. In addition,
the execution of messages can be delayed by adding a plus sign after the message.
In the following examples:
skycolor(0.1 0.2 0.7)+10
skycolor(0.1 0.2 0.7)+
skycolor(0.1 0.2 0.7)++
skycolor(0.1 0.2 0.7)+10f
the first skycolor message will be executed after a delay of 10 seconds, the
second message will be delayed a single frame, the third message with be delayed
2 frames, and the final message will be delayed 10 frames.
The formal syntax for messages is as follows:
[node_name.] message_type [ '(' [argument] [ (, | ' ') argument] ')' ] [+delay_time]
Node names and message names are not case sensitive. However, all filesystem
related items such as model, sound, and textures filenames are case sensitive.
Messages can be sent to any node during runtime by typing them into the shell window and hitting return or by setting up messages that are sent in response to events.
Events
Events are the means by which the virtual world is changed during runtime. The
most basic events involve button presses or entering a designated region of
the world. Although initial messages setup the initial properties of nodes,
another class of messages callled event messages
can be sent in response to an event during runtime. In the following example:
userTrigger( volume(sphere), when( enter, myEnvironment.skycolor(0.1
0.2 0.3) ) )
the when message sets up a message to be sent when
the enter event occures. The userTrigger
node establishes a region in the shape of a sphere within the world. When the
user enters the region an enter event is generated
and the attatched message will be sent to the environment node. The documentation
for the userTrigger node gives the following description for the enter
event:
enter | user | a user has entered the space |
Ygdrasil includes nodes for geometry, matrix transformation, spatialized sound,
user avatars, and an array of dynamic elements that include triggers, timers,
and geometry modifiers. Each node is documented in the nodes section and has
a working example scene that demonstrates its use. For example, the example
file for ygObject can be executed by typing
yg ygObject.yg
at the command prompt. All included example scenes can be found in the data/scenes
directory located under the /usr/loca/yg installation
directory. The core Ygdrasil nodes all have names that begin with yg,
yet each can also be created by dropping the first 2 letters in scene files.
All other nodes are created from a DSO which allows for easy modification or
addition of new nodes. The configuration section
covers how to create and add new nodes to the Ygdrasil system.
Media such as models, textures, and sounds are searched for in a path that includes the data/models and data/textures directories in the Ygdrasil installation directory. By default, the current working directory and a subdirectory called data are searched first for content. The configuration section covers how to customize path to search other directories.
Each node in the documentation includes a list of the available messages for that node and a list of the events generated by that node. In addition, there are notes on usage and an outline of the comments included in the source code. The reset method in the comments section lists the default values for each message. The documentation is organized into sections labeled foundation, user, geometry, sound, transformation, selection, attributes, trigger, math, and system.
Foundation
The foundation section lists core nodes from which many other nodes are derived.
This includes the ygViewer node that establishes a viewpoint and the ygSoundServer
node from which all sound related nodes are derived.
ygNode
All Ydrasil nodes are derived from a single base node called ygNode.
The ygNode provides a set of messages that can be sent to any Ygdrasil node.
These messages include the print message, for printing
to the shell window, and the reset message for setting
the node back to the initial properties defined in the scene file. In addition,
ygNode also provides the when message which is used
for sending event messages when events occure. Although many nodes generate
their own events, any Ygdrasil node can be set up to respond to an event and
forced to generate that event by sending the message event.
For examples of this functionality see the example scene for ygNode.
Messages are also provided by ygNode for creating new nodes and for changing the structure of the Ygdrasil scene graph during runtime. The create message creates a new node of the given node type and makes it a child of the current node. The addChild message can be used to remove existing nodes from the scene graph and make them a child of the current node. The removeChild message can be used to take a node out of the current scene graph.
Because all nodes are derived from ygNode, the documentation for any node only shows the messages that it is responsible for adding. When looking for the documentation on a particular message be sure to follow the links to parent nodes located at the top of the documentation page.
ygWorld
The ygWorld node is the node
that manages the local virtual world. A ygWorld node is created automatically
for each Ygdrasil application and all nodes created by a scene are children
of the ygWorld node. Messages can be sent to the local copy of the ygWorld node
by prefixing them with the node name "world". For example, the sending
the message
world.quit
at anytime will quit the Ygdrasil application. The ygWorld node provides the
load message for loading scene files during runtime.
The current scene can also be saved by sending the save
message with the name of the desired filename to save to. The delete
message allows nodes and all of their children to be deleted from the scene
graph during runtime.
ygSpace
The ygSpace node is the base
node from which all nodes that establish a region of space are derived. The
ygSpace node provides for the creation of rectangular, spherical, and cylindrical
shaped volumes of space though the volume message.
In addition, volumes can also be designated as infinite, encompassing all space,
or as points, encompasing an infinitely small volume that can never be entered.
The userTrigger node and several other trigger nodes are derived from ygSpace. The ygEnvironment node is derived from ygSpace to allow for environmental effects to be limited to regions within the virtual world. In addition, most sound related nodes are also derived from ygSpace.
User
Networked virtual worlds are unique in that the majority of interaction with
them happens through interaction between user avatars and the world itself.
As a result, a virtual world without a user cannot be explored or interacted
with. In addition, your user avatar establishes how you appear to other users
with whom you are interacting in the virtual world. The user section lists nodes
useful for creating a user presence. A default user avatar scene is loaded automatically
whenever a scene is loaded. In order to create a customized version of your
user, copy the file ygUser.yg from the scenes directory
into your local directory and modify it.
The ygHead and ygWand nodes establish the position of the user head and wand respectively within the virtual world. The userTrigger node detects the entrance of the ygHead node into its volume while the wandTrigger node detects the entry of the ygWand node. Because virtual reality systems rarely track users over a large distance, a method of navigating the user throught the world other than actual walking is necessary. The ygUser node establishes a transform representing the user locatation, and the ygNavigator node is responsible for implementing a method of navigating this transform through the virtual world.
Ygdrasil uses the CAVElib simulation library for interfacing with tracking systems and controller devices such as the Wanda. The ygCAVENavigator node implements a navigation method called point-and-go that moves the user in the direction the wand is pointing. The ygCAVENavigator node also implements the collision detection strategy for walking on floor objects and preventing the user from moving through walls.
The ygCAVETracker node is used to bring in the position and orientation of sensors attatched to the user. When running Ygdrasil in the simulator window, the mouse and keyboard interaface is used to simulate tracking and controller sensor data.
The ygCAVEWand node is derived from ygWand and generates button related events related to the Wanda device. When operating in the simulator window, the ygCAVEWand node generates button1 and buttonUp1 events for the left mouse button. The second and third button events are similiarly mapped to middle and right mouse buttons.
Geometry
Ygdrasil provides nodes that create geometry directly or by loading model files.
Most nodes in the geometry section are derived from a node called ygGeometry
which provides messages for drawing attributes and collision attributes. The
draw message makes geometry visible either to local
users, remote users, both, or neither. The floor
and wall messages make geometry a surface for walking
and a surface that cannot be penetrated respectively. Collision detection with
geometry depends on two factors, the status of the geometry related node and
the collision or fly status of the user navigator node.
The ygScene node is a powerful node for inlining scene files multiple times. While the C style include directive will simply cut and paste a scene file into place, the ygScene node is capable of renaming references to node names when they are incremented in order to preserve the behaviors within the scene file. Because node names are incremented as they are encountered within a scene file, multiple nodes already having with incremental names within a scene file should be ordered in reverse order in order to prevent ambiguous references (i.e. timer5, timer4, timer3, etc.).
Models
The ygObject node loads models
from a number of file formats. Because Ygdrasil is built upon the Performer
scene graph library, it can take advantage of the built-in model loaders provided
with it. Performer comes with loaders for the following model formats:
OpenGL Performer fast binary format | *.pfb |
OpenGL Performer ASCII format | *.pfa |
SGI OpenInvetnor format | *.iv |
VRML version 2.0 format | *.wrl |
MultiGen OpenFlight format | *.flt |
Alias Wavefront format | *.obj |
AutoDesk 3DStudio binary format | *.3ds |
AutoDesk AutoCAD ASCII format | *.dxf |
Several things should be considered when loading models into Ygdrasil:
Some information on specific loaders:
pfb, pfa
This is the native file format of Performer and is the only file format that
Performer can save to. Performer includes a utility called pfconv
that can be used to convert models into pfb and pfa
formtas. All models are converted to pfb as they
are loaded, so converting them beforehand can speed up loading times for your
scenes. However, some IRIX systems may be using an older version of Performer,
so always keep the original model files available in case they need to be converted
into an older version of the pfb format. The pfa
format is mainly useful for making small changes to models that are originaly
in a binary format, but editing pfa files is ony
recommended for those who know what they are doing.
The windows versin of Perfomer includes a plug-in that allows Maya 6.0 to export
directly to the pfb format. The plug-in is not availlable
as a download at this site because the Performer installation makes some configuration
changes that allow the plug-in to work.
iv
Because Perfomer and Inventor are both SGI products, the OpenInventor format
has a high likeliehood of being loaded correctly. Most recent versions of Maya
can export to OpenInventor version 2.0. In Maya you may have to go to the plug-in
manager and load the plugin for the exporter. In the export options be sure the
normals are included and set the texture to sample the original file. If you
allow Maya to resample the texture file, be sure to move the resampled file
to the target system. Experience
has shown that some larger model files and those containing numerous textures
can be problematic for the iv loader. The inventor loader will not work without first installing OpenInventor on your system. The Inventor loader can load gif, jpg, and rgb image files.
flt
The OpenFlight loader has proven a capable format for loading as MultiGen was
targeted as a product for Performer users. Most recent versins of Maya can export
to OpenFlight. A binary editor such as HexEdit for windows will be necessary
to overwrite the absolute path with a relative pathname.
wrl
Performer versions prior to 3.2 come with a loader that can load VRML version 2.0 files.
The CosmoWorlds modeler and some other web-oriented modelers can save to the
wrl format. Many VRML files downloaded on the web
have been compressed using the gzip utility. These files need to be uncompressed
before they can be loaded by Performer. Often the size of wrl
model ends up very small when loaded into Ygdrasil, so be sure to try sizing
the model up if it is not immediately visible. VRML version 1.0 files are actually
the same as OpenInventor version 2.0 files. They can be loaded by changing the
header to "#Inventor V2.0 ascii" and changing their file extention
to *.iv. The VRML loader can only load image files in the rgb format.
obj
The Alias WaveFront file format is reliable for loading geometry alone but I
have little experience with using it to load textured models. The obj
format uses mtl material files, so be sure that you
have the material files for your models.
3ds, dxf
The 3D Studio Max binary format has been used with some success. Because the
3ds format is not updated regularly by SGI, you may need to save your model
into an older 3ds format to have it load properly. Be careful about polygon
counts with Max because rounding off of corners may look good in a rendering
but it produces significantly more polygons. The dxf format is an older format
and is usually a second choice when both format exports are availlable.
Textures
The ygTexture and surface
nodes can both create a rectangular polygon and load a texture onto it. These
nodes allow content to be easily created without the need for modeling skills.
The ygTexture node only creates two triangles and is not affected by lighting.
The surface node can create a rectangle with a variable number of vertices and
is affected by lighting and material changes. Both nodes only load images in
the rgb format either run-length compressed or not.
Performer tries to optimize the use of texture memory by keeping textures in
powers of 2, so be sure to size your textures accordingly (i.e. 256x512,128x128,etc.).
These nodes currently do not provide options for mip-mapping so these features
but Performer does support them by creating your own geometry in a modeler.
Sound
This section lists several availlable nodes for creating, recording, and monitoring
sound. Ygdrasil uses the Bergen Sound Server to play back and record sound using
the sound card on the local machine or a remote machine. In combination with
Ygdrasil, Bergen can spatialize and directionalize sounds located in the virtual
world.
Sounds are spatilaized by adjusting their amplitude based on the distance between the user and the sound source. All sound related nodes are derived from ygSpace and, as such, allow a volume to be defined for them. The volume assigned to a sound node defines the area within which the amplitude is always at the maximum (i.e. a box for a room). Once outside the volume a falloff calculation determines the rate at which the amplitude decreases with distance from the sound. Sounds that should not be spatialized can use the default infinite volume, and sounds that should allways be spatialized (i.e. a bee) can be assigned a point volume.
Sounds are directionalized by playing them at different amplitudes in different speakers. This requires that Bergen be configured with the location of each physical speaker. Bergen can do stereo spatialization on Linux machines and Quad spatializatin on SGI Indigo and O2 machines. Ygdrasil calculates a distance from the center of the volume and Bergen uses this information to spread sound to all speakers when the listener is at the center of the volume. The ygSound node is the primary node for playing sampled sounds from files. Because sounds are directionalized by Bergen, sample files should be mono. And, because the default sampling rate is 22050khz, sound files be stored at a multiple of that frequency (i.e. 44100khz, 16bits, mono).
The soundRecorder and amplitude nodes monitor the microphone input of the sound card. They are not designed to record the sounds being played by Bergen. Spatialization of nodes that monitor sound input acts to decrease the amplitude of the recorded sound when the listener is at a distance from the recording node. Recordings that should not be spatialized in this manner can use the default infinite volume.
The ratSource node can spatialize and directionalize an audio stream using the Robust Audio Tool (RAT). Each user involved in a RAT session can add a ratSource node to their avatar and configure it with their RAT session identifier.
For more detailed information on how to configure Bergen see the configuration section.
Transformation
The transformation section lists nodes related to matrix transformation which
is at the heart of OpenGL and other scene graph based rendering systems. Placing
ygTransform nodes in a
tree structure allows geometry to be translated, oriented, and scaled in logical
groupings. A number of nodes derived from the ygTransform node provide functions
such as pointing at objects, moving from location to location, and following
paths stored in files. Several nodes in this section including the mover
and pointFollower are
designed to accept a set message that dictates the
location of the transformation between a beginning and end location. The timer
node described in the math section is useful for creating dynamic movement with
these nodes.
For convenience, both the ygObject and ygTexture nodes create ygTransform nodes automatically when passed position, orientation, and size messages. In order to avoid the recreation of these nodes, be sure to change the name of the parent transform when changing the name of ygObject and ygTexture nodes in scene files.
Selection
After matrix manipulations, selection is the second most important feature of
using scene graphs to organize geometry. Selectors, such as the ygSwitch
node, allow sections of the scene graph to be turned off. When a ygSwitch node
is turned off, all content associated with its children nodes will no longer
be included in the world. The ygSelector
performs a similiar function but allows the scene graph under only a single
child node to be included in the world. Performer uses the scene graph structure
to eliminate parts of the world from rendering that are not visible. Selection
nodes can also allow you to keep frame rates high by turning off content when
possible. The levelOfDetail
node can select a lower resolution model when the user is farther away from
an object and the visibility
node can make portions of the world invisible when a user enters of leaves an
area (i.e. the furniture become invisible when the user leaves the room).
Attributes
The attributes section lists nodes that can be used to change attributes of
geometry such as textures and materials. Like most nodes in this section, the
material node affects the
material and transparency properties of all the nodes that are its children.
Of note in this section are the viewTexture
node which can render an alternate viewpoint onto an existing texture and the
applyTexture node which
can add smaller textures to an existing texture to create effects such as burn
markes and transparent holes. Other attribute nodes such as clipPlane
and stencilBuffer allow
clipping planes and stencil masks to affect the rendering of geometry in other
locations in the scene graph.
Video
The movieTexture node
uses the openQuicktime library to play *.mov files
on the texture of its children nodes. A separate ygSound node and appropriate
sample file are required for sound playback of movies. The quicktime format
used by openQuicktime is called PhotoJPEG. Premier and the Professional version
of Apple Quicktime software can save mov files in
the PhotoJPEG file format. Because they are loaded as textures, movies should
be reformated to a power of 2 and can have their aspect ratio adjusted by transforming
the size of the polygon they are played on.
Trigger
The trigger section lists nodes that trigger events based on interactions within
the virtual world. The userTrigger
and wandTrigger nodes detect
the presence of ygHead and ygWand nodes respectively. The nodeTrigger
node detects the presence of a particular type of node (i.e. detect(ygObject)).
They each generate enter and exit events when the respective nodes they detect
enter and exit their volume. Like all nodes derived from ygSpace, these nodes
default to an infinite volume and, as a result, will detect thier respective
nodes immediately upon startup if their volumes are not reduced.
The pointAtTrigger
generates events when a ygWand is pointing at any of the geometry of its children
nodes. For example, the following
pointAtTrigger( when(start, print(the user is pointing) ) )
{
ygObject( file(ground.pfb) )
ygObject( file(tree.pfb) )
}
will print out a message to the shell window when the user is pointing at either
the ground or the tree. In addition to detecting the presence of the ygWand
node, both the wandTrigger and pointAtTrigger nodes also generate any events
being generated by the ygWand while they are active. For example, the
Math
The math section lists nodes that are used to make logical and arithmatic calculations.
The most important nodes in this section are the value
node and the timer node derived
from it. The value node is a general purpose numerical array that can store
any number of values and generates and event called
changed when any of them change. The value node has
messages for clamping the possible values in its array called maximums
and minimums. And, it can also be configured to easily
increment and decrement
by particular deltas. The following is an example
of a value node setup to hold the values (0.2 6.5 8.0):
value( values(0.2 6.5 8.0) )
The interpolate node is
derived from the value node and is useful for performing simple linear calculations.
The input message sets the values in the array according
to the properties set by the startValues and endValues
messages. An input message of 0.0 will set the values in the array to the startValues
and an input message of 1.0 will set the values in the array to the endValues.
In the following example
interpolate( endValues(0.2 60.0), when(changed, print(array values are: $values0
$values1), input(0.5) )
the input message will interpolate the resulting array half way between the
start and end values. Having changed, the node will print out
array values are: 0.1 30.0
The timer node is an interplate node that sets the input between 0.0 and 1.0
over a duration. Sending the timer node the start
message moves the input value forward from 0.0. The stop, forward, and reverse
messages can be used to pause, continue, and reverse the timer respectively.
Because the array can be configured to assume values between any start and end
value, the timer node is ideal for manipulating values over time. In the following
example
timer( duration(5), startValues(10 20), endValues(20
60),
when( changed, myTransform.position(0
$values0 $values1) ) )
ygTransform myTransform( position(0 10 20) )
the timer will change the transform position from (0 10 20) to (0 20 60) over
a period of 5 seconds. Note that the timer node constructs the position message
by replacing $values0 and $values1 with the values in its array. The index values
of the values variable is not related in any way
to the fact that they are replacing the second and third arguments in the position
message.
The boolean node is useful
for keeping track of simple true/false relations and generates events to reflect
changes in its state. Because it uses a very simple parsing mechanism for scene
files, Ygdrasil organizes math nodes in the scene graph to form more complicated
calculations and logical operations. For example, the following math nodes
and openDoor( when(changedTrue, doorTimer.start) )
{
greaterThan( )
{
value knobOrientation( )
value( set(10.0) )
}
boolean doorLocked( false )
}
will start a timer called doorTimer when both the
knobOrientation is greater than 10.0 and the boolean
node doorLocked has been set to true.
In addition to the example scenes for each node, there are also a number of additional example scenes located in the data/scenes directory located at /usr/local/yg.
example1.yg | demonstrates using the pointAtTrigger and the timer node to create a spinning banana |
example2.yg | demonstrates using the wandTrigger, sound, and CAVENavigator nodes |
widget_arm.yg | demonstrates using the pointAtNode and the distance node to create an articulated arm for the user avatar |
widget_leg.yg | demonstrates using the moveToNode, the distance node, and timers to create an articulated leg for the user avatar |
widget_velocity.yg | demonstrates using the add, multiply, and mathematics nodes to calculate the user velocity |
ygUser_articulated.yg |
demonstrates using the ygScene node and mathematics to create user arms and legs |
userMirror.yg | demonstrates using the userPosition node and the interpolate node to create a distorted image of the the user avatar |
pathSelector.yg | demonstrates using the boolean, and, or, and nodeTrigger nodes to create a user puzzle |
applyScale.yg | demonstrates using the applyTexture node and interpolate node to map an "X" on a texture |
spatialized.yg | demonstrates each of the available sound nodes |
stencilMirror.yg | demonstrates how to use the reflection and stencilBuffer nodes to create a mirror |
Runtime options for Ygdrasil are controlled by a configuration file located
in /usr/local/yg/etc called yg.config.
Configuration file variables are defined as follows:
YG_PATH=models:textures:${YG_PATH}
where YG_PATH is the name of the variable being set
and ${YG_PATH} can be expanded to the value of the
current variable when necessary. The following configuration options can be
adjusted in the yg.config file or superceded by a
.ygrc file located in the user home directory or
the local working directory where Ygdrasil is started:
variable | default | description |
YG_PATH | data:${YG_DIR}/data: |
location of models, textures, scene files, and sounds (unless BERGEN_PATH has been set) |
YG_DSO_PATH | modules:${YG_DIR}/modules | location of user and system dynamic shared objects |
YG_DEBUG | not defined (i.e. "world.sendmessages net.* *.display ygSelector.select") |
initialize node and system wide debug flags (also see ygWorld, ygNet, ygNetClient, ygDSOLoader) |
YG_PRELOAD_CLASSES | not defined (i.e "clipPlane stencilBuffer") |
some nodes will indicate in their documentation that they must be preloaded |
YG_PF_DBASE_CONVERTERS | not defined (i.e. "iv flt") | preloading database converters can increase stability |
YG_PF_FONT_DIR | ${YG_DIR}/data/fonts | location of fonts used by the graphical interface and text node |
YG_NET_SERVER | not defined | set the name of the host running ygrepeater server |
YG_NET_PORT | 3500 | set the port used to communicate with the server |
YG_NET_REPEATER | not defined | indicate that ygrepeater should be started on the server |
YG_NET_PROCESS_INTERVAL | 0 (networking processed each frame) | set a delay time between network processing |
YG_NET_DOWNLOAD_DELAY | 300 | frames distributed nodes must wait before downloading |
YG_NET_UPLOAD_DELAY | 10 | frames distributed nodes must wait before uploading |
YG_NET_TRANSFORM_INTERVAL | 0 (transforms updated each frame) | set a delay time between transform updates |
YG_NET_THREAD | not defined (Linux systems thread by default) | set to 0 or 1 for a separate thread for networking |
YG_NET_NOTHREAD | not defined | set to 1 to prevent creating a networkng thread |
YG_NET_DEFAULT_UNRELIABLE | not defined | set to 1 to make all comunications UDP |
YG_NET_CACHE_SERVER | not defined (defaults to YG_NET_SERVER) | set the host machine for intial scene download |
YG_NET_CACHE_PORT |
not defined(default YG_NET_PORT+1) |
set the port for initial scene download |
YG_FILESERVER_HOST | not defined (usually YG_NET_SERVER) |
set the host machine running the fileserver |
YG_FILESERVER_PORT | not defined | set the port for the fileserver to use |
YG_FILESERVER_DIRECTORY | ./ | set the location for downloads and uploads |
YG_SERVER_DO_SLEEP | not defined | sleep to reduce spinlock when run with --noview |
YG_MESSAGE_PORT | 1967 | port for receiving messages from other processes |
YG_PF_SHOW_TEXTURES | not defined | display Performer textures as they are loaded |
YG_PF_MULTIPROCESS | not defined (i.e. PFMP_FORK_DRAW) |
setup processing for multi-precessor systems |
YG_CPP | "/lib/cpp -C" (SGI:"/usr/bin/cc -E") | C preprocessor command line |
YG_NOCPP | not defined | set to 1 in order to disable C preprocessing |
YG_INTERFACE | not defined | set to 1 to start the interface when a server is defined |
YG_SOUND_INTERVAL | 0.1 | frequency of sound node position updates |
YG_LISTENER_INTERVAL | 0.1 | frequency of listener position updates |
BERGEN_SERVER | not defined | set the remote host to run the snerd server |
BERGEN_RAT_EXECUTABLE | rat-4.2.23 | name of the executable running RAT |
BERGEN_RAT_INTERVAL | 0.2 | frequency of amplitude and pan updates |
PFSHAREDSIZE | 500000000 | size in bytes of the Performer shared memory arena |
PFVIDEORATE | not defined (i.e. 60) | refresh rate may need to be set for Performer |
__GL_SYNC_TO_VBLANK | 1 | Nvidia specific setting to lock Performer frame rate |
__GL_FSAA_MODE | 1 | Nvidia specific setting to set anitaliasing mode |
Networking
Ygdrasil nodes automatically share their state when running in a networked configuration.
Remote users can join an existing world by simply connecting to a server, without
needing the scene file for the world. When the YG_NET_SERVER variable is defined
in the Ygdrasil configuration file, Ygdrasil will start the server program,
ygrepeater, on the server machine when starting the
application. A public key must be generated for Secure Shell authorization in order to allow remote execution on the server machine. On a client machine, when the YG_NET_SERVER variable has been defined,
simply typing
yg
at the command prompt will connect to the server and load the remote scene.
The default user avatar in ygUser.yg will be used unless another copy has been
placed at an earlier location in YG_PATH.
There are two main considerations when scripting scenes that will be networked between multiple users. First, care should be taken not to make user interaction relative to a specific user. Using the user variable in trigger events (i.e. when(enter.$user.teleport(0 0 0) ) ) will help to keep user interaction generalized. Second, Ygdrasil normaly does not require large bandwith to connect multiple users in complex scenes, however setting the YG_NET_TRANSFORM_INTERVAL variable to a frequency of 0.1 seconds can significantly reduce network traffic. Individual ygTransform nodes that require shorter or longer intervals can then be set individualy with the updateInterval message.
By default, Linux machines create a separate thread to handle the sending and receiving of network data. However, some Linux systems may suffer from jumpy frame rates due to this configuration. Setting either the YG_NET_THREAD or YG_NET_NOTHREAD variables in the Ygdrasil configuration file may help avoid this problem. The frame rate may also be improved by decreasing the frequency at which network messages are processed by adjusting the YG_NET_PROCESSING_INTERVAL variable.
Ygdrasil can use a combination of CAVElib distribution and networking to run distributed in a cluster environment. Once the CAVE library has been properly configured, typing
ygdistrib example1.yg
at the command prompt will start the repeater on the YG_NET_SERVER machine and start Ygdrasil on each of the machines listed in the .ygclients file. A public key must be generated for Secure Shell authorization in order to allow remote execution on each client machine.
The server program, ygrepeater, can be run on the local machine by setting YG_NET_SERVER to localhost, but generaly it is preferable to dedicate a separate machine as the networking server. A single machine can host a world without graphics by setting the server to localhost and running yg with the --noview command line option.
Bergen
The Bergen sound library can be used to send sound requests to a sound server
on either the local or a remote machine. The default configuration uses a program
called snerd to generate sounds on the sound server machine. Alternately, sound requests can be sent to a sound server running
SuperCollider or MaxMSP using OSC protocol. Snerd uses a configuration file located at /usr/local/bergen/etc
called snerd.config. This configuration file is where
the number of speakers and their location is defined along with the spatialization
method. The following configuration options can be placed in the snerd.config
file or superceded by a .snerdrc file located in
the user home directory or the local working directory where snerd is started:
variable | values | default | description |
speaker | three floats | none | add one line for each speaker defined |
spatialization | none | mono | stereo | quad | none | configures the sound card hardware |
srate | integer | 22050 | sampling rate |
udpport | integer | 5900 | bergen to snerd communication port |
listenerfilter | float | 0.2 | linear filter constant for listenter position |
soundfilter | float | 0.2 | linear filter constant for position of each sound |
The default configuration runs snerd on the local machine. The sound server machine on which snerd should be started is set with the BERGEN_SERVER variable in the Ygdrasil configuration file. When the variable is set, the start script will automatically start and stop snerd on the remote machine. A public key must be generated for Secure Shell authorization in order to allow remote execution on the server machine. The path snerd uses to find sound files is determined set automatically by Ygdrasil as the YG_PATH described above. This path can be overriden by setting the variable BERGEN_PATH in the Ygdrasil configuration file when snerd is not run on the local machine.
The listenerfilter and soundfilter settings are useful for preventing abrupt changes in sound amplitude due to position changes. Ygdrasil updates the position of the listener and each sound at a default frequency of 0.1 seconds. The default value can be overriden by setting the YG_SERVER_UPDATE_INTERVAL variable in the Ygdrasil configuration file.
Robust Audio Tool
The Robust Audio Tool (RAT) is an audio conferencing tool that can be used for
networked virtual reality. The SoundBlaster Live! series of sound cards have
proven reliable at allowing both Bergen and RAT to use the sound card simultaniously.
As will likely be most common, the RAT application should be started before
the snerd sound server. Starting the applications in the opposite order will
not allow RAT to initialize.
The Ygdrasil ratSource node
is capable of manipulating any number of RAT source streams to spatialize and
directionalize the sources by adjusting gain and pan values. Each ratSource
node must be given the name of a single session ID (SSID). Each participant
can add a ratSource node to their user avatar and configure the Ydrasil configuration
file to pass the SSID value onto the ratSource node. The BERGEN_RAT_SOURCE variable
set in the configuration file will be passed onto the scene file in the form
of a macro of the same name. For example, the following lines
ratSource( volume(sphere), falloffDistance(10),
source(BERGEN_RAT_SOURCE)
)
will create a source for the local user and replace the BERGE_RAT_SOURCE variable
with the value assigned in the Ygdrasil configuration file. The default executable
name for RAT is rat-4.2.23 and can be adjusted by
setting the BERGEN_RAT_EXECUTABLE variable in the Ygdrasil configuration file.
The default frequency at which RAT sources are updated is 0.2 seconds and can
be adjusted by setting the BERGEN_RAT_UPDATE_INTERVAL variable in the Ygdrasil
configuration file.
CAVELib
Ygdrasil uses the CAVElib simulation library to manage display windows and capture
inputs from tracking sensors and controller devices. The software reads a configuration
file called cave.config in the directory /usr/local/CAVE/etc
at startup. Ygdrasil uses a customized version of the CAVElib and the installation
adds the following lines from /usr/local/yg/etc/yg.cave.config
to the existing cave.config file:
wallDisplay simulator -1 window 800x640+100+100
simulatorMode wand
simulatorShowWand n
simulatorShowOutline n
simulatorWandPosition 0 4.5 -2
wallEyes simulator right
interocularDistance 0.0
hideCursor y
simulatorControls F5KEY F3KEY F1KEY F2KEY F4KEY F9KEY ENDKEY HOMEKEY INSERTKEY DELKEY
PAD8 PAD2 PAD4 PAD6 PAD5 PADMINUS PADPLUSKEY PAD8 PAD4 PAD2 PAD6 PAGEUPKEY PAGE
DOWNKEY F6KEY LEFTARROWKEY RIGHTARROWKEY UPARROWKEY DOWNARROWKEY F7KEY F8KEY
TAB
KEY PADENTER PADENTER
These options enlarge the simulator window from the default 512x512 up to 800x640
and hide the CAVE outline, the wand indicator, and the mouse cursor. The last
option moves the keyboard controls off of the alphabetic and numeric keys in
order to utilize the keyboard without interference. Systems configured for stereo
viewing can be used in simulator mode by adding the following line to a local
.caverc file:
simulator y
Configurations that have been setup for stereo viewing will have also have a
host.config file where host
is the hostname of the machine. The configuration options above set the interocular
distance to 0.0 in order to eliminate distortions in the graphical interface
in simulator mode. This option will likely need to be removed for immersive
stereo viewing and will not affect the overall performance of the graphical
interface.
The customized version of the CAVE library includes a new simulator interface
that alternates between two modes of control for the mouse; one that controls
the viewpoint and one that positions the wand at the same location as the mouse.
The simulator mode configuration option can be set as follows:
simulatorMode classic
in order to return to the classic simulator interface.
User Nodes
The majority of the nodes available for Ygdrasil scripting are compiled as Dynamic
Shared Object (DSO) files so that they can be easily added or removed from the
system. Users can customize existing nodes or add nodes with new features
by following the procedure below:
If your new class is derived from another node class that is not built-in (that
is, from some other DSO class), the DSO for the parent class must be loaded
before the derived class's DSO. Otherwise, the derived class's DSO will have
unresolved symbols, and it will fail to load. To tell Ygdrasil about other classes
to load before a given class, list them in a .ygdep
dependencies file. For example, if the class myUserTrigger is derived
from userTrigger, then in the same directory that contains myUserTrigger.so
there should be a text file named myUserTrigger.ygdep,
with the following line:
userTrigger
If there is more than one dependency, list each one on a separate line. You
do not need to list any dependencies of the parent class; those will be found
recursively as the parent class is loaded.
Coding
Beginning with Ygdrasil version 0.4.0, message names and arguments are established
by making calls to addNetMessage() in the class constructor.
This allows the system to automatically parse messages and place their contents
in the appropriate class variables. In addition, this system allows Ygdrasil
to save the current scene graph and display message names and their arguments
in the grahical interface. User nodes developed prior to 0.4.0 can be converted by following the simple procedure found here. The following describes how to establish messages
and their arguments in the class constructor.
Message Registration
Ygdrasil nodes store their state in member variables that are registered with
the messages that adjust them. Identify which messages are needed to define
the node state and assign variables for each message argument. For example,
the ygObject class creates a string variable and a boolean variable to store
the state of the file message. The message name and
associated variables set by the message are registered in the class constructor
by making consecutive calls to the addNetMessage()
function as follows:
cache_ = false;
addNetMessage( "file", &filename_, YG_NET_STRING );
addNetMessage( "file", &cache_, YG_NET_BOOL );
Initialize each variable before registering them in order to establish the default
value. The following data types can be registered with Ygdrasil:
datatype | token | comment |
ygString | YG_NET_CLASS | store the name of a node class |
ygString | YG_NET_NODE | store file name of a node |
ygString | YG_NET_FILE | store a file name on the filesystem |
ygString | YG_NET_STRING | store a character string |
ygString | YG_NET_STRING_ADD | store a character string (concatenate each new entry) |
ygString | YG_NET_STRING_DELETE | store a character string (remove each new entry) |
int | YG_NET_INT | store an integer value or a string mapped to an integer |
float | YG_NET_FLOAT | store a single float value |
bool | YG_NET_BOOL | store a boolean (set to default when no argument given) |
bool | YG_NET_BOOL_NEGATE | store a boolean (set to negated default when no argument) |
pfVec2 | YG_NET_VEC2 | store 2 floats |
pfVec3 | YG_NET_VEC3 | store 3 floats |
pfVec4 | YG_NET_VEC4 | store 4 floats |
vector<float> | YG_NET_VECTOR | store a variable sized array of float values |
pfMatrix | YG_NET_MATRIX | store a full 16 float matrix |
pfCoord | YG_NET_COORD | store a 6 float coordinate translation and orientation |
ygString | YG_NET_EVENT | used by the graphical interface |
ygString | YG_NET_WHEN | used by the graphical interface |
Integer values stored with YG_NET_INT can be assigned to strings by making
a call to addNetMessageMap() for each integer/string
pair. For example, the ygEnvironment node message fog is registered with the
following function calls:
addNetMessage( "draw", &draw_, YG_NET_INT
);
addNetMessageMap( "draw", "false", 0 );
addNetMessageMap( "draw", "true", 1 );
addNetMessageMap( "draw", "local", 2 );
addNetMessageMap( "draw", "remote", 3 );
addNetMessageMap( "fog", "exp2", 4 );
All messages set their associated variables to the default value when no argument
is given. In the case of boolean data, the YG_NET_BOOL_NEGATE data type will
set the variable to the opossite state of the default value. For example, in
the ygGeometry node
floor_ = false;
wall_ = false;
addNetMessage("floor", &floor_, YG_NET_BOOL_NEGATE);
addNetMessage("wall", &wall_, YG_NET_BOOL_NEGATE);
the floor and wall messages
will be set to true when received without an argument.
Some nodes have multiple messages that affect the same node state. In the case of ygSwitch, the toggle, on, and off messages all affect the same state variable. Messages represented by a single boolean are also printed out or saved as only the message name when appropriate. As a result, the off message variable, netOff_, was registered with YG_NET_BOOL_NEGATE so that the printout/save will appear as ygSwitch() when the variable is in its default state and asygSwitch(off) when the variable is negated. Furthermore, it is preferable to keep messages and their argument data agregated together when possible. For example, the ygObject node takes file(string,[cache]) but also allows a separate cache([bool]) message. The cache argument is registered with with the file message and the cache message was left to be parsed manually by message().
Message Parsing
Although registered messages are parsed automaticaly, some further processing
is often necessary once a message has been received. In addition, nodes may
accept unregistered messages that are parsed and handled in the message()
class method. All messages are parsed into ygMessage objects, which contain
the message name and a vector of the arguments, all as ygStrings. For example,
the message position(1 0 2) becomes
a ygMessage with the message name "position" and 3 arguments of "1", "0", and
"2". The == operator is overloaded for messages to easily compare ygMessage
names with ygStrings. There are also a number of convenience functions for converting
message arguments into various types:
msg.stringArg(i) | returns the ygString argument i |
msg.intArg(i) | returns argument i as an int |
msg.floatArg(i) | returns argument i as a float |
msg.boolArg(i) | returns argument i as a bool; "true", "on", or "1" are interpreted as true, everything else as false |
msg.getVec2Args(v,i) | fills in pfVec2 v with the values of aruments i and i+1 (i defaults to 0) |
msg.getVec3Args(v,i) | fills in pfVec3 v with the values of aruments i through i+2 (i defaults to 0) |
msg.getVec4Args(v,i) | fills in pfVec4 v with the values of aruments i through i+3 (i defaults to 0) |
msg.numArgs() | will return the number of arguments |
In the following example from the ygObject node:
void ygObject::message(const ygMessage& msg)
{
//load the given filename with optional caching
if (msg == "file")
{
loadFile(filename_);
}
//set the default object caching mode
else if (msg == "cache")
{
if (msg.numArgs() > 0)
cache_
= msg.boolArg(0);
}
the file message requires that the appropriate file loaded into the filename_
variable be loaded. Registered messages that do not need further processing
should still have an entry in message() in order
to prevent generating an error message when they are not found. In the above
example, the cache message sets the cache_ variable
by parsing the message manually.
Network Keys
Ygdrasil creates the minimum possible subclassed node on remote clients. For
example, nodes derived from ygTransform, such as the mover node, only create
a ygTransform node on remote clients because they do not add any variables that
need to be shared with client nodes. A node is marked as requiring creation
on remote clients by setting the second argument to true in the setClassName()
function.
Ydrasil creates a networking key for each registered message variable. However,
in some situations it is desirable to send the data from multiple messages using
a separate networking key. The ygTransform node, for example, registers a separate
message called coord to share the position and orientation
key data using a YG_NET_COORD datatype. The dontSendNetMessage()
function indicates that the key data associated with the message should not
be sent to client nodes. Alternately, the dontSaveNetMessage()
function indicates that the coord message/key should
not be included in the graph/save printout.
//register the position and orientation messages
addNetMessage("position",&position_,YG_NET_VEC3);
dontSendNetMessage("position");
addNetMessage("orientation",&orientation_,YG_NET_VEC3);
dontSendNetMessage("orientation");
//create a hidden message with the coordinate network key
addNetMessage("coord", &neCoord_, YG_NET_COORD);
dontSaveNetMessage("coord");
unreliableMessage("coord");
Client nodes will receive a coord message and use
the aggregated data type to update their local data. Be sure to update the visible
message parameters when the hidden variables are updated on the client (i.e.
position and orientation should mirror COORD_NETKEY) as follows:
//set the translational component
else if (msg == "position")
{
dcs->setTrans(position_[0],position_[1],position_[2]);
coord_.xyz.set(position_[0],position_[1],position_[2]);
netMessageChanged("coord");
}
//set the rotational component applied before translation
else if (msg == "orientation")
{
dcs->setRot(orientation_[2],orientation_[0],orientation_[1]);
coord_.hpr.set(orientation_[2],orientation_[0],orientation_[1]);
netMessageChanged("coord");
}
else if (msg == "coord")
{
setPosition(coord_.xyz);
setOrientation(coord_.hpr[1],coord_.hpr[2],coord_.hpr[0]);
}
Note that the netMessageChanged() function is used
to indicate that a variable associated with a message has changed and that remote
clients should be updated.
The reset() method is provided for setting class variables back to their default value. The resetNetMessage() function is provided to reset variables associated with messages to their default value. If the value is different from the default value then client nodes will be updated automatically. Nodes that do not update values on remote clients need not use the resetNetMessage() function to initialize values.
Documentation
The documentation for each Ygdrasil node is produced automatically by a code
documentation generator called cxxDocumentor.
The comments and function calls within the C++ source file are used to generate
the documentation for each node. User developed nodes can be added to the local
documentation by following the guidlines below.
Heading
All comments before the first class method definition are assumed to be the
documentation heading. These comments are placed at the top of the documentation
page with the comment indicators removed. Only C++ style comments will be included
in the documentation. Any HTML tags imbedded within the comments will subsequently
be interpreted by the browser. As a result, the unordered list tag has been
used to create a series of notes within the heading of each documented node.
Tags
The parsing system looks for a pre-defined set of tags followed by a semi-colon
within the comments. These tags currently include Description, Category, Author,
and Revision. The description and category tags are used to organize and briefly
describe the function of each node. Documented nodes that do not include a category
tag will not be included in the node index page. New categories can be added
by editing the index template file, /usr/netusr/www/yg/ygIndex.templatel. The
revision tag is used to generate a listing of revisions in cronological order.
Revision tags must begin with a date of the form MM/DD/YY.
Comments
All intra-method comments not associated directly with a message, event, or
key with be used to construct a comment tree of the code. Each if,
while and for statement
starts a new subheading of comments. Comments that give a general overview of
how the class functions will help users to better understand the actual implementation
of the node they are using. Furthermore, the comments in the reset
method are used to establishing the default state of the node.Coding
The cxxDocumentor documentation system is a generalized C++ parsing engine that has been extended to generate documentation for Ygdrasil messages, events, and debug flags.
Messages
The names of node messages and their arguments are extracted from the C++ code
by the parsing system. Message argument syntax is derived from either addNetMessage
and related function calls or from the structure of function calls in the messages
method.
Parsing the meaning of Ygdrasil messages from addNetMessage and addNetMessageMap function calls requires that code adhere to the following general guidelines:
Coding
Parsing the meaning of Ygdrasil messages from the messages
method requires that code adhere to the following general guidelines:
Ambiguous dangling-else structures are of the form:
if (msg == "clip")
if (msg.args.size() == 2)
setClip(msg);
else
msg.error(name(),"(wrong number
of arguments)");
The C++ parsing algorithm used by the documentation system cannot resolve these
structures and they should be clarified as follows:
if (msg == "clip")
{
if (msg.args.size() == 2)
setClip(msg);
else
msg.error(name(),"(wrong number
of arguments)");
}
The documentation system cannot extract the type of arguments being used unless
they are extracted from ygMessage within the message
method. As a result, the previous example should let the system know that
two float arguments are required by including the method calls to the ygMessage
instead of passing the ygMessage object as follows:
if (msg == "clip")
{
if (msg.args.size() == 2)
setClip(msg.floatArg(0),msg.floatArg(1));
else
msg.error(name(),"(wrong number
of arguments)");
}
Optional message arguments can be indicated by extracting them from the ygMessage
within an if-elseif-else structure. If the
statements within the else section do not extract any arguments and they are
not specifying the message error, then the other arguments will be considered
as optional. The following example extracts a single optional argument:
if (msg == "wall")
{
if (msg.args.size() > 0)
setWall(msg.boolArg(0));
else
setWall();
}
The following example extracts a single argument that is not optional:
if (msg == "file")
{
if (msg.args.size() == 1)
loadFile(msg.args[0]);
else
msg.error(name(),"(wrong number
of arguments)");
}
Comments immediately above the message name filter will be used as the description
for that message:
//load the given case sensitive filename
if (msg == "file")
{
if (msg.args.size() == 1)
loadFile(msg.args[0]);
else
msg.error(name(),"(wrong number
of arguments)");
}
//set collision detection status
else if (msg == "wall")
{
if (msg.args.size() > 0)
setWall(msg.boolArg(0));
else
setWall();
}
Events
Event names are extracted by either finding text in the eventOccured
message or by resolving the ygString argument.
The resolution of ygString involves the processing
of the statements such as:
ygString myString("yg");
myString += "String";
Event arguments are resolved in a similiar manner with the portion before each
equal sign being interpreted as the argument name. The following eventOccured
method call will generate two event arguments named wand and user:
ygString myArgs("wand=wand1 user=user1");
eventOccured("enter",myArgs);
Comments immediately above the eventOccured method call will be included as
the event description:
//the switch has turned on
eventOccurred("SwitchOn");
Debug Flags
Debug flag names and are found by examining the debugFlag
method:
debugFlag("volume",&p_->debugVolume);
Comments immediately above the debugFlag method
call will be includedas the debug description:
//show a wireframe of the volume
debugFlag("volume",&p_->debugVolume);
Examples
Scripting examples are an important part of good documentation
and an example scene file should be created for each new node added. The documentation
for each node inlcudes a link to an example file of the same name. The name
of the file is file.scene where file
is the name of the new node.
Revisions
All revisions/changes should be documented in the C++ code heading in the cxx
file. Move the previous revision below the revision tag so that the most recent
revision is immediately following the tag:
//Author: Alex Hill
// 10/01/01
//Revision: 09/01/04 Alex Hill - changed to allow "volume" debug to be sent
at any time
Your revision will be listed on the revisions page ordered by revision date.
Regenerating
User developed modules and modifications to existing nodes can be added to the
existing documentation by following the commenting guidlines above:
This YGDOC script will execute the documentation system and produce all of the HTML files again. If properly commented, any new nodes should appear in one of the categories listed on the node index page.
Utilities
The /usr/local/yg/tools directory contains several
useful utilities for file and geometry management. These include:
utility | usage | description |
pfBounds | infile | prints out the extent of any model loaded by Performer; commonly used to determine extent and origin of a model |
pfTransform | [-t xtrans ytrans ztrans] [-r xrot yrot zrot] [-s scale] [-s3 xscale yscale zscale] infile outfile |
applies a transformation to any model loaded by Performer and saves to either pfb or pfa format; commony used to reposition the center of rotation for models |
pfCull | [-c (off|front|back|both)] infile outfile | sets the face culling state for geometry in a model; commonly used to turn off back face culling |
pfTransparency | [-b (on|blend|off)] infile outfile | sets the transparency state of geometry in a model; commonly used to turn on transparency in models with material transparency but appear solid |
pfFixSGIpfa | infile outfile | converts a Performer 3.X pfa file to one that can be read by Perfomer 2.4 |
makeNode | classname [parentclass] | creates skeleton *.h and *.cxx files for creating a new node DSO |
updateClass | infile outfile | converts yg_0.1.x DSO node files to the yg 0.4.x naming convention |
updateScene | infile outfile | converts yg_0.1.x and yg 0.4.x scene files to work with yg 0.4.2 and above |
ygdrasil.xml | kate syntax file | copy into /opt/kde3/share/apps/katepart/syntax on SUSE systems |
Rebuilding
The source files for Ygdrasil can be recompiled if necessary to change core
functionality or for distribution to other platforms. The core Ygdrasil executable
includes static versions of CavernSoft's QUANTA networking library, VRCO's CAVElib
library, and the Bergen client library. The QUANTA library is open source and
availlable in the downloads section
or at www.evl.uic.edu/cavern/quanta.
Researchers working in collaboration with the Electronic Visualization Laboratory
can get authorization to receive a software license from VRCO
by contacting Daniel Sandin. Proper interaction
with the desktop interface of the Ygdrasil GUI requires a version of customized
version of the CAVE libraries availlable from EVL.
The majority of Ygdrasil modules do not rely on external libraries. The movieTexture node uses the OpenQuicktime version 1.0b library to play PhotoJPEG movies. The software can be downloaded from the downloads section or at www.openquicktime.org.
To recompile Ygdrasil for IRIX systems, change the ARCHITECTURE variable in the primary Makefile to sgi. Change the YG_DIR and BERGE_DIR variables if the source code has been installed in another location.