DIVERSE Basics
August 16, 2004

John Kelso
NIST
kelso@nist.gov

                             

Abstract

This section will teach you how to use existing DIVERSE programs to load model files in various environments, using different navigational styles.  All of our examples will use DPF, the DIVERSE interface to OpenGL Performer.  No programming is required.

  1. Introduction and basic concepts
We will use Unix commands to create virtual environments- these commands, with minor changes, will work on a range of VE platforms- from laptops to CAVEs.  In this session we will use the DPF and DTK modules of DIVERSE.

The components we will be using are:
  1. Using command line tools
A Unix command is a single word, which is the name of an executable program.  You've already used some of these, including  diversifly.  Commands of relevance are:
and several others.  Here's a summary of each one:
loads model files, which are specified as command parameters.  Examples:
            % diversifly sub.pfb
loads the model file "sub.pfb" using the default configuration for this system.  Press the escape (ESC) key, with the cursor in the graphics window, to exit the program.
            % diversifly cube.pfb
loads the model file "cube.pfb" using the default configuration for this system.
            % diversifly sub.pfb cube.pfb
loads both the model file "sub.pfb" and "cube.pfb" using the default configuration for this system.
            % diversifly esprit.flt
loads the model file "esprit.flt" using the default configuration for this system.  What went wrong?
            % diversifly --examine esprit.flt
loads the model file "esprit.flt" using the default configuration for this system, and specifying the diversifly command option "--examine".  This option tells diversifly to move and scale the object so it's in front of you, and can fit in your display window.

With the cursor in the graphics window, press the "?" key.  Notice that the "ORIGIN" is non-zero, and the "SCALE" is not one.  The "--examine" option is very useful to quickly see and object when you know nothing about its geometry.
            % diversifly --origin .246 -4.96 .541 0 0 0 --scale .409 esprit.flt
 does the same thing as the previous command, but the origin and scale are specified manually as command options.
            % diversifly
prints out the diversifly "Usage" command, as you specified no models to load.  It prints out all of the options and parameters which diversifly can use.

are used to print useful information about the DPF and DTK installations on the system where the command is run.  You can use the output of this command to make shell scripts more portable, find files, check versions and so forth.  Each command, by itself, will print a "Usage" statement with all possible options.  Try it, and a few of the parameters:
        % dpf-config --about
        % dtk-config --about
        % dpf-config --env
        % dtk-config --env
is used to tell you the size of one or more model files.  You can use this information to calculate the origin and scale options for diversifly.  The dpf-bounds command, by itself, will print a "Usage" statement with all possible options.  For example:
        % dpf-bounds esprit.flt
returns a radius of 2.44.  The inverse of this number is the --scale option you passed to diversifly.  The X and Z values are the X and Z values you used in the --origin option to diversifly.  The Y option value is the negation of twice the radius of the bounding sphere plus the Y center of the object.  See the DPF Programmer's Guide if you need more details.
is one of several ways to modify the position, orientation and size of one or more model files.  It takes one or more model files as input, and a single model file as output.  Don't use the same file for both input and output!  The dpf-transform command, by itself, will print a "Usage" statement with all possible options.  For example:
        % dpf-bounds sub.pfb
        % dpf-transform --center sub.pfb /tmp/sub.pfb
        % dpf-bounds /tmp/sub.pfb
Notice that the center of /tmp/sub.pfb is at the origin.

Another way to modify the position, orientation and size of a model file is using a "pseudo loader".  These are Performer file loaders which apply a transformation when loading a model file.  For example:
        % diversifly esprit.flt.-0.246,4.95,-0.54.trans.0.41,0.41,0.41.scale
invokes the trans pseudo-loader to translate the model by (-0.246, 4.95, -0.54) and the scale pseudo-loader to scale the model by .041 in all directions.  The advantage of pseudo-loaders is that you can specify the exact order of all transformations, nesting them as deeply as you wish, all in one command.  You can combine pseudo loaders with the dpf-transform command and the options to dpf-transform will apply to the file loaded via the pseudo loaders.  For example:
        % dpf-transform --euler 0 0 60 \
              esprit.flt.-0.246,4.95,-0.54.trans.0.41,0.41,0.41.scale /tmp/esprit.pfb
        % diversifly /tmp/esprit.pfb
lists all the DSOs installed on the system on which the command run.  This is real handy when you can't remember the exact spelling (and CaSe counts too!) of a DSO.  More about this later.
erases DTK shared memory segments on the system on which the command was run.  More about this later.  You generally need to run this command after every reboot.

  1. Creating interfaces using existing DSOs
The environment variable "DPF_DSO_FILES" is used to specify a list of DSOs to be loaded when you run a DPF command.  An environment variable is set in a window, and affects only commands typed in that particular window.  For example:
        % #notice the value of DPF_DSO_FILES
        % dpf-config --env

        % export DPF_DSO_FILES="desktopCaveSimGroup"

        % #notice the value of DPF_DSO_FILES
        % dpf-config --env
You use them like this:
        % # this erases the variable so you get the default
        % unset DPF_DSO_FILES

        % # press "?" and there's no head or wand- we're in desktop mode!
        % diversifly sub.pfb

        % # use the cave simulator group
        % export DPF_DSO_FILES="desktopCaveSimGroup"

        % # press up-arrow twice to reuse- press "?" and there's now a head and a wand!
        % diversifly sub.pfb
So what's a DSO?   A DSO:
Here's the desktopCaveSimGroup DSO:
        % # Warning- trick shell stuff below!  
        % # It might not work on all machines depending on permisions
        % dpf-config --source
        % ls `!!`
        % cat `dpf-config --source`/DSOs/desktopCaveSimGroup.C
The heart of the DSO are the lines:
  if(app->load("caveSimDisplay:"
               "xkeyboardMouseInput:"
               "iconSleepKeyboardMod:"
               "caveSimInput:"
               "wandJoystickNav:"
               "toggleObjectsGroup:"
               "buttonNavControl:"
               "keyboardNavControl:"
               "debugHeadsUp"))

When you load this DSO you're really loading all of these other DSOs.  These DSOs have their programs executed in the order they're listed, so one DSO can communicate with other DSOs.  The above DSOs are:
configures the graphical output to be a single window, with a "symmetric" view frustum, field of view and scale to match a CAVE system
loads the keyboard and mouse hardware input devices using the X window system
is a little program that puts the program that this DSO gets inserted into in a sleep state when all of its graphical displays have been unmapped (minimized).  Notice that this DSO assumes a display has been created, and a keyboard device has been loaded.
creates simulated head, wand, joystick and button devices using the keyboard and mouse, which must already be loaded.  These devices are commonly found in an immersive system such as a CAVE.
is an immersive navigation that uses the wand and joystick to navigate a virtual environment.  This DSO requires a wand and joystick be created, but doesn't know if the wand and joystick are real hardware devices, or simulated by other DSOs.
displays little model files which help debug a virtual environment.  It uses the keyboard to toggle the visibility of the objects, such a cube showing the CAVE walls.
uses the buttons on a wand to control aspects of the current navigation, such as response, and to switch between all of the loaded navigational DSOs
does the same thing as buttonNavControl, but uses keys on the keyboard instead of wand buttons.
brings up an informational display when the "?" key is pressed.

So when you load this one DSO, you get all this functionality by combining other, simpler DSOs in a specific order,  You can set the DPF_DSO_FILES environment variable to contain a list of DSOs to load if you want to create your own lists, or add to other group DSOs.

Notice that you can load more than one navigation, and switch between them.  For example, let's say you wanted to load the wandJoystickHPRNav navigation in addition to the navigation loaded by the desktopCaveSimGroup DSO.
        % # use the cave simulator group
        % export DPF_DSO_FILES="desktopCaveSimGroup"

        % # press "?" and notice what navigation you're using- try rotating with space and mouse L/R
        % diversifly sub.pfb

        % # multiple DSOs are separated by a ":"
        % export DPF_DSO_FILES="desktopCaveSimGroup:wandJoystickHPRNav"

        % # press "?" and notice what navigation you're using- try rotating
        % diversifly sub.pfb
Notice how the sub rotates around the wand in the virtual CAVE? 

Try again with just desktopCaveSimGroup,
press "j" to jump outside the CAVE and rotate the sub,
press "w" to see the wand,
and "h" to see the head

