Skip to content

Instantly share code, notes, and snippets.

@gwaldron
Created October 8, 2015 20:12
Show Gist options
  • Select an option

  • Save gwaldron/7750ebee8417fc1708b6 to your computer and use it in GitHub Desktop.

Select an option

Save gwaldron/7750ebee8417fc1708b6 to your computer and use it in GitHub Desktop.
Use a CullVisitor to collect information about a scene
/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2015 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include <osgViewer/Viewer>
#include <osgEarth/Notify>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/ExampleResources>
#include <osgEarth/Units>
#include <osgEarth/Viewpoint>
#define LC "[viewer] "
using namespace osgEarth;
using namespace osgEarth::Util;
void
extractBounds(osgUtil::StateGraph* sg, const osg::Matrix& viewToWorld, osg::BoundingSphere& worldBS)
{
// Do a depth-first recursive traversal of the state graph:
for(osgUtil::StateGraph::ChildList::const_iterator i = sg->_children.begin(); i != sg->_children.end(); ++i)
{
extractBounds( i->second.get(), viewToWorld, worldBS );
}
// Each StateGraph has a list of render leaves, each containing a Drawable
// and a modelview/projection matrix pair. We only care about the modelview
// matrix at this time.
for(osgUtil::StateGraph::LeafList::const_iterator i = sg->_leaves.begin(); i != sg->_leaves.end(); ++i)
{
osgUtil::RenderLeaf* leaf = i->get();
// The modelview matrix, which will transform geometry into camera space
const osg::Matrix& localToView = (*leaf->_modelview);
const osg::Drawable* drawable = leaf->getDrawable();
// Cast the drawable to a geometry:
const osg::Geometry* geometry = drawable->asGeometry();
if ( geometry )
{
// The list of local-space vertices in this geometry:
const osg::Vec3Array* vertices = dynamic_cast<const osg::Vec3Array*>(geometry->getVertexArray());
for(osg::Vec3Array::const_iterator v = vertices->begin(); v != vertices->end(); ++v)
{
const osg::Vec3f& vert = *v;
// transform into view space (aka camera space)
osg::Vec3d vertView = vert * localToView;
// optional viewport clipping: Discard any verts that are outside the current viewpoint.
osg::Vec4d vertClip = osg::Vec4d(vertView.x(), vertView.y(), vertView.z(), 1.0) * (*leaf->_projection);
double absw = fabs(vertClip.w());
if ( fabs(vertClip.x()) > absw || fabs(vertClip.y()) > absw || fabs(vertClip.z()) > absw )
continue;
// transform into world space
osg::Vec3d vertWorld = vertView * viewToWorld;
// use that to expand our bounds.
worldBS.expandBy( vertWorld );
}
}
}
}
int
main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
// create a viewer:
osgViewer::Viewer viewer(arguments);
viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );
viewer.setCameraManipulator( new EarthManipulator(arguments) );
// load an earth file, and support all or our example command-line options
// and earth file <external> tags
osg::Node* node = MapNodeHelper().load( arguments, &viewer );
if ( node )
{
viewer.setSceneData( node );
while(!viewer.done())
{
viewer.frame();
// Construct a cull visitor to collect data in view:
osg::ref_ptr<osgUtil::CullVisitor> cv = osgUtil::CullVisitor::create();
cv->setStateGraph( new osgUtil::StateGraph() );
cv->setRenderStage( new osgUtil::RenderStage() );
// Set the framestamp to that of the view. This is important so that paging
// doesn't get interrupted.
cv->setFrameStamp( viewer.getFrameStamp() );
// Run the visitor against our main camera's scene graph:
viewer.getCamera()->accept( *cv.get() );
// Go through the results and calculate the world-space bounds:
osg::BoundingSphere worldBS;
extractBounds( cv->getRootStateGraph(), viewer.getCamera()->getInverseViewMatrix(), worldBS );
OE_NOTICE << "Approximate visible radius = " << worldBS.radius() << std::endl;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment