One of the primary features of FreeVR is the configuration flexibility. However, this boon can be the bane of the person responsible for administering the VR system. Flexibility necessitates a somewhat complex configuration file. The plan for the future is to aid the administrative process with GUI and other tools that can create a config file based on a set of parameters. For the moment however, the creating of the configuration file is largely a manual process, though some assistance can be garnered by looking at the freevr.bnf file (which describes the "language" of the configuration file). There are also many example configuration files in the etc directory named rc_sample_... something. Each has a specific flavor — the rc_sample_ks is the "Kitchen Sink" version which just has a lot of examples.
The one program that can provide some assistance in particular circumstances is the cave2fvr AWK script. If you have, or can easily create a configuration file for the CAVE library, then this script can be used to rapidly produce a usable FreeVR configuration file.
One tool that is available to help debug configurations as well as the library and some applications is the ability to communicate with a running FreeVR application via a socket port. This provides administrators and developers the ability to telnet or otherwise connect to a socket and view and manipulation information on the running FreeVR application. This process is described in the auxiliary Telnet/Socket Interface Manual.
Another aid for honing a configuration file is to use what we will refer to as a "live" simulator view — a simulator window with live tracking.
FreeVR contains a default configuration that provides some reasonable control and display features for testing a FreeVR application on a typical desktop environment (keyboard, mouse & monitor). This will have a simulator view under user control.
The inputs of the default configuration, and some of the configurations that can be specified operate in a way that mimics the presence of body-tracking hardware to allow the program developer to move the user's head and hand (with wand) around as well as push buttons, and move the joystick. The default system assumes a typical CAVE[tm] hardware setup, which includes two body trackers (head and wand), three buttons, and a 2-valuator joystick. The typical CAVE working volume is a 10x10x10' cube.
NOTE: Currently some operating system configurations (such as Solaris) map the keypad keys to an inconvenient setting. This setting can make operation of the simulated hardware difficult. It is hoped that the xmodmap command will help alleviate the problem, but we haven't had the time to figure it out yet.
The primary key to know is the '?' (or '/') key. Pressing this key should display to the shell a usable collection of information to allow you to control the simulated inputs. The rest of the default inputs is:
The simulated window also has some controls to change the view into the virtual world: (NOTE: many of these are affected by the "bad" xmodmap of Solaris.)
FreeVR currently looks in three places for configuration files that can override the built-in default configuration. Each subsequent file can override the previously read configuration files, so order matters. The order is:
When the FreeVR distribution is first untarred, it is very likely that none of these files exist (the distribution does not contain any file called .freevrrc. However, one of the sample configuration files (rc_sample_<type>), or a configuration created by the cave2fvr script can be copied or renamed to .freevrrc to run in some way other than the default.
The file freevr.bnf (in the source directory) is an extended Baukus-Naur Form describing the syntax of configuration statements. Legal configuration files should fit this form. All the available, and currently planned options for each of the statements are listed in this file. Options that are not yet implemented are denoted by the ASCII frowny-face icon (:-().
The basic syntactical form is a group of statements that define configuration "objects" that can be linked together to describe a complete "system." The generic format of an object description is:
<object type> <object name> { "=" | "+=" } "{" <option 1> { "=" | "+=" | "*=" } <option settings> ";" ... "}"Where <object type> is one of: system, proc, window, eyelist, user, inputdevice, inputmap, or prop. The <object name> can be any valid string. The assignment operators ("=", "+=" or "*=") signify what type of assignment should take place. The basic equals ("=") assignment will override any previous value for the object type or option. The plus-equals ("+=") will append or add the given value to the object description, or option value. The times-equals ("*=") assignment is only valid for options with numeric values (including arrays and matrices), and will multiply the current value by the given value. A comma-separated list of <option settings> is terminated by a semicolon.
Statements other than object definition statements are also possible in the configuration description. Such statements include the usesystem statement, the set and setdefault statements, plus some miscellaneous commands such as echo and readconfig.
Separation of tokens in the configuration description is based only
on generic whitespace.
The use of newlines or tabs is never required.
Configuration Conditionals
A major factor in making the FreeVR configuration system so flexible is
the ability to use conditionals during the configuration parsing.
Conditionals can be used to startup a different system based on
the machine's hostname, or based on the version of FreeVR that an
application was compiled with, or even based on an environment variable
set in the shell from which the application is launched.
For example, an application launcher tool might have a setting to choose
between sterescopic and monoscopic rendering, and that setting can be
passed to the configuration through the use of an environment variable.
Or a CAVE with movable side walls might have mutltiple wall configurations
built in, with the proper configuration selected by checking a system value.
The syntax for the conditional statement will be familiar to any
C/C++/C#/Java/etc. programmer:
if <condition> then <statement> [else <statement>]where:
Thus portions of the configuration can be skipped or included based on factors external to the application and perhaps changing for particular circumstances — such as using monoscopic rendering for a VR photo-shoot.
Possible variables and functions available within the configuration
system are discussed in the following two sections.
Configuration Variables
One of the unique features (among VR libraries) of FreeVR is the ability to set and make use of variables in the FreeVR configuration file. The two primary uses of configuration variables are 1) allow a single setting to be used in multiple places within the configuration (including in mathematical expressions); and 2) for conditional settings within the configuration file, using the conditional statement. Another use can be for outputting information about the system to the terminal during initialization.
Configuration variables are of two types: built-in system variables, and standard shell environment variables. The environment variables may be set in the shell prior to running the VR application, or they may be set within the config file itself with the "setenv" command.
The built-in variables are typically used by the VR administrator to create a configuration system that can respond to specific conditions of the FreeVR setup. Some variables are not useful within the configuration, but can be used in the socket/telnet interface. Here is the current list of built-in variables
Variables are used by prepending their name with the dollar symbol ($). The current implementation of FreeVR config parsing does not, in general, allow strings to be concatenated by default, so multiple string segments must be specifically constructed in the one command that does do concatenation, and that is the setenv command.
Note that a complete list of debug levels can be found in the debug.1fv manpage.
Configuration Functions
There are a limited number of functions available in the FreeVR configuration parsing system. And thus far their use is limited to making a query about the existing of whether a particular configuration object has already been defined. Specifically:
The use of these functions would mostly be in the circumstance where a
personal configuration file ("~/.freevrrc") alters the configuration
based on how the general system configuration files have been parsed.
Configuration Objects and Hierarchy
The basis of FreeVR configuration is a collection of config-objects related in a directed graph. There are eight defined types of objects within the graph, two of which presently have very limited configurability ("Input-map" and "Prop").
The general organinzation of the directed graph is:
System / \ / \ / \ Processes Input-map / \ \ (Vis-Ren) (Input) \... Windows Input-devices | Eye-list / | \ Props Eye Eye Eye ... \ / \ User User
A VR "system" is built up from objects describing a portion
of the overall layout.
Multiple systems can be defined in the same configuration file.
The usesystem config statement is used to select from among
the available systems.
Several systems are defined in the example freevr.rc file.
The "system" Object
The system object is used to bring together the main components that describe how the current hardware to be used. The system object links to a group of process objects, and a single inputmap object.
The system object has options for running an independent program at the beginning and end of FreeVR operation. These can be any program commands that might be typed into a shell. These options are: ExecAtStart and ExecAtStop. The are followed by the equal sign (=) and a string with the command (usually within quotation marks). Prior to execution, the string will replace the constants #N, and #P with the name and process-id of the system respectively. These two options are also available on a per-process basis.
If problems with the configuration are encountered during system initialization an error flag are set for each problem. Each flag is assigned a separate bit in the overall error code, and when any error is encountered, a shell command can be executed, and/or the system can prematurely terminate operations. To execute a command, the ExecUponError option can be set to a string in the same manner as ExecAtStart and ExecAtStop. The ExecUponError option has one additional string replacement — a #E in the command will be replaced with the decimal representation of the error code. This is useful to warn the user that the system may not be functioning properly.
A related option is the ExitUponError which task a bitmask of the error types and if there are any errors, and the error code anded with the bitmask are non-zero, then the system will exit immediately — because things probably weren't going to work anyway. The ExitUponError value is set by given an equal sign and a number. [NOTE: ideally this number can be specified in hex or binary, but a bug in the current config parsing prevents this — or maybe it would work if given inside quotations.]
The types of errors currently encoded in the startup error code (and their bit values) are:
system "cave" = { procs = "cave-visren1", "cave-visren2", "cave-visren3", "cave-visren4"; inputmap = "default"; exituponerror = 2; execuponerror = "xmessage 'There is a problem in the configuration — #E' > /dev/null"; execatstart = "xmessage 'Visbox system #N starting. PID is #P' > /dev/null &"; execatstop = "xmessage 'Visbox system #N stopping.' > /dev/null"; }
A FreeVR process is an operation that can be forked off of the main process and run independently. FreeVR processes are each defined to serve a particular role in the execution of the application. Thus far, the process types that have been implemented are: the visual rendering process (visren) and the input device communication process (input).
The two main options that need to be set for all processes are
the
Three other useful options are the sync, execAtStart, and
execAtStop options.
However, there is a bug in the process-syncing code, so I won't bother
describing it in this edition of the guide.
The execAtStart and execAtStop options work the
same as their counterparts in the system object configuration.
For debugging purposes, there are three additional useful
options: printcolor, printstring, and printfile.
These all affect how (and where) text printed by the process will appear.
The printcolor option is used to specify a number that
fits in the ANSI terminal sequence for changing the text color
on that terminal.
Any ANSI mode number can be used.
Some common ones are:
The printstring option is used to specify a string that
is prepended to all messages printed by the process.
(For example, the name of the process.)
The printfile option is used to specify a file that
all messages should be sent to instead of the startup-terminal.
Note that if a terminal device is given, then the text will
appear on that terminal instead.
In fact, this was the initially desired use.
Note that the three print options can be used together in any way
the configurer desires.
A basic visual-rendering "process" object definition might appear:
A basic input "process" object definition might appear:
A window in FreeVR is the basic means of presenting
the visual aspects of a virtual world to the user.
At the moment, the type of graphics rendering that will occur
within the window needs to be defined for each window
(eg. "glx", "java3d", "performer").
At the moment, only type "glx" is implemented.
It is uncertain if this choice will continue to be specifically
linked to the window definitions.
The only bits of information that are dependent on the type of
graphics rendering are display options such as multi-sampling,
and the method of determining which physical screen to render
to (although on UNIX systems, the X-windows method can generally
be assumed).
The type of graphics window is set via the graphicstype
option.
Window objects can be of four major types: in a fixed position
in the real world, as is typically of CAVEs and other projection-based
VR displays; attached to a user's head, as is the case for HMDs and
BOOMs; attached to a user's hand, a less common but valid form of
display; and finally as a "simulated" view into the virtual world.
Currently, the only three types of window displays that have been
implemented are the "fixed", "headmount" and "simulator" types.
The nature of the window is set with the mount option,
with potential values of: fixed, fixed, handheld
and simulator.
Currently, the "headmount" option has not been thoroughly tested,
but at least partially works.
The position of the window in the real world, relative to the (RW) origin,
is specified using the rw2w_translate, rw2w_rotate and
rw2w_transform options.
Operations on the rw2w (ie. real-world to window) transformation
matrix can be combined using the "*=" operation.
Each method of transforming the matrix takes a different number
of arguments.
The rw2w_translate option takes three numbers — an X,Y, and Z
displacement.
The rw2w_rotate option takes four numbers — an axis specified by
X,Y, and Z, followed by a rotation in degrees.
The rw2w_transform options simply takes the 16 numbers that
make up the complete matrix, in column-major ordering.
The eyelist and visrenmode options control how rendering
to multiple eyes is handled.
This is explained in more detail under the description of the
eyelist objects.
Finally, window objects can have arguments specific to the type
of rendering format being used (eg. "glx").
The args option is basically just a long string that
is passed to the window-specific routines, and parsed therein.
To keep things short, the three major window-argument options
for "glx" are display, geometry, and decoration.
The display and geometry arguments are the
basic values for X-windows, and decoration should
be set to either "none" or "title."
Here is a typical description of a window:
The FreeVR eyelist object is the key to making the system extremely
flexible with regards to the many ways stereoscopic and multi-user
rendering can be configured.
The object however is nothing more than six lists of eyes,
where each eye specifies a user; the left, right or other eye
of that user; and a colormask (which defaults to full color
when not specified).
The six lists correspond to four different visual rendering
modes that can be selected by the visrenmode option
of a "system," "window," or the global default.
If no visrenmode is specified for a window, then
it uses the default value for the system.
If no visrenmode is specified for the system,
then the global default is used.
If no global default visrenmode is specified by
the configuration, then the library default is used,
which is the eyelist named "default."
The five choices for visrenmode are: "mono," stereo,"
"dualfb," "dualvp" and "anaglyphic."
NOTE: The "stereo" selection was intended to be a special case
in that it would determine what method of stereoscopic rendering
is most appropriate based on the configuration, and the hardware available.
However, the "stereo" choice was never implemented, and is now slated
for deprecation.
The selected visrenmode choice then determines
which of the lists of eyes will be used for rendering.
For "mono" rendering, the "monofb" list is used.
For "dualfb" (ie. dual frame buffer) rendering, the
"leftfb" and "rightfb" lists are used.
For "dualvp" (ie. dual view-port) rendering, the
"leftvp" and "rightvp" lists are used.
For the "anaglyphic" method, the "anaglfb" list is used.
The format of specifying an eye is:
<user-name>:<eye-type>:<colormask> —
with the final colon, and colormask being optional.
Choices for eye-type are: "lefteye," "righteye"
and "cyclops."
The latter is best choice for monoscopic rendering.
These two examples will hopefully shed some light on this:
Currently, the Freevr "user" object is used to specify just two things.
The most important of these things is the interocular distance.
The other is the color the user's head will be represented as
in simulator display windows.
Here is an example:
Input devices are one of the keys to providing a flexible VR library.
A handful of input devices have already been integrated into
FreeVR, with hopes that dozens more will soon be added.
One of the goals of input configuration is that the application
shouldn't have to know what types of inputs are available,
in fact, applications should be runnable in as many environments
as possible, and thus input devices need to be able to mimic
other devices.
The main option of inputdevice specification is the type.
The list of possible types can be found in the vr_input.opts.h file.
This is the file used by FreeVR to access the routines necessary
for communicating with the input device based on the type selected.
Input devices providing 6-dof position input information have two
matrix transformations used to describe the relationship between
the input hardware and the real-world.
The "t2rw" transformation describes the relationship from the
hardware's transmitter to the real-world origin.
the "r2e" transformation describes the shift from the hardware's
receiver to some entity (a user's bodypart, or some prop).
The operations (t2rw_translate, t2rw_rotate, t2rw_transform,
r2e_translate, r2e_rotate and r2e_transform) are all specified
in the same manner as "rw2w" is for windows (above).
As with windows, a device independent argument string can be
set with the args option.
Arguments typically at least include the information necessary
with communicating with the device — serial ports, baud rates,
shared memory keys, etc.
The source code of many of the input devices lists the available
arguments at the comment at the top of the file.
Also, the example .freevrrc file includes an "inputdevice" object
for each of the implemented input devices.
Finally, "inputdevice" object must specify the inputs available
from that device, and how those inputs are related to the
physical hardware.
The input and control options are used to
specify this information.
The format of the input option is:
The format of the control option is:
Here is a simple "inputdevice" object example for the Magellan.
For a more complete example, see the .freevrrc file:
Here is a table of the current list of controls
available to various input devices:
Valuator controls:
In the current version of FreeVR, the "inputmap" system has not yet
been implemented, with the exception of a couple of hard-coded settings.
For now, the only inputmap that should be selected in the
system configuration objects is the "default" map.
In this mapping, every input from all the input devices in the
selected system are included in the mapping.
They are simply ordered by the order of the devices as they
appear in the objects list of the input-processes, and the
order in which they appear in the input options within
those devices.
How props will be involved in FreeVR has not been completely
worked out yet, so little will be said about them in this draft.
Very little.
One again, let me reiterate that the boon of FreeVR is the wide range
of VR setups that can be configured — all at runtime.
Yet, this means the configuration description will be a little
complicated.
Hopefully we'll have some more tools to aid in this process in the near
future, but for now, it's easiest to work from one of the provided examples
Good luck.
(But the best advice is to start with an example configuration and work from there.)
Red is also a valid choice, but it is already used by FreeVR to signify
important warning and error messages, so it's use here is discouraged.
NOTE: For readability, it is generally wise to set some
variables that map the numbers to the corresponding colors.
For example:
setenv ANSI_BLUE 34;
[...]
process "visren-default" += {
printcolor = $ANSI_BLUE;
}
process "cave-visren2" = {
type = visren;
objects = "left-cave"; # the left screen of the CAVE
sync = 1; # sync with all processes that use barrier #1
printcolor = $ANSI_BLUE; # print in blue
printstring = "visren1: ";
printfile = "/dev/console";
}
process "xwinsim-input" = {
type = input;
printcolor = $ANSI_MAGENTA;
objects = "xwinsim";
#DebugThisToo = 153; # uncomment this to see Xwindow debugging details
}
The "window" Object
window "left-cave" = {
GraphicsType = "glx";
args = "display=:0.0; geometry=1024x768+0+0; decoration=none";
# These two options specify where the window is located in the RW
mount = "fixed";
rw2w_translate = 5.0, 0.0, -5.0;
rw2w_rotate *= 0.0, 1.0, 0.0, 90.0;
# Note that by defining the eyes and visrenmode to "default" will
# specifically override any settings in the "system" option, so
# they should only be included when necessary.
# eyelist = "default";
# visrenmode = default;
}
The "eyelist" Object
eyelist "default example" = {
monofb = default:cyclops;
leftfb = default:lefteye;
rightfb = default:righteye;
leftvp = default:lefteye;
rightvp = default:righteye;
anaglfb = default:lefteye:red, default:righteye:blue;
};
# The following eyelist renders stereoscopic images to two tracked
# people by combining the dual frame buffer method of stereo with
# anaglyphic rendering.
eyelist "specialA" = {
leftfb = default:lefteye:blue, user2:lefteye:red ;
rightfb = default:righteye:blue, user2:righteye:red;
};
The "user" Object
user "greenuser" = {
iod = 0.5; # interocular distance (in feet)
color = 84, 134, 72; # a forest-green hue
}
The "inputdevice" Object
"input" <arbitrary input name> = <input type>(<input source>);
Where, the "arbitrary input name" is the string that will be used
to specify a particular input in "inputmap" objects; input type is
one of "2switch," "valuator" or "6sensor"; and input source is what
part of the hardware (or virtual device) should be used to generate
the input.
For example, for the magellan 6-dof input device, a button press input
can be generated by pressing the "1" button on the hardware using:
input "first magellan button" = "2switch(button[1])";
"control" <device control> = <input type>(<input source>);
In this case, the "device control" is a specific string that is
particular to the type of input, and activates some internal change
in the input device.
For example, to get the "magellan" device to reset the current 6-dof
sensor when the "8" button is pressed:
control "reset_sensor" = "2switch(button[8])";
In this case "reset_sensor" is defined in the "magellan" source code,
with a list of possible controls given at the top of the file.
inputdevice "mag-default" = {
type = "magellan";
args = "baud= 9600; port = /dev/input/magellan";
t2rw_translate = 0.0, 4.0, 0.0;
r2e_rotate = 0.0, 0.0, 1.0, -90.0;
r2e_translate *= 1.0, 0.0, 0.0;
input "2switch[1]" = "2switch(button[1])";
input "2switch[2]" = "2switch(button[2])";
input "2switch[3]" = "2switch(button[3])";
input "valuator[x]" = "valuator(mag[tx])";
input "valuator[y]" = "valuator(mag[ty])";
input "6sensor[0]" = "6sensor(6dof[0], r2e)";
input "6sensor[1]" = "6sensor(6dof[1])";
input "6sensor[2]" = "6sensor(6dof[2])";
control "toggle_space_limit" = "2switch(button[4])";
control "toggle_relative" = "2switch(button[7])";
control "next_sensor" = "2switch(button[5])";
control "reset_sensor" = "2switch(button[6])";
control "toggle_valuator" = "2switch(button[8])";
}
The "inputmap" Object
The "prop" Object
Conclusion
© Copyright William R. Sherman, 2021.