About two weeks ago, shortly after finishing part 3 I got in contact with Cygon from the Mogre forums. As far as I could tell he is the only person who has sucessfully wrapped the Terrain and Paging component into Mogre. With his help, I’ve managed to integrate his changes into the MogreBuilder to finally bring Mogre up to date with the latest stable version of Ogre (v1.7.4). This is great news for the Mogre community who have been longing for Terrain and Paging in the official build for many months.

Terrain and Paging

My first attempt at getting Terrain and Paging into Mogre was to try and figure out how Cygon had done it from the scattered bits of information floating around the forums. This worked up to a point but I ran into a wall when the AutoWrap tool failed to pickup the files. A little more digging around and I got a little closer followed by one failure after another. Cygon kindly offered to give me a copy of his entire codebase from when he manually wrapped Terrain and Paging with Ogre 1.7.3.

I was very excited when the email arrived with a link to download his code. Eager  and try it out I quickly dumped the code into the MogreBuilder and ran it. After a little tweaking it spat out some binaries. I threw together a really quick test using the Mogre Terrain and Paging sample on the wiki combined with the samples code found in the last installer. It worked like a charm and I went to bed with a grin :)

Mogre TerrainAndPaging Sample using binaries built with MogreBuilder

The following weekend I sat down to clean up the code and get it loaded into the bitbucket repository. This turned into a bit of a chore because the code that I had was a few months old and I had to merge the changes with more recent changes in the repository. Added to that was updating the patching tool in MogreBuilder because Cygon’s patch wasn’t compatible with hg. I also added an extra patch to improve the size and the resulting DLL’s and remove some code not used in C#. Thanks again to Cygon for providing these changes.

I’m pleased to say that in the end it all went well and the Terrain and Paging components are now included in the official MogreBuilder. This should make it easier to maintain future builds of Mogre and might lead the way to getting other plugins wrapped.

Automatic version updating

Another small but important change I made during this iteration is automatic versioning of the Mogre DLL. Thanks to Ümit YILDIZ for pointing out that the previous lot of binaries indicated a version of 1.7.1 even though it was built against Ogre 1.7.4. To correct this issue I added a task into the MogreBuilder to automatically detect the version of Ogre and update Mogre’s assembly information to match.

Here’s a snippet from Ogre’s OgrePrerequisites.h

// Define ogre version
#define OGRE_VERSION_MAJOR 1
#define OGRE_VERSION_MINOR 7
#define OGRE_VERSION_PATCH 4
#define OGRE_VERSION_SUFFIX ""
#define OGRE_VERSION_NAME "Cthugha"

And the resulting code in Mogre’s AssemblyInfo.cpp

[assembly:AssemblyVersionAttribute("1.7.4")];

Using this approach we could also add the Ogre version name or add an additional digit into Mogre’s version using the MogreBuilder config. I’ve left this task for another time.

Mogre Samples

I’ve also added a new Terrain and Paging sample to the Mogre samples found in the installer. Unfortunately, there is still nowhere to load my changes on bitbucket so instead you can download them directly including the binaries, source code and media.

Download Mogre Samples including Terrain and Paging

The end result

I really couldn’t have asked for a better couple of weeks on this project. All of the important chips fell into place at the right time and delivered some great improvements for the Mogre community. I’ve learned a lot about the Mogre build process and I feel more confident that I can help maintain it in the future. Thanks to everyone who provided feedback, it makes all the difference.

Download Mogre 1.7.4 binaries with Terrain and Paging

And of course, the source code is available in the bitbucket repositories.

I’m pleased to say the command line version of MogreBuilder is now complete. A lot of blood, sweat and tears has gone dealing with the various issues, but I guess that’s what happens towards the end of a project as you run out of the easy things to do.

The first thing I tried to do with week was get the GUI sitting on top. I had big plans to pull the whole thing out of the Console and output everything to a nice window. At the same time, I didn’t want to remove the ability to run it on the command line because that is useful too.

I was now faced with a half working GUI version and half working command line version. What I needed to do is combine the best bits of both. So, the first step is to do a bit of a redesign and make the code easier to work with.

The Redesign

My goal with the redesign was to pull all of the hard coded paths out of the tasks and into a common location. The existing OutputManager seemed like a reasonable approach, so I created an InputManager to keep it company. I also refactored the OutputManager to an interface with the intention that the Console and GUI would implement it.

Everything went as planned until I ran to some threading issues while running it in a GUI. At this point I’d already spent a load of time on it and I started to think about just how important a GUI is for this application. While it would be nice, there are far more important tasks that need to take higher priority. There’s a to-do list at the end of the post.

The Config File

So, instead of doing the GUI I came up with the next best thing. Pull all of the configuration out into a simple human editable text file. This way, you can setup different build configurations and run them whenever you like with every little effort. This approach doesn’t replace the GUI so much as it sits along side it nicely.

// build
BuildConfiguration = "Debug";

// clr
ClrDirectory = @"Main\Ogre\";
ClrConfigHeaderFile = @"Main\OgreSrc\ogre\OgreMain\include\CLRConfig.h";
ClrObjectsBuildFile = @"Main\OgreSrc\build\include\CLRObjects.inc";
ClrObjectsAutoFile = @"Main\include\auto\CLRObjects.inc";

// mogre
MogreSolutionFile = @"Main\Mogre_vs2010.sln";
MogreRepository = @"https://bitbucket.org/mogre/mogre/";
MogreBranch = @"default";

// ogre
OgreRootDirectory = @"Main\OgreSrc\ogre\";
OgreBuildDirectory = @"Main\OgreSrc\build\";
OgreMainDirectory = @"Main\OgreSrc\ogre\OgreMain\";
OgreIncludeDirectory = @"Main\OgreSrc\ogre\OgreMain\include\";
OgreSourceDirectory = @"Main\OgreSrc\ogre\OgreMain\src\";
OgreProjectFile = @"Main\OgreSrc\build\OgreMain\OgreMain.vcxproj";
OgreSolutionFile = @"Main\OgreSrc\build\OGRE.sln";
OgreRepository = @"https://bitbucket.org/sinbad/ogre/";
OgreBranch = @"v1-7";

// cmake
CMakeExecutable = @"C:\Program Files (x86)\CMake 2.8\bin\cmake.exe";
CMakeCachePath = @"Main\OgreSrc\build\CMakeCache.txt";

// dependencies
DependenciesURL = "http://surfnet.dl.sourceforge.net/project/ogre/ogre-dependencies-vc%2B%2B/1.7/OgreDependencies_MSVC_20100501.zip";
DependenciesZip = @"Main\OgreSrc\ogre\Dependencies.zip";
DependenciesDirectory = @"Main\OgreSrc\ogre\Dependencies\";
DependenciesSolutionFile = @"Main\OgreSrc\ogre\Dependencies\src\OgreDependencies.VS2010.sln";

// patch
PatchExecutable = "pat-ch.exe";
PatchFile = @"Main\Ogre Patches\58266f25ccd2.patch";

// cpp2java
Cpp2JavaDirectory = @"Codegen\cpp2java";
Cpp2JavaMetaDataFile = @"Codegen\cpp2java\build\all.xml";

// autowrap
AutoWrapExecutable = @"Codegen\AutoWrap\bin\Debug\AutoWrap.exe";
AutoWrapSolutionFile = @"Codegen\AutoWrap\AutoWrap_vs2010.sln";
AutoWrappedCodeDirectory = @"Main\src\auto\";
AutoWrapWorkingDirectory = @"Codegen\AutoWrap\bin\Debug\";

The Patch Issue

Solving the issue with the patch file had be a little stumped for a while. I hadn’t really played with patch files much, nor have I had much experience using hg. So into the documentation I dove and slowly pieced together a solution. In the end it was fairly easy, change the file manually, do a diff and update the patch file with the changes. Everything else stays the same and the patch file now applies correctly. I’m confident that future issues like this can be solved fairly easily too.

Hg Clone Tasks

Cloning the repositories used to a be a manual step, now the tasks have been added to the builder and the whole thing can be run from an empty directory to a fully build Mogre.dll with one command. Very nice :)

The Result

You can get the source code to MogreBuilder on bitbucket.

You can download the binaries here.

What’s next?

Here’s the new to-do list prioritised on importance.

  1. MOIS – include in the build process
  2. Samples – upload the souce code to the repository
  3. Terrain and Paging – get this working somehow
  4. GUI – sit the on top of the input manager

The last 3 weeks have been long and tiring. At this point I’m going to take a break for a while and get back to working on our game.

Implementing SSAO in Mogre is easier than ever thanks to the efforts of the Ogre and Mogre community. Lets take a look at what we need to do to convert the C++ implementation into C# and get this great looking effect into our game with the least amount of effort.

What is SSAO?

Screen Space Ambient Occlusion (SSAO) is a rendering technique for efficiently approximating the well-known computer graphics ambient occlusion effect in real time. The algorithm is implemented as a pixel shader, analyzing the scene depth buffer which is stored in a texture. For every pixel on the screen, the pixel shader samples the depth values around the current pixel and tries to compute the amount of occlusion from each of the sampled points.

Pros

  • Can be applied easily to any scene to make it look a lot better
  • Runs in screen space and therefore does not degrade with scene complexity
  • Works well with dynamic scenes with lots of objects
  • Runs entirely on the GPU
  • Works in the same consistent way for every pixel on the screen.
  • No pre-processing required, no loading time, no system memory usage.

Cons

  • Chews a lot of your frame rate due to multipass smooth/blur
  • Requires pixel shader capability on the graphics card
  • Degrades with the screen resolution
  • Objects that are outside of the screen do not contribute to occlusion
  • Computed occlusion is dependent on viewing angle and camera position

