Grabbing the osgEarth::FeatureNode's Vertex Array

classic Classic list List threaded Threaded
6 messages Options
Blanky Blanky
Reply | Threaded
Open this post in threaded view
|

Grabbing the osgEarth::FeatureNode's Vertex Array

Hi,

I wanted to create lines a bit more light weight than currently provided by osgEarth. However, I wanted to use osgEarth to construct the points for me and just reuse the Vertex Array that the underlying geometry constructed by osgEarth uses itself. However, when I try to grab the vertex array, the vertexes seems to not be translated to their correct coordinates. For example this is a high level overview of what I'm doing:

1. Create an osgEarth::Symbology::LineString and push back to it two points in latitude/longitude with an altitude for the x,y, and z values.

2. Create an osgEarth::Features::Feature using said LineString from step 1.

3. Create an osgEarth::Features::FeatureNode now using said Feature from step 2.

Now at this point I would normally just add the FeatureNode to the map node or some other group contained within the scene graph, however I need to add upwards to 5000 lines at any one point and these get relatively heavy very quickly for the CPU even after about 1000 lines.

Snooping through the FeatureNode class I learned of the osg::Node* named "_compiled" and realized that's truly what's being rendered after the FeatureNode has been built by build(). My goal is to strip away everything from the FeatureNode and just temporarily use its Vertex Array. I've come to realize under the hood that the underlying Geometry is in fact held by an osg::MatrixTransform after much searching. Now, I grabbed the osg::MatrixTransform's children until I finally found the Geode and thus the Geometry. From that I called osg::Array getVertexArray() and make a deep copy of each point to add to my own Geode.

I want to simply add a geode without all the overhead of the above FeatureNode by combining multiple primitives for each line's vertexes with an offset based on the size of each line's vertexes (which can all be variable length) to be collected in a single geode that will be added to the map. I wish to do this because I won't have to traverse what seems to be around 5000 FeatureNodes all with the overhead of about 4 or so nodes in the hierarchy, summing up to nearly 20000 nodes for just simple lines. I need to cut this number down to 1 because when testing this and creating a bunch of different points I could make nearly 10000 lines and still run at full performance so long as all vertex information is bunched into one geode.

What I'm noticing is that the position of the nodes all seem to cross the origin in a projected map style, but I know I'm providing the correct information because all of the FeatureNodes draw correctly, but their raw vertex lists seem to be off.

1. Is this an effect of stripping the vertex array from the matrix transform?

2. If 1. is true, is there a way for me to simulate the translation that needs to occur before grabbing the vertex array?

3. Or is there a better way to utilize a FeatureNode for displaying multiple lines without needing so many nodes? ( A FeatureList perhaps instead of just a Feature? But this would still generate a lengthy hierarchy of groups with sub-groups composed each of matrix transforms which then again hold their own groups and Geodes, thus multiplying the total amount of nodes being inserted into the scene graph )

We've been attempting to optimize a program containing a very large amount of non-culled items (Somewhere around 6000 geodes for moving objects or icons and nearly 5000 lines) and the lines are currently the only bottleneck since we've managed to circumvent performance with the other geodes rather well.
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Grabbing the osgEarth::FeatureNode's Vertex Array

Blanky,
FeatureNode has a constructor that takes a FeatureList.

https://github.com/gwaldron/osgearth/blob/master/src/osgEarthAnnotation/FeatureNode#L61
Glenn Waldron / Pelican Mapping
Blanky Blanky
Reply | Threaded
Open this post in threaded view
|

Re: Grabbing the osgEarth::FeatureNode's Vertex Array

Hey Glenn,

The FeatureList thing was exactly the solution, however we also need to "update/move" these very large lists of lines as quickly as 30 Hz. We noticed we could make literally as many lines as we wanted statically (near 100k) with very little performance drop.

When we set up a QTimer to loop every 0.5 seconds (We'll really have to do it like every 0.03 seconds) to update all of the Features' LineSymbol's start and end points it was great until we had to dirty the entire FeatureNode. Is there anyway we can streamline the dirty call to be done in a thread by subclassing the FeatureNode and completing the function's calculations in a separate thread such that it won't bog down the main thread the viewer is running single threaded in?

So far we attempted to subclass FeatureNode as a multi-inherited QObject and emplaced it in a QThread after creation, but we didn't really see any performance difference in that. Does the recompilation of the underlying _compiled node of the FeatureNode have rather expensive operations for calculating the line strip points that its Matrix Transfrom and ultimately its Geometry use to display?

We also know if we broke it down into more FeatureNodes with less Features per node that the dirty call would be less expensive per FeatureNode, but we still need to update all of them just as frequently, so that wouldn't really be a solution either.

We're also assuming there's no way to dirty a single Feature of the FeatureNode's FeatureList without having to dirty the entire FeatureNode either to break up the work into more bite sized chunks for the CPU to handle, correct? If it is possible, how would you do so? Thanks for all of the help!

P.S. We also optimized your PlaceNode and ModelNode functionality just by adding simple GeoTransforms with a geode right underneath it to make those slightly more efficient and we noticed we can update the position of the GeoTransforms of any amount (Even 12000 entities at 0.5 seconds) and calling setPosition on them has absolutely no overhead versus not calling setPosition on all of them. We're assuming that under the hood that the FeatureNode deals with everything much differently than the GeoTransforms.

- Blanky
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Grabbing the osgEarth::FeatureNode's Vertex Array

Blanky,

The FeatureNode isn't really designed for the large-scale dynamics you are attempting. If you just want to mess around with the underlying vertex arrays in the osg::Geometry, you can just call dirty() on the array object itself and it will update on the GPU. Of that's not sufficient you are probably better off writing your own custom code instead of using FeatureNode.
Glenn Waldron / Pelican Mapping
Blanky Blanky
Reply | Threaded
Open this post in threaded view
|

Re: Grabbing the osgEarth::FeatureNode's Vertex Array

This is essentially how we're currently doing it, we're just making one very large vertex array to hold all of the lines and, like you said, calling dirty on it to update it. This is fine for a projected map where 2D straight lines are fine (unless we get into the accuracy of a rhumb vs. geo-centric line as being displayed, which is why we really like the LineString's implementation with an osgEarth::Features::Feature). On the 3D map, if the lines are long enough and/or not high enough above the ground, (we have to draw lines between flying objects and sometimes to ground objects) and using a line instead of a line strip that samples the elevation at each point, then we get some nasty occulting with the map layer and might have a line that chops in half in the middle. We're currently using GeoPoints to determine their coordinate values and converting everything to world coordinates.

Now, this just goes back to the original question:

Is it possible to use the same math that the builder for the Feature uses, but stripped down for our purposes that just spits us out the geometry such that we can update accurately the lines at the rate we need for the SRS type we need? I looked into the code for the GeoemtryCompiler during the FeatureNode's build process, but never dug far enough down to find the exact calculations that constructed the vertex array correctly. If it's impossible, we'll have to live with our current light weight implementation as its the only one that performs at the framerate and speed we need. Thanks for all of the help as usual!

- Blanky
gwaldron gwaldron
Reply | Threaded
Open this post in threaded view
|

Re: Grabbing the osgEarth::FeatureNode's Vertex Array

Blanky,
It is certainly possible since the classes are all there and the APIs exposed AFAIK. It will just take some effort to plow through the pipeline and figure out what you need and don't need :)
Glenn Waldron / Pelican Mapping