Skip to main content

History: Basic Tutorial 1

Preview of version: 159

Tutorial Introduction
Ogre Tutorial Head

This first tutorial will cover the basic elements of building a scene in Ogre. The primary focus will be the SceneManager, SceneNode, and Entity. An Entity is anything represented by a mesh. A SceneNode is what attaches an object to your scene. Finally, the SceneManager is the object that organizes everything. It keeps track of the entities and nodes in your scene and determines how to display them.

We'll start with an explanation of some of the basic concepts in in Ogre. Don't worry, this first tutorial has a little more explanation than the rest, but that changes very quickly once you get to the later tutorials. We will be building plenty of things. We just have to lay a little groundwork first, so you have somewhere to stand.

The full source for this tutorial is here.

Any problems you encounter during working with this tutorial should be posted in the Help Forum(external link).

Prerequisites

This tutorial assumes that you already know how to set up an Ogre project and compile it successfully. If you need help with this, then read Setting Up An Application.

basicsetup_visual.png

How Ogre Works

We are going to provide a quick introduction to the basic elements of an Ogre scene.

SceneManager

Everything that appears on the screen is managed by the SceneManager. The SceneManager keeps track of the locations of the objects in your scene. The SceneManager also manages any cameras that you add to your scene. The SceneManager is what organizes all of the elements of your scene.

There are multiples types of SceneManagers. There are managers focused on rendering terrain. There are other managers focused on rendering BSP maps. The different types of SceneManager are listed here.

Entity

An Entity is one type of object that you can render in your scene. An entity is anything that is represented by a 3D mesh. Even terrain objects are very large entities. Lights, Billboards, Particles, and Cameras are examples of scene elements that are not entities.

Ogre uses a well-known design pattern that separates renderable objects from information like their location. This means that you don't directly place an Entity into your scene. Instead, you place a SceneNode into your scene, then attach your Entity to that SceneNode. The Entity is then rendered using information taken from the SceneNode.

SceneNode

SceneNodes carry information that is used for all of the objects that are attached to it. An Entity is not rendered in your scene until it is attached to a SceneNode. In addition, a SceneNode is not a visible object in your scene. It only holds abstract information like location and orientation. Only when it is connected to something like an Entity is that information used to actually render something in the scene.

SceneNodes can have more than one object attached to them. We may want to have a light that will follow a character around in a scene. To do this, we could attach both the character Entity and the light to the same SceneNode. This will cause them both to share the same location information. We can even attach SceneNodes to other SceneNodes. This is useful in many circumstances. Imagine you have a character and you want to attach a tool to their hand. You wouldn't want to attach the tool to SceneNode for the entire character. Instead, you could attach a SceneNode representing their hand to the character's main SceneNode, and then attach the tool Entity to that "child" SceneNode. more complicated uses of SceneNodes will be covered in later tutorials.

One final thing to keep in mind about SceneNodes is that their position is always relative to their parent SceneNode, and each SceneManager creates a root Node to which all other SceneNodes are attached.

Setting Up the Scene

It's finally time to start building something in our scene. The first thing we want to do is turn on the lights. Add the following to TutorialApplication::createScene:

Copy to clipboard
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));

The setAmbientLight method takes an Ogre::ColourValue. The three values represent the red, green, and blue values of the colour, and they range between 0 and 1.

mSceneMgr is a variable that is defined in BaseApplication. There are a number of variables, like mCamera, that we inherit from BaseApplication. They will be introduced as we need them.

The next thing we do is ask the SceneManager to create an Entity.

Copy to clipboard
Ogre::Entity* ogreEntity = mSceneMgr->createEntity("ogrehead.mesh");

The parameter given to this function must be a mesh that was loaded by Ogre's resource manager. For now, resource loading is one of the many things that BaseApplication is taking care of for us. It will be explained further in later tutorials.

Now that we have an Entity, we need to create a SceneNode so the Entity can be displayed in our scene. Every SceneManager has a root node. That node has a method called createChildSceneNode that will return a new SceneNode attached to the root. In older versions of Ogre, you were required to provide a name for your Entities and SceneNodes. This is now optional. Ogre will generate unique names for them if you do not provide one.

Copy to clipboard
Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

We save the SceneNode pointer that is returned by the method so that we can attach our Entity to it.

