[原][osgEarth]添加自由飞行漫游器
Posted 南水之源
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[原][osgEarth]添加自由飞行漫游器相关的知识,希望对你有一定的参考价值。
//头文件里
#define MANIPULATOR_W 0x01
#define MANIPULATOR_A 0x02
#define MANIPULATOR_S 0x04
#define MANIPULATOR_D 0x08
#define MANIPULATOR_R 0x10
#define MANIPULATOR_F 0x20
#define MANIPULATOR_MAX 127
//所有漫游器都必须实现的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); void reFreshSawEarth();//在当前经纬度,姿态回正:1.视点向地面 2.头部向正北 void reFreshSawSkyline(osg::Vec3d eye=osg::Vec3d(0,0,0));//在当前经纬度,头部回正:1.视点中心不变 2.头部向天 osg::Vec3d _eye; //视点位置 osg::Quat _rotate; //旋转姿态 osg::Quat _rotateNew; //旋转姿态 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; //速度 float _speedBase; float _speedMultiple; //速度倍数 float _timerRoll; bool _updateAltitude; bool _updateRollStart; //更新滚转 bool _updateRoll; //更新滚转 bool _openStree; // Internal event stack comprising last two mouse events. osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t1; osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t0;
//cpp文件 void setByMatrix(const osg::Matrixd& matrix)//设置相机的位置姿态矩阵 { gMinpulatorContgrol = 0; _eye = matrix.getTrans(); osg::Vec3d v3Eye, v3Center, v3Up; v3Eye = _eye;//使用相机实际位置 osg::Vec3d v3EyeLonLat; _srs->transformFromWorld(v3Eye, v3EyeLonLat); //先获取当前位置的经纬度,再获取当前正上,正北 osg::Matrix mRealAttitude; if (v3EyeLonLat.z() < 10000)//距离地面1千万米以内需要矫正 //reFreshSawSkyline(); _updateRoll = true; else reFreshSawEarth(); } osg::Matrixd getInverseMatrix() const { osg::Matrix mat; mat.setRotate(-_rotate); mat.preMultTranslate(-_eye); return mat; //return osg::Matrixd::inverse(getMatrix()); }void 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(); } } void reFreshSawSkyline(osg::Vec3d eye) { osg::Vec3d v3Eye; osg::Vec3d v3EyeLonLat; v3Eye = _eye;//使用相机实际位置 if (eye != osg::Vec3d(0, 0, 0)) { v3Eye += eye; } _srs->transformFromWorld(v3Eye, v3EyeLonLat); //先获取当前位置的经纬度,再获取当前正上,正北 if (v3EyeLonLat.z() < 10000)//距离地面1千万米以内需要矫正 { osg::Matrix mRealAttitude; GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z()); gEyeGeo.createLocalToWorld(mRealAttitude); osg::Vec3d v3HorizonUp;//指天向量 gEyeGeo.createWorldUpVector(v3HorizonUp); _rotate.get(mRealAttitude);//要使用当前相机的姿态 osg::Vec3d theEye,v3Center, v3Up; mRealAttitude.getLookAt(theEye, v3Center, v3Up);//获取新的位置和姿态 osg::Vec3d v3Direction = v3Center - theEye; mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), v3Direction, v3HorizonUp); _rotate = mRealAttitude.getRotate(); } //_eye = v3Eye; } void reFreshSawEarth() { osg::Vec3d v3Eye, v3Center, v3Up; 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() < 89.99999 && v3EyeLonLat.y() > -90.0) { mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), -v3HorizonUp, v3NorthHeadUp); } _rotate = mRealAttitude.getRotate(); } bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us) { bool handled = false; switch (ea.getEventType()) { case(osgGA::GUIEventAdapter::FRAME): { if (gMinpulatorContgrol & MANIPULATOR_MAX) { osg::Vec3d 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 RealEye = _eye; osg::Vec3d testHight = v3Direction*100; double _DvalueHight = 0.0; { osg::Vec3d testLonLat1, testLonLat2; _srs->transformFromWorld(RealEye, testLonLat1); RealEye = _eye; osg::Vec3d testEye = RealEye + testHight; _srs->transformFromWorld(testEye, testLonLat2); _DvalueHight = abs(testLonLat2.z() - testLonLat1.z()); if (_DvalueHight < 10)//趋近水平使用水平方向 { testLonLat2.z() = testLonLat1.z(); _srs->transformToWorld(testLonLat2, testEye); v3Direction = testEye - RealEye; v3Direction.normalize(); } } osg::Vec3d v3CrossVector = v3Up^v3Direction; v3CrossVector.normalize(); /*********************************************************/ //计算地面高度 osg::Vec3d v3EyeLonLat; v3Eye = _eye; _srs->transformFromWorld(v3Eye, v3EyeLonLat); double mAltitude = VRE_ENGINE.GetToolsFunc()->GetGeoPointAltitude(v3EyeLonLat.x(), v3EyeLonLat.y()); float height = osg::clampBetween(v3EyeLonLat.z() - mAltitude, 100.0, 1000000.0); _speed = height / 200.0;//根据离地面高度计算当前速度值 RealEye = _eye; if (gMinpulatorContgrol & MANIPULATOR_W) { RealEye += v3Direction * _speed *_speedMultiple * _speedBase; _updateAltitude = false; }if (gMinpulatorContgrol & MANIPULATOR_A) { RealEye += v3CrossVector * _speed *_speedMultiple * _speedBase; _updateAltitude = false; }if (gMinpulatorContgrol & MANIPULATOR_S) { RealEye -= v3Direction * _speed *_speedMultiple * _speedBase; _updateAltitude = false; }if (gMinpulatorContgrol & MANIPULATOR_D) { RealEye -= v3CrossVector * _speed *_speedMultiple * _speedBase; _updateAltitude = false; }if (gMinpulatorContgrol & MANIPULATOR_R) { //_eye += v3Up * _speed *_speedMultiple * _speedBase; v3EyeLonLat.z() += _speed *_speedMultiple * _speedBase; osg::Vec3d newv3Eye; _srs->transformToWorld(v3EyeLonLat, newv3Eye); RealEye = newv3Eye; _updateAltitude = false; }if (gMinpulatorContgrol & MANIPULATOR_F) { //_eye -= v3Up * _speed *_speedMultiple * _speedBase; v3EyeLonLat.z() -= _speed *_speedMultiple * _speedBase; osg::Vec3d newv3Eye; _srs->transformToWorld(v3EyeLonLat, newv3Eye); RealEye = newv3Eye; _updateAltitude = false; } _eye = RealEye; //reFreshSawSkyline(RealEye); } if (_updateRoll) { osg::Vec3d v3Eye; osg::Vec3d v3EyeLonLat; v3Eye = _eye;//使用相机实际位置 _srs->transformFromWorld(v3Eye, v3EyeLonLat); //先获取当前位置的经纬度,再获取当前正上,正北 if (v3EyeLonLat.z() < 10000)//距离地面1千万米以内需要矫正 { osg::Matrix mRealAttitude; GeoPoint gEyeGeo(_srs, v3EyeLonLat.x(), v3EyeLonLat.y(), v3EyeLonLat.z()); gEyeGeo.createLocalToWorld(mRealAttitude); osg::Vec3d v3HorizonUp;//指天向量 gEyeGeo.createWorldUpVector(v3HorizonUp); _rotate.get(mRealAttitude);//要使用当前相机的姿态 osg::Vec3d theEye, v3Center, v3Up; mRealAttitude.getLookAt(theEye, v3Center, v3Up);//获取新的位置和姿态 osg::Vec3d v3Direction = v3Center - theEye; mRealAttitude.makeLookAt(osg::Vec3d(0, 0, 0), v3Direction, v3HorizonUp); _rotateNew = mRealAttitude.getRotate(); _updateRoll = false; _updateRollStart = true; _timerRoll = 0.0; } else { _updateRoll = false; } } if (_updateRollStart) { _timerRoll += 0.01; if (_timerRoll > 1.0) { _timerRoll = 1.0; _updateRollStart = false; } _rotate.slerp(_timerRoll, _rotate, _rotateNew); } if (_updateAltitude) { //每帧调节高度 osg::Vec3d newEye = _eye; osg::Vec3d v3EyeLonLat; _srs->transformFromWorld(newEye, v3EyeLonLat); double _mAltitude = v3EyeLonLat.z(); double mAltitude = VRE_ENGINE.GetToolsFunc()->GetGeoPointAltitude(v3EyeLonLat.x(), v3EyeLonLat.y()) + MANIPULATOR_PERSONVIEWHEIGHT; double interprolationAltitude = mAltitude - _mAltitude; if (interprolationAltitude > 1) { interprolationAltitude /= 10.0; v3EyeLonLat.z() += interprolationAltitude; } else if (interprolationAltitude > 0.1) { v3EyeLonLat.z() += 0.1; } else { _updateAltitude = false; } osg::Vec3d FinalEye; _srs->transformToWorld(v3EyeLonLat, FinalEye); _eye = FinalEye; } }break; case(osgGA::GUIEventAdapter::PUSH): { }break; case(osgGA::GUIEventAdapter::RELEASE): { flushMouseEventStack(); }break; case(osgGA::GUIEventAdapter::DRAG): { if (calcMovement(ea))//根据鼠标在屏幕中的位置调整相机转向 { //reFreshSawSkyline(); _updateRoll = true; us.requestRedraw(); return true; } }; case(osgGA::GUIEventAdapter::SCROLL)://由于已经每帧都调整姿态,所以手动滚动不需要了 { osg::Vec3d 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(); switch (ea.getScrollingMotion()) { case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_UP: { _eye += v3Direction * _speed *_speedMultiple; //reFreshSawSkyline(); _updateRoll = true; }break; case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_DOWN: { _eye -= v3Direction * _speed *_speedMultiple; //reFreshSawSkyline(); _updateRoll = true; }break; } //reFreshSawSkyline(); return true; }break; case (osgGA::GUIEventAdapter::KEYDOWN): { if (ea.getKey() == ‘r‘ || ea.getKey() == ‘R‘)//往头部前进 { gMinpulatorContgrol |= MANIPULATOR_R; } if (ea.getKey() == ‘f‘ || ea.getKey() == ‘F‘)//往尾部后退 { gMinpulatorContgrol |= MANIPULATOR_F; } if (ea.getKey() == ‘w‘ || ea.getKey() == ‘W‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前进 { gMinpulatorContgrol |= MANIPULATOR_W; } if (ea.getKey() == ‘s‘ || ea.getKey() == ‘S‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//后退 { gMinpulatorContgrol |= MANIPULATOR_S; } if (ea.getKey() == ‘a‘ || ea.getKey() == ‘A‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移 { gMinpulatorContgrol |= MANIPULATOR_A; } if (ea.getKey() == ‘d‘ || ea.getKey() == ‘D‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移 { gMinpulatorContgrol |= MANIPULATOR_D; } if (ea.getKey() == ‘-‘ || ea.getKey() == ‘_‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)//减10倍移动速度 { _speedBase /= 10.0; if (_speedBase < 0.1) { _speedBase = 0.1; } } if (ea.getKey() == ‘=‘ || ea.getKey() == ‘+‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)//加10倍移动速度 { _speedBase *= 10.0; if (_speedBase > 1000.0) { _speedBase = 1000.0; } } if (ea.getKey() == ‘h‘ || ea.getKey() == ‘H‘)//在当前经纬度,姿态回正:1.视点向地面 2.头部向正北 { reFreshSawEarth(); } if (ea.getKey() == ‘g‘ || ea.getKey() == ‘G‘)//在当前经纬度,头部回正:1.视点中心不变 2.头部向天 { reFreshSawSkyline(); } if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_R) { _speedMultiple = 10.0; } }break; case (osgGA::GUIEventAdapter::KEYUP): { if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_R) { _speedMultiple = 1.0; } if (ea.getKey() == ‘a‘ || ea.getKey() == ‘A‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移 { gMinpulatorContgrol &= ~MANIPULATOR_A; _updateAltitude = true; } if (ea.getKey() == ‘d‘ || ea.getKey() == ‘D‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移 { gMinpulatorContgrol &= ~MANIPULATOR_D; _updateAltitude = true; } if (ea.getKey() == ‘w‘ || ea.getKey() == ‘W‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)//前进 { gMinpulatorContgrol &= ~MANIPULATOR_W; _updateAltitude = true; } if (ea.getKey() == ‘q‘ || ea.getKey() == ‘Q‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)//往头部前进 { gMinpulatorContgrol &= ~MANIPULATOR_R; _updateAltitude = true; } if (ea.getKey() == ‘e‘ || ea.getKey() == ‘E‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)//往尾部后退 { gMinpulatorContgrol &= ~MANIPULATOR_F; _updateAltitude = true; } if (ea.getKey() == ‘s‘ || ea.getKey() == ‘S‘ || ea.getKey() == osgGA::GUIEventAdapter::KEY_Down)//后退 { gMinpulatorContgrol &= ~MANIPULATOR_S; _updateAltitude = true; } }break; default: break; } return handled; }
以上是关于[原][osgEarth]添加自由飞行漫游器的主要内容,如果未能解决你的问题,请参考以下文章
[原][译][osg][osgEarth]飞行模拟软件JSBSim的操作(FGFCS类)
[osg][osgEarth]EarthManipulator关于oe漫游器的handle部分解读
[原][译]关于osgEarth::VirtualProgram
[原][译]关于osgEarth::VirtualProgram