osgEarth基础入门(转载)
osgEarth基础入门
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中。
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(); _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: ; // 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::) << 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() % == ) { 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; ; } //建立一个组节点 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(,,new LabelControl("Coords (Lat, Long):")); grid->setControl(,,new LabelControl("Vertical Datum:")); grid->setControl(,,new LabelControl("Height (MSL):")); grid->setControl(,,new LabelControl("Height (HAE):")); grid->setControl(,,new LabelControl("Isect (HAE):")); grid->setControl(,,new LabelControl("Resolution:")); //设置几个Label文字控件显示在场景中的第行 s_posLabel = grid->setControl(,,new LabelControl("")); s_vdaLabel = grid->setControl(,,new LabelControl("")); s_mslLabel = grid->setControl(,,new LabelControl("")); s_haeLabel = grid->setControl(,,new LabelControl("")); s_mapLabel = grid->setControl(,,new LabelControl("")); s_resLabel = grid->setControl(,,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(); }
osgEarth基础入门(转载)的更多相关文章
- osgEarth基础入门
osgEarth基础入门 2015年3月21日 16:19 osgEarth是基于三维引擎osg开发的三维数字地球引擎库,在osg基础上实现了瓦片调度插件,可选的四叉树调度插件,更多的地理数据加载插件 ...
- 【转载】20分钟MySQL基础入门
原文:20分钟MySQL基础入门 这里持续更新修正 开始使用 MySQL 为关系型数据库(Relational Database Management System),一个关系型数据库由一个或数个表格 ...
- 王者荣耀是怎样炼成的(二)《王者荣耀》unity安装及使用的小白零基础入门
转载请注明出处:http://www.cnblogs.com/yuxiuyan/p/7535345.html 工欲善其事,必先利其器. 上回书说到,开发游戏用到unity和C#.本篇博客将从零开始做一 ...
- Oracle数据库基础入门《二》Oracle内存结构
Oracle数据库基础入门<二>Oracle内存结构 Oracle 的内存由系统全局区(System Global Area,简称 SGA)和程序全局区(Program Global Ar ...
- Oracle数据库基础入门《一》Oracle服务器的构成
Oracle数据库基础入门<一>Oracle服务器的构成 Oracle 服务器是一个具有高性能和高可靠性面向对象关系型数据库管理系统,也是一 个高效的 SQL 语句执行环境. Oracle ...
- MyBatis基础入门《二十》动态SQL(foreach)
MyBatis基础入门<二十>动态SQL(foreach) 1. 迭代一个集合,通常用于in条件 2. 属性 > item > index > collection : ...
- 卷积神经网络(CNN)学习笔记1:基础入门
卷积神经网络(CNN)学习笔记1:基础入门 Posted on 2016-03-01 | In Machine Learning | 9 Comments | 14935 Vie ...
- MyBatis基础入门《十九》动态SQL(set,trim)
MyBatis基础入门<十九>动态SQL(set,trim) 描述: 1. 问题 : 更新用户表数据时,若某个参数为null时,会导致更新错误 2. 分析: 正确结果: 若某个参数为nul ...
- MyBatis基础入门《十八》动态SQL(if-where)
MyBatis基础入门<十八>动态SQL(if-where) 描述: 代码是在<MyBatis基础入门<十七>动态SQL>基础上进行改造的,不再贴所有代码,仅贴改动 ...
随机推荐
- 善用log日志
#-*- coding:utf-8 -*- import logging logger = logging.getLogger() #定义一个log日志对象 hdlr = logging.FileHa ...
- DedeCMS中实现在顶层banner中显示自定义登录信息
一.需求描述 dedeCMS自带的模板中有互动中心模块,如下图所示: 由于会员登陆对我来说不是网站的重要模块且默认DedeCMS的会员中心模块的初始化很慢,常会显示“正在载入中,请稍候...”, 所以 ...
- Struts2 语法--action
xml的注释: <!--叨叨叨叨--> web.xml注释格式": <?xml version="1.0" encoding="UTF-8&q ...
- HDU 1204 基础DP 非连续字段的最大和
其实这个感觉是一眼题,只不过我真心太菜了. 题目已经告诉你了,有m段,n个数字,那么我们就只需要dp[m][n]即可,然后最后的答案肯定是dp[m][]的那一行,所以其他行都是没有用的,因为我们可以把 ...
- Android的Activity跳转动画各种效果整理
Android的Activity跳转就是很生硬的切换界面.其实Android的Activity跳转可以设置各种动画,本文整理了一些,还有很多动画效果,就要靠我们发挥自己的想象力 大家使用Android ...
- BAT54C 二极管是如何工作的?
这是一个多电源供电的电路:Vcc是正常供电电源(如5V,由市电变换得到),电压大于(Vcc1-Vf),正常供电时二极管不导通:Vcc1是电池供电电源,当Vcc撤掉时,DD1(上边的二极管)导通,由Vc ...
- zf-关于荆州图片链接和弹出页面问题
target="_blank" 属性不能写在div 里 所以我在里面加了个a标签 这个属性的作用就是弹出一个新的页面,不会在原先的页面上换地址 如果 style 的加载图片卸载cs ...
- Struts+Spring+Hibernate的Web应用执行过程
struts1和spring有两种整合的方法 一种是action和spring bean映射:一种是将action交给spring初始化 第一种方式:访问.do的URL->tomcat接收到r ...
- IE6下绝对定位元素父级宽高是奇数,绝对定位元素的right和bottom值会有1个像素的偏差
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 文件I/O的操作实例
1_open.c: #include <sys/types.h> #include <stdio.h> #include <sys/stat.h> #include ...