Planning the Spontaneous

It's more than just a blueprint.

Route = Scenic;

Posted by Robert Chow on 23/10/2009

A scene graph depicts how objects are fitted into the scene, and how objects are related by their position.  For example, in a room, there may be a table – it’s position within the room. On the table, a mug, and a computer. Both of which, their positions can be described as relative to the table which they are sat on. It has been argued that scene graphs are a complete waste of time. Some think so, others not so. I on the other hand believe that if they can be used to help the problem that you are trying to solve, then why not. The rendering component I am creating, will use an interface where each object that can be drawn, such as a square, or a triangle (using vertex buffer objects of course) will be “queued” into the component, ready to be drawn. To then use a scene graph that is opinionated towards this design is a major help, and will prevent many state changes that will happen when rendering in immediate mode – when coming to draw the object, the world matrix of the object is taken from the scene graph and loaded into OpenGL using a single call, whereas, typically, it may need several transformations to get the object to where we want it to be. Each one of these transformations is a state change – OpenGL is in effect, one huge state machine – and each state change is a cost in the rendering pipeline.

One of the best exercises to do to show you understand how a scene graph works is to model the solar system.  It’s relatively straight forward, and easy to picture.  You have your scene, whereby there is the sun.  Relative to the sun are the planets.  Relative to each of the planets, are their moons.

Solar SystemSolar System.  The top screenshot depicts the four planets Mercury (purple), Venus (yellow), Earth (blue) and Mars (red), with their respective satellites, circling the sun.  The bottom screenshot is an overhead view of the scene, at a different time frame.

Scene Graph

There are lots of different implementations of scene graphs, but the majority use composition, to produce a tree-like hierarchy.  At every branch in the tree is a node, often representing a transformation, and plays a part in determining the position of the rest of the branch.  The object being drawn, is finally represented as a leaf – it’s position determined by all the branches needed to pass to get to the root of the tree.  So if you were to plan out the solar system, it may look a little like this.

Solar System Scene Graph. Each transformation helps to form a part of a branch in the tree, and at the end of each branch is a planet, acting as a leaf.  The transformations have been vastly simplified – in reality there are a lot more transformations to consider when building a solar system that incorporates planet rotation, tilt and so forth.  And before you say anything, yes I know there is more to the Solar System than up to Mars.

To represent this, I have built my scene graph using 2 classes.  A class to manage the scene graph, SceneGraph, and a class to make the scene graph tree possible, GraphNode.  I have omitted the implementation of these for brevity.

GraphNode – represents a node in the scene graph.

public GraphNode Parent { get; private set; }
public Matrix Matrix { get; private set; }

SceneGraph – keeps a track of the current node, and manipulates the scene graph stack.

public GraphNode CurrentNode { get;  private set; }

public void PushMatrix();
public void PopMatrix();
public void LoadIdentity();
public void Clear();
public void AddMatrix(Matrix matrix);
public Matrix GetWorldMatrix();

private Stack<GraphNode> nodeStack;

It’s fairly simple really.  The Graph Node doesn’t really do anything, except it’s holder for the matrix it represents, and make sures it always has a constant reference to the node above it in the tree.  This reference can be traversered to find all other nodes the current node branches off, right to the root.  It plays its part when GetWorldMatrix() is called – this is when we want to draw an object.  Calling the method traverses up to the root using the parent reference, multiplying each matrix along the way.  You’ll remember me saying OpenGL is a state machine – we want to minimise the state changes as much as possible – these range from changing textures and enabling lighting, all the way to changing color, or even making a transformation.  Calling GetWorldMatrix() uses a matrix class, which is only used by OpenGL at the very end, when a call to glLoadMatrixfv() is called.  We are then able to draw the object at the current position, which is determined by the world matrix.

The rest of the SceneGraph implementation is a mirror of the OpenGL matrix stack – you can load identity, and push and pop matrices on and off a stack.

If you want to find out more about scene graphs, I’d suggest reading a couple of these links.[[Scene%20Graphs%20-%20just%20say%20no]] – Why this user believes scene graphs are a complete and utter waste of time.  I actually partially agree with him.  But you can’t always win. – This guy’s managed to produce a 3D engine, using this scene graph he created himself.  Everything in the scene plays a part in the scene graph, including the camera, and lights.  That makes sense.  But like I said, you can’t always win.

This post’s been cut a little short – it was intended to cover something else in the solar system, but you’ll just have to wait.


2 Responses to “Route = Scenic;”

  1. […] RSS – Posts « Route = Scenic; […]

  2. […] scene graph itself looks rather different this time to that I outlined in this post.  In that post, the client will push and pop matrices on and off the transformation stack […]

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: