There are many types of input devices that VR Juggler
application objects can use including positional, digital, and
analog. All application objects share the same processes
and concepts for acquiring input from devices. The main thing to
remember about getting input in applications is that all VR
Juggler applications receive input through device proxies managed
by
gadget::DeviceInterface<T> instantiations. There are
gadget::DeviceInterface<T>
instantiations for each type of input data that Gadgeteer can
handle. There is one for positional input, one for analog, and so
on. In this section, we will only demonstrate the use of position
and digital device interfaces. Refer to the section called “Device Proxies and Device Interfaces” for more detailed
information on the use of all the available device
interfaces.
While there has already been a brief presentation about getting input in an application, we need something more. Since all device interfaces look the same, we will focus on an example of getting positional input. All other types are very similar. We begin with a simple application object skeleton.
class myApp : public vrj::App
{
public:
init();
preFrame();
private:
gadget::PositionInterface mWand;
}Note the declaration of the variable
mWand of type
gadget::PositionInterface. This is the
first addition to an application. Device interfaces are usually
member variables of the user application class, as in this
example.
myApp::init()
{
mWand.init("NameOfPosDevInConfiguration");
}The device interface has to be told about the device from
which it will get data. This is done by calling the device
interface object's init() method with
the symbolic string name of the device. This device name comes
from the active configuration. We are now ready to read from
the device.
... const float units = getDrawScaleFactor(); gmtl::Matrix44f wand_pos(mWand->getData(units)); ...
The above code shows an example of using the positional device interface in an application. It shows some sample code where the application copies the positional information from a device interface. When it is dereferenced, the device interface figures out what device it points to and returns the data from that device. Again, refer to the section called “Device Proxies and Device Interfaces” for more information about using device proxies and device interfaces.
In the previous section, we showed how to get input from devices, but we never said where to put the code. The location, surprisingly, is application dependent. There are some very good guidelines regarding where applications should process input. Before explaining them, however, we should review the VR Juggler kernel control loop, presented again in Figure 4.1, “VR Juggler kernel control loop”.
This diagram looks complicated, but the key here is the
updateAllData() call near the bottom
of the diagram. This is where the Gadgeteer Input Manager
updates all the cached device data that will be used in drawing
the next frame. This updated copy is used by all user
references to device data until the next update and the end of
the next frame of execution.
This means two things:
The device data is most fresh in
vrj::App::preFrame(), and
Any time spent in
vrj::App::preFrame() increases
the overall system latency.
The first point is important because it means that the
copy of the device data with the lowest latency is always
available in the preFrame() member
function. The second point is equally important because it says
why user applications should not waste any time in
preFrame(). Any time spent in
preFrame() increases system latency
and in turn decreases the perceived quality of the environment.
Hence, it is crucial to avoid placing computations in
preFrame().
In this section, we present a tutorial that demonstrates simple input handling using Gadgeteer device interfaces. The tutorial overview is as follows:
Description: Simple application that prints the location of the head and the wand.
Objective: Understand how to get positional and digital input in a VR Juggler application.
Member functions:
vrj::App::init(),
vrj::App::preFrame()
Directory:
$VJ_BASE_DIR/share/samples/OGL/simple/simpleInput
Files: simpleInput.h,
simpleInput.cpp
In the following class declaration, note the data
members (mWand, mHead,
etc.). This application has four device interface member
variables: two for positional input
(mHead and mWand) and
two for digital input (mButton0 and
mButton1). Each of these member variables
will act as a handle to a “real” device from
which we will read data in
preFrame().
1 class simpleInput : public vrj::GlApp
{
public:
virtual void init();
5 virtual void preFrame();
public:
gadget::PositionInterface mWand; // Positional interface for Wand position
gadget::PositionInterface mHead; // Positional interface for Head position
10 gadget::DigitalInterface mButton0; // Digital interface for button 0
gadget::DigitalInterface mButton1; // Digital interface for button 1
};The devices are initialized in the
init() member function of the
application. For each device interface member variable, the
application calls the variable's own
init() method. The argument passed
is the symbolic name of the configured device from which
data will be read. From this point on in the application,
the member variables are handles to the
named device.
1 virtual void init()
{
// Initialize devices
mWand.init("VJWand");
5 mHead.init("VJHead");
mButton0.init("VJButton0");
mButton1.init("VJButton1");
}The following member function implementation gives an example of how to examine the input data using the device interface member variables.
1 virtual void preFrame()
{
if ( mButton0->getData() )
{
5 std::cout << "Button 0 pressed" << std::endl;
}
if( mButton1->getData() )
{
std::cout << "Button 1 pressed" << std::endl;
10 }
std::cout << "Wand Buttons:"
<< " 0:" << mButton0->getData()
<< " 1:" << mButton1->getData()
15 << std::endl;
// -- Get Wand matrix --- //
const float units = getDrawScaleFactor();
gmtl::Matrix44f wand_matrix(mWand->getData(units));
20 std::cout << "Wand pos: \n" << wand_matrix << std::endl;
}
| These statements check the status of the two digital buttons and write out a line if the button has been pressed. |
| This writes out the current state of both buttons. |
| The final section prints out the current location of the wand in the VR environment. |