After dealing with a lot of issues, I managed to port my project from Ogre 1.9 to Ogre 2.1 with everything working (again). Except a few things that aren't currently doable in Ogre 2.1. I would like to share some information about issues I faced because somebody else might have the same problems and would have to spend a lot of time reinventing the wheel.
1. Getting the stuff to compile
The official porting manual helped me a lot with this, but there were a few cases when I had to look at the documentation or even the source code. Adding the number 2 behind many class names helped a lot. RTSS had to be removed completely, but HLMS did its work pretty well, so all I had to do was to change material codes (accepted arguments are quite hidden, they're in the documentation of the specific HLMS datablock constructors) and initialise HLMS instead of RTSS. SdkTrays no longer compile, it gave me a kick to finally stop using the last bits of it and replace it with CEGUI. Terrain was removed, and there is no replacement (hopefully, there will be one soon, I don't feel like making one myself just to realise that a much better one is being made).
The way the startup is done has also changed quite significantly, but fortunately, the porting manual explains this well enough. The samples' transition to SDL2 motivated me to get rid of the old and obsolete OIS (used because it was in the old samples) and use SDL2 instead. It gave me a much better desktop integration, I can still alt+tab away if I get a freeze and non-english keyboards do not kill input.
This piece of code written by someone I don't know (username jserve on CEGUI forums) helped me a lot, although I mixed it with the v2 samples' code to set up the SDL2 window, get its handle and make ogre render into its window.
I can make some sort of v2 AdvancedOgreFramework if somebody helps me with writing compilation scripts, I am really bad at that.
Replacing Ogre::Entity with Ogre::Item often worked with find 'n' replace, most method names remained identical. The removal of mandatory entity names could cause mess in Ogre::SceneManager::createItem() arguments, so this had to be gone through manually, but entity names were mostly of little use and it was often a nuisance to generate loads of unique names. Skeletal animations changed, but it's mostly about names of objects. Animation weight is now a public member variable, which is a bit counter-intuitive, but definitely not bad.
2. Worsened threading support with SceneNode
With Ogre v1, I could construct the SceneNode tree from other threads without problems, so I could do a lot of scene rebuilding on a background thread. It was possible to prepare all resources for all meshes and then could construct and attach the entities at the end, committing the changes, which could make massive changes to the scene without framerate drops.
With Ogre v2, constructing SceneNodes is no longer thread safe. It's still possible still do all the construction logic (like procedurally generated levels) on background thread, but it seemed necessary to write all the output in a buffer that the rendering thread would read and commit. I have found a partial workaround, to create and fill a storage of nodes on the rendering thread and set all the orientations, positions, scales and other stuff on the background thread, so that there's no need to store and copy these on the rendering thread. I don't know how meaningful it actually is.
3. Lighting issues
There was darkness. The scene appeared to have no lights, light-ignoring particles were the only visible things. I eventually googled that Forward3D has to be enabled in SceneManager (shortly afterwards, it was written in Questions and Answers), but that totally wrecked the performance. I had frame drops to about 1 FPS almost all the time. After a frustrating investigation, I learned that if I use setAttenuationBasedOnRadius() on point lights instead of setAttenuation(), the frame drops vanish. I really liked the old attenuation, because the scene can be well lit without massive radii of the lights' reach.
4. HLMS loads all stuff at startup
Investigation why the game took so long to start up and consumed humongous amounts of memory has led me to a discovery that HLMS constructs all materials while parsing the scripts, loading all necessary textures in the process. This can be practical for games with levels, where everything needed for a level is loaded when entering the level. However, for an open world game with a large exterior area, it is a problem. Even worse if many areas details are procedurally generated, so it's impossible to tell what will be needed.
I have found a trick to deal with it, however. I renamed all files with material scripts to files with a .materials suffix, causing HLMS manager to ignore them. During startup, they are parsed by a function that splits them into strings, one for each material. When a material is needed, its script is looked up and the string is parsed with Ogre::ScriptCompiler (which is capable of parsing strings as well as files). This however needs a special function to create entities (and a special function to destroy entities, because it's necessary to keep track of the materials' usage).
5. No background resource loading (unsolved)
It appears to be impossible to load stuff in the background. This is annoying, if the player walks, let's say, from a forest into a city, the city's resources need to be loaded and when this is done on the rendering thread, the game becomes quite jerky for a while. Doing it by bits on every frame isn't good enough, some textures are large.
The impossibility to compile scripts in the background isn't so bad, no disk reads are necessary and it can be done script by script, one or two per frame, but the textures must be prepared. The above mentioned trick to compile scripts only when needed can be used to read all textures needed by the script and prepare them ahead, but it has a problem. While Ogre::TextureManager does have a method named prepare() that accepts an argument if it should be loaded on the background, it appears to load on the rendering thread anyway.
While CEGUI was ported to Ogre 2.1 and its API is the same, the bootstrap has changed a bit to:
Code: Select all
CEGUI::OgreRenderer::bootstrapSystem(*renderWindow_); // returns a reference to CEGUI::OgreRenderer
Code: Select all
CEGUI::System::getSingleton().injectTimePulse(evt.timeSinceLastFrame); CEGUI::System& guiSystem = CEGUI::System::getSingleton(); guiSystem.injectTimePulse(evt.timeSinceLastEvent); CEGUI::Renderer* guiRenderer(guiSystem.getRenderer()); guiRenderer->beginRendering(); guiSystem.getDefaultGUIContext().draw(); guiRenderer->endRendering(); CEGUI::WindowManager::getSingleton().cleanDeadPool();
Ogre 2.1 does not support fixed function pipeline anymore, meaning that the classical materials no longer work. While it was poor for PBS and often needed RTSS or custom shaders, the old scripts allowed a lot of cool effects like halo, lightnings, aureola, corona etc. HLMS Unlit seems quite insufficient. While it does support multiple materials and their vivid combinations with operations, it does not seem to support animations.
An item with a skeletal animation will not be animated when its material comes from HLMS Unlit. This is quite a bummer because animated unlit items can do a lot of effects that would be hard to do and consume a lot of CPU time if done with particles. A semi-transparent wispy ghost can't be done at the moment. A tornado-like particle system would require huge amounts of particles and complicated affectors, while a properly textured mesh would only need some writhing and twisting animations. With particles, explosions look mostly like flames erupting from a location, an animated entity can create a very nice blast wave with debris. Creating a force field armour on characters is outright impossible with particles.
I also haven't figured out how to animate the material, like scrolling textures (for tornadoes) or looping between a few textures (for electric discharges). The description says that it can accept an animate argument, it does not explain what do the numbers mean. The source code seem to suggest that they refer to some matrices, but I could not find how to define these matrices. It does not seem to support looping between textures at all. Making a custom HLMS for these few things look like an overkill.
The performance is hard to compare because HLMS materials are different from RTSS materials and AttenuationBasedOnRadius needs massive radii to illuminate the area properly, causing many lights to affect objects faintly (if the radius is high) or create ugly edges where the light is cut off (when the threshold is high). It was probably not intended for illuminating areas, just for making small lights. The usual attenuation could help a lot here, but its implementation with Forward3D has weird performance problems as described above.
A big improvement I have noticed is that the rendering thread takes very little CPU time even if the framerate is not limited (testing it on a poor video card, though). I can't remember seeing a game not consume significant portions of CPU time unless it's something with little demands. In this, Ogre really has Almost Zero Driver Overhead.
I hope this report will be useful to somebody. And hopefully some of the unsolved issues will be addressed. Thanks for reading this long post.
Appendix 1. Update to Ogre 2.1 after the merge of the PSO branch
Most changes were trivial and their fixes are intuitive. A namespace change requiring the removal of the ::v1 part, replacing some IdStrings with actual strings. Target swapping is done a bit differently, but the difference can be checked in Ogre's source.
The main unexpected trap I would like to share with others to avoid the issues I had is that it suddenly begun to throw this shortly afters startup:
Code: Select all
An exception has occurred: OGRE EXCEPTION(5:ItemIdentityException): Parameter called f3dGrid does not exist.
CEGUI could be ported to use PSO with the use of the patch on this thread: http://www.ogre3d.org/forums/viewtopic. ... 1&start=25
Compared to 1.9, features that Ogre 2.1 still sickly misses are animations in HlmsUnlit and support for resource loading on background threads.