The Ogre Scene Graph

Exclusive offer: get 50% off this eBook here
OGRE 3D 1.7 Beginner's Guide

OGRE 3D 1.7 Beginner's Guide — Save 50%

Create real time 3D applications using OGRE 3D from scratch

$26.99    $13.50
by Felix Kerger | December 2010 | Open Source Web Graphics & Video

This article will introduce us to the concept of a scene graph and how we can use its functions to create complex scenes.

In this article, Felix Kerger, author of Ogre 3D 1.7, we shall:

  • Learn the three basic operations in 3D space
  • How a scene graph is organized
  • The different 3D spaces we can operate in

So let's get on with it.

 

OGRE 3D 1.7 Beginner's Guide

OGRE 3D 1.7 Beginner's Guide

Create real time 3D applications using OGRE 3D from scratch

  • Easy-to-follow introduction to OGRE 3D
  • Create exciting 3D applications using OGRE 3D
  • Create your own scenes and monsters, play with the lights and shadows, and learn to use plugins
  • Get challenged to be creative and make fun and addictive games on your own
  • A hands-on do-it-yourself approach with over 100 examples

Images

        Read more about this book      

(For more resources on this subject, see here.)

Creating a scene node

We will learn how to create a new scene node and attach our 3D model to it.

Time for action – creating a scene node with Ogre 3D

We will follow these steps:

  1. In the old version of our code, we had the following two lines in the createScene() function:

    Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.mesh");
    mSceneMgr->getRootSceneNode()->attachObject(ent);

  2. Replace the last line with the following:

    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");

  3. Then add the following two lines; the order of those two lines is irrelevant forthe resulting scene:

    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  4. Compile and start the application.

What just happened?

We created a new scene node named Node 1. Then we added the scene node to the root scene node. After this, we attached our previously created 3D model to the newly created scene node so it would be visible.

How to work with the RootSceneNode

The call mSceneMgr->getRootSceneNode() returns the root scene node. This scene node is a member variable of the scene manager. When we want something to be visible, we need to attach it to the root scene node or a node which is a child or a descendent in any way. In short, there needs to be a chain of child relations from the root node to the node; otherwise it won't be rendered. As the name suggests, the root scene node is the root of the scene. So the entire scene will be, in some way, attached to the root scene node. Ogre 3D uses a so-called scene graph to organize the scene. This graph is like a tree, it has one root, the root scene node, and each node can have children. We already have used this characteristic when we called mSceneMgr->getRootSceneNode()->addChild(node);. There we added the created scene node as a child to the root. Directly afterwards, we added another kind of child to the scene node with node->attachObject(ent);. Here, we added an entity to the scene node. We have two different kinds of objects we can add to a scene node. Firstly, we have other scene nodes, which can be added as children and have children themselves. Secondly, we have entities that we want rendered. Entities aren't children and can't have children themselves. They are data objects which are associated with the node and can be thought of as leaves of the tree. There are a lot of other things we can add to a scene, like lights, particle systems, and so on. We will later learn what these things are and how to use them. Right now, we only need entities. Our current scene graph looks like this:

The first thing we need to understand is what a scene graph is and what it does. A scene graph is used to represent how different parts of a scene are related to each other in 3D space.

3D space

Ogre 3D is a 3D rendering engine, so we need to understand some basic 3D concepts. The most basic construct in 3D is a vector, which is represented by an ordered triple (x,y,z).

Each position in a 3D space can be represented by such a triple using the Euclidean coordination system for three dimensions. It is important to know that there are different kinds of coordinate systems in 3D space. The only difference between the systems is the orientation of the axis and the positive rotation direction. There are two systems that are widely used, namely, the left-handed and the right-handed versions. In the following image, we see both systems—on the left side, we see the left-handed version; and on the right side, we see the right-handed one.

Source:http://en.wikipedia.org/wiki/File:Cartesian_coordinate_system_handedness.svg

The names left-and right-handed are based on the fact that the orientation of the axis can be reconstructed using the left and right hand. The thumb is the x-axis, the index finger the y-axis, and the middle finger the z-axis. We need to hold our hands so that we have a ninety-degree angle between thumb and index finger and also between middle and index finger. When using the right hand, we get a right-handed coordination system. When using the left hand, we get the left-handed version.

