![]() |
DI-Guy C++ SDK Reference
13.0
|
This file provides an overview of the various programming examples available for the DI-Guy Graphics API. The actual code for the examples is in various subdirectories of $DIGUY/programming_examples/diguy_graphics_api.
In normal use, DI-Guy does all of its own rendering. DI-Guy ships with high-performance rendering libraries for immediate mode and scene graph rendering environments, including those tailored for OpenGL, DirectX9, and Vega Prime. It is quick and cost-effective for most users to get DI-Guy up and running in their applications using these standard options; most users get DI-Guy characters working in their simulators in a day using these libraries.
However, some users need more control over the rendering process or access to low-level rendering data to more tightly integrate DI-Guy into their system. The DI-Guy Graphics API can be used to:
The DI-Guy Graphics API provides a variety of functions to support these needs and to allow DI-Guy to be used in almost any rendering environment. The DI-Guy Graphics API supports both scene graph renderers (e.g. - Open Scene Graph, Performer and Vega Prime) and immediate mode renderers (e.g. - OpenGL).
DI-Guy Graphics API programming should be done by experienced C++ programmers comfortable with object-oriented design and familiar with their particular renderer. If you fit this description, you will find the DI-Guy Graphics API a well-architected programming solution for customizing DI-Guy graphics to your renderer.
The basic concept for using the DI-Guy Graphics API is quite simple. A set of classes, defined below, is available to the user. The user can make subclasses of these, and thus tailor DI-Guy rendering to the target rendering system.
DI-Guy characters are composed of a hierarchy of links. These links, also known as bones, form the skeleton of the character. Links have no visible geometry of their own, but serve as attachment points for shapes. Links are not shared among characters; each character has its own collection of links.
Links are implemented with the diguyGraphicsLink object.
Shapes are visible parts that are attached to links to "flesh out" the skeleton; with no shapes the link would not be visible. As links move, the shapes attached to them move. Shapes are not shared among characters; each character has its own collection of shapes.
Shapes are implemented with the diguyGraphicsShape object.
Shapes are read from geometry files. DI-Guy most often uses the OpenFlight (.flt) format for static geometry, and the Collada (.dae) format for skinned geometry.
Geometry files are implemented with the diguyGraphicsFile object.
Each shape is composed of one or more polygonal meshes. Each mesh consists of polygonal faces that have vertices, normals, and texture indices, as well as a graphics state that includes material, texture, and lighting settings. All faces in a mesh share the same graphics state. Meshes are shared among characters; if two characters with the same appearance are loaded, only one copy of each mesh is loaded.
Meshes are implemented with the diguyGraphicsMesh object.
Graphics states encode all information about how the polygons in a mesh should be drawn. This includes material information, a texture, and other lighting information. Graphics states are shared among characters; if two characters with the same appearance are loaded, only one copy of each state is defined.
Graphics states are implemented with the diguyGraphicsState object.
Materials specify the colors and lighting used to display the mesh. Materials include the ambient, diffuse, and specular components that are commonly used in renderer lighting models. Materials are shared among characters; if two characters with the same appearance are loaded, only one copy of each material is loaded.
Materials are implemented with the diguyGraphicsMaterial object.
Textures are 2D images that are painted onto mesh faces. Textures combine with materials to determine the appearance of the mesh. Textures are shared among characters; if two characters with the same appearance are loaded, only one copy of each texture is loaded.
Textures are implemented with the diguyGraphicsTexture object.
Most rendering environments use some type of shader system that offloads rendering operations from the CPU to a GPU. Terminology varies, but DI-Guy uses the term "shader" to refer to a pair of sub-programs: a vertex shader and a pixel shader (or fragment shader in OpenGL).
Shader programs are shared among characters; if two characters use the same shader, the same shader object is used for both.
Shader programs are implemented with the diguyGraphicsShaderProgram object
A shader technique describes the various shaders that can be used to render a character. These include a number of different shaders that represent different quality levels and depending on the camera's distance from a character a different one can be picked. A technique can be subclassed and an end user can add additional shaders to it and implement their own LOD system or switch in a different shader for alternative lighting situations
Shader Technique are implemented with the diguyGraphicsShaderTechnique object.
As mentioned above shader programs are shared among characters. Shader instances allow non-shared, character-specific shader state to be maintained. An example is having different uniform variable values for different characters, such as a highlight color that is applied during shading.
Shader instances are implemented with the diguyGraphicsShaderInstance object.
The DI-Guy Graphics API classifies renderers into two types: immediate mode and scene graph. The type of renderer has a large impact on which DI-Guy Graphics API classes are subclassed, and which virtual functions of those subclasses the user overrides.
Immediate mode renderers expect the user's code to perform transformations, bind materials and textures, and draw geometry at the appropriate times during the rendering of each frame. A primary example of an immediate mode renderer is OpenGL.
The most important stages in implementing DI-Guy support for an immediate mode renderer are the Build Stage and the Draw Stage. During the Build Stage renderer-specific objects may be created from the meshes, materials, and textures to facilitate later draws. During each Draw Stage calls are made to bind materials and textures, and transform and draw the objects.
The following classes are usually subclassed for immediate mode renderers:
Scene graph renderers typically build a hierarchy of graphical objects. The scene graph renderer automatically takes care of transformations, binding materials and textures, and drawing geometry. Examples of scene graph renderers are Open Scene Graph and Vega Prime.
The most important stages in implementing DI-Guy support for a scene graph renderer are Build Stage and Update Stage. During the Build Stage all geometry, materials, and textures and turned into renderer-specific objects and inserted in the scene graph. During the Update Stage the scene graph objects are updated with new information based on DI-Guy motion data.
The following classes are usually subclassed for scene graph renderers:
DI-Guy comes with a built-in geometry file loader that is used for some graphics environments (e.g., OpenGL, DirectX, and DI-Guy Graphics API), and makes use of native file loaders in graphics environments that provide them (e.g. Vega Prime). The DI-Guy Loader can load and parse various types of files, most notably OpenFlight (.flt) and Collada (.dae) files for object geometry, and a selection of various texture file types. The DI-Guy Loader correctly loads the human character geometry files provided in a DI-Guy Data distribution.
Unlike the main DI-Guy API, which makes extensive use of callback functions to notify the user's application of events, the DI-Guy Graphics API makes use of virtual functions in C++ classes. Each class has a set of virtual functions that can be overridden in a user-defined subclass. At appropriate times during program execution these virtual functions will be called by the DI-Guy Graphics API.
The virtual functions are called at specific stages of program execution. These stages are the Build Stage, the Update Stage, the Draw Stage, and the Unbuild Stage.
Build Stage functions are typically called during program initialization, when geometry files are being read and the information therein being turned into renderer-specific objects. Build functions may also be called during program main loop execution if new characters or appearances that haven't been preloaded are called upon.
The Build Stage is very important for both scene graph and immediate mode renderers.
Update Stage functions are called during program main loop execution, when the state of objects should be modified based on motion data from DI-Guy. Most often this means updating degree-of-freedom (DOF) type objects in a scene graph with new joint angles, but may also include showing or hiding objects.
The Update Stage is very important for scene graph renderers.
Draw Stage functions are also called during program main loop execution, when it is time for objects to be rendered. Though they do not contain any visible geometry themselves, link objects "draw" themselves by applying updated transformation state to the renderer. Similarly, materials and textures have bind functions that are called during the Draw Stage.
The Draw Stage is very important for immediate mode renderers.
Unbuild Stage functions are typically called during program shutdown. They are responsible to freeing any renderer-specific resources that may have been allocated during the Build Stage.
The Unbuild Stage is very important for both scene graph and immediate mode renderers.
During the function calls of the various stages listed above, the user obtains information by calling "accessor" functions.
A diguyGraphicsLink subclass object, for example, can determine which link is its parent (the link it is attached to in the link hierarchy), and which links are its children (the links that are attached to it) by calling the functions get_parent_link() and get_child_link_at_index(), respectively.
A diguyGraphicsTexture subclass object can call the function get_texture_map_data(), which returns a buffer containing the RGB data for the texture which can then be used to define a renderer-specific texture object.
The DI-Guy Graphics API is responsible for creating and destroying all objects; the new and delete operators should not be called on DI-Graphics API classes or subclasses. In fact, the constructors and destructors of the classes are all protected, so compilers should refuse to compile code that breaks this rule.
In order to create subclass objects, object creation functions can be registered with the DI-Guy Graphics API. These create functions will be called whenever the API needs to allocate a new object, allowing the user to allocate and return a subclass of the object specialized for a specific renderer. The create functions should be registered before the initialization function discussed below is called.
Note that renderer-specific objects typically should not be created in the subclass constructor, but should instead be created in the Build Stage. Objects are typically created before their data has been fully read by the loader, with the consequence that the accessor functions cannot yet return valid data.
To make use of the DI-Guy Graphics API for rendering instead of one of DI-Guy's built-in renderers, a different initialization function must be called. Instead of calling diguy_ogl_initialize() to make use of the built-in OpenGL renderer, for example, a program using the DI-Guy Graphics API would call diguy_graphics_initialize(). Similarly, instead of including the header file diguy_graphics_ogl.h, the DI-Guy Graphics API program would include diguy_graphics_api.h.
The base link of a DI-Guy character's graphics hierarchy can be retrieved using the function diguyCharacter::get_base_link(). Once the base link has been retrieved, function calls to the base link can retrieve pointers to child links and shapes attached to links.
A pointer to the character to which a link or shape belongs can be retrieved using the functions diguyGraphicsLink::get_character() and diguyGraphicsShape::get_character(), respectively.
All other DI-Guy Graphics API types are shared among multiple characters, so there is no single character to which they belong and therefore no get_character() function.
This example shows the use of the DI-Guy Graphics API for immediate mode rendering using the DI-Guy Loader. It uses OpenGL as the renderer.
The following examples are provided:
The following subclasses are implemented in this example:
This example shows the use of the DI-Guy Graphics API in a scene graph renderer using the DI-Guy Loader. It uses Open Scene Graph as the renderer.
The following examples are provided:
The following subclasses are implemented in the examples: