Base Application Object Interface

Within this section, we provide a brief overview of the member functions from the base VR Juggler application interface. This interface is defined by vrj::App, and the member functions are shown in Figure 2.3, “Application object interface”. Refer to Figure 2.2, “Kernel loop sequence” for a visual presentation of the order in which the methods are invoked.

The base interface of the application object defines the following functions:

As previously described, the VR Juggler kernel calls these functions from its control loop to allocate processing time to them. These functions handle initialization and computation. Other member functions that can be used for reconfiguration, focus control, resetting, and exiting will be covered later in this book.

Figure 2.3. Application object interface

Application object interface

Initialization

The following is a description of the application objects related to the initialization of a VR Juggler application. The order of presentation is the same as the order of execution when the application is executed by the kernel.

vrj::App::init()

The init() method is called by the kernel to initialize any application data. When the kernel prepares to start a new application, it first calls init() to signal the application that it is about to be executed.

Timing

This member function is called immediately after the kernel is told to start running the application and before any graphics API handling has been started by VR Juggler.

Uses

Typical applications will utilize this method to load data files, create lookup tables, or perform some steps that should be done only once per execution. In other words, this method is the place to perform any pre-processing steps needed by the application to set up its data structures.

vrj::App::apiInit()

This member function is for any graphics API-specific initialization required by the application. Data members that cannot be initialized until after the graphics API is started should be initialized here.

Note

In OpenGL, there is no concept of initializing the API, so this method is normally empty in such applications.

Timing

This member function is called after the graphics API has been started but before the kernel frame is started.

Uses

In most cases, scene graph loading and other API-specific initialization should be done in this method.

Frame Functions

Once the application object has been initialized by the VR Juggler kernel, the kernel frame loop begins. Each frame, there are specific application object methods that are invoked, and understanding the timing and potential uses of these methods can improve the functionality of the immersive application. In some cases, it is possible to use these member functions to optimize the application to improve the frame rate and the level of interactivity.

vrj::App::getDrawScaleFactor()

As of VR Juggler 2.0 Alpha 1, applications can specify the units of measure that are the basis for the graphics they render. The default unit of measure is feet (identified by the constant scale factor gadget::PositionUnitConversion::ConvertToFeet) to maintain backwards compatibility with the previous VR Juggler semantics. By overriding this method, applications can identify the unit of measure they expect. The default implementation is the following:

float vrj::App::getDrawScaleFactor()
{
   return gadget::PositionUnitConversion::ConvertToFeet;
}

Overriding this method means changing the rendering scale factor used by the VR Juggler Draw Managers. The current list of constants (defined in gadget/Position/PositionUnitConversion.h) is as follows:

  • gadget::PositionUnitConversion::ConvertToFeet

  • gadget::PositionUnitConversion::ConvertToInches

  • gadget::PositionUnitConversion::ConvertToMeters

  • gadget::PositionUnitConversion::ConvertToCentimeters

Because the value returned is simply a scaling factor, user applications can define whatever units they want. Note that internally, VR Juggler is treating all units as meters, so the scaling factor converts from meters to the desired units.

vrj::App::preFrame()

The preFrame() method is called when the system is about to trigger drawing. This is the time that the application object should do any last-minute updates of data based on input device status. It is best to avoid doing any time-consuming computation in this method. The time used in this method contributes to the overall device latency in the system. The devices will not be re-sampled before rendering begins.

Timing

This method is called before triggering rendering of the current frame.

Uses

In general, this method should be reserved for “last-millisecond” data updates in response to device input (latency-critical code).

vrj::App::latePreFrame()

The latePreFrame() method is called after preFrame() and after shared application-specific data is synchronized among the cluster nodes (see the section called “Cluster Application Programming” for more details) but before the scene is rendered. Scene graph-based application objects making use of application-specific data in a cluster configuration should perform scene graph updates based on the most recently received copy of the shared application data. Application objects not using a scene graph can make state updates in this method or in the rendering method (draw() in the case of vrj::GlApp). The writer node must have written to the shared application data in preFrame() to minimize the latency of the data.

Timing

This method is called after application-specific data is sychronized among the cluster nodes but before triggering rendering of the current frame.

Uses

When using shared application-specific data with a scene-graph based application object in a cluster configuration, the nodes that read from the shared data (those where cluster::UserData<T>::isLocal() returns false) should perform state updates based on the freshly received update to the shared data.

vrj::App::intraFrame()

The code in this method executes in parallel with the rendering method. That is, it executes while the current frame is being drawn. This is the place to put any processing that can be done in advance for the next frame. By doing parallel processing in this method, the application can increase its frame rate because drawing and computation can be parallelized. Special care must be taken to ensure that any data being used for rendering does not change while rendering is happening. One method for doing this is buffering. Use of synchronization primitives is not recommended because that technique could lower the frame rate.

Timing

This method is invoked after rendering has been triggered but before the rendering has finished.

Uses

The primary use of this method is performing time-consuming computations, the results of which can be used in the next frame.

vrj::App::postFrame()

Finally, the postFrame() method is available for final processing at the end of the kernel frame loop. This is a good place to do any data updates that are not dependent upon input data and cannot be overlapped with the rendering process (see the discussion on vrj::App::intraFrame() above).

Timing

This method is invoked after rendering has completed but before VR Juggler updates devices and other internal data.

Uses

Some possible uses of this method include “cleaning up” after the frame has been rendered or synchronizing with external networking or computational processes.