Click or drag to resize
DigitalRuneScene Graph

This topic contains the following sections:

Scene

A scene (interface IScene) manages a collection of scene nodes. A scene node (base class SceneNode) usually represents an instance of a graphics object (a mesh, a camera, a light, etc.).

A scene has two important purposes:

The default implementation (class Scene) is derived from SceneNode. That means the Scene is always the root node of a scene graph.

The scene graph is the organization of the scene nodes that is visible to the application logic. But internally, a scene can organize scene nodes in a way which is optimal for rendering. Different types of scenes might require different implementations: For example, indoor levels, outdoor levels, top-down views, side-scrolling games, etc. might require different data structures in order to enable efficient queries. Therefore, different applications can use different implementations of IScene.

The default implementation Scene internally uses a CollisionDomain with a DualPartitionT to accelerate scene queries.

Scene nodes

A SceneNode usually represents an instance of a graphics object. Derived classes are for example: ModelNode, MeshNode, CameraNode, LightNode, LensFlareNode, DecalNode, BillboardNode, ParticleSystemNode, SpriteNode, FigureNode, FogNode, etc. (see namespace DigitalRune.Graphics.SceneGraph).

The scene node hierarchy, defined by the properties Parent and Children, is a tree (a graph without cycles). A scene node can only have zero or one parent - it cannot be the child of multiple nodes.

Scene nodes implement IGeometricObject, which means that scene nodes have a bounding shape (property Shape) and a transformation (properties ScaleLocal and PoseLocal/PoseWorld).

The bounding shape of the scene node is used by the scene for frustum culling and other optimizations. Be aware that the bounding shape of a scene node is not a hierarchical bounding shape. It defines only the bounds of the current node. The bounding shape does not include the bounds of the children! Some scene nodes have an Empty bounding shape. These scene nodes are ignored in scene queries, i.e. they do not show up in the query results.

Transformations can be specified in world space or local space (relative to the parent node). Scene nodes are attached to their parent: When the parent node is transformed (scaled, rotated or translated), all descendant nodes move together with the parent node.

A scene node has two additional properties, which store the pose and scale of the last frame: LastPoseWorld and LastScaleWorld. These properties are usually only read by advanced effects, e.g. post-process motion blur. Both properties are not set automatically - they must be set manually! That means, you typically call the helper methods SetLastPose or SetLastScale before changing the pose or scale. For example:

C#
// Set LastPoseWorld of the model node and all child nodes to the current pose.
myModelNode.SetLastPose(true);
// Update the pose.
myModelNode.PoseWorld = pose;

See class documentation SceneNode for more information.

The SceneHelper provides useful extension methods for scene nodes. (For example: Scene nodes can be traversed using LINQ.)

Important note Important

It is necessary to point out that the scene graph in DigitalRune Graphics is not a traditional scene graph: The sole purpose of a scene is to define the hierarchical and spatial relationship of graphics objects. The scene graph does not implement game logic. That means the scene graph does not have an update traversal and the scene nodes do not have an Update method.

It is important to distinguish between scene nodes and game objects ("entities"). Game objects implement game logic. See DigitalRune Game for more information on game objects.

Caution note Caution

Non-uniform scaling and rotated scene nodes: Scene nodes support scaling. When a parent scene node is scaled, all children are also scaled. If a child is rotated, the scaling can result in a shearing transformation. - Shearing is not supported. DigitalRune Graphics will automatically use a plausible non-sheared transformation for bounding shapes instead of the specified transformation. In general, it is recommended to avoid non-uniform scaling.

The reason for avoiding shearing is that DigitalRune Graphics uses optimized collision detection algorithms for basic shapes, like boxes or spheres. These algorithms do not support shearing. Sheared shapes require slower collision algorithms.

Cloning and disposal

Scene nodes are cloneable (see method Clone). When a scene node is cloned, the instance data is duplicated. But the data objects (e.g. the Camera or the Mesh) are copied by reference. Cloning can be used to quickly create multiple instances of an object in a scene.

Tip Tip

It is recommended to create a clone when loading a model using the XNA ContentManager. This ensures that the original instance is not modified.

Scene nodes implement the interface IDisposable. The Dispose method should be called when the scene node is no longer needed. This is necessary in order to prevent potential memory leaks. Once the method has been called, the scene node is no longer usable. Reusing a previously disposed scene node may result in undefined behavior.

The parameter of the Dispose method determines whether data objects (e.g. the Camera, or the Mesh) are disposed as well. In most cases the data objects need to be kept intact because they might be shared between scene nodes.

Dispose is a recursive method: It is applied to the current scene node and all descendant scene nodes. I.e. if the entire scene should be disposed, it is sufficient to call scene.Dispose(false).

The following example demonstrates cloning and disposal of a model.

C#
// Load and clone a model, which was processed using the DigitalRune Model Processor.
// Cloning ensures that the original instance stored by the XNA ContentMananger is 
// not modified.
ModelNode model = game.Content.Load<ModelNode>("tank").Clone();

// Position the model in a scene.
model.ScaleLocal = new Vector3F(0.8f);
model.PoseWorld = new Pose(new Vector3F(0, 0, -2), Matrix33F.CreateRotationY(-0.3f));
scene.Children.Add(model);

...

// Don't forget to dispose the model if it is no longer needed.
scene.Children.Remove(model);
model.Dispose(false);  // Disposes the model and all descendant nodes!
                       // (Data objects are not disposed.)
model = null;