These formats are supported by the Syzygy Scene Graph:
The Syzygy object-importing code was originally written to work only using the scene graph. This means that while you can use most of these objects in master/slave applications via the scene graph owned by each master/slave framework, it is a pain in the behind.
We are gradually factoring the code to allow it to be used more simply without using the scene graph. So far only the OBJ-format objects have been liberated.
The arOBJRenderer allows you to easily read and render an OBJ file in a master/slave program. See the Wavefront OBJ section for information about the format. Simply:
arOBJRenderer myObj;
if (!myObj.readOBJ( const string& fileName,
const string& subdirectory,
const string& dataPath ))
oops;
The dataPath argument can be a semicolon-delimited list of directory paths. You should
read the file in both master and slaves.
myObj.draw();New 07/08: arOBJRenderers render much more quickly now, because texture maps are mip-mapped by default. Also, if you want to load one into an OpenGL display list, you should call the new
activateTextures() method first:
myObj.activateTextures();
int dl = glGenLists(1);
if (dl == 0) {
oops;
}
glNewList( dl, GL_COMPILE );
myObj.draw();
glEndList();
This causes any texture maps to be downloaded to the graphics card, which you
want to do before compiling a display list; otherwise, the action of loading the
texture to the card will be compiled into the display list, resulting in slower
performance than if you hadn't used a display list at all.
Other optional methods:
string arOBJRenderer::getName(); int arOBJRenderer::getNumberGroups(); void arOBJRenderer::clear(); void arOBJRenderer::normalizeModelSize(); float arOBJRenderer::getIntersection( const arRay& theRay ); arBoundingSphere arOBJRenderer::getBoundingSphere(); arAxisAlignedBoundingBox arOBJRenderer::getAxisAlignedBoundingBox(); arOBJGroupRenderer* arOBJRenderer::getGroup( unsigned int i ); arOBJGroupRenderer* arOBJRenderer::getGroup( const string& name );
Of particular interest are the getGroup() and getBoundingSphere() methods.
The former returns an arOBJGroupRenderer that can be rendered
separately from the parent object (i.e. if an obj file contains named groups of faces,
you can render the groups indvidually). The arOBJGroupRenderer object also has a
getBoundingSphere() method. These allow you to do
frustum culling:
// draw callback
float modView[16];
float proj[16];
glGetFloatv( GL_MODELVIEW_MATRIX, modView );
glGetFloatv( GL_PROJECTION_MATRIX, proj );
arMatrix4 frustumMatrix = arMatrix4( projectionMatrix ) * arMatrix4( modelViewMatrix );
if (myObj.getBoundingSphere().intersectViewFrustum( frustumMatrix )) {
myObj.draw();
}
Note that getBoundingSphere() is an expensive operation, so normally you would compute the
arBoundingSphere once,
cache it, and use its transform() method to apply any constant transformations.
Objects in Syzygy interact directly with the scene graph. To use objects in your program, you must either define a scene graph or use a framework with one provided.
All Syzygy objects derive from the arObject class, which encapsulates the functions needed to animate, name, and get various properties from an objects (such as number of Triangles, if it supports animation, etc.). In most cases, you shouldn't need to deal with any of arObject's subclasses directly.
To read in and attach an arObject to your scenegraph, call arReadObjectFromFile():
arObject* myObject = arReadObjectFromFile("myFile.ext", "");
This will return a pointer to an instantiated arObject subclass, based on the extension of the file given (.3ds, .obj, etc.)., or a NULL pointer if Syzygy failed to read in the file (an error message with additional information will also be printed). At this point, the object is not yet bound to the scenegraph. (A scenegraph doesn't even need to exist yet). You can optionally normalize the object's size by transforming it to the origin and forcing it to fit in a sphere of radius 1 unit:
myObject->normalizeModelSize();
Once the scenegraph is initialized, you can attach the object to it:
theObject->attachMesh("MyObjectName", "parentNode");
The first argument to attachMesh() is an optional name for the object. The second argument is the name of the scenegraph node to which you want to attach the object. This will add multiple nodes to the scenegraph to accomodate the data in the object in an efficient manner.
That's it! The object is now contained in the scenegraph, and will be displayed when the database is drawn. The arObject itself still contains information about the node, and in some cases can be used to alter corresponding nodes in the database (animation, for example).
Syzygy supports most of the official OBJ spec, and tries to fix some of the inconsistencies that programs tend to stick into exported files. A simple OBJ file looks like this:
# myfile.obj o object_name v -1 -1 -1 v -1 -1 1 v -1 1 -1 f 1 2 3 f 2 3 4 ...
Syzygy supports shading groups, normals, texture coordinates, material files, object names, and convex polygons. It does not support splines or raytracing options.
You can also specify an OBJ Material file, which usually ends in ".mtl". This file must be referenced from an .obj file via the "usemap" command. A material file will let you specify basic colors or textures for the .obj file. The format of an .mtl file is:
newmtl shaderName
Kd 0.5 0.5 0.5
Ka 0.1 0.1 0.1
Ks 1.0 1.0 1.0
map_Kd texturefilename.ppm
newmtl ...
Where shaderName is the name of the corresponding shading group in the .obj file, Kd is the diffuse coeefficient (base color), Ka is the ambient coefficient (background or fill light), and Ks is the specular coefficient (color of highlight). Currently the Ns, or specular power term, is unused since we are using basic OpenGL for rendering. If you specify a map with map_Kd, the texture specified will be used instead of Kd. All .mtl file parameters are optional, and have consistent default values.
Used with our Motion Analysis motion capture setup and software, an HTR specifies a series of transformations frame by frame to define animations. By calling arHTR's attachMesh with an additional boolean true value, the HTR will use randomly colored line segments as its "bones":
((arHTR*)myObject)->attachMesh(my_name, my_parent, 1);
We use lib3ds to read in 3ds files, so we can only use versions 3 and 4. If your .3ds file doesn't display or you see an error message when trying to read in the file, this is probably the reason. Simply convert it to version 3 or 4 (there are several free utilities out there), and the new .3ds should load into Syzygy. Basic materials and normals are supported.
Syzygy allows you to easily attach an OBJ mesh to an HTR animation with one command:
attachOBJToHTRToNodeInDatabase((arOBJ*)myMesh,(arHTR*)myAnim,"myParent");
Where "myParent" is the parent node in the database. There are two steps for setup: Make sure that the HTR's Base Position is aligned and scaled correctly with the OBJ's mesh. Define groups in the OBJ to attach to HTR segments, and make sure each corresponding segment and group have the same name. (To export an OBJ with groups from Maya, use polygon edit mode and define a Set of faces. Maya's built-in OBJ exporter exports Sets as OBJ groups.)