Distant objects
Posted: 06 Sep 2017, 18:31
As with shadows, I won't have any time to work on this, but I can give my 2 cents on how it should be done.
I actually wrote all this a while ago, to someone who asked, but said person stopped replying back so I think it's safe to say the task is up for grabs again.
Basics
The first question is whether or not we pre-generate (and/or cache) the LODs before the game starts, or create everything on-the-fly (as the terrain engine does). I think on-the-fly generation is very much possible and our best option - there's no need to delete a cache when changing mods, and when we use many different pages at different levels of detail depending on where the player is then generating all these in advance would be prohibitively expensive anyway.
A basic implementation shouldn't be too hard to do by reusing much of the code / concepts of the distant terrain code (e.g. the Quad Tree, the View and the way preloading works). Much of the speed-up compared to loading cells normally will come from being able to ignore physics, NPCs, particles, and smaller objects. Also running an optimizer pass that merges objects (which we can't normally do because normal objects move all the time) should help a lot.
Ignoring small objects presents a dilemma: we need to know the size of the mesh before we load it, but we have to load it to know its size. So basically we'll have to load everything anyway. To mitigate the impact of this I propose that we store in cache a 'mesh file -> bounding box/size' file so we can avoid loading all meshes everytime the game starts.
Mesh LOD
Ok, LODs. The first 'solution' here is to not simplify anything (other than running the optimizer pass to merge nodes). After all, Morrowind is an old game and its meshes are already low-poly by today's standards. So before implementing anything crazy I'd suggest to try using things as they are.
That said for very high view distances and/or modded high-poly meshes some form of simplification is still going to be necessary. This will be difficult because some meshes can't be simplified further and we also don't know which meshes are supposed to be smooth (organic) or solid. I suspect this will involve lots of trial, error and heuristics. But it should absolutely be our goal that things like whitelists/blacklists/manual parameters for certain meshes are not going to be necessary and everything will just work out of the box. In any case, osg provides a Simplifier class which looks to be a half-decent starting point (note you have to apply osg commit a13b66135f826688acb860fc7f0f0c911435645d to make it work).
An alternative simplification method is to use impostors (prerendered 2d billboards). A great example of this technique is Ogre3D paged geometry. This method tends to work great for trees, foliage, and rocks, but not so well for other meshes. It should be possible for some heuristics to select the simplification method to use (e.g. if a model is Z-rotionally invariant and uses transparency, it's probably a tree/foliage).
Note OSG provides an Impostor class but no way to batch them, so we'd have to roll our own.
Texture LOD
As with the above, how much LOD we really need remains to be seen. But I suspect textures might be more of a problem than vertices. A potential optimization is texture atlasing (in other words, merging several textures into one texture, then using UV coordinates to select the correct texture for each mesh).
The usual issue with texture atlasing is that we don't know which textures are going to be used together and for how long. But for distant objects, we do know - they rarely move relative to the player - so using texture atlasing might be a good technique here. We can build one or more atlas per quad tree node. The only problem is handling 'repeat' textures/UVs. I wonder how MGE handles those?
osg includes a TextureAtlasVisitor. I briefly tried it once and it didn't work correctly, but I may have done something wrong. Also there was an issue with handling of Drawables which has been fixed (but likely still needs to be applied to your osg install).
Enable / disable distant objects
Some people have asked if OpenMW is going to have the same issue as in MGE where objects dynamically enabled/disabled by scripts at runtime are not going to have their distant LOD updated. In theory this can be implemented with a little bit of effort, if we can accept a minor stuttering in FPS as LODs are rebuilt. It should be noted, though, that issues could remain if the relevant script only runs when the cell is loaded (as with the Strongholds, AFAIK). In this case the object would be initially enabled until you visit the cell. This can be easily fixed by modders, i.e. add a script that disables the object on the start of the game.
I actually wrote all this a while ago, to someone who asked, but said person stopped replying back so I think it's safe to say the task is up for grabs again.
Basics
The first question is whether or not we pre-generate (and/or cache) the LODs before the game starts, or create everything on-the-fly (as the terrain engine does). I think on-the-fly generation is very much possible and our best option - there's no need to delete a cache when changing mods, and when we use many different pages at different levels of detail depending on where the player is then generating all these in advance would be prohibitively expensive anyway.
A basic implementation shouldn't be too hard to do by reusing much of the code / concepts of the distant terrain code (e.g. the Quad Tree, the View and the way preloading works). Much of the speed-up compared to loading cells normally will come from being able to ignore physics, NPCs, particles, and smaller objects. Also running an optimizer pass that merges objects (which we can't normally do because normal objects move all the time) should help a lot.
Ignoring small objects presents a dilemma: we need to know the size of the mesh before we load it, but we have to load it to know its size. So basically we'll have to load everything anyway. To mitigate the impact of this I propose that we store in cache a 'mesh file -> bounding box/size' file so we can avoid loading all meshes everytime the game starts.
Mesh LOD
Ok, LODs. The first 'solution' here is to not simplify anything (other than running the optimizer pass to merge nodes). After all, Morrowind is an old game and its meshes are already low-poly by today's standards. So before implementing anything crazy I'd suggest to try using things as they are.
That said for very high view distances and/or modded high-poly meshes some form of simplification is still going to be necessary. This will be difficult because some meshes can't be simplified further and we also don't know which meshes are supposed to be smooth (organic) or solid. I suspect this will involve lots of trial, error and heuristics. But it should absolutely be our goal that things like whitelists/blacklists/manual parameters for certain meshes are not going to be necessary and everything will just work out of the box. In any case, osg provides a Simplifier class which looks to be a half-decent starting point (note you have to apply osg commit a13b66135f826688acb860fc7f0f0c911435645d to make it work).
An alternative simplification method is to use impostors (prerendered 2d billboards). A great example of this technique is Ogre3D paged geometry. This method tends to work great for trees, foliage, and rocks, but not so well for other meshes. It should be possible for some heuristics to select the simplification method to use (e.g. if a model is Z-rotionally invariant and uses transparency, it's probably a tree/foliage).
Note OSG provides an Impostor class but no way to batch them, so we'd have to roll our own.
Texture LOD
As with the above, how much LOD we really need remains to be seen. But I suspect textures might be more of a problem than vertices. A potential optimization is texture atlasing (in other words, merging several textures into one texture, then using UV coordinates to select the correct texture for each mesh).
The usual issue with texture atlasing is that we don't know which textures are going to be used together and for how long. But for distant objects, we do know - they rarely move relative to the player - so using texture atlasing might be a good technique here. We can build one or more atlas per quad tree node. The only problem is handling 'repeat' textures/UVs. I wonder how MGE handles those?
osg includes a TextureAtlasVisitor. I briefly tried it once and it didn't work correctly, but I may have done something wrong. Also there was an issue with handling of Drawables which has been fixed (but likely still needs to be applied to your osg install).
Enable / disable distant objects
Some people have asked if OpenMW is going to have the same issue as in MGE where objects dynamically enabled/disabled by scripts at runtime are not going to have their distant LOD updated. In theory this can be implemented with a little bit of effort, if we can accept a minor stuttering in FPS as LODs are rebuilt. It should be noted, though, that issues could remain if the relevant script only runs when the cell is loaded (as with the Strongholds, AFAIK). In this case the object would be initially enabled until you visit the cell. This can be easily fixed by modders, i.e. add a script that disables the object on the start of the game.