The entire setup is available here. I recommend going through this guide if you want to know the significance of each part.
I found it difficult to get set up with Ogre 2 in a way I was comfortable with. I think most users still use v1, so 2 is lacking in documentation.
This guide is my contribution to improving ramp-up for Ogre 2. Notably, I cover everything from initial project set up to getting your own textured meshes rendering. The manual seemed lacking in instructions on how to actually create the data, so I provide some details on that here.
This guide assumes a Linux operating system. Windows users may still find some use in this guide.
Cloning the source
The first step is getting a local copy of the Ogre 2 source code. You could get prebuilt binaries via your distrubution's package manager, but I'm generally suspicious of the longetivity of such an approach. If you clone an exact version to your repository, you can ensure compatibility much easier.
The following commands initialize a git repository (skip if you already have a repository):
mkdir ogre-start-project
cd ogre-start-project/
git init
From now own, I mostly assume you are running commands in the repository's root. In this case, that's ogre-start-project
.
Next, I like to create a folder for 3rd-party dependencies. The following commands add Ogre as a submodule so that the main repository keeps track of our Ogre version for us (among other things, see git submodules):
mkdir Dependencies
git submodule add https://github.com/OGRECave/ogre-next Dependencies/ogre-next
git submodule add https://github.com/OGRECave/ogre-next-deps Dependencies/ogre-next-deps
# Make sure the dependencies are recursively added:
cd Dependencies/ogre-next-deps
git submodule update --init --recursive
Note that we also clone Ogre's 3rd-party dependencies. Again, this is to assist in portability for long-term development.
If you're looking for the most up-to-date way to clone Ogre, check the Build scripts.
Cloning this repository
From now on, if you are cloning this (your) repository, you can automatically clone the correct Ogre version as well:
git clone --recurse-submodules <your remote URL>
# Or, if you've already cloned without --recurse-submodules:
git submodule update --init --recursive
Building Ogre
I typically like to have a single .sh
file, BuildDependencies_Debug.sh
, in my project root which will build all 3rd-party dependencies for my project. You should never just run the build commands, because you're guaranteed to forget them after a while, especially if you don't do it very often.
The most up-to-date, cross-platform instructions for building Ogre are available in the manual. Refer to it if you encounter problems with the following instructions.
If you're looking for the most up-to-date way to build Ogre, check the Build scripts. My version is mostly copied from them. Copy the following into a .sh
script:
#!/bin/sh
cd Dependencies/
# See the official script at
# https://raw.githubusercontent.com/OGRECave/ogre-next/master/Scripts/BuildScripts/output/build_ogre_linux_c%2B%2Blatest.sh
echo "Building Ogre dependencies..."
cd ogre-next-deps && mkdir -p build && cd build && cmake -G Ninja .. || exit $?
ninja || exit $?
ninja install || exit $?
echo "Building Ogre..."
cd ../../ogre-next
if test ! -f Dependencies; then
ln -s ../ogre-next-deps/build/ogredeps Dependencies
fi
# -p = don't error if it already exists
mkdir -p build/Debug
mkdir -p build/Release
cd build/Debug
echo "--- Building Ogre (Debug) ---"
cmake -D OGRE_USE_BOOST=0 -D OGRE_CONFIG_THREAD_PROVIDER=0 -D OGRE_CONFIG_THREADS=0 \
-D OGRE_BUILD_COMPONENT_SCENE_FORMAT=1 \
-D OGRE_BUILD_SAMPLES2=1 -D OGRE_BUILD_TESTS=1 \
-D CMAKE_BUILD_TYPE="Debug" -G Ninja ../.. || exit $?
ninja || exit $?
# While we're at it, build the optimized version
cd ../Release
echo "--- Building Ogre (Release) ---"
cmake -D OGRE_USE_BOOST=0 -D OGRE_CONFIG_THREAD_PROVIDER=0 -D OGRE_CONFIG_THREADS=0 \
-D OGRE_BUILD_COMPONENT_SCENE_FORMAT=1 \
-D OGRE_BUILD_SAMPLES2=1 -D OGRE_BUILD_TESTS=1 \
-D CMAKE_BUILD_TYPE="Release" -G Ninja ../.. || exit $?
ninja || exit $?
Once you get everything set up, you can come back to this script and configure Ogre to your project.
Finally, run the script (this will take a while!):
# Only need to run this once, to give executable permission
chmod +x BuildDependencies_Debug.sh
./BuildDependencies_Debug.sh
If you get an error early on when building Ogre's dependencies, make sure you ran git submodule update --init --recursive
in Dependencies/ogre-next-deps
(this bit me while I was writing this tutorial).
I prefer not to "install" libraries, again, because each project should keep track of the known-compatible version of the dependency. What we built with that script exists in Dependencies/ogre-next/build/Debug
(or Release
, you get the idea).
Testing
Let's try the samples in Dependencies/ogre-next/build/Debug/bin
, to make sure everything is set up:
cd Dependencies/ogre-next/build/Debug/bin
./Sample_PbsMaterials
You can explore the other samples if you'd like. This gives you some motivation to continue with the integration!
Building your code
I'm a big fan of having as complete an understanding of your code as possible. The sample/starter Ogre 2 projects consist of several files in Dependencies/ogre-next/Samples/2.0/Common/src
. The manual recommends following the tutorials in Dependencies/ogre-next/Samples/2.0/Tutorials
. However, I prefer a single-file approach. Once you've gotten that set up, you can refer to the tutorials for your desired features (e.g. multi-threading).
Before we get into the file, let's make sure we can compile and link the file successfully. The Ogre manual encourages using CMake, but I prefer the more hands-on approach, which is manually adding the necessary search directories and link arguments. By following this approach, you should be able to use any build system you like for your project.
If you are familiar with C/C++ dynamically-linked project setup, you'll find Ogre is very straightforward. If you're new to this sort of thing, you may want to do some research on more basic setups first.
Here are the arguments you will need to add in order to build an Ogre-based project:
Compile arguments
GCC and clang should work fine with the same arguments.
These arguments ensure your compiler can find the Ogre header files when you #include
them:
-IDependencies/ogre-next/OgreMain/include
-IDependencies/ogre-next/Components/Hlms/Common/include
-IDependencies/ogre-next/Components/Hlms/Pbs/include
-IDependencies/ogre-next/Components/Hlms/Unlit/include
-IDependencies/ogre-next/build/Debug/include
-IDependencies/ogre-next/Components/Overlay/include
In Debug, you should make sure that the headers you #include
generate the same code by adding the preprocessor debug #define
:
-D_DEBUG
Link arguments
There are two main parts to the link arguments: which dynamic libraries to link, and where to look for them when starting up.
Note: This article assumes you are dynamically linking Ogre. Consult Ogre's manual if you want to statically link.
Here are the arguments requesting dynamic libraries we will use, as well as an argument to tell the linker where to find them:
# Compiled libraries we need
-lOgreHlmsPbs_d -lOgreHlmsUnlit_d -lOgreMain_d -lOgreOverlay_d
# Where to find them
-LDependencies/ogre-next/build/Debug/lib
(for Release, drop the _d
).
If you attempted to link at this point, everything would be fine, but running the program would fail, because the operating system doesn't know where the actual .so
libraries are. We need to add our lib
directory to the dynamic library search paths:
-Wl,-rpath,.:Dependencies/ogre-next/build/Debug/lib
An explanation of this command:
-Wl
forwards arguments to the linker. Clang (etc.) provides this command because it's actually running two different stages, and we want our arguments to go to the second stage. The forwarded arguments are comma-delimited instead of space-delimited because we can continue to specify arguments to the first stage after-Wl
and a space-rpath
sets the dynamic library search path.
says search for dynamic libraries in the working directory of the executableDependencies/ogre-next/build/Debug/lib
adds Ogre's lib dir to the search path
Note that when you ship your project to end users, you should move the .so
files into e.g. a lib
folder near the executable, and add lib
to the rpath instead of that long Dependencies
path.
If you have trouble linking, check out my article, Know what your linker knows. It provides some tools for debugging linking issues.
Initial code
Let's create main.cpp
and start filling it with the code necessary to initialize Ogre.
The entirety of the file is available here (and in raw form for direct saving/copy paste).
There is a good amount of it because Ogre is a powerful, complex rendering engine. Don't worry too much about the details for now; you can come back to this code once you've gotten more familiar with the engine, and have a working example to tweak and debug on.
Because there is so much, I recommend just copy-pasting it and learning it later. I wanted one big file rather than a complicated OOP problem to decode (complicated like Samples/Common
, which is admittedly trying to solve a different problem). You should feel free to rearrange, simplify, abstract, etc. this code to suit your fancy.
Do a quick skim of this code, then give it a build:
clang++ -c main.cpp -IDependencies/ogre-next/OgreMain/include \
-IDependencies/ogre-next/Components/Hlms/Common/include \
-IDependencies/ogre-next/Components/Hlms/Pbs/include \
-IDependencies/ogre-next/Components/Hlms/Unlit/include \
-IDependencies/ogre-next/build/Debug/include \
-IDependencies/ogre-next/Components/Overlay/include
Finally, link it into an executable:
clang++ -o ogreApp main.o -LDependencies/ogre-next/build/Debug/lib \
-lOgreHlmsPbs_d -lOgreHlmsUnlit_d -lOgreMain_d -lOgreOverlay_d \
-Wl,-rpath,.:Dependencies/ogre-next/build/Debug/lib
(These build commands are in BuildDebug.sh for your convenience, but you should integrate them with a proper build system to save time on rebuilds).
If you do ./ogreApp
now, you'll get an error like this one:
Render system not found!
Mesh: Loading Suzanne.mesh.
terminate called after throwing an instance of 'Ogre::FileNotFoundException'
what(): OGRE EXCEPTION(6:FileNotFoundException): Cannot locate resource Suzanne.mesh
in resource group General or any other group. in ResourceGroupManager::openResource at
../../OgreMain/src/OgreResourceGroupManager.cpp (line 790)
Aborted (core dumped)
Not to worry! Ogre is working, but it cannot find the data we requested to be loaded.
Initial data
If you've gotten this far, you're on the home stretch. The final things we need to do involve copying the data we are going to load. This includes two major types of data:
- Plug-ins, which include rendering backends such as OpenGL or Vulkan (these are dynamic libraries)
- Assets, such as meshes, textures, materials, etc.
Plug-ins
Plug-ins are e.g. rendering backends. These can be statically linked, but for now we'll use the default dynamic linking setup.
Create a file data/plugins_d.cfg
with the following contents (assumes debug build):
# Defines plugins to load
# Define plugin folder
PluginFolder=Dependencies/ogre-next/build/Debug/lib
# Define plugins
# Plugin=RenderSystem_Direct3D11
Plugin=RenderSystem_GL3Plus_d
# Plugin=RenderSystem_GLES
# Plugin=RenderSystem_GLES2
# Plugin=RenderSystem_Metal
Plugin=Plugin_ParticleFX_d
# Plugin=Plugin_CgProgramManager
You can comment/uncomment plugins which make sense for your platform.
Fundamental materials/shaders
The manual recommends copying some data from the samples in order for Hlms to function:
- Bundle the data files in Samples/Media/Hlms/Common with your application
- Bundle the data files in Samples/Media/Hlms/Pbs with your application
- Bundle the data files in Samples/Media/Hlms/Unlit with your application
The following commands will perform this for you:
mkdir data
mkdir data/Hlms
mkdir data/CommonMaterials
rsync -av Dependencies/ogre-next/Samples/Media/Hlms/Common data/Hlms/
rsync -av Dependencies/ogre-next/Samples/Media/Hlms/Pbs data/Hlms/
rsync -av Dependencies/ogre-next/Samples/Media/Hlms/Unlit data/Hlms/
rsync -av Dependencies/ogre-next/Samples/Media/2.0/scripts/materials/Common \
data/CommonMaterials
Once you are well advanced in your project, you can come back to these folders and delete unused materials.
Resources
A file resources2.cfg
is used by registerHlms()
to specify where the materials files are. I would like to remove the need to make this file by specifying it all in code, but I have not yet.
Create data/resources2.cfg
and add the following contents:
General]
[FileSystem=CommonMaterials
FileSystem=CommonMaterials/GLSL
FileSystem=CommonMaterials/HLSL
FileSystem=CommonMaterials/Metal
# Do not load this as a resource. It's here merely to tell the code where
# the Hlms templates are located
Hlms]
[DoNotUseAsResource=./
Mesh
Finally, we need the "Suzanne.mesh" asset. You can follow the Asset pipeline section below or copy the mesh from here (do right click save as on the Raw). You should copy it to data/Models
.
Try it out!
Run it:
./ogreApp
If it works, you should see a Suzanne monkey moving across the screen. Huzzah!
If you have troubles, there are usually a couple things that could be going wrong:
- Runtime data isn't being found. Make sure your
plugins.cfg
andresources2.cfg
are correct, and the paths inmain.cpp
are correct. Make sure you copied theCommonMaterials
andHlms
directories exactly (I made this mistake while preparing this) - Link libraries aren't being found. Check your
rpath
on your link command as well as yourplugins.cfg
- Something's crashing/throwing. Try rebuilding, then use
gdb
to debug as usual
Ogre can be a bit ornery. Stick with it though, and remember how it's one of the largest libraries you'll likely have to set up in your entire project!
What's next?
Read over the code and try to get an understanding of what is happening. You can start playing with the constants, then making your own lights, changing where resources get loaded from, and setting up your own Hlms materials.
There is a lot of hard-coded stuff in there that makes assumptions about the user's platform. You will have to do more work to make it platform-independent. Refer to Ogre's official samples for help with that.
I commented root->showConfigDialog()
because I find it very frustrating during development to click through. The renderer is hard-coded to GL3 and the resolution is set to 1920x1080. Check ogreInitializeInternal()
to change these.
ogreCreatePbsSpheres()
is an example of the High-level material system. Read the manual to get an idea of what's going on with it. Copy SaintPetersBasilica.dds into data/Materials/Textures
and uncomment the "Reflection texture" block to see what reflections look like with an actual cubemap. (I did not include this because I wanted to avoid including non-essential assets).
Once you get a feel for Ogre, you should restructure/split the file as desired to be the right level of modularity/data-driven/whatever you need.
Follow the Asset pipeline instructions and get your own models into your project!
Asset pipeline
It was quite hard to find documentation on actually getting my assets into Ogre. Most resources refer to v1. Here, I'll use Blender to create an asset and export it to my Ogre project.
Clone the exporter
There are different exporters for the various 3D asset creation programs out there. I'm only going to cover Blender.
Download the exporter:
git submodule add https://github.com/OGRECave/blender2ogre Dependencies/blender2ogre
We'll put it in our Dependencies folder, because being able to build assets is about as important as building the project!
Blender setup
- Install Blender. I can confirm Blender 2.91 works.
- Copy
blender2ogre
to Blender plugins (replace the version number with whatever number shows up when you first open Blender. Note that if blender updates, you'll need to copy the add-on again to the new version's folder):
cp -r Dependencies/blender2ogre/io_ogre/ ~/.config/blender/2.91/
- Open Blender, then open Preferences (Edit->Preferences), and click Add-ons
- Search for "Ogre" and check the box to enable the OGRE Exporter
- Build Ogre, if you haven't already (run
BuildDependencies_Debug.sh
) - Set
OGRETOOLS_XML_CONVERTER
to where you built OgreMeshTool. You'll need to browse toDependencies/ogre-next/build/Debug/bin/OgreMeshTool_d
You are now ready to export. Open your model or create one, then do File -> Export -> Ogre3D
. See the following section for settings. Note: I will be making command-line driven auto-exporting to reduce these manual steps.
OGRE Export Settings
- Don't export materials. These are v1 materials as far as I know, which don't work with Ogre 2
- Don't export scene. I don't use these files
- Ensure mesh export version is set to
v2
Materials and Textures
The blender2ogre
plugin doesn't do much to help with Ogre v2 materials.
The following steps require competence in using Blender. See Blender's support page if you have difficulty creating your asset.
To create a textured mesh:
Create the mesh itself
UV unwrap the mesh
Create new image for texturing
Add a new material and set the diffuse input to your new image. Name the material what you'd like it to be called in your project as well
Paint the texture as desired
In the Image Editor window, do
Image -> Save As
and save the image to a lossless format (I used PNG)Run the following to use ImageMagick to convert the image to
.dds
(which will be a larger file, but will load drastically faster):convert assets/MyTexture.png data/Materials/Textures/MyTexture.dds
Export the mesh. Because export materials doesn't do us any good yet, we only export the mesh to get the updated UV coordinates and material (name only)
Create a
.material
text file like below (commented lines for common additional texture types) and put it indata/Materials
:hlms MyMaterial pbs {0.4 roughness 1.33 fresnel diffuse_map MyTexture.dds// normal_map Rocks_Normal.tga // roughness_map Rocks_Spec.tga // specular_map Rocks_Diffuse.tga }
Finally, add the material to the
Ogre::Item
:"MyMaterial"); item->setDatablock(
This is only necessary if the mesh didn't already have the Material name set.
Converting .mesh.xml
to .mesh
You shouldn't need to do this step if you set OGRETOOLS_XML_CONVERTER
, but in case blender2ogre didn't recognize it, here's how I worked around it:
cd Dependencies/ogre-next/build/Debug/bin
./OgreMeshTool_d -e -O puqs ../../../../../test/data/Models/Suzanne.mesh.xml
Run this after you've made an attempted export from the Blender OGRE plugin.
Bonus: Using SDL to create the window
I had to switch rendering engines on my last project, so tying my input to the renderer is something I'm cautious of.
Instead, I want to create my own window and only use Ogre for rendering. That way, if I had to switch, I wouldn't have to rewrite my input code, nor manage an input abstraction layer.
I chose SDL because it handles many other things I want besides input.
Here is code to create an SDL window suitable for Ogre output:
bool sdlInitialize(SDL_Window** windowOut)
{if (SDL_Init(SDL_INIT_VIDEO) < 0)
{"SDL_Error: %s\n", SDL_GetError());
printf(return false;
}
// This is necessary to make sure the context is created using a newer version. I mainly did
// this because RenderDoc said it needed it. This version comes from my current machine's
// version, and isn't a requirement to be this high
4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 6);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION,
"Ogre Window",
(*windowOut) = SDL_CreateWindow(
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,1920, 1080,
(SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL));if (!(*windowOut))
{"SDL_Error: %s\n", SDL_GetError());
printf(return false;
}
// Must explicitly create the GL context for Ogre
if (!SDL_GL_CreateContext((*windowOut)))
{"SDL_Error: %s\n", SDL_GetError());
printf(return false;
}return true;
}
To use your window instead of Ogre's, pass true
to ogreInitializeInternal()
(from our reference file). Refer to what useCurrentWindow
does in order to see the necessary changes.