osgEarth基礎入門

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便可獲得下面的效果。

clip_image002

 

//引入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();
}
相關文章
相關標籤/搜索