History: Basic Tutorial 1
Source of version: 201
- «
- »
Copy to clipboard
{TRANSCLUDE(page="tutbox")}This first tutorial will cover the basic elements of building a scene in Ogre. The primary focus will be the [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_manager.html|SceneManager], [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_node.html|SceneNode], and [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_entity.html|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 ((BasicTutorial1SourceCurrent|here.))
{TRANSCLUDE}
%tutorialhelp%
!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)).
{img fileId="2273" rel="box[g]"}
{maketoc}
!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 ((SceneManagersFAQ|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 {MONO()}TutorialApplication::createScene{MONO}:
{CODE(wrap="1", colors="c++")}
mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
{CODE}
The {MONO()}setAmbientLight{MONO} method takes an [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_colour_value.html|Ogre::ColourValue]. The three values represent the red, green, and blue values of the colour, and they range between 0 and 1.
{MONO()}mSceneMgr{MONO} is a variable that is defined in BaseApplication. There are a number of variables, like {MONO()}mCamera{MONO}, 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.
{CODE(wrap="1", colors="c++")}
Ogre::Entity* ogreEntity = mSceneMgr->createEntity("ogrehead.mesh");
{CODE}
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 {MONO()}createChildSceneNode{MONO} 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.
{CODE(wrap="1", colors="c++")}
Ogre::SceneNode* headNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
{CODE}
We save the SceneNode pointer that is returned by the method so that we can attach our Entity to it.
{CODE(wrap="1", colors="c++")}
headNode->attachObject(ogreEntity);
{CODE}
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.
{CODE(wrap="1", colors="c++")}
Ogre::Light* light = mSceneMgr->createLight("MainLight");
{CODE}
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
{CODE(wrap="1", colors="c++")}
light->setPosition(20, 80, 50);
{CODE}
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...
{img fileId="2270" rel="box[g]"}
!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 [http://mathworld.wolfram.com/Right-HandedCoordinateSystem.html|right-handed coordinate system].
{IMG(src="display1921",alt="Cartesian coordinate system")}{IMG}
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 - [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_vector3.html|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. [http://www.wildbunny.co.uk/blog/vector-maths-a-primer-for-games-programmers/|This site] has produced a nice primer on vectors focused on game programmers.
!Adding Another Entity
It's time to get back to the coding. With our first Entity, we did not specify the location we wanted anywhere. Many of the functions in Ogre have default parameters. The [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_node.html#aeaee9cb1cb0c23fab2cc9bab08f51181|{MONO()}SceneNode::createChildSceneNode{MONO}] method can take three parameters, but we called it with none. The parameters are the name, position, and rotation of the SceneNode being created. We've already mentioned that Ogre generates a unique name for us. It also uses (0, 0, 0) as a default position.
First, let's move the camera so we can fit more Entities on screen. Place this call right after you set the ambient light in {MONO()}createScene{MONO}:
{CODE(wrap="1", colors="c++")}
mCamera->setPosition(0, 47, 222);
{CODE}
Now, let's create another Entity and SceneNode, but this time we'll give it a new position.
{CODE(wrap="1", colors="c++")}
Ogre::Entity* ogreEntity2 = mSceneMgr->createEntity("ogrehead.mesh");
Ogre::SceneNode* ogreNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
Ogre::Vector3(84, 48, 0));
ogreNode2->attachObject(ogreEntity2);
{CODE}
This is the same thing we did the first time, except we are now providing a Vector3 to our {MONO()}createChildSceneNode{MONO} method. This will override the default position. Remember, the SceneNode's position is always relative to its parent. In this case, the parent SceneNode is the root SceneNode, which is positioned at (0, 0, 0) by default.
Compile and run your application. Your Ogre head should have a buddy.
{img fileId="2274" rel="box[g]"}
!More About Entities
The [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_entity.html|Entity] class is very extensive. We will now introduce just a few more of its methods that will be useful. The Entity class has {MONO()}setVisible{MONO} and {MONO()}isVisible{MONO} methods. If you want an Entity to be hidden, but you still need it later, then you can use this function instead of destroying the Entity and rebuilding it later.
__Note:__ Entities do not need to be pooled like they are in some graphics engines. Only one copy of each mesh and texture is every loaded into memory, so there is not a big savings from trying to minimize the number of Entities.
The {MONO()}getName{MONO} method returns the name of an Entity, and the {MONO()}getParentSceneNode{MONO} method returns the SceneNode that the Entity is attached to. In our case, this would be the root SceneNode.
!More About SceneNodes
The [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_node.html|SceneNode] class is very complex. For now, we will only cover some of the most useful methods.
You can set the position after creating the node with {MONO()}getPosition{MONO}. This is still relative to its parent node. You can move an objective relative to its current position by using {MONO()}translate{MONO}.
SceneNodes are used to set a lot more than just position. They also manage the scale and rotation of objects. You can set the scale of an object with {MONO()}setScale{MONO}. And you can use {MONO()}yaw{MONO}, {MONO()}pitch{MONO}, and {MONO()}roll{MONO} to set the object's orientation. You can use {MONO()}resetRotation{MONO} to return the object to its default orientation. Finally, you can use {MONO()}rotate{MONO} to perform more complicated rotations. This will involve the use of quaternions, which will not be covered until the ((Intermediate Tutorials)).
We've already used the {MONO()}attachObject{MONO} method of a SceneNode. There are few more methods that are useful for dealing with the objects that are attached to a SceneNode. You can use {MONO()}numAttachedObjects{MONO} to return the number of children attached to your node. You can use one of the many versions of [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_node.html#af011d009a2b6d3dfa498721d18a58473|getAttachedObject] to retrieve one of the SceneNode's children. The method {MONO()}detachObject{MONO} can be used to remove a specific child node, and {MONO()}detachAllObjects{MONO} can be used to remove all.
Since the position of a child node is ''relative'' to its parent, it makes it very easy to move large groups of nodes together. For example, if we changed this line:
{CODE(wrap="1", colors="c++")}
Ogre::SceneNode* ogreNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(
Ogre::Vector3(84, 48, 0));
{CODE}
To this:
{CODE(wrap="1", colors="c++")}
Ogre::SceneNode* ogreNode2 = ogreNode->createChildSceneNode(
Ogre::Vector3(84, 48, 0);
{CODE}
Then our new node would be parented directly to the SceneNode for our first Entity and not to the root SceneNode. This would mean that moving {MONO()}ogreNode{MONO} would also move {MONO()}ogreNode2{MONO}.
If you're having trouble with the idea of a relative location, then maybe an example will help. Let's say we put our first node, {MONO()}ogreNode{MONO}, at (10, 10, 10) to start. Then we attach {MONO()}ogreNode2{MONO} directly to {MONO()}ogreNode{MONO}. Then we set the position of {MONO()}ogreNode2{MONO} to be (-10, -10, -10). To figure out where {MONO()}ogreNode2{MONO} is we would add its position to the position of its parent.
{CODE(wrap="1", colors="ini")}
(10, 10, 10) + (-10, -10, -10) = (0, 0, 0)
ogreNode ogreNode2
child parent
{CODE}
So this means that {MONO()}ogreNode2{MONO} would actually be placed at (0, 0, 0) in our world, even though we set its position to (-10, -10, -10). If we detached this node and reattached it to the root SceneNode, then it would actually sit at (-10, -10, -10), because:
{CODE(wrap="1", colors="ini")}
(-10, -10, -10) + (0, 0, 0) = (-10, -10, -10)
ogreNode root
child parent
{CODE}
Take a few seconds to soak this in. Relativity is hard. That's why it took an Einstein to really get it.
Lastly, you can get a SceneNode or Entity by its name (if you gave it one), by calling {MONO()}getSceneNode{MONO} or {MONO()}getEntity{MONO}, which are [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_scene_manager.html|SceneManager] methods. This way you don't have to keep a pointer to all of your SceneNodes. You should generally only define pointers for nodes you will use often.
!Changing An Entity's Scale
We can set the scale of an Entity by calling the {MONO()}setScale{MONO}. This method allows us to provide a scale factor for each dimension. Let's add another Ogre head and give it a different scale for demonstration. We will also position it so it fits well on the screen.
{CODE(wrap="1", colors="c++")}
Ogre::Entity* ogreEntity3 = mSceneMgr->createEntity("ogrehead.mesh");
Ogre::SceneNode* ogreNode3 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
ogreNode3->setPosition(0, 104, 0));
ogreNode3->setScale(2, 1.2, 1);
ogreNode3->attachObject(ogreEntity3);
{CODE}
Compile and run your application. You should see a fat Ogre head up top.
{img fileId="2275" rel="box[g]"}
!Rotating An Entity
An Entity's rotation can be changed using the {MONO()}yaw{MONO}, {MONO()}pitch{MONO}, and {MONO()}roll{MONO} methods.
{img fileId="2272" rel="box[g]"}
These methods will take either an [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_degree.html|Ogre::Degree] or [http://www.ogre3d.org/docs/api/1.9/class_ogre_1_1_radian.html|Ogre::Radian]. As the picture demonstrates, rotation around the y-axis is called yaw, around the x-axis is called pitch, and around the z-axis is called roll. These are terms often used in describing the movements of an aircraft.
There is a well-known trick for remembering which direction is a positive rotation around an axis. It is called the [http://en.wikipedia.org/wiki/Right-hand_rule|right-hand rule]. Point your thumb in the direction of the axis, and the direction your fingers curl towards is the positive direction. You can now see why these are often called "right-handed coordinate systems". There are about a million ways of doing the right-hand rule. This is why you might see a group of physics students throwing gang signs while doing their homework. They're trying to remember which direction the magnetic field is headed.
Let's put this to use and place a rotated Entity into our scene. We will also position it nicely.
{CODE(wrap="1", colors="c++")}
Ogre::Entity* ogreEntity4 = mSceneMgr->createEntity("ogrehead.mesh");
Ogre::SceneNode* ogreNode4 = mSceneMgr->getRootSceneNode()->createChildSceneNode();
ogreNode4->setPosition(-84, 48, 0);
ogreNode4->roll(Ogre::Degree(-90));
ogreNode4->attachObject(ogreEntity4);
{CODE}
Compile and run your application. We should now have a rotated Ogre in our scene.
{img fileId="2273" rel="box[g]"}
!The Ogre Environment
The library and configuration files for Ogre can be found in the 'bin' folder of your OgreSDK. You should use the debug files when building your application in debug mode.
!!Libraries and Plugins
Ogre is divided into three shared library groups: main library, plugins, and third-party libraries.
!!!Main library
The main library group contains the Ogre library itself and the shared libraries it relies on. The Ogre library is contained within OgreMain.dll or libOgreMain.so depending on your platform. This library must be included in all of your Ogre applications. OgreMain.dll requires a few other libraries like cg.dll.
!!!Plugins
The second group of shared libraries are the plugins. Ogre pushes a good portion of its functionality into shared libraries so that they may be turned on or off easily. The core plugins that are included with Ogre have names that start with "Plugin_". You can laos write your own plugins.
Ogre also uses plugins for the different render systems (such as OpenGL, DirectX, etc). These plugins start with "RenderSystem_". This is also so that you can add only the systems you will need. This can be useful if you right shaders that rely on a particular system, because you can simply remove the incompatible system so that the program won't try to run incorrect code. This also means you can write your own plugins if you want to extend Ogre into another render system.
!!!Third-party Plugins With Additional Functionality
The last major group contains third-party libraries and other general support libraries. Ogre is focused sharply on being a graphics rendering library. This group makes it easy to integrate external libraries to add things like physics, input, and GUI systems. These libraries are used together to form a full game development environment. You might find this piecemeal approach a little strange, but it is a very common design pattern in large software projects. It is harder to comprehend at first, but it is a much more flexible approach when you want to start building more complicated scenes.
The Ogre demos and SDK include some of these third-party libraries. The ((OIS|Open Input System)) is used to manage input events and distribute them to Ogre. This is contained in OIS.dll or libOIS.so. You can also make use of Cg, which is used by CgProgramManager. This library allows you to produce materials with custom shaders. There are other libraries (not included with Ogre) that offer functionality such as sound and physics.
!!!Testing vs Release
When you're building your application you can just leave every plugin activated. This will allow you to experiment with using them or not. But when you get ready to distribute a release build of your work, then you will want to deactivate any of the plugins you are not using.
!!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: (alias(Basic_Tutorial_1))