Scenery LOD ideas for FlightGear: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
No edit summary
(Comments from Stuart)
Line 120: Line 120:




'''Stuart:'''
Now, this is very interesting. I need to have a bit of a play with it to see what the CPU cost of the simplification is, but at first glance, it should be straightforward to build scenery LoD by using this for the distant scenery, and simply re-loading the BTG file (which is fairly cheap) at closer range as part of the PagedLoD system we've got for trees etc.  Obviously there's a bit of a problem at the edges, but because the scenery tiles have straight-ish edges and are single-sided, I suspect the visual artifacts will be minimal.
Hooray - I'm not sure there's much value in tying this to a SGPropertyChangeListener, as its not something that can be dynamically changed.  I 99% sure the visitor goes through the OSG tree modifying the data itself, so the original data is no-longer available afterwards.  Effectively it's a destructive transformation.  So, to apply some new setting would require loading the BTG file from disk again. 
(An alternative would be to have a different type of visitor that creates a new OSG sub-tree with cloned data, but that obviously increases memory occupancy.)
I'm also not sure of the implications of applying it to aircraft,  but it should be easy to try out at least. 
-Stuart





Revision as of 11:27, 19 February 2014

02/2014 (F-JJTH)

F-JJTH: Looking at your topic about the framerate dropdown because of the new scenery I would ask you to test the following patch:

http://pastebin.com/p5HXirn5

diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx
index edb35f2..767c930 100644
--- a/simgear/scene/tgdb/obj.cxx
+++ b/simgear/scene/tgdb/obj.cxx
@@ -40,6 +40,7 @@
 #include <osg/Referenced>
 #include <osg/StateSet>
 #include <osg/Switch>
+#include <osgUtil/Simplifier>
 
 #include <boost/foreach.hpp>
 
@@ -1213,6 +1214,25 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options
     terrainGroup->setName("BTGTerrainGroup");
 
     osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib);
+
+    bool simplifierState = false;
+    double ratio         = 0.001;
+    double maxLength     = 1000.0;
+    double maxError      = 1000.0;
+    if(options){
+        SGPropertyNode* propertyNode = options->getPropertyNode().get();
+        if (propertyNode) {
+            simplifierState = propertyNode->getBoolValue("/sim/rendering/terrain/simplifier/enabled", simplifierState);
+            ratio = propertyNode->getDoubleValue("/sim/rendering/terrain/simplifier/ratio", ratio);
+            maxLength = propertyNode->getDoubleValue("/sim/rendering/terrain/simplifier/max-length", maxLength);
+            maxError = propertyNode->getDoubleValue("/sim/rendering/terrain/simplifier/max-error", maxError);
+        }
+    }
+    if(simplifierState) {
+        osgUtil::Simplifier simplifier(ratio, maxError, maxLength);
+        node->accept(simplifier);
+    }
+
     if (node)
       terrainGroup->addChild(node);

http://pastebin.com/zn0W31HV

diff --git a/preferences.xml b/preferences.xml
index da8416c..3b701c3 100644
--- a/preferences.xml
+++ b/preferences.xml
@@ -58,6 +58,14 @@ Started September 2000 by David Megginson, david@megginson.com
                        <season type="string" preserve="y">summer</season>
                </startup>
                <rendering>
+                       <terrain>
+                               <simplifier>
+                                       <enabled type="bool">false</enabled>
+                                       <ratio type="double">0.001</ratio>
+                                       <max-error type="double">1000.0</max-error>
+                                       <max-length type="double">1000.0</max-length>
+                               </simplifier>
+                       </terrain>
                        <materials-file>Materials/regions/materials.xml</materials-file>
                        <rembrandt>
                                <enabled type="bool">false</enabled>

Then start FG with --prop:/sim/rendering/terrain/simplifier/enabled=true

Every params take effect at run-time as soon as you reload the scenery after changing the value, but I've experimented a lot of value and the default values are fine. For information the expected result is to have less vertex:

http://clement.delhamaide.free.fr/osg/

Of course less vertex = less detail... but I think it's more reasonable to give a "low-vertex-scenery" for those who don't have the requiered hardware.

Also keep in mind that this patch has only a positive effect (at least I hope) on FPS, not on RAM (the whole BTG file is still loaded in RAM)

Well, let me know if it improve the situation.


