# Scene Graph Basics

## What is a Scene Graph?

A scene graph is a directed acyclic graph (DAG) that consists of a collection of LVT Nodes arranged in a tree structure. A scene graph defines the objects in the 3D scene we wish to draw, and specifies their relationship to each other.

Scene graph Nodes are joined together via special nodes called Groups. A group is simply a collection of other Nodes (often including other Groups). When any action is applied to a Group (such as rendering or picking) that action is passed on to the Group's children in the order in which they were added to the group. Groups (and related Nodes, such as Separators) are the glue which hold scene graphs together.

## A Simple Scene Graph Example

Let's take a look at how we can construct and display a 3D scene using a scene graph. This first example will display a cube in the center of the screen, and allow us to rotate it, and view it from multiple angles.

Our scene graph will consist of six parts:

• A root `Group` node, to contain the whole graph.
• A `Camera` object to define the projection of the scene
• A `Light` object to light the scene
• A `Translation` object to position the cube where we want it
• An `Examiner` object to allow us to manipulate a portion of the scene
• A `Cube` object, which will draw a cube
Pictorially, our scene graph will look like this:

As always, we need to include the appropriate header files and initialize the library:

```#include <lvt/lvt.h>

using namespace LVT;

int main(int argc, char *argv[])
{
App myApp;
Wnd myWnd;

myApp.Init(&argc, &argv);

myWnd.Create("Cube", PF_DEFAULT_3D);
myWnd.SetClearColor(0.2f, 0.2f, 0.2f);
```

Notice that our call to `Wnd::Create` is slightly different. As a second parameter, `Wnd::Create` takes a pixel format which tells LVT what type of framebuffer to request from the windowing system. The default value is `PF_DEFAULT`, which is used for 2D applications like we have been creating so far. By contrast, `PF_DEFAULT_3D` initializes a z-buffer for depth testing, and a back buffer for smooth drawing. If you are unfamiliar with the different parts of the OpenGL framebuffer, you should consult the OpenGL Red Book for information. In most cases, `PF_DEFAULT_3D` will suffice.

LVT Also allows for more fine-grained control over the attributes of the framebuffer. Consult the LVT class reference for more details.

`Wnd::SetClearColor` sets the background color of our window. In OpenGL terms, the default handler of `Wnd::OnPaint` clears the framebuffer to the color specified by `SetClearColor`.

Now that initialization is complete, we are ready to begin constructing our scene graph. We begin with a `Group` which will be the root of our scene graph:

```    Group *root = new Group;
```

```    PerspectiveCamera *cam = new PerspectiveCamera;
```

One of the first things usually done is to attach a `Camera` object to the scene graph. In this case, we're using a `PerspectiveCamera` to set up a perspective projection. If we so chose, we could have used an `OrthographicCamera` to define an orthographic projection.

Once the camera is created, we add it to the scenegraph by calling `Group::AddChild`.

```    Light *light = new Light;
light->SetColor(1.0f, 1.0f, 1.0f);
```

We next attach a `Light` object to our root node to light the other objects in the scene graph. Remember that scene graphs are traversed depth-first, left-to-right, so any object that affects other objects (such as lights, cameras, materials, and so forth) will affect any object attached after it. Referring back to the diagram above, this light object will affect the three nodes that follow it.

```    root->AddChild(new Translation(0.0, 0.0, -5.0f));
```

Scene graph nodes are defined in their own local coordinate system, thus we make use of transformation objects to position them in world space. In this case, we push any following nodes out five units along the negative z-axis.

```    Examiner *exm = new Examiner;
```

An `Examiner` translates mouse movement into a rotation. This allows us to view objects at any angle by dragging the left mouse button.

```    root->AddChild(new Cube);
```

And finally, we attach a `Cube` object, which not surprisingly, draws a cube on the screen. And with that, our scene graph is complete. Now we have some final maintenance to perform before we can start viewing it:

```    myWnd.AdjustCamera(cam);
myWnd.SetInputHandler(exm);
myWnd.ShowScene(root);
```

We often want to keep the aspect ratio of a `Camera` object the same as that of the window in which we're viewing a scene. In this way, we avoid any stretching or distortion of the scene graph objects. `Wnd::AdjustCamera` takes care of that for us. When the `Wnd` object is resized, it will resize the aspect ratio of the `Camera` object passed to it to match.

In order for our `Examiner` object to work, we need some way of informing it about mouse movement. One way to do this would be to override the `OnLButtonDown`, `OnLButtonUp`, and `OnMouseMove` messages and manually forward them to the `Examiner`. A cleaner way, however, is to inform the `Wnd` object to forward all of its input messages to an `InputHandler` class. An `InputHandler` (from which `Examiner` is derived) accepts input from a `Wnd` object and processes any input messages it understands. By attaching the `Examiner` to our `Wnd` object in this way, we don't have to worry about manually forwarding mouse messages to it.

Finally, we tell the `Wnd` object that we want it to display our scene graph whenever the window needs repainted. We do this by simply passing the root node in to a call to `Wnd::ShowScene`. (The alternative would be to override the `Wnd::OnPaint` message and manually call the `Render` method of the root node).

And that's all we need. We start the message loop as usual:

```    return myApp.Run(myWnd);
}
```

Try compiling the `cube.cpp` example program in the LVT source distribution to see what this code produces.

In the next section, we'll look at more intricate scene graph examples, and learn more about how the library manages scene graphs internally.

 Previous Home Up Next