SSAO in Ogre

There is a great article about implementing simple SSAO in Ogre on the Ogre Wiki. Implementing this in Ogre only requires a few simple steps:

  1. Download the source code, materials and shaders.
  2. Unpack the materials and shaders into your media folder.
  3. Add the new sub-directories to your resource locations.
  4. Add the source code files to your your project.
  5. Create an instance of the PFXSSAO class and pass in your initialised RenderWindow and Camera

Converting to Mogre

Fortunately, the first 3 steps above stay exactly the same when converting this to Mogre. What we need to do is convert the PFXSSAO class from C++ to C# code. While we’re at it lets rename it to something more fitting.

public class SsaoManager : SceneManager.Listener
{
	private SceneManager _sceneManager;
	private Camera _camera;
	private Viewport _viewport;
	private RenderWindow _renderWindow;
	private CompositorInstance _compositor;

	public SsaoManager(RenderWindow renderWindow, Camera camera)
	{
		MaterialManager.Singleton.SetDefaultTextureFiltering(TextureFilterOptions.TFO_ANISOTROPIC);

		_renderWindow = renderWindow;
		_camera = camera;
		_sceneManager = camera.SceneManager;
		_viewport = camera.Viewport;

		InitialiseShadows();
		InitialiseSSAO();
	}

	private void InitialiseSSAO()
	{
		_compositor = CompositorManager.Singleton.AddCompositor(_viewport, "ssao");
		_compositor.Enabled = true;
		_compositor.NotifyMaterialRender += new CompositorInstance.Listener.NotifyMaterialRenderHandler(NotifyMaterialRender);
	}

	private void NotifyMaterialRender(uint passId, MaterialPtr material)
	{
		if (passId != 42)
			return;

		unsafe
		{
			Vector3 farCorner = _camera.GetViewMatrix(true) * _camera.WorldSpaceCorners[4];
			Pass pass = material.GetBestTechnique().GetPass(0);
			GpuProgramParametersSharedPtr parameters = pass.GetVertexProgramParameters();

			if (!parameters._findNamedConstantDefinition("farCorner").IsNull)
				parameters.SetNamedConstant("farCorner", farCorner);

			parameters = pass.GetFragmentProgramParameters();

			Matrix4 clipSpaceToImageSpace = new Matrix4(
				0.5f,    0,    0,  0.5f,
				0,   -0.5f,    0,  0.5f,
				0,      0,    1,    0,
				0,      0,    0,    1);

			if (!parameters._findNamedConstantDefinition("ptMat").IsNull)
				parameters.SetNamedConstant("ptMat", clipSpaceToImageSpace * _camera.ProjectionMatrixWithRSDepth);

			if (!parameters._findNamedConstantDefinition("far").IsNull)
				parameters.SetNamedConstant("far", _camera.FarClipDistance);
		}
	}

	public bool Enabled
	{
		get
		{
			return _compositor.Enabled;
		}
		set
		{
			_compositor.Enabled = value;
		}
	}

	private void InitialiseShadows()
	{
		_sceneManager.ShadowTextureSelfShadow = true;
		_sceneManager.SetShadowTextureCasterMaterial("shadow_caster");
		_sceneManager.ShadowTextureCount = 4;

		_sceneManager.SetShadowTextureSize(256);
		_sceneManager.SetShadowTexturePixelFormat(PixelFormat.PF_FLOAT16_RGB);
		_sceneManager.ShadowCasterRenderBackFaces = false;

		uint numShadowRTTs = _sceneManager.ShadowTextureCount;
		for (uint i = 0; i < numShadowRTTs; ++i)
		{
			TexturePtr texture = _sceneManager.GetShadowTexture(i);
			Viewport viewport = texture.GetBuffer().GetRenderTarget().GetViewport(0);
			viewport.BackgroundColour = new ColourValue(1, 1, 1, 1);
			viewport.SetClearEveryFrame(true);
		}

		_sceneManager.ShadowTechnique = ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED;
		_sceneManager.AddListener(this);
	}

	public override void ShadowTextureCasterPreViewProj(Light light, Camera camera, uint iteration)
	{
		float range = light.AttenuationRange;
		_camera.NearClipDistance = 0.01f;
		_camera.FarClipDistance = 99990f;
	}
}

Now all you have to do to start using SSAO in your Mogre project is create an instance of the SsaoManager like so (assuming you already have a RenderWindow and Camera):

SsaoManager ssaoManager = new SsaoManager(RenderWindow, Camera);

Results

Left: Without SSAO;  Right: With SSAO
Left: Without SSAO; Right: With SSAO

References

Simple SSAO on Ogre Wiki
SSAO on Wikipedia
A simple and practical approach to SSAO on GameDev.net