The number of vertex should be definitely reduced. My screenshots (wireframe) are showing that osg::Simplifier works fine. But maybe the simplification is not enough important for seeing a positive effect.

I will give a try tomorrow at KSFO, are you able to confirm me that enabling osg::Simplifier reduce the number of vertex (or not). A simple test is:

  • Start FG
  • Enable wireframe
  • Look at outdoor
  • Take a screenshot
  • Enable osg::Simplifier from property tree
  • Reload scenery
  • Take a screenshot

Then compare the 2 screenshots and yo will immediately see if the effect is here

Hooray: I have worked through quite a few OSG docs, and I think we can make this work - ideally, you would push your changes to gitorious, so that we can both work on them. I also asked poweroftwo (osgEarth) to have a look, because he's more familiar with the scenery/terrain and OSG side of things (also CC'ing Stuart and Zakalawe and the TG guys, so that they're aware of this).

I would really love to see this implemented as a custom SimGear class, something like "LODManager" that is property-driven. We could then use it for 1) terrain, 2) main aircraft models (cockpit!) and 3) AI objects to expose a property-driven interface to customize LOD at runtime.

The first thing that we could change is using SGPropertyChangeListener or property objects so that properties can be changed at runtime, without requiring a scenery-reload.

I think we would only need to subclass osgUtil::Simplifier and make it derive from SGPropertyChangeListener, too - would that work ?

class SGLODManager : public osgUtil::Simplifier, SGPropertyChangeListener
{
// implement the osgUtil::Simplifier & listener interfaces here
};

The question is we can modify the visitor after it's been applied, or if that requires changes on the OSG side.

It also seems that we can use some OSG machinery to simplify textures, too.


Stuart:

Now, this is very interesting. I need to have a bit of a play with it to see what the CPU cost of the simplification is, but at first glance, it should be straightforward to build scenery LoD by using this for the distant scenery, and simply re-loading the BTG file (which is fairly cheap) at closer range as part of the PagedLoD system we've got for trees etc. Obviously there's a bit of a problem at the edges, but because the scenery tiles have straight-ish edges and are single-sided, I suspect the visual artifacts will be minimal.

Hooray - I'm not sure there's much value in tying this to a SGPropertyChangeListener, as its not something that can be dynamically changed. I 99% sure the visitor goes through the OSG tree modifying the data itself, so the original data is no-longer available afterwards. Effectively it's a destructive transformation. So, to apply some new setting would require loading the BTG file from disk again.

(An alternative would be to have a different type of visitor that creates a new OSG sub-tree with cloned data, but that obviously increases memory occupancy.)

I'm also not sure of the implications of applying it to aircraft, but it should be easy to try out at least.

-Stuart



Ideas (2012)

Moving forum discussion to the wiki:


Maybe there could be one single globe texture, and each tile btg would have it's correct texture coordinates into that image.

For LOD, I'd implement something like this :

  • Allocate a huge texture for a single 10x10 degrees area
  • load tiles as usual
  • render the tile to a small sub-part of the huge texture
  • replace the tile geometry by a quad using the corners of the tile and map the small chunk of texture to it
  • unload the tile geometry to free memory
  • repeat for each tile of that area
  • save the texture to disk and repeat for another 10x10 degrees area

Sharing the same texture for a huge area save state changes. The tile quad geometry could be saved in the btg format to a Terrain.LowRes directory tree, using the material property to reference the shared texture


  • For the LOD algorithm, CDLOD [1] would probably be the best bet. CDLOD is like Chunked LOD, but plays nice with the GPU, and subdivides the LOD based on the distance from the camera/view point. Traditional CLOD implementations are not GPU friendly, this implementation is, and has the benefit of LOD based on camera position. The algorithm that would be the best bet for implementation is something similar to the streaming CDLOD implementation in the code samples.
  • the LOD algorithm should be moved to a separate thread, otherwise it really will just drain on the main thread, and will have less, if not worse performance that is possible with a properly implemented LOD system. This may have some problems however due to the potential for the LOD system to have issues with the property tree and threading.
  • It may be wise to base the LOD changes off of Rembrandt, rather than the current FGFS code base. Deferred rendering from Rembrandt is a major rendering change, and it may or may not play nice with a new LOD implementation based on the non-deferred rendering of the current code base.
  • For higher end GPUs, implementing some of the techniques from these blog posts may help increase FPS on OpenGL 3 and 4 level hardware. [2] [3] [4] [5] [6]

References