Here I will try to explain in a few words the design decisicions behind 3dengfx and how everything falls together.
The core of the 3d engine is the animation system, it is very tightly
integrated with everything. There are three key concepts at play here, the
PRS the XFormNode and the MotionController.
The PRS (gfx/3dgeom.hpp) is a class that represents the position and
orientation of something in 3d space. It is comprised of 3 parts, a position
vector, a rotation quaternion and a scale vector (PRS =
Position, Rotation,
Scale).
It can be used to represent orientation at
specific instances of time and provides for easy interpolation to obtain
intermediate PRS states, this was the main reason why a quaternion was used
for the orientation, because we can slerp (spherical linear interpolation)
between to quaternions easily and with nice results.
The XFormNode (gfx/3dgeom.hpp) is really the base class of mostly
everything in the 3d engine, it provides unified transformation and animation
functionality that is then inherited by all kinds of 3d constructs like
objects, cameras, lights, particles, etc.
The XFormNode contains motion
controllers (see below) seperately for translation, rotation and
scaling, and keyframes (PRS - time pairs). Additionally if keyframes
are not used it has a local PRS that stays constant throughout time
to acompany the various motion controllers, or be used for simple stationary
positioning, or even to bypass the animation system entirely by manually
tweaking it through time.
The MotionController (gfx/controller.hpp) encapsulates the concept of
a function of time. Currently it can be either an analytically defined
function like sin and cos, with parameters that specify frequency, phase, and
amplitude, or an implicit function defined as a number of positions and
interpolated through catmull-rom splines or approximated through
B-Splines.
The motion controllers, being a part of the XFormNode which is an integral
part of every transformable object of the 3d engine, can be used everywhere.
The XFormNode keeps a number of these for each property (translation,
rotation, scaling) and adds them together to produce the actuall property in
time, so they can be used not only to entirely control the position let's say
of an object, but also to provide small-scale turbulence to its otherwise
smooth motion. Use wisely, and remember that it all gets
added to the keyframe-interpolated or local PRS of the object.