[osg][osgEarth][原]基于OE自定义*飞行漫游器(初级版)

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

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

类头文件:EarthWalkManipulator.h

#pragma once
//南水之源 20180101
#include <osgGA/CameraManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/Viewpoint>
#include <osgEarth/GeoData> 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<osg::Node> _root; osg::observer_ptr<osg::Node> _node;
osg::observer_ptr<osgEarth::MapNode> _mapNode; osg::ref_ptr<const osgEarth::SpatialReference> _srs; float _speed; //速度 // Internal event stack comprising last two mouse events.
osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t1;
osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t0; };

类实现:EarthWalkManipulator.cpp

//南水之源  20180101
#include "EarthWalkManipulator.h"
#include <osgViewer\Viewer> #include <osgDB\ReadFile>
#include <osg\MatrixTransform> using namespace osgEarth; EarthWalkManipulator::EarthWalkManipulator()
{
_eye = osg::Vec3d(, , );
//_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());
} void
EarthWalkManipulator::home(double unused)
{
_eye = osg::Vec3d(, , );
_speed = 1.0;
} void
EarthWalkManipulator::home(const osgGA::GUIEventAdapter&, osgGA::GUIActionAdapter& us)
{
home(0.0);
us.requestRedraw();
} void
EarthWalkManipulator::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, , , 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() < )//v3EyeLonLat.z()是眼点实际海拔
v3EyeLonLat.z() = ;//将海拔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(, , ), -v3HorizonUp, v3NorthHeadUp);
}
_rotate = mRealAttitude.getRotate();
}
}break;
default:
return false;
}
} bool
EarthWalkManipulator::established()
{
if (_srs.valid() && _mapNode.valid() && _node.valid())
return true; // lock down the observed node:
osg::ref_ptr<osg::Node> 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(, , );
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 <osg/Image>
#include <osgGA/StateSetManipulator>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarth/Registry>
#include <osgEarthSymbology/Geometry>
#include <osgEarthSymbology/GeometryRasterizer>
#include <osgEarthUtil/EarthManipulator>
#include <osgEarthUtil/AutoClipPlaneHandler>
#include <osgEarth/ImageToHeightFieldConverter>
#include <osgEarth/ImageUtils>
#include <osgEarth/FileUtils>
#include <osgEarth/Registry>
#include <osgEarth/MapFrame>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile> #include <osgEarthUtil/ExampleResources>
#include <math.h> #include <osgGA/NodeTrackerManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#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 -;
}
osg::Group* root = new osg::Group();
root->addChild(earthFile); osg::Matrix matrixGood1;
osg::Vec3d geopoint1, geopoint2, geopoint3;
GeoPoint point1(s_mapNode->getMapSRS(), , , );
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<osg::MatrixTransform> pat = new osg::MatrixTransform;
//pat->addChild(cow);
//pat->setMatrix(osg::Matrix::scale(200000, 200000, 200000)); //osg::Matrix maaat2;
//osg::ref_ptr<osg::MatrixTransform> 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(), , , );
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, );
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, );
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('', "earthMan", new EarthManipulator());
keyPtr->addMatrixManipulator('', "trakerMan", nodeTrack);
keyPtr->addMatrixManipulator('', "animationPathMan", animationPathMp);
keyPtr->addMatrixManipulator('', "earthWalkMan", new EarthWalkManipulator());
viewer.setCameraManipulator(keyPtr);
//viewer.setUpViewOnSingleScreen(0); {
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
traits->x = ;
traits->y = ;
traits->width = ;
traits->height = ;
traits->windowDecoration = true;
traits->doubleBuffer = true;
traits->sharedContext = ; osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get()); osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(gc.get());
camera->setViewport(new osg::Viewport(, , 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.按‘4’切换到自定义的漫游器,现在你的视点在球心,啥也看不到

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

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

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

上一篇:【转】asp.net导出数据到Excel的三种方法


下一篇:Android中UI线程与后台线程交互设计的5种方法