In the whole scheme of things it’s taken a long, long time to get this far. Fortunately, I’ve learned a lot in that time and the past few weeks of development have been more productive then ever before. This week I’ve implemented basic brush / block creation for building rooms and a texture browser for making them look a lot nicer.
Brushes and a Texture Browser
Turning Glue Editor into a level editor for Ogre
As some of you may already know I’ve been continuing the development of Glue Editor. Things are coming along nicely as the end of the first iteration approaches. I would like to share with everyone what I have planned for Glue Editor in the coming months and find out if I’m heading in the right direction. Your honest opinion is appreciated
Motivation
Building a game with Ogre or Mogre has never been an easy task. The Ogre graphics engine provides incredible rendering capabilities and great flexibility to build whatever type of game you can dream of. However, putting together a complete and finished game takes a considerable amount of programming effort “gluing” the graphics engine to physics, sound, GUI, networking and so on. Once all that’s done the various art resources are created such as meshes, textures, sounds and collision shapes.
Many of these resources can be created with your favorite modelling program, paint program or sound generator. Yet, there’s still something missing. Placing all of these resources together into a game could be hacked together in code and exported from modelling programs with a little blood and sweat but it never feels nearly as productive as it could be.
Intention
Glue Editor’s primary purpose is to fill the missing gap. To provide a productive tool to piece together the various resources into levels for your Ogre game projects. Then to be able to save the levels into a file format easily loaded into your game containing the data to let the graphics, physics and sound engines to do what they do best. To help you provide the best interactive experience for your players in the shortest development cycle possible.
I’m developing Glue Editor using an “Agile” approach in my spare time in monthly iterations. At the start of each month I set some goals to achieve during the iteration focusing on what I can do to provide the most value towards the ultimate goal. The main goals of an iteration are called stories and are from the perspective of the user, for example: “As a user I want to be able to rotate objects so that I can make more natural looking scenes”. Then these high level goals are broken down into smaller tasks, prioritised and picked off one by one. At the end of an iteration any half finished features are polished, removed or disabled to get the program ready for a release and/or the remaining work is rolled over into the next iteration.
Results
I’ve made some great progress this month, using the Agile approach and defining some clear goals have really helped focus on the important features and not get distracted by the less important stuff. The project has already come a long way from where I left it a few years ago. I had to pull it apart and put it back together to lay the foundation for new features so many things are still broken. The one question remains, what should I really put my blood and sweat into next iteration?
Introducing Gizmo
It turns out that implementing a “gizmo” for manipulation of objects in 3D is a fairly difficult task. It’s taken most of my week to get the ‘move’ gizmo working and it’s still not perfect. I’ll also need to add one for rotation and scaling but at least some of the problems are solved.
I think it’s worth the effort though because it makes editing much easier in the 3D view and reduces the need to have multiple viewports. I’d still like to keep the ability to have more than one viewport particularly for editing geometry.
Its easy to get caught up perfecting each feature and then realising how much time it sucks out of the project. Next week I’m going to put some energy into the new “entity” system because it’s the foundation of many new features and although I beleive it will work really well the current state is fairly primitive. Once the new system is in place different “entity” types can be added such as sky, terrain, static meshes, lights and so on. Although I’d like to also have the tools to edit each type (like terrain for example) a good first step is to be able to place them in the scene.
Glue Editor Revamp (Part 2)
There’s still a lot to do in the new development work on Glue Editor, so far though, it’s going really well.
Tool System
We’ve revamped the tool system to expand the selection of tools to make it more of a level editor rather than just a scene editor. It’s going to take some time to implement each of these tools but here’s a list of current thoughts.
Select
Allows an object to be selected when the left mouse button is clicked if it is in the currently editable layers.
Highlights the object under the mouse when hovering.
Move
Shows a widget with arrows on the 3 axes and the 3 moveable planes.
Planes and axes are highligted when the mouse is over them.
Left clicking and dragging an axis or plane allows the object to be moved.
Rotate
Shows 3 rotational axes that highlight when the mouse is over them.
When left clicked and dragged the selected object rotates.
Scale
Shows a widget with 5 modes of scaling. Uniform, 3 planes and 3 axes.
When left clicked and dragged the selected object scales.
Camera
Right clicking and dragging allows the camera to rotate.
Middle clicking and dragging allows the camera to pan.
Scrolling the mouse wheel moves the camera backward and forward.
WASD moves the camera in fly mode.
Texture
Left clicking on a surface applies the current texture.
A texture for the walls, roof and floors can be set independently.
Decal
Left clicking on a surface places a decal.
A decal can be selected from the decal browser.
Entity
An entity can be chosen from the entity browser.
Left clicking places the entity on the surface taking collision into account.
Block
Static geometry can be created by dragging boxes with the left mouse button.
Once a box is in place it can be resized by dragging the vertices around.
After a box is placed it is automatically selected.
Starting a new box deselects currently selected boxes.
Selecting and deselecting boxes can be done by left clicking on a certain spot.
Widget System
The windows in Glue Editor Lite are fairly rigid. With the amount of new functionality coming in the editor it makes a lot more sense to have a widget based window model allowing the user to customise the display and providing more options for each tool in a dockable window. Maybe we’ll expand this into a plugin system for user tools, not really sure yet. More info on this later.
Ripping apart Glue Editor
This week I’ve been busy gearing up for an iteration on Glue Editor. The plan is to implement the constructive solid geometry (CSG) features into the editor for building levels.
It’s been a while since I worked on Glue Editor so I had to get familiar with the code again. The engine code has changed a lot since the last time it was used in the editor so the first step was to get them working in harmony. This was a pretty big refactor and as I ploughed through I stripped the code back to basics. I’ve dropped many of the features that don’t fit our current direction with a plan to rebuild the editor from a more solid base. At this stage I think it’s best to keep the two code bases separate so that the old version remains as is.
There’s still a lot to do but here’s a screenshot of very basic CSG in action. Very much a hacked up prototype just to get my head around the problem at this stage. Over the next month I hope to complete a working alpha version. Once that happens I’ll start doing periodic releases for testing and feedback.
Level creation with subtractive CSG
Yesterday I mentioned breifly that I was working on a CSG algorithm for level creation. Today I thought I’d share a few screenshots from a prototype level that I created using only a few lines of code. The level you see here is constructed from only a few axis aligned boxes that form the inside of the room. When they are placed next to each other they “cut” the space out making it more interesting.
You’ll also notice in the wireframe that each of the walls are created from “grids”. This is not required but produces better dynamic lighting. An alternative approach is to apply a second pass to remove t-junctions and apply static light maps. Many first person games use an approach like this with BSP based levels.
Working on a Constructive Solid Geometry (CSG) algoritm
I’ve been pretty busy this week working on a CSG algorithm for indoor level creation. The idea is to be able to create hollow spaces for rooms using a “substractive brush” approach. So far I’ve got the first part of a reasonably robust algorithm working on 2 axis aligned boxes. I suspect it will work fairly well on any pair of convex solids but I haven’t tested that yet.
public IEnumerable<Polygon> Subtract(ConvexSolid solid)
{
List<Polygon> polygonList = new List<Polygon>();
foreach (Polygon polygon in Polygons)
{
bool wasSplit = false;
Polygon polygonToSplit = polygon;
foreach (Polygon otherPolygon in solid.Polygons)
{
Plane splittingPlane = otherPolygon.Plane;
Polygon.PlaneClassification classification = otherPolygon.ClassifyTo(polygonToSplit.Plane);
if (classification == Polygon.PlaneClassification.Behind || classification == Polygon.PlaneClassification.Straddling)
{
Polygon.SplitResult splitResult = polygonToSplit.Split(splittingPlane);
if (splitResult != null)
{
if(splitResult.FrontPolygon != null)
wasSplit = true;
if (splitResult.BackPolygon != null)
polygonList.Add(splitResult.BackPolygon);
if (splitResult.FrontPolygon != null)
polygonToSplit = splitResult.FrontPolygon;
}
}
}
if (!wasSplit)
polygonList.Add(polygon);
}
return polygonList;
}
It might be a little hard to tell whats going on in these screenshots but I figure a picture speaks louder than words. There is one degenerate case that I haven’t been able to solve when the cutting face is in front of the face to be cut. This shows up only when the solids overlap and one of the faces is coplanar with another as seen in the last screenshot. If anyone can spot a way to fix this I’d be greatly appreciated
I’ve gone over the alorithm many times with a fine tooth comb and written unit tests. Unforunately I don’t think I’m going to be able to solve the remaining bug without a big refactor. Probably by keeping all of the split polygons and having a second pass to remove any that are inside the solids.
Building a better Mogre (Part 4)
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
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.
Building a better Mogre (Part 3)
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.
- MOIS – include in the build process
- Samples – upload the souce code to the repository
- Terrain and Paging – get this working somehow
- 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
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:
- Download the source code, materials and shaders.
- Unpack the materials and shaders into your media folder.
- Add the new sub-directories to your resource locations.
- Add the source code files to your your project.
- 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
References
Simple SSAO on Ogre Wiki
SSAO on Wikipedia
A simple and practical approach to SSAO on GameDev.net





