Copy to clipboard
headNode->attachObject(ogreEntity);

Lights will be covered in detail in the next tutorial, but we will still add a simple one to this scene as a teaser. New Light objects can also be requested from the SceneManager. We give the Light a unique name when it is created.

Copy to clipboard
Ogre::Light* light = mSceneMgr->createLight("MainLight");

Once the Light is created, we set its position. The three parameters are the x, y, and z coordinates of the location we want to place the Lightl

Copy to clipboard
light->setPosition(20, 80, 50);

We now have a basic scene set up. Compile and run your application. You should see an Ogre's head on your screen. This is only the beginning...

basicsetup_visual.png

Coordinates Systems

Before we go on, let's cover some basics of Ogre's coordinate system. Ogre, like many other graphics engines, uses the x-z plane as the "floor" in a scene. This means that the y-axis is the vertical axis to ensure Ogre is using a right-handed coordinate system.
Cartesian coordinate system
The x-axis starts with negative values to the left and increases to the right (passing through zero at the origin). The z-axis runs forwards and backwards. The positive direction of the z-axis points "out of the screen". So if a character walks towards the screen, then its z value will be increasing. Finally, the y-axis runs from the bottom to the top. Values that are "below ground" are negative. Don't take these terms in parenthesis literally. You can put the ground wherever you want. It is just to help you orient yourself in the scene.

When you run your application, notice how your Ogre head is facing towards the camera down the positive z-axis. This is a property of the mesh itself and the orientation of the camera. Cameras are covered in a later tutorial. The Ogre head is sitting at the origin of our world, (0, 0, 0). The direction the head is facing by default is a result of which way it was facing when it was originally modeled. You can effectively change this from within Ogre as well, but it will require some knowledge of quaternions, which aren't really covered until the Intermediate Tutorials.

Ogre uses a vector class to represent positions and directions (there is no point class). There are vectors defined for 2-4 dimensions. They are called Vector2, Vector3, and Vector4. Vector3 being the most commonly used by far. If you are not familiar with the concept of vectors it is highly recommended to learn a little before attempting these tutorials. Even though Ogre is an abstraction over many of the complications involved with OpenGL and DirectX, there is still no escaping some mathematical concepts. Vectors and basic linear algebra will be some of the most useful things you can learn if you intend to proceed with 3D rendering. This site has produced a nice primer on vectors focused on game programmers.

Adding another Object

Now that you understand how the coordinate systems work, we can go back to our code. In the three lines we wrote, nowhere did we specify the exact location where we wanted our Ogre head to appear. A large majority of the functions in Ogre have default parameters for them. For example, the SceneNode::createChildSceneNode member function in Ogre has three parameters: the name of the SceneNode, the position of the SceneNode, and the initial rotation (orientation) the SceneNode is facing. The position, as you can see, has been set for us to the coordinates (0, 0, 0). Let's create another SceneNode, but this time we'll specify the starting location to be something other than the origin:

Copy to clipboard
Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 );

This should look familiar. We have done the exact same thing as before, with two exceptions. First of all, we have named the Entity and SceneNode something slightly different. The second thing we have done is specified that the starting position will be 100 units in the x direction away from the root SceneNode (remember that all SceneNode positions are relative to their parents). Compile and run the demo. Now there are two Ogre heads side-by-side. You may have to move back using the 's' key or the down arrow to see both heads.

Entities more in Depth

The Entity class is very extensive, and we will not be covering here how to use every portion of the object, just enough to get you started. For now, there are a few immediately useful member functions in Entity that I'd like to point out.

The first is Entity::setVisible and Entity::isVisible. You can set any Entity to be visible or not by simply calling this function. If you need to hide an Entity, but later display it, then call this function instead of destroying the Entity and later recreating it.

 "Pooling" Entities
You don't need to "pool" Entities up. Only one copy of any object's mesh and texture are ever loaded into memory, so you are not saving yourself much by trying to save them. The only thing you really save is the creation and destruction costs for the Entity object itself, which is relatively low.


The getName function returns the name of Entity, and the getParentSceneNode function returns the SceneNode that the Entity is attached to.

SceneNodes more in Depth

The SceneNode class is very complex. There are a lot of things that can be done with a SceneNode, so we'll only cover some of the most useful methods.

