Horde3D Usage Guide
Basic concepts
Objects in Horde3D
Horde3D employs two basic components that are part of most graphics engines: a scene graph and a resource manager. Both are responsible for managing subordinate objects namely scene graph nodes and resources. The Horde3D API provides access to these objects with special handles which are basically just numerical IDs. Objects are constructed with specific creation functions which return a handle to the created object or a zero handle (similar to a NULL pointer) in case of failure. This handle can later be used to access the object in appropriate functions for setting or getting its properties or releasing it.
Resource management
The engine distinguishes between resource data and concrete instances of that data in the scene. Resources are
data blocks which are loaded from a file, an archive or any similar source. They can be referenced by nodes of the
scene graph or other resources. The advantage of this separation is obvious: resources only have to be loaded once and
can afterwards be instanced an arbitrary number of times in the scene without the costly need of reloading redundant
data. So if you have a character model that you want to see several times in your scene you load the model data at
the beginning as a resource and can afterwards add an arbitrary number of clones in your virtual world.
The following resource types are available:
SceneGraph - Represents a scene graph hierarchie as a XML file
Geometry - Contains vertex and triangle data in a binary format
Animation - Contains keyframe animation data in a binary format
Material - Defines the apperance of a surface by referencing textures and a shader in a XML file
Code - Defines a shader code block in a simple text format
Shader - Contains shader code and parameters in a XML file
Texture2D - Stores a standard two-dimensional texture map in one of several binary image formats
TextureCube - Stores a cube texture map in one of several binary image formats
Effect - Contains the configuration of particle properties in a XML file
The resources are managed by a resource manager which is e.g. responsible for loading them. Some resource types like
materials can depend on other resources. To make the manager robust it is using some sort of garbage collection with
reference counting. Resources can only be removed if they are not referenced by other resources or a scene node.
Horde offers a special function that can be called to free all resources that are no longer referenced.
When a resource is added, it is always initialized with some default data. After adding, the data for the resource
should be loaded. This can only be done once for a resource and in this process the data structures and values
are established. After the resource is loaded it is generally possible to alter the data values but not the
data structure. That means for example that you can change the pixel colors of a texture image but not the dimensions
or color depth of the image. It is also possible to unload a resource and set it back to its default state before
loading which enables reloading of resources.
For detailed information see the API Reference section dealing with
resource management functions.
Scene Graph
Horde3D has a scene graph which represents the objects in the virtual world in a hierarchical tree structure.
Technically speaking it is a transform graph with an bounding volume hierarchy made up by axis aligned bounding
boxes. Every node except the root node has a parent and a local transformation relative to that parent. When
a node is transformed, all of its children are also transformed accordingly. So as an example, if you want to move
the whole scene a bit, you just have to set the transformation for the root node and the rest happens
automatically. There are different types of scene nodes all of which represent concrete objects in the
world. The root node is from the node type Group and has a constant predefined handle.
There are some rules that define which node types can be attached to what parent node. What follows is an
annotated list of the available node types with valid parent types:
Group - Represents a generic container with LOD support for other nodes. Can be attached to any node type.
Model - Represents a static or articulated 3d model. Can be attached to any node type.
Mesh - Represents a part of the model geometry having a single material. Can be attached to Model or Mesh.
Joint - Reperesents a joint (bone) used for skeletal animation of a model. Can be attached to Model or Joint.
Light - Represents a light source associated with different shaders. Can be attached to any node type.
Camera - Represents a camera used for viewing the scene. Can be attached to any node type.
Emitter - Represents an emitter used for creating particle systems. Can be attached to any node type.
Every node type has a specific creation function that takes a set of different parameters. Some of them can
only be specified at creation time and are immutable, others can be changed again later. For accessing nodes
there are some general functions which operate on all nodes and some specific to a single type of node. The latter
require as a parameter usually a valid handle to a node of the corresponding type. To make life easier it
is also possible to pass to these functions a Group node in which case all of the children of the specified
group are affected by the function call.
The scene is always rendered from the perspective of a virtual camera. The camera is also represented as a scene
node and can be positioned with the standard node transformation function. There exists also a default camera node
which is always available and has a constant predefined handle. Camera nodes can be attached to any other node and
work as all other node types the way you would usually expect. So if you attach it for example to the joint of an
animated model it will automatically be influenced by the currently active model animation.
For more detailed information see the API Reference section dealing with
scene graph functions
Bringing content to the engine
Importing geomtry data using Collada Converter
Every serious graphics engine needs a convenient way to bring art assets from a 3d modelling package to the engine and finally your application. Not so long ago it was necessary to write a plenty of special exporters for the different modelling packages. Luckily things have recently become a bit better with the evolution of some standards for asset exchange. Horde3D uses Collada, an open format specification developed by Sony Entertainment and maintained by the Khronos Group. The Horde SDK contains a special tool called Collada Converter which converts Collada 1.4 assets to an optimized Horde3D specific format. Besides the conversion of basic geometry and material data it supports a plenty of advanced features like skeletal meshes with several skin modifiers, keyframe animation data and morph targets. The Collada Converter is a small command line tool and is pretty easy to use. Usually the workflow for converting a model and brining it to the engine is as follows:
- Export the model from your favorite modelling software using a Collada exporter There are very good ones available for 3d Studio Max and Maya
- Open the windows explorer and drag&drop the exported DAE file on the ColladaConv executable Alternatively you can use the included batch file to specify more options
The converter will now do its job and output some files.
- Copy the myModel.geo and myModel.scene.xml to the model directory of your application By default this is the content/models folder but you can change that if desired
- Copy the myModel material folder to the material directory of your application
- If you need animations copy myModel.anim to your animations folder
If you have several animations stored in different Collada files you can convert all of them as described
but you only need to copy the animation files. The exported geometry is always the same and doesn't have to
be copied again.
That's all you have to do in order to get a simple model to Horde3D. There are some further options for the converter
which are described in the following:
ColladaConv inputFile [-o outputName] [-s shaderName] [-opt]
inputFile | filename of the Collada document |
-o outputName | name of the output files, without file extension (optional) |
-s shaderName | filename of the default shader that is used for the created material files (optional) |
-opt | enable geometry optimization for better performance; this could cause problems with some models (optional) |
Important Note:
At the moment there are some restrictions for Collada files to be compatible with the converter.
All geometry has to stored as triangle data. Furthermore transformations have to be stored as
matrices which is usually achieved by enabling the 'bake matrices' option in your Collada exporter.
Finally animations should be exported as sampled keyframe data.
Advanced topics
Animation system
Horde3D has a quite powerful animation system. It supports keyframe based rigid and skeletal animation
with inter-frame interpolation for smooth animations and full animation blending and mixing. Furthermore
the engine supports morph targets which are often used for facial animation and lip synchronization and
can be combined with dynamic animation systems like IK or ragdoll.
In modern games it is often required that a character does several things at the same time, e.g. walking
and waving with the hands. Although it is in principle possible to create a single animation for this
specific case and all other combinations, that would neither be efficient considering memory usage nor be
productive for the artist. A better solution is to create two different animations and combine them
in the animation engine. This is called animation mixing. Another common case is the transition from one
animation to another called animation blending. That is for example useful when you want to switch your
character from running to walking. All this is possible in Horde3D using the concept of animation stages.
A stage is a channel on a model to which you can assign an animation resource. You can set the weight of
each stage to configure the influence of its animation compared to the other stages. The weights will always
sum up to 1.0 and higher values are ignored. Furthermore stages are layered with the lower stage numbers
having higher priority. As an example imagine you have a walk animation on stage 0 and a run animation on
stage 1. If you set the weight of stage 0 to 1.0 the model will only show the walk cycle since the weight
sum is already 1.0 and the first stage has the highest priority. If you set the weight to 0.5 and weight
of stage 1 also to 0.5 you get the average of the two animations which would be something like a "walk fast"
animation.
If you want to play two independent animations at the same time both with full intensity (like walking and
waving) you have two options. The first is to define a mask for the channels. The mask specifys which bones
are affected by the animation. For our character you could set the mask so that the walk animation only
affects the lower body and the wave animation only the upper body. Now the weights always sum up to 1.0 in
each body part since there is only one active animation per body part. But a simpler way to do animation mixing
is using additive animations. If a stage is configured to be additive the engine calculates the difference
between the current frame and the first frame in the animation and adds this delta to the current transformation
of the joints. So in our sample you could configure the walk animation as normal with weight 1.0 and the wave
animation as additive (meaning the weight doesn't matter) and finally get the desired results, a walking and waving
character.
Another serious issue that is of growing importance for next-generation games is dynamic animations like
inverse kinematics or ragdoll physics. These can also be integrated in Horde3D. Joints in Horde are standard
scene nodes which means that you can easily get and set their transformation. Since the animation system is
working directly on the scene graph it is no problem to get the new joint transformation after an animation,
use this for calculations in the ragdoll system and finally set it to the values that come back from the
external system.
For more information see the
Model node functions in the API Reference.
Overview of shader data flow
Horde defines a special data flow for constituting the appearance of your models which gives you a plenty
of flexibility and power when it comes to advanced rendering effects. This section is intended to give
you a short overview. For more detailed information see the the Data Format Reference
and Rendering Pipeline Documentation.
The data flow starts with the pipeline configuration. In this XML file you can define renderable texture targets
and specify what data is rendered to which target at which time. There are commands to tell the engine
to draw some objects like meshes. Each of these objects has its own material. A material resource defines the
apperance of the object by specifying a shader and setting up different texture maps and shader parameters.
Materials can also have a class attribute and it possible to render only objects of a specific class with the
available pipeline commands. On the other hand a shader can have different contexts. When you execute a draw command
you can also specify a shader context which is used for rendering the desired objects. This makes it possible to
define a plenty of visual effects for an object. The complete system enables you to employ most modern rendering
techniques like deferred shading and high dynamic range rendering and to create post processing effects like
motion blur or depth of field.
Integration with other game engine libraries
An essential issue for a modular middleware component like a graphics engine is the integration with a game engine
and the interoperability with other middleware libraries. This is especially important for modern games where
you have a plenty of sophisticated components like a physics engine, dynamic animation control or an AI engine
which you have to bring all together.
One way to achieve this is to treat the graphics engine completely as a black box. In this case you would have your
game object classes and just store a handle to the scene graph node with each object. This works fine for applications
with simple game logic but becomes difficult when you have more complex interactions as with a physics module. You
always have to notify the graphics engine when an object is transformed due to a physics event and even worse, the
physics engine has to know when an object is moved by an animation of the grahics engine. So you always have to
mediate updates of the different modules within your game classes. Another downside of the black box approach is
that you have duplicated data. The graphics engine has its own scene graph with graphics related information and your
game usually also needs a scene graph with additional information like 3D sound sources, collision shapes or game
specific attributes for game entities like characters.
To overcome these problems Horde3D offers a special Integration Library. With version 0.11 Horde introduces the
concept of node attachments. An attachment is a derived class that you can attach to Horde scene graph nodes and which
can contain all your game specific data. The key point is that this class is handled by Horde when updating the
scene graph which means that you get a notification when a child or parent node is transformed. This concept makes it
easy to let the graphics engine interact with e.g. a physics engine and enables you to store game specific semantics
and meta data directly with the graphics objects. To further extend this idea Horde offers the possibility to
define attachment data in the XML scene graph resources and to register hook functions which give a callback when
a scene node with an attachment is created by the engine. This makes it possible to store all game object data with
the scene graph files and diminishes the need for a separate game specific world format.