博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)
阅读量:6287 次
发布时间:2019-06-22

本文共 14211 字,大约阅读时间需要 47 分钟。

由于受够了OE的漫游器,想搞个可以在全球飞行的漫游器,所以就做了一个:

请无视我的起名规则······

类头文件:EarthWalkManipulator.h

#pragma once//南水之源  20180101#include 
#include
#include
#include
class EarthWalkManipulator :public osgGA::CameraManipulator{public: EarthWalkManipulator(); ~EarthWalkManipulator(); //所有漫游器都必须实现的4个纯虚函数 virtual void setByMatrix(const osg::Matrixd& matrix) {} //设置相机的位置姿态矩阵 virtual void setByInverseMatrix(const osg::Matrixd& matrix) {} //设置相机的视图矩阵 virtual osg::Matrixd getMatrix() const; //获取相机的姿态矩阵 virtual osg::Matrixd getInverseMatrix() const; //获取相机的视图矩阵 //所有操作在这里响应 virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us); // Attach a node to the manipulator. virtual void setNode(osg::Node*); virtual osg::Node* getNode(); bool established(); /** * Sets the camera position, optionally moving it there over time. */ //virtual void setViewpoint(const osgEarth::Viewpoint& vp, double duration_s = 0.0); virtual void home(double /*unused*/); virtual void home(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us); void addMouseEvent(const osgGA::GUIEventAdapter& ea); bool calcMovement(const osgGA::GUIEventAdapter& ea);protected: osg::Vec3 _eye; //视点位置 osg::Quat _rotate; //旋转姿态 osg::ref_ptr
_root; osg::observer_ptr
_node; osg::observer_ptr
_mapNode; osg::ref_ptr
_srs; float _speed; //速度 // Internal event stack comprising last two mouse events. osg::ref_ptr
_ga_t1; osg::ref_ptr
_ga_t0;};

类实现:EarthWalkManipulator.cpp