You can get and set the position of a SceneNode with getPosition and setPosition (always relative to the parent SceneNode). You can move the object relative to its current position by using the translate method.

SceneNodes not only set position, but they also manage the scale and rotation of the object. You can set the scale of an object with the scale function. You can use the pitch, yaw, and roll functions to rotate objects. You can use resetOrientation to reset all rotations done to the object. You can also use the setOrientation, getOrientation, and rotate functions for more advanced rotations. We will not be covering Quaternions until a much later tutorial though.

You have already seen the attachObject function. These related functions are also useful if you are looking to manipulate the objects that are attached to a SceneNode: numAttachedObjects, getAttachedObject (there are multiple versions of this function), detachObject (also multiple versions), detachAllObjects. There are also a whole set of functions for dealing with parent and child SceneNodes as well.

Since all positioning and translating is done relative to the parent SceneNode, we can make two SceneNodes move together very easily. We currently have this code in the application:

Copy to clipboard
mSceneMgr->setAmbientLight(Ogre::ColourValue(1.0, 1.0, 1.0)); Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode"); headNode->attachObject(ogreHead); Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 );

If we change the 6th line from this:

Copy to clipboard
Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) );

To this:

Copy to clipboard
Ogre::SceneNode* headNode2 = headNode->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) );

Then we have made headNode2 a child of headNode. Moving headNode will move headNode2 along with it, but moving headNode2 will not affect headNode. For example this code would move only headNode2:

Copy to clipboard
headNode2->translate( Ogre::Vector3( 10, 0, 10 ) );

The following code would move headNode, and since headNode2 is a child of headNode, headNode2 would be moved as well:

Copy to clipboard
headNode->translate( Ogre::Vector3( 25, 0, 0 ) );

If you are having trouble with this, the easiest thing to do is to start at the root SceneNode and go downwards. Let's say (as in this case), we started with headNode at (0, 0, 0) and translated it by (25, 0, 0); headNode's new position would be (25, 0, 0) relative to its parent. headNode2 started at (100, 0, 0) and we translated it by (10, 0, 10), so its new position is (110, 0, 10) relative to its parent.

Now let's figure out where these things really are. Start at the root SceneNode. Its position is always (0, 0, 0). Now, headNode's position is (root + headNode): (0, 0, 0) + (25, 0, 0) = (25, 0, 0). Not surprising.

Now, headNode2 is a child of headNode, so its position is (root + headNode + headNode2): (0, 0, 0) + (25, 0, 0) + (110, 0, 10) = (135, 0, 10).

This is just an example to explain how to think about SceneNode position inheritance. You will rarely ever need to calculate the absolute position of your nodes. Lastly, note that you can get both SceneNodes and Entities by their name by calling getSceneNode and getEntity methods of the SceneManager, so you don't have to keep a pointer to every SceneNode you create. You should hang on to the ones you use often though.

Things to Try

By now you should have a basic grasp of Entities, SceneNodes, and the SceneManager. We suggest starting with the code above and adding and removing Ogre heads from the scene. Once you have done that, clear all the contents out of the createScene method, and play with each of the following code segments:

Scale

You can scale the mesh by calling the scale method in SceneNode. Try changing the values in scale and see what you get:

Copy to clipboard
mSceneMgr->setAmbientLight(Ogre::ColourValue(1.0, 1.0, 1.0)); Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode"); headNode->attachObject(ogreHead); headNode->scale( .5, 1, 2 ); Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 ); headNode2->scale( 1, 2, 1 );
Image

Rotations

You can rotate the object by using the yaw, pitch, and roll methods using either Degree or Radian objects. Pitch is rotation around the x axis, yaw is around the y axis, and roll is around the z axis. Using your right hand as a guide: point your thumb in the direction of an axis, curl your remaining fingers. The direction of the curl matches the positive rotation around that axis:

right_hand_rule.gif

Try changing the Degree amount and combining multiple transforms:
After trying around Basic Tutorial 1

