The engine is fairly bare-bones, with the only slightly more advanced bit being the use of vertex buffer objects if available. Without having any highly complicated technology, the engine is able to play scenes containing over a million triangles on modern 3d hardware.
The engine consists of a bunch of simple classes. The scene class (AmbroseScene) owns all mesh, camera, light, material, texture and animation objects. Each mesh refers to one material. Materials can have several texture slots, and each texture slot refers to one texture object. Animation objects refer to lights, cameras or meshes.
The exported scene hierarchy is flat - all exporter meshes are in a linear array owned by the scene.
An example of the basic usage is demonstrated in the main.cpp of the source distribution. In order to "play" a 3d scene, you need to perform the following steps:
The AmbroseScene class acts as the container and root for the 3d scene. Additionally it contains the functions to play animations and render the scene.
Additionally the scene class includes methods to find different objects within the scene so that they can be adjusted. For example, you may want to access the vertex data of some object - you can use findMesh() to find the mesh object by name.
The animation tweening is not done correctly at the moment, as it simply lerps between matrices. A more proper way would be to store the translation, scaling and rotation data separately, and using a slerp operation for the rotation data in quaternion form.
AmbroseObject is the superclass of AmbroseMesh, AmbroseLight and AmbroseCamera. These objects all have a couple things in common: name and transformation matrix. So basically everything that can be moved in a scene is a AmbroseObject.
Meshes are the 3d objects in the scene. The AmbroseMesh class contains a vertex buffer (which then takes care of vertices, normals, vertex colors, uv coordinates and indices) and a link to a AmbroseMaterial object.
The AmbroseLight represents a dynamic light source in the scene. Currently all lights are considered point lights, and as such the only piece of data stored is the light color.
The AmbroseCamera class contains information about a camera in the scene. In addition to the transformation matrix, a camera needs near and far clip plane information and the field of view.
The AmbroseMaterial class contains information about what kind of surface material each object has. In addition to id and name, currently the material consists of transparency alpha value, diffuse and specular colors, and up to eight texture slots. Only one texture slot and diffuse color are actually used by the default renderer.
Texture slot class
Since different objects may use a single texture, and textures can be applied in different ways, each material contains up to eight texture slots. Each texture slot then includes information on how the texture should be used, and a link to a AmbroseTexture object. The default renderer ignores the texture blending and usage options and uses the textures in a "normal" way.
The texture class contains id and name of the texture, as well as the texture filename in case of a image texture. Blender also supports different kinds of procedural textures, which we're not supporting at this time. On top of these the texture class contains the texture handle.
The animations are done by having a copy of the transformation matrix per frame for all AmbroseObject objects (meshes, cameras and lights). Animations are done simply by copying the frame's transformation matrix over the object's current transformation matrix.
The vertex buffer class contains everything that has to do with mesh data, including vertex, normal, vertex color, uv coordinate and index data. Since it has been written this way, the vertex buffer can internally store the vertex data in VBOs on the display ram increasing performance dramatically.
A simple function to load textures in OpenGL.
All file IO in Ambrose3d goes through a few simple helper functions. In case the engine is to be ported to a platform with a different byte order, changing these functions should solve the majority of byte order problems.