//南水之源  20180101#include "EarthWalkManipulator.h"#include 
#include
#include
using namespace osgEarth;EarthWalkManipulator::EarthWalkManipulator(){ _eye = osg::Vec3d(0, 0, 0); //_rotate = osg::Quat(-osg::PI_2, osg::X_AXIS); _speed = 1.0;}EarthWalkManipulator::~EarthWalkManipulator(){}//获取相机的姿态矩阵 osg::Matrixd EarthWalkManipulator::getMatrix() const{ osg::Matrix mat; mat.setRotate(_rotate);//先旋转 mat.postMultTranslate(_eye);//再平移 return mat;}osg::Matrixd EarthWalkManipulator::getInverseMatrix() const{ osg::Matrix mat; mat.setRotate(-_rotate); mat.preMultTranslate(-_eye); return mat; //return osg::Matrixd::inverse(getMatrix());}voidEarthWalkManipulator::home(double unused){ _eye = osg::Vec3d(0, 0, 0); _speed = 1.0;}voidEarthWalkManipulator::home(const osgGA::GUIEventAdapter&, osgGA::GUIActionAdapter& us){ home(0.0); us.requestRedraw();}voidEarthWalkManipulator::setNode(osg::Node* node){ // you can only set the node if it has not already been set, OR if you are setting // it to NULL. (So to change it, you must first set it to NULL.) This is to prevent // OSG from overwriting the node after you have already set on manually. if (node == 0L || !_node.valid()) { _root = node; _node = node; _mapNode = 0L; _srs = 0L; established(); osg::Matrix matrixGood1; GeoPoint point1(_srs, 0, 0, 10000.0); point1.createLocalToWorld(matrixGood1); _eye = matrixGood1.getTrans(); osg::Vec3d worldup; point1.createWorldUpVector(worldup); osg::Matrix mat; matrixGood1.getRotate().get(mat); osg::Vec3d eye, center, up; mat.getLookAt(eye, center, up); mat.makeLookAt(eye, -worldup, up); _rotate = mat.getRotate(); }}osg::Node*EarthWalkManipulator::getNode(){ return _node.get();}bool EarthWalkManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us){ switch (ea.getEventType()) { case(osgGA::GUIEventAdapter::FRAME): { if (calcMovement(ea))//根据鼠标在屏幕中的位置调整相机转向 us.requestRedraw(); return true; }break; case(osgGA::GUIEventAdapter::SCROLL): { osg::Quat qat; osg::Matrix mat; _rotate.get(mat); osg::Vec3d eye, center, up; mat.getLookAt(eye, center, up); osg::Vec3d dirction = center - eye; dirction.normalize(); up.normalize(); osg::Vec3d cross = dirction^up; cross.normalize(); cross *= 0.01; switch (ea.getScrollingMotion()) { case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_UP://逆时针旋转相机 { mat = osg::Matrix::lookAt(eye, center, up + cross); _rotate = mat.getRotate(); }break; case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_DOWN://顺时针旋转相机 { mat = osg::Matrix::lookAt(eye, center, up - cross); _rotate = mat.getRotate(); }break; } return true; }break; case (osgGA::GUIEventAdapter::KEYDOWN): { osg::Vec3 v3Direction; //视点方向 osg::Matrix mCameraQuat; osg::Vec3d v3Eye, v3Center, v3Up; _rotate.get(mCameraQuat); mCameraQuat.getLookAt(v3Eye, v3Center, v3Up);//这里的v3Eye不是实际相机的位置,而是0,0,0 v3Direction = v3Center - v3Eye; v3Direction.normalize(); osg::Vec3d v3CrossVector = v3Up^v3Direction; v3CrossVector.normalize(); if (ea.getKey() == 'w' || ea.getKey() == 'W' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前进 { _eye += v3Direction * _speed; } if (ea.getKey() == 's' || ea.getKey() == 'S' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//后退 { _eye -= v3Direction * _speed; } if (ea.getKey() == 'a' || ea.getKey() == 'A' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移 { _eye += v3CrossVector * _speed; } if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移 { _eye -= v3CrossVector * _speed; } if (ea.getKey() == '-' || ea.getKey() == '_' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L)//减10倍移动速度 { _speed /= 10.0; if (_speed < 1.0) { _speed = 1.0; } } if (ea.getKey() == '=' || ea.getKey() == '+' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L)//加10倍移动速度 { _speed *= 10.0; if (_speed > 100000.0) { _speed = 100000.0; } } if (ea.getKey() == 'h' || ea.getKey() == 'H')//在当前经纬度,姿态回正:1.视点向地面 2.头部向正北 { v3Eye = _eye;//使用相机实际位置 osg::Vec3d v3EyeLonLat; _srs->transformFromWorld(v3Eye, v3EyeLonLat); //先获取当前位置的经纬度,再获取当前正上,正北 osg::Matrix mRealAttitude; if (v3EyeLonLat.z() < 0)//v3EyeLonLat.z()是眼点实际海拔 v3EyeLonLat.z() = 100;//将海拔0以下的物体拉到海拔100米 GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z()); gEyeGeo.createLocalToWorld(mRealAttitude); osg::Vec3d v3HorizonUp;//指天向量 gEyeGeo.createWorldUpVector(v3HorizonUp); _eye = mRealAttitude.getTrans(); mRealAttitude.getLookAt(v3Eye, v3Center, v3Up);//获取新的位置和姿态 osg::Matrix mDeviationAttitude;//向北位置偏移0.00001纬度,为了计算正北方向 GeoPoint gDeviationEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y() + 0.00001, v3EyeLonLat.z()); gDeviationEyeGeo.createLocalToWorld(mDeviationAttitude); osg::Vec3d v3DeviationNorthPoint = mDeviationAttitude.getTrans(); osg::Vec3d v3NorthHeadUp = v3DeviationNorthPoint - v3Eye; v3NorthHeadUp.normalize();//指北向量 //if (v3EyeLonLat.y() < 90.0 && v3EyeLonLat.y() > 0.0)//没研究出为什么北半球和南半球需要相反,但实际使用没问题 //{ // mRealAttitude.makeLookAt(osg::Vec3d(0,0,0), -v3HorizonUp, -v3NorthHeadUp); //} if (v3EyeLonLat.y() < 89.99999 && v3EyeLonLat.y() > -90.0) { mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), -v3HorizonUp, v3NorthHeadUp); } _rotate = mRealAttitude.getRotate(); } }break; default: return false; }}boolEarthWalkManipulator::established(){ if (_srs.valid() && _mapNode.valid() && _node.valid()) return true; // lock down the observed node: osg::ref_ptr
safeNode; if (!_node.lock(safeNode)) return false; // find a map node or fail: _mapNode = osgEarth::MapNode::findMapNode(safeNode.get()); if (!_mapNode.valid()) return false; // Cache the SRS. _srs = _mapNode->getMapSRS(); return true;}void EarthWalkManipulator::addMouseEvent(const osgGA::GUIEventAdapter& ea){ _ga_t1 = _ga_t0; _ga_t0 = &ea;}bool EarthWalkManipulator::calcMovement(const osgGA::GUIEventAdapter& ea){ osg::Quat qat; osg::Matrix mat; _rotate.get(mat); osg::Vec3d eye, center, up; mat.getLookAt(eye, center, up); osg::Vec3d dirction = center - eye; dirction.normalize(); up.normalize(); osg::Vec3d cross = dirction^up; cross.normalize(); double x1 = ea.getXnormalized(); double y1 = ea.getYnormalized(); osg::Vec3d deviation(0, 0, 0); if (x1 > 0.1) { deviation += cross * 0.001; } else if (x1 < -0.1) { deviation -= cross * 0.001; } if (y1 > 0.1) { deviation += up * 0.001; } else if (y1 < -0.1) { deviation -= up * 0.001; } mat = osg::Matrix::lookAt(eye, deviation + center, up); _rotate = mat.getRotate(); return true;}

使用:main.cpp

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "EarthWalkManipulator.h"using namespace osgEarth;using namespace osgEarth::Util;using namespace osgEarth::Symbology;int main(int argc, char** argv){ //正常的.earth文件加载 osg::ArgumentParser arguments(&argc, argv); osgViewer::Viewer viewer; MapNode* s_mapNode = 0L; osg::Node* earthFile = MapNodeHelper().load(arguments, &viewer); if (earthFile) s_mapNode = MapNode::get(earthFile); if (!s_mapNode) { OE_WARN << "Unable to load earth file." << std::endl; return -1; } osg::Group* root = new osg::Group(); root->addChild(earthFile); osg::Matrix matrixGood1; osg::Vec3d geopoint1, geopoint2, geopoint3; GeoPoint point1(s_mapNode->getMapSRS(), 0, 0, 1000); point1.createLocalToWorld(matrixGood1); //matrixGood1.getLookAt(geopoint1, geopoint2, geopoint3); //osg::Vec3 _vector = geopoint1 - geopoint2; //添加一头牛,查看位置是否正确 //osg::Node* cow = osgDB::readNodeFile("D:\\temp\\node\\cow.osg"); // //osg::ref_ptr
pat = new osg::MatrixTransform; //pat->addChild(cow); //pat->setMatrix(osg::Matrix::scale(200000, 200000, 200000)); //osg::Matrix maaat2; //osg::ref_ptr
pat2 = new osg::MatrixTransform; //pat2->setMatrix(osg::Matrix::rotate(matrixGood1.getRotate())* // osg::Matrix::translate(matrixGood1.getTrans())); //pat2->addChild(pat); //root->addChild(pat2); viewer.setSceneData(root); //模型漫游器 osgGA::NodeTrackerManipulator* nodeTrack = new osgGA::NodeTrackerManipulator(); nodeTrack->setTrackNode(root); /*************************************动画漫游器**下*********************************/ GeoPoint gPoint1(s_mapNode->getMap()->getSRS(), 32, 118, 400); osg::Matrix gMatrix1; gPoint1.createLocalToWorld(gMatrix1);//获取当前地球上的正确姿态 //由于相机,自身向下看,所以在当前姿态基础上抬起60度,注意是前乘! gMatrix1.preMultRotate(osg::Quat(osg::DegreesToRadians(60.0), osg::X_AXIS)); osg::Quat q1; gMatrix1.get(q1);//获取当前矩阵姿态 osg::Vec3d vPos1 = gMatrix1.getTrans();//获取当前矩阵位置 GeoPoint gPoint2(s_mapNode->getMap()->getSRS(), 32.01, 118.01, 400); osg::Matrix gMatrix2; gPoint2.createLocalToWorld(gMatrix2); gMatrix2.preMultRotate(osg::Quat(osg::DegreesToRadians(60.0), osg::X_AXIS)); osg::Quat q2; gMatrix2.get(q2); osg::Vec3d vPos2 = gMatrix2.getTrans(); GeoPoint gPoint3(s_mapNode->getMap()->getSRS(), 32.02, 118.02, 400); osg::Matrix gMatrix3; gPoint3.createLocalToWorld(gMatrix3); osg::Quat q3; gMatrix3.get(q3); osg::Vec3d vPos3 = gMatrix3.getTrans(); //获取相机之后再顺旋转,其实是错误的姿态 osg::Quat qbuf(osg::DegreesToRadians(60.0), osg::X_AXIS); q3 *= qbuf; //使用动画漫游器 osgGA::AnimationPathManipulator *animationPathMp = new osgGA::AnimationPathManipulator(); //给动画漫游器添加关键帧 osg::AnimationPath* _animationPath = new osg::AnimationPath; _animationPath->insert(0.0, osg::AnimationPath::ControlPoint(vPos1, q1));//姿态正确 _animationPath->insert(3.0, osg::AnimationPath::ControlPoint(vPos2, q2));//姿态正确 _animationPath->insert(6.0, osg::AnimationPath::ControlPoint(vPos3, q3));//姿态错误! _animationPath->setLoopMode(osg::AnimationPath::SWING);//设置路径是回摆的 animationPathMp->setAnimationPath(_animationPath); /*************************************动画漫游器**上*********************************/ //这里添加三个漫游器,使用一个控制漫游器选择,按键盘‘3’就切换到路径动画漫游器了 osgGA::KeySwitchMatrixManipulator* keyPtr = new osgGA::KeySwitchMatrixManipulator(); keyPtr->addMatrixManipulator('1', "earthMan", new EarthManipulator()); keyPtr->addMatrixManipulator('2', "trakerMan", nodeTrack); keyPtr->addMatrixManipulator('3', "animationPathMan", animationPathMp); keyPtr->addMatrixManipulator('4', "earthWalkMan", new EarthWalkManipulator()); viewer.setCameraManipulator(keyPtr); //viewer.setUpViewOnSingleScreen(0); { osg::ref_ptr
traits = new osg::GraphicsContext::Traits; traits->x = 40; traits->y = 40; traits->width = 600; traits->height = 480; traits->windowDecoration = true; traits->doubleBuffer = true; traits->sharedContext = 0; osg::ref_ptr
gc = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr
camera = new osg::Camera; camera->setGraphicsContext(gc.get()); camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height)); GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT; camera->setDrawBuffer(buffer); camera->setReadBuffer(buffer); // add this slave camera to the viewer, with a shift left of the projection matrix viewer.addSlave(camera.get()); } while(!viewer.done()) viewer.frame(); return 1;}

 

由于是初级版,所以有些操作还是比较反人类···

运行起来是用其他漫游器告诉你:能看到个地球

开始操作:

1.按‘4’切换到自定义的漫游器,现在你的视点在球心,啥也看不到

2.按‘s’或者‘下’,再按‘h’现在应该是在地球表面了(别问为什么会需要这么SB的操作···)

3.然后自己体验吧(不要晕了···)

后期会更新一个有良好操作的版本

 

转载地址:http://ynhva.baihongyu.com/

你可能感兴趣的文章
Mysql,Case When,Case多个字段
查看>>
56、LVS NAT模型实战
查看>>
互联网、因特网、万维网、局域网、广域网的区别
查看>>
原创:新手布局福音!微信小程序使用flex的一些基础样式属性
查看>>
MYSQL 编译参数
查看>>
Sharding与数据库分区(Partition)的区别
查看>>
bandit系列0--10
查看>>
文本过滤之grep,egreo及fgrep 三剑客及正则表达式
查看>>
实现Singleton模式在C#
查看>>
服务发现:Zookeeper vs etcd vs Consul
查看>>
微软企业项目管理系统技术研讨会
查看>>
Kafka设计篇之消息传输的事务定义
查看>>
我的友情链接
查看>>
使用windows 7 系统安装盘 DOS普通用户提权为管理员
查看>>
老男孩教育每日一题第115天:如何在centos 6下面实现命令补全?效果如下
查看>>
国内可用的yum源
查看>>
linux df -h 命令卡住 解决方法
查看>>
搭建高可用mongodb集群(三)—— 深入副本集内部机制
查看>>
laravel学习资源
查看>>
使用超链接
查看>>