Copy to clipboard
mSceneMgr->setAmbientLight(Ogre::ColourValue(1.0, 1.0, 1.0)); Ogre::Entity* ogreHead = mSceneMgr->createEntity("Head", "ogrehead.mesh"); Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("HeadNode"); headNode->attachObject(ogreHead); headNode->yaw( Ogre::Degree( -90 ) ); Ogre::Entity* ogreHead2 = mSceneMgr->createEntity( "Head2", "ogrehead.mesh" ); Ogre::SceneNode* headNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode2", Ogre::Vector3( 100, 0, 0 ) ); headNode2->attachObject( ogreHead2 ); headNode2->pitch( Ogre::Degree( -90 ) ); Ogre::Entity* ogreHead3 = mSceneMgr->createEntity( "Head3", "ogrehead.mesh" ); Ogre::SceneNode* headNode3 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "HeadNode3", Ogre::Vector3( 200, 0, 0 ) ); headNode3->attachObject( ogreHead3 ); headNode3->roll( Ogre::Degree( -90 ) );


In Microsoft Visual Studio 2010, a problem may be found that 'Degree' is an undeclared identifier.
This can be fixed by calling the function as 'Ogre::Degree', allowing the compiling with rotation.

The Ogre Environment

Most of the files (.DLL and .CFG) referred to in this section (and throughout the tutorials) can be found in the OgreSDK "bin" folder under either debug or release. Debug programs should use the files in the debug OgreSDK folder, while release programs should use the files in the release folder.

 Windows, Linux, and OSX
Most of this section uses Windows-specific monikers. The same information basically applies to Linux and Mac OS X, but some things may be slightly different, such as the shared libraries ending in .so and residing in alternative locations. If you have problems, be sure to post your question to the Ogre help forums.

DLLs and Plugins

Now that we have played with the Ogre environment a bit, I'd like to explain how the Ogre library works in general, so as to make your life easier when working with it.

Ogre is divided into 3 large shared library groups: main library, plugins, and third-party libraries.

Main library

The first group consists of the library itself and the shared libraries it relies on. The Ogre library is contained, in its entirety, in OgreMain.dll. This dll requires a few other libraries such as cg.dll. These DLLs must be included with every Ogre application without exception.

Plugins

The second group of shared libraries are the plugins. Ogre pushes a good portion of functionality out into shared libraries so that they may be turned on or off depending on the needs of your application. The basic plugins included with Ogre have filenames which start with the "Plugin_" prefix. You can create new plugins yourself if your application needs them, but we will not be covering this in any tutorial.

Ogre also uses plugins for the render systems (such as OpenGL, DirectX, etc). These plugins start with the "RenderSystem_" prefix. These plugins exist so that you can add or remove render systems from your application. This can be especially useful if you write shaders or something which is specific to (for example) OpenGL and you need to disable the ability to run the program in DirectX. Simply remove the appropriate RenderSystem plugin and it will be unavailable. Additionally if you are targeting a non-standard platform, you can write your own RenderSystem plugin, though this will not be covered in the tutorial. We will cover how to remove plugins in the next section.

Third party libraries and helper libraries

The third group of shared libraries are the third party libraries and helper libraries. Ogre itself is just a graphics rendering library. It does not include things such as GUI systems, input control, physics engines, and so on. You will have to use other libraries to do these things.

The Ogre demos and SDK include a few of these third party helper libraries:

  • Keyboard and mouse input is accomplished through OIS (an input system). This is contained in OIS.dll.
  • Cg (C for Graphics) is used by the CgProgramManager, and is contained in Cg.dll.

There are also other libraries (not included with the SDK) that offer more functionality (such as sound and physics), which you can find more information about in other places such as the Wiki and the forums.

Testing vs Release

When you are testing your application locally you can leave everything "turned on" (that is, not remove anything), as the size of the testing files are often unimportant. When you are ready to distribute your application, you will need to build it in Release mode and want to include only the plugins necessary for release.

Example

If your program doesn't use the Cg ProgramManager but does use OIS, then you shouldn't bother including the Cg and the CgProgramManager DLLs, but you must include the OIS DLL or your application will not run.

Configuration Files

Ogre runs off of several configuration files. They control which plugins are loaded, where the application's resources are located, and so on. We will briefly look at each of the configuration files and what they do. If you have more specific questions, you should direct them to the Ogre help forums.

