osgEarth基礎入門canvas
2015年3月21日數組
16:19app
osgEarth是基於三維引擎osg開發的三維數字地球引擎庫,在osg基礎上實現了瓦片調度插件,可選的四叉樹調度插件,更多的地理數據加載插件(包括GDAL,ogr,WMS,TMS,VPB,filesystem等),再結合一套地理投影轉換插件,這樣就可以實現高效處理加載調度地理數據在三維地球上的顯示,實現三維虛擬地球。函數
想要實現一個簡單的基於osgEarth的三維地球,有兩種方式,這兩種方式是互通的。一種基於XML標籤的earth文件加載,另一種是採用C++代碼,本質是同樣的,osgEarth內部支持直接解析XML標籤文件,轉換爲代碼實現,具體參考tests文件夾例子,代碼則參考application下面例子。可是大多數狀況下,你須要更靈活掌控性更強的代碼來實現功能,由於只有一個加載了基礎數據的三維地球是隻能看,不能解決實際問題的,須要界面一般採用QT,更多的三維渲染和仿真業務則由osg來完成。所以學好osg是作這一切的基礎。工具
osgEarth的特色:支持加載常見的柵格數據(影像和DEM),可是大數據必須創建金字塔,設置爲地理投影,想要高效率最好處理爲瓦片,這樣也便於部署在服務端。矢量數據,最好儘量的簡化,由於大的矢量會十分影響渲染速度,固然也能夠對矢量柵格化處理加快速度,對於模型的話,大數據量必定要作LOD或者pageLod。佈局
osgEarth程序的常規流程:大數據
建立osgViewer---->建立MapNode---->設置Earth操做器---->設置場景參數----->run優化
MapNode是繼承自osg的Node,是osgEarth中地球節點,你所添加的影像,DEM,模型都包含在MapNode中,由於它們都加入到Map中,Map則相似二維中的Map能夠添加各類圖層。剩餘的無論是模型節點Node,或者是標註Node,仍是其餘的都是能夠直接添加到MapNode中或者另外的Group中。spa
Earth操做器則和其餘osg操做器同樣,只不過專門爲三維地球瀏覽定製,具體參數能夠設置。插件
場景參數則主要有自動地形裁剪,最小裁剪像素等其餘優化場景的參數。
下面就簡單闡述一個小例子說明:
代碼功能主要實現了查詢實時高程,並顯示XYZ座標的功能。
使用命令app.exe test.earth便可獲得下面的效果。
//引入osg和osgEarth的頭文件和命名空間 #include <osgGA/StateSetManipulator> #include <osgGA/GUIEventHandler> #include <osgViewer/Viewer> #include <osgViewer/ViewerEventHandlers> #include <osgUtil/LineSegmentIntersector> #include <osgEarth/MapNode> #include <osgEarth/TerrainEngineNode> #include <osgEarth/ElevationQuery> #include <osgEarth/StringUtils> #include <osgEarth/Terrain> #include <osgEarthUtil/EarthManipulator> #include <osgEarthUtil/Controls> #include <osgEarthUtil/LatLongFormatter> #include <iomanip> using namespace osgEarth; using namespace osgEarth::Util; using namespace osgEarth::Util::Controls; static MapNode* s_mapNode = 0L; static LabelControl* s_posLabel = 0L; static LabelControl* s_vdaLabel = 0L; static LabelControl* s_mslLabel = 0L; static LabelControl* s_haeLabel = 0L; static LabelControl* s_mapLabel = 0L; static LabelControl* s_resLabel = 0L; // An event handler that will print out the elevation at the clicked point //查詢高程的一個事件回調,在場景有事件更新觸發時調用,詳細參考osg或者osgGA::GUIEventHandler struct QueryElevationHandler : public osgGA::GUIEventHandler { //構造函數 QueryElevationHandler() : _mouseDown( false ), _terrain ( s_mapNode->getTerrain() ), _query ( s_mapNode->getMap() ) { _map = s_mapNode->getMap(); //初始化最大查詢LOD級別 _query.setMaxTilesToCache(10); _path.push_back( s_mapNode->getTerrainEngine() ); } //更新回調,具體的內容能夠參考父類,傳進來的參數是屏幕座標xy,和osgViewer void update( float x, float y, osgViewer::View* view ) { bool yes = false; // look under the mouse: //採用線去對地球作碰撞檢測,根據鼠標點擊點去檢測,獲得交點,就是當前點的xyz osg::Vec3d world; osgUtil::LineSegmentIntersector::Intersections hits; //判斷求交結果是否爲空 if ( view->computeIntersections(x, y, hits) ) { //獲得世界座標系下面的座標,就是osg的xyz座標 world = hits.begin()->getWorldIntersectPoint(); // convert to map coords: //將其轉換爲地球的地理座標,轉換方法都照抄便可 GeoPoint mapPoint; mapPoint.fromWorld( _terrain->getSRS(), world ); // do an elevation query: double query_resolution = 0; // 1/10th of a degree double out_hamsl = 0.0; double out_resolution = 0.0; //根據輸入參數查詢當前點位置的高程,須要設置分辨率,就是查詢精度 bool ok = _query.getElevation( mapPoint, out_hamsl, query_resolution, &out_resolution ); //若是查詢成功 if ( ok ) { // convert to geodetic to get the HAE: mapPoint.z() = out_hamsl; GeoPoint mapPointGeodetic( s_mapNode->getMapSRS()->getGeodeticSRS(), mapPoint ); //經緯度座標的格式化工具,也能夠本身用字符串去拼接xyz數字 static LatLongFormatter s_f; //更新顯示的xyz值,label是傳入的控件 s_posLabel->setText( Stringify() << std::fixed << std::setprecision(2) << s_f.format(mapPointGeodetic.y()) << ", " << s_f.format(mapPointGeodetic.x()) ); //還能夠輸出分辨率,橢球體信息等 s_mslLabel->setText( Stringify() << out_hamsl ); s_haeLabel->setText( Stringify() << mapPointGeodetic.z() ); s_resLabel->setText( Stringify() << out_resolution ); yes = true; } // finally, get a normal ISECT HAE point. GeoPoint isectPoint; isectPoint.fromWorld( _terrain->getSRS()->getGeodeticSRS(), world ); s_mapLabel->setText( Stringify() << isectPoint.alt() ); } //若是查詢不到高程的話 if (!yes) { s_posLabel->setText( "-" ); s_mslLabel->setText( "-" ); s_haeLabel->setText( "-" ); s_resLabel->setText( "-" ); } } //參數一個是事件的動做,另一個是對應的操做 bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa ) { //判斷若是是移動鼠標事件才進行更新當前的座標顯示 if (ea.getEventType() == osgGA::GUIEventAdapter::MOVE && aa.asView()->getFrameStamp()->getFrameNumber() % 10 == 0) { osgViewer::View* view = static_cast<osgViewer::View*>(aa.asView()); update( ea.getX(), ea.getY(), view ); } return false; } //Map對象 const Map* _map; //地形對象 const Terrain* _terrain; bool _mouseDown; //查詢高程使用的對象 ElevationQuery _query; osg::NodePath _path; }; //main函數, int main(int argc, char** argv) { //這兒兩個參數,第一個是命令參數的個數爲,後面是字符串數組輸入earth文件的路徑osg::ArgumentParser arguments(&argc,argv); //osg的場景 osgViewer::Viewer viewer(arguments); //構造MapNode,arguments裏面有earth文件的路徑,命令行輸入 s_mapNode = MapNode::load(arguments); //若是路徑不正確或者earth文件錯誤,沒有構造好MapNode if ( !s_mapNode ) { OE_WARN << "Unable to load earth file." << std::endl; return -1; } //創建一個組節點 osg::Group* root = new osg::Group(); //將組節點設置爲場景節點 viewer.setSceneData( root ); // install the programmable manipulator. //設置earth操做器 viewer.setCameraManipulator( new osgEarth::Util::EarthManipulator() ); // The MapNode will render the Map object in the scene graph. //將MapNode添加到組節點中去 root->addChild( s_mapNode ); //下面是設置一個控件,grid的意思是用格網去佈局裏面的小控件 // Make the readout: Grid* grid = new Grid(); //設置幾個Label文字控件顯示在場景中的第行 grid->setControl(0,0,new LabelControl("Coords (Lat, Long):")); grid->setControl(0,1,new LabelControl("Vertical Datum:")); grid->setControl(0,2,new LabelControl("Height (MSL):")); grid->setControl(0,3,new LabelControl("Height (HAE):")); grid->setControl(0,4,new LabelControl("Isect (HAE):")); grid->setControl(0,5,new LabelControl("Resolution:")); //設置幾個Label文字控件顯示在場景中的第行 s_posLabel = grid->setControl(1,0,new LabelControl("")); s_vdaLabel = grid->setControl(1,1,new LabelControl("")); s_mslLabel = grid->setControl(1,2,new LabelControl("")); s_haeLabel = grid->setControl(1,3,new LabelControl("")); s_mapLabel = grid->setControl(1,4,new LabelControl("")); s_resLabel = grid->setControl(1,5,new LabelControl("")); //獲得空間參考,橢球面信息,並顯示對應上面的label const SpatialReference* mapSRS = s_mapNode->getMapSRS(); s_vdaLabel->setText( mapSRS->getVerticalDatum() ? mapSRS->getVerticalDatum()->getName() : Stringify() << "geodetic (" << mapSRS->getEllipsoid()->getName() << ")" ); //控件繪製容器 ControlCanvas* canvas = new ControlCanvas(); //將要顯示的控件加入到root組節點中去 root->addChild(canvas); canvas->addControl( grid ); //添加剛剛自定義的查詢高程的事件回調 // An event handler that will respond to mouse clicks: viewer.addEventHandler( new QueryElevationHandler() ); //添加狀態顯示,窗口改變等事件回調 // add some stock OSG handlers: viewer.addEventHandler(new osgViewer::StatsHandler()); viewer.addEventHandler(new osgViewer::WindowSizeHandler()); viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet())); //run return viewer.run(); }