Ogre uses the right-handed system, but rotates it so that the positive part of the x-axis is pointing right and the negative part of the x-axis points to the left. The y-axis is pointing up and the z-axis is pointing out of the screen and it is known as the y-up convention. This sounds irritating at first, but we will soon learn to think in this coordinate system. The website http://viz.aset.psu.edu/gho/sem_notes/3d_fundamentals/html/3d_coordinates.html contains a rather good picture-based explanation of the different coordination systems and how they relate to each other.

Scene graph

A scene graph is one of the most used concepts in graphics programming. Simply put, it's a way to store information about a scene. We already discussed that a scene graph has a root and is organized like a tree. But we didn't touch on the most important function of a scene graph. Each node of a scene graph has a list of its children as well as a transformation in the 3D space. The transformation is composed of three aspects, namely, the position, the rotation, and the scale. The position is a triple (x,y,z), which obviously describes the position of the node in the scene. The rotation is stored using a quaternion, a mathematical concept for storing rotations in 3D space, but we can think of rotations as a single floating point value for each axis, describing how the node is rotated using radians as units. Scaling is quite easy; again, it uses a triple (x,y,z), and each part of the triple is simply the factor to scale the axis with.

The important thing about a scene graph is that the transformation is relative to the parent of the node. If we modify the orientation of the parent, the children will also be affected by this change. When we move the parent 10 units along the x-axis, all children will also be moved by 10 units along the x-axis. The final orientation of each child is computed using the orientation of all parents. This fact will become clearer with the next diagram.

The position of MyEntity in this scene will be (10,0,0) and MyEntity2 will be at (10,10,20).

Let's try this in Ogre 3D.

Pop quiz – finding the position of scene nodes

Look at the following tree and determine the end positions of MyEntity and MyEntity2:

  1. MyEntity(60,60,60) and MyEntity2(0,0,0)
  2. MyEntity(70,50,60) and MyEntity2(10,-10,0)
  3. MyEntity(60,60,60) and MyEntity2(10,10,10)

Setting the position of a scene node

Now, we will try to create the setup of the scene from the diagram before the previous image.

Time for action – setting the position of a scene node

  1. Add this new line after the creation of the scene node:

    node->setPosition(10,0,0);

  2. To create a second entity, add this line at the end of the createScene() function:

    Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","Sinbad.
    mesh");

  3. Then create a second scene node:

    Ogre::SceneNode* node2 = mSceneMgr->createSceneNode("Node2");

  4. Add the second node to the first one:
  5. node->addChild(node2);

  6. Set the position of the second node:

    node2->setPosition(0,10,20);

  7. Attach the second entity to the second node:

    node2->attachObject(ent2);

  8. Compile the program and you should see two instances of Sinbad:

What just happened?

We created a scene which matches the preceding diagram. The first new function we used was at step 1. Easily guessed, the function setPosition(x,y,z) sets the position of the node to the given triple. Keep in mind that this position is relative to the parent. We wanted MyEntity2 to be at (10,10,20), because we added node2, which holds MyEntity2, to a scene node which already was at the position (10,0,0). We only needed to set the position of node2 to (0,10,20). When both positions combine, MyEntity2 will be at (10,10,20).

Pop quiz – playing with scene nodes

We have the scene node node1 at (0,20,0) and we have a child scene node node2, which has an entity attached to it. If we want the entity to be rendered at (10,10,10), at which position would we need to set node2?

  1. (10,10,10)
  2. (10,-10,10)
  3. (-10,10,-10)

Have a go hero – adding a Sinbad

Add a third instance of Sinbad and let it be rendered at the position (10,10,30).

Rotating a scene node

We already know how to set the position of a scene node. Now, we will learn how to rotate a scene node and another way to modify the position of a scene node.

Time for action – rotating a scene node

