FreeVR Library Programming Tutorial (w/ OpenGL)

The FreeVR Library will be used to exemplify many VR interface and programming techniques. FreeVR will work in most local VR facilities (eg. CAVE™ or Head-Based-Display), as well as on the available desktop machines in a simulated-VR mode. It can be used on PC's with Linux and OpenGL installed, or in a (currently very) limited way on PC's with Cygwin installed.

The FreeVR webpage is www.freevr.org.

This tutorial takes the approach of starting with an extremely simple initial example and then advancing in very small increments (baby steps) until we can perform some interesting tasks in virtual reality. Another point to make about this tutorial is that it is not intended as a means to learn advanced OpenGL programing. The computer graphics in these examples are all very simple. The goal of the tutorial is to highlight programming tasks that are unique to programming for a virtual reality system.

On the other hand, some basic OpenGL techniques can be learned by following this tutorial, as it will show how to handle texture maps, billboards, cutting planes, and moveable lights.

Other tutorials are under development for interfacing FreeVR to additional rendering and world simulation systems. Presently there is a tutorial available for the SGI Performer scene-graph library, but as Performer has greatly decreased in usage new tutorials will cover similar, but more popular libraries.

This tutorial has been most recently tested with FreeVR version 0.6a.


Part 1: Examples 0 - 5

In Part 1 of this tutorial we will cover five example programs (with some varients of those). These five examples will bring us to the point where we can retrive some very basic input information from the user of the VR system and make basic alterations of the virtual world.

We will also discuss:








Components of a VR system

The FreeVR integration library — a crucial component of a VR system

Features of a typical VR-integration library



Example 0: A simple virtual world — in Xwindows (ex0)

 



Basic structure of FreeVR Library application

The FreeVR Library runs many tasks in parallel. This helps reduce tracker lag, as well as maintain better frame rates.

Function callbacks are used to inform the library how to render, etc. Shared memory is used by the library to maintain consistency across processes, and by the application to pass data from the simulation to the rendering.



Example 1: The bare essentials FreeVR application (ex1)

 


Example 2: A more civilized FreeVR application (ex2)



Example 3: A world with some action (ex3)

The two objects of the simple virtual world are now dynamic. They move over a simple path. One new (static) object has been added to the world. The user still cannot interact with the world other than moving to view it from another perspective.



Aside: Simulating VR on the Desktop

Frequently, the availability of a virtual reality facility might be limited. This might be the result of high usage of the facility, or for some developers, the facility might be located at a distance that precludes frequent visits. In any case, there is a general need for developers of VR applications to be able to do some amount of testing at their desktop, on systems that do not have the input or output capabilities of a true VR display. Therefore most VR integration libraries include the ability to simulate running VR applications with more mundane interfaces.

Aside: FreeVR naming conventions

To facilitate the writing and interpretation of FreeVR application code, the FreeVR library adheres to a set of naming conventions. The conventions are:




Aside: FreeVR complex types

FreeVR provides a small set of type definitions for operations on mathematical types that contain more than a single scalar value. In most cases, the internal data representation is a single dimensional array of values.

The types are:

The types vrPoint and vrVector have identical internal representations. Therefore they can be easily converted through a simple type-cast. However, mathematically points and vectors are different, therefore it is strongly advised that the appropriate type be used for any given circumstance.
NOTE: one can think of points and vectors as actually being 4 element arrays, with the fourth element of a point being '1' and the fourth element of a vector being '0'.

The use of the vrEuler type is strongly discouraged. There are two occasions in which vrEuler is not discouraged:

For functions returning values as a complex type, the first argument is always a pointer to the location into which the result will be copied. The function then returns a copy of that pointer as the return value. The reason for doing this is to eliminate the need for the library to continually allocate and deallocate memory when performing these operations. By returning a copy of the pointer as the return value, it is possible to nest operations.




Aside: FreeVR inputs

Having the ability to render worlds that provide the proper perspective for a VR user is a good start to creating a virtual reality experience. But a world in which all the user can do is move their head about to see from different perspectives can become boring rather quickly. Therefore, the next two examples (ex4 & ex5) begin to demonstrate the basic means by which physical inputs from a hand-held controller can affect the virtual world.

Later examples with introduce more complex means of interaction, including direct input interactions, virtual input interactions, as well as a means by which agent input interactions can be accomplished.

There are three types of FreeVR inputs that are most commonly used:

Each type of input can be querried in one of two ways:

Using the "Delta" form of the input queries can be especially useful when determining whether a button was just pressed or just released.

NOTE: In general, input queries should take place only in the simulation routine, and not in any of the rendering routines. The effects of the inputs should then be calculated as part of the simulation, and passed to the rendering routines as part of the state of the world.




Example 4: Very simple inputs — buttons (ex4)

The use of buttons to affect the virtual world is the most basic form of input possible. In this example, buttons 1 and 3 (which frequently correspond to left and right buttons on a VR controller) move the green pyramid up and down by one unit. Button 2 resets the green pyramid back to the center of the working volume.

                  

This type of interaction where the manipulation of a physical input device causes an immediate response to an object in the virtual world is known as the "physical control" input method.

Here is a sample of the new code:

	update_world(WorldDataType *wd)
	{
		...
		if (vrGet2switchDelta(1) == 1)
			wd->obj3_y += 1.0;
		if (vrGet2switchDelta(2) == 1)
			wd->obj3_y =  5.0;
		if (vrGet2switchDelta(3) == 1)
			wd->obj3_y -= 1.0;
		...
	}

NOTE that by using the "Delta" version of the input query we can easily specify that the world database should be altered precisely when a particular button has just been pressed (vs. all the time that it is pressed).

  • There are minor differences between ex3 and ex4.

    Example 5: Very simple inputs — valuators/joysticks (ex5)

    Another typical controller input for virtual reality (as well as other hardware such as game controllers) is the joystick. A joystick is really just two valuators connected to allow one to easily move in both the X and Y directions at the same time.

                      

    NOTES:

  • It is generally a good idea to have a "dead zone" around the zero value due to the nature of physical inputs — often there is no precise zero value so a small positive or negative number will be returned instead. Also, light presses on sensitive joysticks may cause unwanted movement. The JS_EPSILON factor represents the size of the dead zone.

  • This example shows two ways of handling the "dead zone". In the case of the joy_x value, as soon as the X dimension of the joystick moves past the epsilon value, the movement will immediately jump to that value, causing a discontinuity in the movement.

    For the joy_y value, the epsilon value is subtracted from the input (in a sign-neutral way) such that when the input moves slightly outside the epsilon range, it will respond with slight movements reflecting the small delta between the actual value and the epsilon.

  • The previous button inputs (from example 4) are still active, so they too can control the green pyramid, and in particular button 2 will reset the location of the pyramid — though the code changed a bit to reset all three location parameters.

    
    
    
    Last modified 10 January 2010.
    Bill Sherman, shermanw@indiana.edu
    
    
    © Copyright William R. Sherman, 2010.
    All rights reserved. In particular, republishing any files associated with this tutorial in whole or in part, in any form (included electronic forms) is prohibited without written consent of the copyright holder. Porting to other rendering systems is also prohibited without written consent of the copyright holder.