plugins.cfg: This file contains which plugins your application uses. If you want to add or remove a plugin in application, you will need to modify this file. To remove a plugin, simply remove the appropriate line, or comment it out by putting a # at the beginning of the line. To add a plugin, you will need to add a line like "Plugin=[PluginName]". Note that you do not put .DLL at the end of the plugin name. Your plugin also does not have to start with "RenderSystem_" or "Plugin_". You can also decide where Ogre looks for plugins by changing the "PluginFolder" variable. You can use both absolute and relative paths, but you cannot use environment variables like $(SomeVariable).

resources.cfg: This file contains a list of directories which Ogre should scan to look for resources. Resources include scripts, meshes, textures, and so on. You can use both absolute and relative paths, but you cannot use environment variables like $(SomeVariable). Note that Ogre will not scan subfolders, so you must manually enter them if you have multiple levels. For example, if you have a directory tree like "res\meshes" and "res\meshes\small", you will have to add two entries to the resources file containing both of these paths.

media.cfg: This file tells Ogre more detailed information about some of the resources. It is unlikely that you will need to modify this file at this time, so we will skip over the details. More information can be found in the Manual and in the Ogre forums.

ogre.cfg: This file is generated by Ogre's configuration screen. This file will be specific to your individual computer and graphics setup. You should not distribute this file to other people when you share your application, as they are likely to have different settings than you do. Note you should not edit this file directly, instead use the configuration screen.

quake3settings.cfg: This file is used with the BSPSceneManager. You will not need this file unless you are using this scene manager (which you are not using at this point), so ignore it. You should not distribute this file with your application unless, again, you are using the BSPSceneManager, and even then it will likely be completely different depending on the needs of your program.

These are all of the configuration files that Ogre manipulates directly. Ogre must be able to find "plugins.cfg", "resources.cfg", and "media.cfg" to run properly. In a later tutorial we will cover more about these files and how to change their location and manipulate them to do more advanced things.

Conclusion

By this point you should have a very basic grasp of the SceneManager, SceneNode, and Entity classes. You do not have to be familiar with all of the functions that we have introduced. Since these are the most basic objects, we will be using them very often. You will get more familiar with them after working through the next few tutorials.

You should also be familiar with setting up a working Ogre environment for your projects.

Proceed to Basic Tutorial 2 Cameras, Lights, and Shadows


Alias: Basic_Tutorial_1

History

Information Version
Sun 27 of May, 2018 22:40 GMT-0000 paroj 251
Sun 29 of Oct, 2017 22:51 GMT-0000 paroj 250
Sat 07 of Oct, 2017 12:40 GMT-0000 paroj 249
Fri 10 of Jul, 2015 22:09 GMT-0000 Duke missing right parenthesis 248
Fri 08 of May, 2015 04:54 GMT-0000 kabbotta 247
Fri 08 of May, 2015 04:54 GMT-0000 kabbotta 246
Tue 21 of Apr, 2015 22:28 GMT-0000 a0903638 typo fixes 245
Tue 21 of Apr, 2015 22:26 GMT-0000 a0903638 2 small fixes 244
Sun 19 of Apr, 2015 06:17 GMT-0000 kabbotta 243
Sun 19 of Apr, 2015 00:09 GMT-0000 kabbotta 242
Sun 19 of Apr, 2015 00:09 GMT-0000 kabbotta 241
Sun 05 of Apr, 2015 07:55 GMT-0000 kabbotta 240
Sun 05 of Apr, 2015 07:55 GMT-0000 kabbotta 239
Sun 05 of Apr, 2015 07:54 GMT-0000 kabbotta 238
Sun 05 of Apr, 2015 07:53 GMT-0000 kabbotta 237
Sun 05 of Apr, 2015 07:53 GMT-0000 kabbotta 236
Sun 05 of Apr, 2015 07:52 GMT-0000 kabbotta 235
Sun 05 of Apr, 2015 07:51 GMT-0000 kabbotta 234
Sun 05 of Apr, 2015 07:50 GMT-0000 kabbotta 233
Thu 02 of Apr, 2015 02:05 GMT-0000 kabbotta 232
Wed 01 of Apr, 2015 21:25 GMT-0000 kabbotta 231
Wed 01 of Apr, 2015 21:25 GMT-0000 kabbotta 230
Wed 01 of Apr, 2015 21:21 GMT-0000 kabbotta 229
Wed 01 of Apr, 2015 21:20 GMT-0000 kabbotta 228
Wed 01 of Apr, 2015 21:19 GMT-0000 kabbotta 227