We will use the previous code, but create completely new code for the createScene() function.

  1. Remove all code from the createScene() function.
  2. First create an instance of Sinbad.mesh and then create a new scene node. Set the position of the scene node to (10,10,0), at the end attach the entity to the node, and add the node to the root scene node as a child:

    Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    node->setPosition(10,10,0);
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  3. Again, create a new instance of the model, also a new scene node, and set the position to (10,0,0):

    Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","Sinbad.
    mesh");
    Ogre::SceneNode* node2 = mSceneMgr->createSceneNode("Node2");
    node->addChild(node2);
    node2->setPosition(10,0,0);

  4. Now add the following two lines to rotate the model and attach the entity to the scene node:

    node2->pitch(Ogre::Radian(Ogre::Math::HALF_PI));
    node2->attachObject(ent2);

  5. Do the same again, but this time use the function yaw instead of the function pitch and the translate function instead of the setPosition function:

    Ogre::Entity* ent3 = mSceneMgr->createEntity("MyEntity3","Sinbad.
    mesh");
    Ogre::SceneNode* node3 = mSceneMgr->createSceneNode("Node3",);
    node->addChild(node3);
    node3->translate(20,0,0);
    node3->yaw(Ogre::Degree(90.0f));
    node3->attachObject(ent3);

  6. And the same again with roll instead of yaw or pitch:

    Ogre::Entity* ent4 = mSceneMgr->createEntity("MyEntity4","Sinbad.
    mesh");
    Ogre::SceneNode* node4 = mSceneMgr->createSceneNode("Node4");
    node->addChild(node4);
    node4->setPosition(30,0,0);
    node4->roll(Ogre::Radian(Ogre::Math::HALF_PI));
    node4->attachObject(ent4);

  7. Compile and run the program, and you should see the following screenshot:

What just happened?

We repeated the code we had before four times and always changed some small details. The first repeat is nothing special. It is just the code we had before and this instance of the model will be our reference model to see what happens to the other three instances we made afterwards.

In step 4, we added one following additional line:

node2->pitch(Ogre::Radian(Ogre::Math::HALF_PI));

The function pitch(Ogre::Radian(Ogre::Math::HALF_PI)) rotates a scene node around the x-axis. As said before, this function expects a radian as parameter and we used half of pi, which means a rotation of ninety degrees.

In step 5, we replaced the function call setPosition(x,y,z) with translate(x,y,z). The difference between setPosition(x,y,z) and translate(x,y,z) is that setPosition sets the position—no surprises here. translate adds the given values to the position of the scene node, so it moves the node relatively to its current position. If a scene node has the position (10,20,30) and we call setPosition(30,20,10), the node will then have the position (30,20,10). On the other hand, if we call translate(30,20,10), the node will have the position (40,40,40). It's a small, but important, difference. Both functions can be useful if used in the correct circumstances, like when we want to position in a scene, we would use the setPosition(x,y,z) function. However, when we want to move a node already positioned in the scene, we would use translate(x,y,z).

Also, we replaced pitch(Ogre::Radian(Ogre::Math::HALF_PI))with yaw(Ogre::Degree(90.0f)). The yaw() function rotates the scene node around the y-axis. Instead of Ogre::Radian(), we used Ogre::Degree(). Of course, Pitch and yaw still need a radian to be used. However, Ogre 3D offers the class Degree(), which has a cast operator so the compiler can automatically cast into a Radian(). Therefore, the programmer is free to use a radian or degree to rotate scene nodes. The mandatory use of the classes makes sure that it's always clear which is used, to prevent confusion and possible error sources.

Step 6 introduces the last of the three different rotate function a scene node has, namely, roll(). This function rotates the scene node around the z-axis. Again, we could use roll(Ogre::Degree(90.0f)) instead of roll(Ogre::Radian(Ogre::Math::HALF_PI)).

The program when run shows a non-rotated model and all three possible rotations. The left model isn't rotated, the model to the right of the left model is rotated around the x-axis, the model to the left of the right model is rotated around the y-axis, and the right model is rotated around the z-axis. Each of these instances shows the effect of a different rotate function. In short, pitch() rotates around the x-axis, yaw() around the y-axis, and roll() around the z-axis. We can either use Ogre::Degree(degree) or Ogre::Radian(radian) to specify how much we want to rotate.

Pop quiz – rotating a scene node

Which are the three functions to rotate a scene node?

  1. pitch, yawn, roll
  2. pitch, yaw, roll
  3. pitching, yaw, roll

Have a go hero – using Ogre::Degree

Remodel the code we wrote for the previous section in such a way that each occurrence of Ogre::Radian is replaced with an Ogre::Degree and vice versa, and the rotation is still the same.

Scaling a scene node

We already have covered two of the three basic operations we can use to manipulate our scene graph. Now it's time for the last one, namely, scaling.

Time for action – scaling a scene node

Once again, we start with the same code block we used before.

  1. Remove all code from the createScene() function and insert the following code block:

    Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    node->setPosition(10,10,0);
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  2. Again, create a new entity:

    Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","Sinbad.
    mesh");

  3. Now we use a function that creates the scene node and adds it automatically as a child. Then we do the same thing we did before:

    Ogre::SceneNode* node2 = node->createChildSceneNode("node2");
    node2->setPosition(10,0,0);
    node2->attachObject(ent2);

  4. Now, after the setPosition() function, call the following line to scale the model:

    node2->scale(2.0f,2.0f,2.0f);

  5. Create a new entity:

    Ogre::Entity* ent3 = mSceneMgr->createEntity("MyEntity3","Sinbad.
    mesh");

  6. Now we call the same function as in step 3, but with an additional parameter:

    Ogre::SceneNode* node3 = node->createChildSceneNode("node3",Ogre::
    Vector3(20,0,0));

  7. After the function call, insert this line to scale the model:

    node3->scale(0.2f,0.2f,0.2f);

  8. Compile the program and run it, and you should see the following image:

OGRE 3D 1.7 Beginner's Guide Create real time 3D applications using OGRE 3D from scratch
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

What just happened?

We created a scene with scaled models. Nothing special happened until step 3. Then we used a new function, namely, node->createChildSceneNode("node2"). This function is a member function of a scene node and creates a new node with the given name and adds it directly as a child to the node which called the function. In this case, node2 is added as a child to the node.

In step 4, we used the scale() function of the scene node. This function takes a triple (x,y,z), which indicated how the scene node should be scaled. x, y, and z are factors. (0.5,1.0,2.0) means that the scene node should be halved on the x-axis, kept the same on the y-axis, and doubled on the z-axis. Of course, in a really strict sense, the scene node can't be scaled; it only holds metadata which isn't rendered. It would be more precise to say that each renderable object attached to this node would be scaled instead of the scene node itself. The node is only a holder or reference frame for all attached children and renderable objects.

In step 6, we used the createChildSceneNode() function again, but this time with more parameters. The second parameter that this function takes is a triple (x,y,z) which is so often used. Ogre 3D has its own class for it called Ogre::Vector3. Besides storing the triple, this class offers functions which implement the basic operations. They can be done with three dimensional vectors in linear algebra. This vector describes the translate which should be used when the scene node is created. createChildSceneNode() can be used to replace the following lines of code:

Ogre::SceneNode* node2 = mSceneMgr->createSceneNode("Node2");
node->addChild(node2);

or even

Ogre::SceneNode* node2 = mSceneMgr->createSceneNode("Node2");
node->addChild(node2);
node2->setPosition(20,0,0);

The last piece of code can be replaced with

Ogre::SceneNode* node2 = node->createChildSceneNode("Node2",Ogre::
Vector3(20,0,0));

If we leave out the Vector3 parameter, we can replace the first piece of code. There are more versions of this function, which we will use later. If you can't wait, take a look at the documentation of Ogre 3D at http://www.ogre3d.org/docs/api/html/index.html

Besides scale(), there is also setScale(). The difference between these functions is the same as between setPosition() and translate().

Pop quiz – creating child scene nodes

  1. Name two different ways of calling createChildSceneNode()
  2. How could the following line be replaced without using createChildSceneNode()?

    Ogre::SceneNode* node2 = node->createChildSceneNode("node1",Ogre::
    Vector3(10,20,30));

  3. This line could be replaced with three lines. The first creates the scene node, the second one translates it, and the third attaches it to the node.

    Ogre::SceneNode* node2 = mSceneMgr->createSceneNode("Node2");
    node2->translate(Ogre::Vector3(10,20,30));
    node->addChild(node2);

    Have a go hero – using createChildSceneNode()

    Refactor all the code you wrote in this chapter to use createChildSceneNode().

    Using a scene graph the clever way

    In this section, we will learn how we can use the characteristics of a scene graph to make some tasks easier. This will also expand our knowledge about a scene graph.

    Time for action – building a tree using scene nodes

    This time, we are going to use another model besides Sinbad: the ninja.

  4. Remove all the code from the createScene() function.
  5. Create Sinbad like we always do:
  6. Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    node->setPosition(10,10,0);
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  7. Now create a ninja, which will follow Sinbad everywhere he goes:
  8. Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntitysNinja","nin
    ja.mesh");
    Ogre::SceneNode* node2 = node->createChildSceneNode("node2");
    node2->setPosition(10,0,0);
    node2->setScale(0.02f,0.02f,0.02f);
    node2->attachObject(ent2);

  9. Compile and run the application. When you take a closer look at Sinbad, you will see a green ninja at his left arm.

  10. Now change the position to (40,10,0):
  11. node->setPosition(40,10,0);

  12. And rotate the model 180 degree around the x-axis:

    node->yaw(Ogre::Degree(180.0f));

  13. Compile and run the application.
  14. You should see that the ninja is still at the left-hand of Sinbad and Sinbad is rotated.
  15. What just happened?

    We created a sneaky ninja who follows each step of Sinbad. We made this possible because we added the node the ninja model is attached to as a child to the scene node Sinbad is attached to. When we moved Sinbad, we used his scene node, so each transform we did is also done to the ninja, because this scene node is the child of the node we modify, and as said before, the transformation of a parent is passed to all its children. This fact about scene nodes is extremely helpful to create the following models or complex scenes. Say, if we wanted to create a truck which carries a complete house, we could create the house using a lot of different models and scene nodes. At the end, we would have a scene node where the whole house and its interior are added as children too. Now when we want to move the house, we simply attach the house node to the truck or anything else, and if the truck moves, the complete house moves with it.

    The arrows show the direction the transformations are propagated along the scene graph.

    Pop quiz – even more about the scene graph

    How is transformation information passed in a scene graph?

  16. From the leaves to the root
  17. From the root to the leaves
  18. Have a go hero – adding a following ninja

    Add a second ninja to the scene, which follows the first ninja.

    Different spaces in a scene

    In this part, we will learn that there are different spaces in a scene and how we can use these spaces.

    Time for action – translating in World space

  19. Again, start with an empty createScene() function; so delete every code you have in this function.
  20. Create a reference object.
  21. Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    node->setPosition(0,0,400);
    node->yaw(Ogre::Degree(180.0f));
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  22. Create two new instances of the model and translate each one with (0,0,10):
  23. Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","Sinbad.
    mesh");
    Ogre::SceneNode* node2 = node->createChildSceneNode("node2");
    node2->setPosition(10,0,0);
    node2->translate(0,0,10);
    node2->attachObject(ent2);

    Ogre::Entity* ent3 = mSceneMgr->createEntity("MyEntity3","Sinbad.
    mesh");
    Ogre::SceneNode* node3 = node->createChildSceneNode("node3");
    node3->setPosition(20,0,0);
    node3->translate(0,0,10);
    node3->attachObject(ent3);

  24. Compile and run the application. Navigate the camera until you see the previous models like this:
  25. Replace the line:
  26. node3->translate(0,0,10);

    with

    node3->translate(0,0,10,Ogre::Node::TS_WORLD);

  27. Again, compile and run the application and navigate the camera like before.
OGRE 3D 1.7 Beginner's Guide Create real time 3D applications using OGRE 3D from scratch
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

What just happened?

We used a new parameter of the translate() function. The result was that the left model in the scene moved in a different direction to the middle model.

Different spaces in a 3D scene

The reason why the model moved differently is because with Ogre::Node::TS_WORLD, we told the translate() function that the translate should happen in world space and not in parent space, where it is normal. There are three kinds of spaces we have in a 3D scene—world space, parent space, and local space. Local space is where the model itself is defined. A cube consists of eight points and can be described as in the following diagram:

The black point is the null point of local space. Each point of the cube is described as a translate from the null point. When the scene is rendered, the cube needs to be in world space. To get the cube in world space, all transformations of these parents in the scene graph are applied to these points. Let's say the cube is attached to a scene node which is added to the root scene node with a translate of (10,0,0). Then the world space with the cube would look like this:

The difference between the two cubes is that the null point has shifted its position, or to be more precise, the cube has been moved away from the null point.

When we call the translate() function, the cube is moved in parent space if the space to use is not defined, like we did in step 5. When no parent of the cube is rotated, translate() behaves the same way with world space as it would when used with parent or local space. This is true because only the position of the null point changes and not the orientation of the axes. When we, say, move the cube (0,0,10) units, it doesn't matter where the null point is—as long as the axes of the coordination system are orientated the same, it won't change the outcome of the translate process. However, when a parent is rotated, this is no longer true. When the parent is rotated, this also rotates the axis of the null point, which changes the meaning of translate(0,0,10).

The left coordination system is not rotated and (0,0,10) means moving the cube 10 units nearer to the viewer. This is because the z-axis is pointing out of the screen. With the 180 degree rotation, (0,0,10) means moving the cube 10 units away from the viewer because the z-axis is pointing into the screen.

We see that it is important in what space we describe the translate() function to get the desired effect. World space always has the same orientation of axis. To be precise, world spaces uses the left coordination system. Parent space uses a coordination system where all roations from the parent upwards are applied. Local space includes all rotations, from the scene node itself to all parents. The default setting of translate() is to use parent space. This enables us to rotate the node itself without changing the direction a node moves when using translate(). But there are cases when we want to translate in a space different to parent space. In such cases, we can use the second parameter from translate(). The second parameter specifies the space we want the translate to happen in. In our code, we used Ogre::Node::TS_WORLD to move the model in world space, which inverted the direction the model used because we rotated the node around 180 degrees, and with this, flipped the direction of the x-and z-axis. Again, look at the image to see the effect.

Translating in local space

We've already seen the effect of translating in parent and world space. Now we will translate in local and parent space to see the difference and get a deeper understanding of the differences between the spaces.

Time for action – translating in local and parent space

  1. Clear the createScene() function once again.
  2. Insert a reference model; this time we will move it nearer to our camera so we don't have to move the camera so much:

    Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","Sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    node->setPosition(0,0,400);
    node->yaw(Ogre::Degree(180.0f));
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  3. Add a second model and rotate it by 45 degrees around the y-axis and translate it (0,0,20) units in parent space:
    Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","Sinbad.
    mesh");
    Ogre::SceneNode* node2 = node->createChildSceneNode("node2");
    node2->yaw(Ogre::Degree(45));
    node2->translate(0,0,20);
    node2->attachObject(ent2);
  4. Add a third model and also rotate it 45 degrees around the y-axis and translate it (0,0,20) units in local space:

    Ogre::Entity* ent3 = mSceneMgr->createEntity("MyEntity3","Sinbad.
    mesh");
    Ogre::SceneNode* node3 = node->createChildSceneNode("node3");
    node3->yaw(Ogre::Degree(45));
    node3->translate(0,0,20,Ogre::Node::TS_LOCAL);
    node3->attachObject(ent3);

  5. Compile and run the application. Then navigate the camera again so that you see the model from above.

What just happened?

We created our reference model and then added two models which were rotated 45 degrees around the y-axis. Then we translated both with (0,0,20), one model in parent space, the default setting, and the other model in local space. The model we translated in parent space moved in a straight line on the z-axis. But because we rotated the models around the y-axis, the model we translated in local space moved with this rotation and ended up moving up and left in the image. Let's repeat this. When we translate, the default setting is parent space, meaning that all rotations, except the rotation of the scene node we translate, are used while translating. When using world space, no rotation is taken into consideration. When translating, the world coordination system is used. When translating in local space, every rotation, even the rotation from the node we translate, is used for the translation.

Pop quiz – Ogre 3D and spaces

Name three different spaces that Ogre 3D knows.

Have a go hero – adding symmetry

Change the rotation and translation of the MyEntity2 to make the image symmetric. Make sure you use the right space; otherwise, it's difficult to create a symmetric image. Here is how it should look afterwards:

Rotating in different spaces

We have already seen how using different spaces while translating works; we will now do the same with rotating.

Time for action – rotating in different spaces

This time, we are going to rotate using different spaces, as follows:

  • And again, we will start with a clean createScene() function, so delete all code inside this function.
  • Add the reference model:

    Ogre::Entity* ent = mSceneMgr->createEntity("MyEntity","sinbad.
    mesh");
    Ogre::SceneNode* node = mSceneMgr->createSceneNode("Node1");
    mSceneMgr->getRootSceneNode()->addChild(node);
    node->attachObject(ent);

  • Add a second model and rotate it the normal way:

    Ogre::Entity* ent2 = mSceneMgr->createEntity("MyEntity2","sinbad.
    mesh");
    Ogre::SceneNode* node2 = mSceneMgr->getRootSceneNode()-
    >createChildSceneNode("Node2");
    node2->setPosition(10,0,0);
    node2->yaw(Ogre::Degree(90));
    node2->roll(Ogre::Degree(90));
    node2->attachObject(ent2);

  • Add a third model using world space:

    Ogre::Entity* ent3 = mSceneMgr->createEntity("MyEntity3","Sinbad.
    mesh");
    Ogre::SceneNode* node3 = node->createChildSceneNode("node3");
    node3->setPosition(20,0,0);
    node3->yaw(Ogre::Degree(90),Ogre::Node::TS_WORLD);
    node3->roll(Ogre::Degree(90),Ogre::Node::TS_WORLD);
    node3->attachObject(ent3);

  • Compile and run the application.
  • What just happened?

    Like always, we created our reference model, which is the left one in the picture. We rotated the second model—first around the y-axis and then around the z-axis. Rotation uses the default space as the local space. This implies that after we rotated the first model 90 degrees around the y-axis, the orientation of z-axis is changed. The second model used the world coordination system and there the orientation of the z-axis stays the same, even when we rotated a scene node.

    The model under number 1 is the original coordination system we had. Under number 2, we see the coordination system after we rotated 90 degrees around the y-axis. Under number 3, we rotated 90 degrees around the z-axis. Now let's look at the same rotations when we use world space instead of local space.

    Here we are doing the same rotations, but because we always used world space, we didn't use the changed coordination system, and therefore we got a different result.

    Scaling in different spaces

    Scaling is always done to die initial model, so there aren't different spaces for scaling. It wouldn't make much sense to scale in different spaces because there isn't really any need to do it.

    Summary

    We learned a lot in this article about the scene graph Ogre 3D uses and how to work with it to create complex scenes.

    Specifically, we covered the following:

    • What a scene graph is and how it works
    • Different ways for changing the position, rotation, and scaling of scene nodes
    • What different kinds of spaces we have for rotations and translation
    • How we can cleverly use the scene graph's properties to create complex scenes

    Further resources on this subject:


    About the Author :


    Felix Kerger

    Felix Kerger is a Computer Science Student at the Technical University of Darmstadt and has been developing 3D real-time applications using OGRE 3D for more than 5 years. He has given several talks on software development and 3D real-time applications at different conferences and has been working for three years as an assistant researcher at the Fraunhofer Institute for Computer Graphics Research. He also works as a freelance journalist and reports yearly from the Game Developer Conference Europe.

    Books From Packt


    Blender 3D 2.49 Architecture, Buildings, and Scenery
    Blender 3D 2.49 Architecture, Buildings, and Scenery

    Unity 3D Game Development by Example Beginner's Guide
    Unity 3D Game Development by Example Beginner's Guide

    3D Graphics with XNA Game Studio 4.0
    3D Graphics with XNA Game Studio 4.0

    Papervision3D Essentials
    Papervision3D Essentials

    3D Game Development with Microsoft Silverlight 3: Beginner's Guide
    3D Game Development with Microsoft Silverlight 3: Beginner's Guide

    Blender 3D 2.49 Incredible Machines
    Blender 3D 2.49 Incredible Machines

    Irrlicht 1.7.1 Realtime 3D Engine Beginner's Guide: RAW
    Irrlicht 1.7.1 Realtime 3D Engine Beginner's Guide: RAW

    Away3D 3.6 Essentials
    Away3D 3.6 Essentials


    No votes yet

    Post new comment

    CAPTCHA
    This question is for testing whether you are a human visitor and to prevent automated spam submissions.
    q
    t
    k
    Q
    m
    n
    Enter the code without spaces and pay attention to upper/lower case.
    Code Download and Errata
    Packt Anytime, Anywhere
    Register Books
    Print Upgrades
    eBook Downloads
    Video Support
    Contact Us
    Awards Voting Nominations Previous Winners
    Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
    Resources
    Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software