The centerPivotNavMod DSO calculates the center of the loaded model files, and rotates about their center:
        % export DPF_DSO_FILES="desktopCaveSimGroup:centerPivotNavMod"
        % diversifly sub.pfb
and try rotating the sub again.

There are many more DSOs to do all sorts of interesting things.  My job at NIST consists primarily of creating DSOs and pseudo-loaders which can be used to implement different visualization techniques.

  1. Running applications on different platforms
Using DIVERSE on different platforms is easy- you just load different DSOs!  The steps I usually take are:
  1. View the model file on the desktop
        % unset DPF_DSO_FILES
        % diversifly --examine sub.pfb
  1. Resize and reposition the model, if desired
        % # dpf-transform --translate X Y Z --euler H P R --scale S sub.pfb /tmp/sub.pfb
        % dpf-transform --euler 45 45 45 --scale 3 sub.pfb /tmp/sub.pfb
  1. View the model on desktop again
        % diversifly /tmp/sub.pfb
  1. View the model in the simulator, adding interface and navigations as I think will work best in the CAVE
        % export DPF_DSO_FILES=desktopCaveSimGroup:wandJoystickHPRNav:centerPivotNavMod
        % diversifly /tmp/sub.pfb
  1. Run it in the CAVE- only need to change one DSO!
        % export DPF_DSO_FILES=vtCaveGroup:wandJoystickHPRNav:centerPivotNavMod
        % diversifly /tmp/sub.pfb
  1. Using DTK shared memory (advanced topic)
DTK shared memory can be used to let different DSOs and processes share information,   DTK shared memory can reside on a single machine, or can be networked and shared between multiple networked shared memory.

DTK shared memory is stored in one or more segments.  Each segment is like a file, and contains data for a particular purpose.  Two commonly used segments are named head and wand, for the position and orientation of the head and wand in the CAVE, or simulator.

First, we'll use DTK shared memory on a single machine.

        % # destroy any existing DTK shared memory segments
        % # don't worry if this gives an error
        % dtk-destroySharedMem -r

        % # write the simulated head and wand data to shared memory
        % export DPF_DSO_FILES=desktopCaveSimGroup:caveDTKOutput

        % # run diversifly as a detached process
        % # look at the head data by using the "?" key
        % # press "j" to jump outside, and "h" to see the head
        % # move the head with the cursor arrows
        % diversifly sub.pfb &

        % # read the head data from shared memory
        % dtk-readFloats head
Other programs use shared memory- these are used to debug the CAVE input devices:
        % dtk-caveDeviceSimulator &
        % dtk-gnomonDisplay head &
        % dtk-floatSliders head -s 3 -180 180 0 -s 4 -180 180 0 -s 5 -180 180 0 -l x y z h p r &
        % dtk-readFloats head
Now, quit all diverse programs and destroy shared memory again.

You can play the same games with the keyboard, joystick, buttons, and any other segment used by the DSOs.

Now, we can do the same thing across the network.  I (ONLY ME!!) do these commands again to send out CAVE and navigation data
        % export DPF_DSO_FILES=desktopCaveSimGroup:caveDTKOutput
        % diversifly sub.pfb &
        % dtk-caveDeviceSimulator &
        % dtk-gnomonDisplay head &
        % dtk-floatSliders head -s 3 -180 180 0 -s 4 -180 180 0 -s 5 -180 180 0 -l x y z h p r &
Now you follow my head:
              % dtk-caveDeviceSimulator &
              % dtk-gnomonDisplay head &
              % dtk-floatSliders head -s 3 -180 180 0 -s 4 -180 180 0 -s 5 -180 180 0 -l x y z h p r &

              % # start a DTK server- it reads/writes data between machines-
              % # the d option means to run as a "daemon"
              % dtk-server -d
              % # connect the head segment to the head segment on the instructor's machine
              % dtk-connectRemoteSharedMem head 192.168.0.43

              % # here's where a group DSO could come in handy!
              % # what's the difference between this and desktopCaveSimGroup?
              % export DPF_DSO_FILES=caveSimDisplay:xkeyboardInput:caveSim:caveDTKInput
              % export DPF_DSO_FILES=$DPF_DSO_FILES:setHeadView:toggleObjectsGroup:debugHeadsUp

              % # watch me move your head around
              % diversifly sub.pfb &

              % # turn off the server
              % dtk-shutdownServer