前言
osgearth_occlusionculling示例,分析了declutter清理器功能。即当有多个同类型的对象同时覆盖在同一个区域时,会隐藏一部分对象。如果想更深入学习declutter功能,推荐 osgearth_cluster 示例。此示例效果一般,就当它只是实现了随机在规定区域生成一些PlaceNode标签。
执行命令
// 开启 declutter
osgearth_occlusioncullingd.exe earth_image\world.earth --declutter
// 或者 不开启 declutter
osgearth_occlusioncullingd.exe earth_image\world.earth
// 经测试,这个参数设置为true或false,看不出什么区别
效果
相机操作器距离地球较远时:
相机操作器距离地球较近时:
代码分析
#include <osgEarth/MapNode>
#include <osgEarth/ScreenSpaceLayout>
#include <osgEarth/ECEF>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/AutoClipPlaneHandler>
#include <osgEarthUtil/ExampleResources>
#include <osgEarthAnnotation/AnnotationEditing>
#include <osgEarthAnnotation/AnnotationRegistry>
#include <osgEarthAnnotation/ImageOverlay>
#include <osgEarthAnnotation/ImageOverlayEditor>
#include <osgEarthAnnotation/CircleNode>
#include <osgEarthAnnotation/RectangleNode>
#include <osgEarthAnnotation/EllipseNode>
#include <osgEarthAnnotation/PlaceNode>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/StateSetManipulator>
#include <osgGA/EventVisitor>
using namespace osgEarth;
using namespace osgEarth::Annotation;
using namespace osgEarth::Util;
int
usage( char** argv )
{
OE_WARN << "Usage: " << argv[0] << " <earthfile>" << std::endl;
return -1;
}
//------------------------------------------------------------------
int
main(int argc, char** argv)
{
osg::Group* root = new osg::Group();
// try to load an earth file.
osg::ArgumentParser arguments(&argc,argv);
osgViewer::Viewer viewer(arguments);
// 输入个数,默认200
unsigned int numObjects = 200;
while (arguments.read("--count", numObjects)) {}
// 输入清理器设置,默认为false,如果设置则为true
bool declutter = false;
if (arguments.read("--declutter")) declutter = true;
// initialize the viewer: 添加操作器
viewer.setCameraManipulator( new EarthManipulator() );
// load an earth file and parse demo arguments
osg::Node* node = MapNodeHelper().load(arguments, &viewer);
if ( !node )
return usage(argv);
// find the map node that we loaded.
MapNode* mapNode = MapNode::findMapNode(node);
if ( !mapNode )
return usage(argv);
root->addChild( node );
// Make a group for 2D items, and activate the decluttering engine. Decluttering
// will migitate overlap between elements that occupy the same screen real estate.
// 定义labelGroup, 清理器会把 覆盖在同一地方相同的元素 做重叠处理。
osg::Group* labelGroup = new osg::Group();
root->addChild( labelGroup );
// set up a style to use for placemarks:
// 设置style 贴地
Style placeStyle;
placeStyle.getOrCreate<AltitudeSymbol>()->clamping() = AltitudeSymbol::CLAMP_RELATIVE_TO_TERRAIN;
// A lat/long SRS for specifying points. 获取地理坐标系
const SpatialReference* geoSRS = mapNode->getMapSRS()->getGeographicSRS();
//--------------------------------------------------------------------
//Create a bunch of placemarks around Mt Rainer so we can actually get some elevation
{
osg::ref_ptr<osg::Image> pin = osgDB::readRefImageFile( "../data/placemark32.png" );
// 中心经纬度
double centerLat = 46.840866;
double centerLon = -121.769846;
double height = 0.2;
double width = 0.2;
// 最小经纬度
double minLat = centerLat - (height/2.0);
double minLon = centerLon - (width/2.0);
OE_NOTICE << "Placing " << numObjects << " placemarks" << std::endl;
for (unsigned int i = 0; i < numObjects; i++)
{
double lat = minLat + height * (rand() * 1.0)/(RAND_MAX-1);
double lon = minLon + width * (rand() * 1.0)/(RAND_MAX-1);
std::string str = osgEarth::Stringify() << "Placemark" << "-" << i;
PlaceNode* place = new PlaceNode(str, placeStyle, pin.get());
place->setMapNode(mapNode);
place->setPosition(GeoPoint(geoSRS, lon, lat));
//Enable occlusion culling. This will hide placemarks that are hidden behind terrain.
//This makes use of the OcclusionCullingCallback in CullingUtils.
// 启用遮挡剔除。这将隐藏 隐藏在地形后面的位置标记。
// 此功能利用了CullingUtils中的OcclusionCullingCallback。
//place->setOcclusionCulling( true );// 原文示例是这句,这样的话,declutter参数就无效了。
place->setOcclusionCulling(declutter);// 经测试,此处设置为true或false,效果没变化。
labelGroup->addChild( place );
}
}
viewer.setSceneData( root );
// AutoClipPlaneCullCallback 根据指定贴图中的参数构造新的自动剪裁平面管理器。
// 如果mapNode=0L,则获取WGS84地图,否则获取椭球体地图信息
viewer.getCamera()->addCullCallback( new AutoClipPlaneCullCallback(mapNode) );
viewer.addEventHandler(new osgViewer::StatsHandler());
viewer.addEventHandler(new osgViewer::WindowSizeHandler());
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
return viewer.run();
}