A virtual reality application can be easily bulit on the top of Metis API. The application is called a simulator, which is run on a server. A viewer, running on a local or remote client machine, renders the scene by connecting to the server via a network and recieving the graphics command sent by the server. The server is responsible for constructing the scene, while the client, by maintaining the Metis scene structure, takes care of displaying the scene graph and interaction with user, communicating with the server if necessary.
The Metis scene structure, mentioned above, consists of a directed acyclic graph of nodes, which represents the static graphical state of the scene, and a constraint graph, which maintains dependency relationships between the nodes and implements dynamic behavior. A node is an abstract description of an object. A node can be a sphere in space or a material description that specifies color and other visual surface properties of an object. All externally visible state of a Node is represented by its variables, which are active objects containing data of various types. For example, a material node is defined as follows:
Material {
Color diffuse;
Color emissive;
Real shininess;
Color specular;
Real transparency;
}
A grouping node can maintain a group of subnodes. The Transform node is such a kind of node. It defines a coordinate system and thus seperates its subnodes from the rest of the scene. The following C++ prototype defines the Transform node.
Transform {
NodeList children;
Quaternion rotation;
Vector scale;
Vector translation;
Matrix matrix;
}
For virtual reality purpose, Metis supports a collection of real three-dimensional input and output devices including spaceball, headtracker, 3D mouse and stereo glasses.
Another component of the Metis scene structure is the constraint system. A constraint is unidirectional and it is analogous to a function, with one output and a number of inputs. Every type of constraint does a particular task very well. By linking certain types of constraints together and attaching their inputs and outputs to variables in the node subsystem, we can build a constraint network that establishes functional dependency relationships between variables in the scene DAG. The Metis constraint solver, which resides in the Metis viewer, evaluates the constraint network and ensures that values of variables everywhere in the scene conform to the desired dependency relationships. While the Metis application programmer must specify the constraints explicitly, it is left up to the Metis constraint solver to maintain the constraint relationships and determine how and when to evaluate them. Metis uses lazy evaluation to evaluate the constraint network. In this way, we can significantly reduce the number of constraint evaluations performed and thus support interaction efficiently.
1. Spaceball
A spaceball provides 6D (six degrees-of-freedom) control over any object in the scene. A typical usage is to control the whole scene by constraining it to the root node of the scene structure. Or, you can use it to move around a camera. The definition of a spaceball node in Metis is as follows:
Spaceball {
Quaternion rotation;
Vector translation;
Integer button;
}
2. 3D mouse and head tracker
A head tracker provides position information of the user's eyes relative to the screen. This information is used to change the viewing matrix in Metis so that as if you are looking a real object in 3D space. The 3D mouse is a free-flying 3D input device to manipulate VR objects in the scene. For example, you can pick up an object using the 3D mouse and rotate it or put it away.
3. Stereo glasses
The stereo glasses allow the user to interact with a virtual world through a stereo window. A sphere on the screen looks like a real shpere in 3D space. You can see the depth of objects and give the illusion of touching them directly with the 3D mouse.
/* declaration */
MeTransform root;
MeTransform boxtransform;
MeShape objshape;
MeAppearance objapp;
MeMaterial objmaterial;
MeBox objbox;
MeTexture texture;
/* set up DAG */
root.children<<=boxtransform.children<<=objshape.geometry<<=objbox;
objshape.appearance<<=objapp.meterial<<=objmaterial;
/* set up material */
objmaterial.diffuseColor = MeColor (0.4, 0.0, 0.0);
objmaterial.specularColor = MeColor (0.4, 0.4, 0.4);
objmaterial.shininess = 50.0f;
/* set up texture */
texture.filename = MeString("rock.gif",sizeof("rock.gif"));
texture.srepeat = MeInteger(1);
texture.trepeat = MeInteger(1);
objapp.texture<<=texture;
/* set up constraint */
root.children<<=spaceball.translation;
setRoot(root);
cout <<"Scene creation done."<<endl;
Here is the source code for the robot demo.
/* declarations. omited */
/* using spaceball to move the whole scene around */
root.translation<<=spaceball.translation;
/* set up the 3D mouse cursor */
root.children<<=
cursor.children<<=cursor_rot.children<<=
cursor_cylinder.children <<= cursor_cone.children <<=
cone_shape.geometry
<<= cur_cone;
cursor_cylinder.children<<=cylinder_shape.geometry
<<= cur_cylinder;
cursor.translation <<= dmouse.translation;
cursor.rotation <<= dmouse.rotation;
MeMatrix tmp_rot;
cursor_rot.rotation =
tmp_rot.createRotator(MeQuaternion(MeVector(1,0,0),0.5*PI));
cursor_cylinder.translation=MeVector(0,-40,0);
cursor_cone.translation=MeVector(0,30,0);
cylinder_shape.appearance <<= curapp.material <<=
curmat;
cone_shape.appearance <<= curapp.material <<= curmat;
curmat.diffuseColor = MeColor (0.4, 0.0, 0.0);
curmat.specularColor = MeColor (0.4, 0.4, 0.4);
cur_cylinder.radius=2.0f;
cur_cylinder.height=60.0f;
cur_cone.radius = 4.0f;
cur_cone.height = 10.0f;
/* set up notifier. The notifier code specify what to do when
certain
event happens, such as pressing a 3D mouse button, rotating or moving
3D
mouse.
*/
butnotifier.source <<= dmouse.button;
curTransnotifier.source <<= dmouse.translation;
curRotnotifier.source <<= dmouse.rotation;
setRoot (root);
cout << "Scene creation done." << endl;