[osg][osgEarth][原]基于OE自定义自由飞行漫游器(第二版)
在初级版上,进行新的漫游方式调整
头文件:
#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(); virtual void computeHomePosition(); /**
* 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); void flushMouseEventStack();
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; //速度
bool _transversal; //横移
// Internal event stack comprising last two mouse events.
osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t1;
osg::ref_ptr<const osgGA::GUIEventAdapter> _ga_t0;
};
实现:
//南水之源 20180101
#include "EarthWalkManipulator.h"
#include <osgViewer\Viewer> #include <osgDB\ReadFile>
#include <osg\MatrixTransform> using namespace osgEarth; EarthWalkManipulator::EarthWalkManipulator()
{
_eye = osg::Vec3d(, , );
_speed = 1.0;
_transversal = false;
} 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::computeHomePosition()
{
} void
EarthWalkManipulator::home(double unused)
{
//经纬度0,0点姿态
//_eye = osg::Vec3d(20078236, 0, 0);
//_speed = 10.0;
//osg::Matrix mHomeAttitude = osg::Matrix::lookAt(osg::Vec3d(0,0,0),osg::Vec3d(-1,0,0), osg::Vec3d(0,0,1)); //使用中国南海上空的姿态
_eye = osg::Vec3d(-, , );
_speed = 10.0;
osg::Matrix mHomeAttitude = osg::Matrix::lookAt(osg::Vec3d(, , ), osg::Vec3d(0.4, -0.77, -0.495), osg::Vec3d(0.228, -0.439, 0.869)); _rotate = mHomeAttitude.getRotate();
flushMouseEventStack();
} 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):
{
osg::Vec3d v3Eye, v3Center, v3Up;
v3Eye = _eye;//使用相机实际位置
osg::Vec3d v3EyeLonLat;
_srs->transformFromWorld(v3Eye, v3EyeLonLat); if (!_transversal && v3EyeLonLat.z() < )//距离地面1千万米以内需要矫正
{
//先获取当前位置的经纬度,再获取当前正上,正北
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); _rotate.get(mRealAttitude);//要使用当前相机的姿态
mRealAttitude.getLookAt(v3Eye, v3Center, v3Up);//获取新的位置和姿态 osg::Vec3 v3Direction = v3Center - v3Eye;
mRealAttitude.makeLookAt(osg::Vec3d(, , ), v3Direction, v3HorizonUp);
float fCosAngle = (v3Direction*v3HorizonUp / v3Direction.length()) / v3HorizonUp.length();
if(abs(fCosAngle) < 0.9)//在cos@小于0.9的时候矫正
_rotate = mRealAttitude.getRotate();
} }break;
case(osgGA::GUIEventAdapter::PUSH):
{
}break;
case(osgGA::GUIEventAdapter::RELEASE):
{
flushMouseEventStack();
}break;
case(osgGA::GUIEventAdapter::DRAG):
{
if (calcMovement(ea))//根据鼠标在屏幕中的位置调整相机转向
{
us.requestRedraw();
return true;
}
};
case(osgGA::GUIEventAdapter::SCROLL)://由于已经每帧都调整姿态,所以手动滚动不需要了
{
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();
switch (ea.getScrollingMotion())
{
case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_UP://逆时针旋转相机
{
_eye += v3Direction * _speed;
}break;
case osgGA::GUIEventAdapter::ScrollingMotion::SCROLL_DOWN://顺时针旋转相机
{
_eye -= v3Direction * _speed;
}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() == 'q' || ea.getKey() == 'Q' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)//往头部前进
{
_eye += v3Up * _speed;
}
if (ea.getKey() == 'e' || ea.getKey() == 'E' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)//往尾部后退
{
_eye -= v3Up * _speed;
}
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)//左移
{
_transversal = true;
_eye += v3CrossVector * _speed;
}
if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移
{
_transversal = true;
_eye -= v3CrossVector * _speed;
}
if (ea.getKey() == '-' || ea.getKey() == '_')//减10倍移动速度
{
_speed /= 10.0;
if (_speed < 1.0)
{
_speed = 1.0;
}
}
if (ea.getKey() == '=' || ea.getKey() == '+')//加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() < 89.99999 && v3EyeLonLat.y() > -90.0)
{
mRealAttitude.makeLookAt(osg::Vec3d(, , ), -v3HorizonUp, v3NorthHeadUp);
}
_rotate = mRealAttitude.getRotate();
}
if (ea.getKey() == 'g' || ea.getKey() == 'G')//在当前经纬度,头部回正: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); _rotate.get(mRealAttitude);//要使用当前相机的姿态
mRealAttitude.getLookAt(v3Eye, v3Center, v3Up);//获取新的位置和姿态 osg::Vec3 v3Direction = v3Center - v3Eye;
mRealAttitude.makeLookAt(osg::Vec3d(, , ), v3Direction, v3HorizonUp);
_rotate = mRealAttitude.getRotate();
}
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L)
{
_speed = 1000000.0;
}
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L)
{
_speed = 100000.0;
}
}break;
case (osgGA::GUIEventAdapter::KEYUP):
{
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L)
{
_speed = 1000.0;
}
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L )
{
_speed = 100.0;
} if (ea.getKey() == 'a' || ea.getKey() == 'A' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)//左移
{
_transversal = false;
}
if (ea.getKey() == 'd' || ea.getKey() == 'D' || ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)//右移
{
_transversal = false;
}
}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;
} void EarthWalkManipulator::flushMouseEventStack()
{
_ga_t1 = NULL;
_ga_t0 = NULL;
} 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(); _ga_t1 = _ga_t0;
_ga_t0 = &ea; if (_ga_t0.get() == NULL || _ga_t1.get() == NULL) return false; double x1 = _ga_t0->getXnormalized() - _ga_t1->getXnormalized();
double y1 = _ga_t0->getYnormalized() - _ga_t1->getYnormalized(); osg::Vec3d deviation(, , );
deviation += cross * x1;
deviation += up * y1; mat = osg::Matrix::lookAt(eye, deviation + center, up);
_rotate = mat.getRotate(); return true;
}
[osg][osgEarth][原]基于OE自定义自由飞行漫游器(第二版)的更多相关文章
- [osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)
由于受够了OE的漫游器,想搞个可以在全球飞行的漫游器,所以就做了一个: 请无视我的起名规则······ 类头文件:EarthWalkManipulator.h #pragma once //南水之源 ...
- [原][osgEarth]添加自由飞行漫游器
//头文件里 #define MANIPULATOR_W 0x01#define MANIPULATOR_A 0x02#define MANIPULATOR_S 0x04#define MANIPUL ...
- 基于jQuery仿QQ音乐播放器网页版代码
基于jQuery仿QQ音乐播放器网页版代码是一款黑色样式风格的网页QQ音乐播放器样式代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div class="m ...
- [原][osg][osgEarth]EarthManipulator关于oe漫游器的handle部分解读以及修改(仿照谷歌,修改oe漫游器中focal(视角切换)功能 续 二)
bool EarthManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) ...
- [原][osg][osgEarth]关于在OE中使用物理引擎的调研
关于物理引擎旋转的一些整理 参考文档 http://blog.wolfire.com/2010/03/Comparing-ODE-and-Bullet 介绍ODE和bullet的利弊 http://s ...
- [osg][osgEarth][osgGA][原] EarthManipulator------基于oe的相机漫游器(浅析)
知识基础:osg漫游器基础 class OSGEARTHUTIL_EXPORT EarthManipulator : public osgGA::CameraManipulator EarthMani ...
- [osgearth][原]仿照谷歌,修改oe漫游器中focal(视角切换)功能
oe中的视角加速感觉好奇怪,就仿照谷歌方式去改了. 先看看oe原来的漫游器改变视角的接口: void CameraManipulator::setViewpoint(const Viewpoint&a ...
- [osg][原]自定义osgGA漫游器
相机矩阵变化基础:http://blog.csdn.net/popy007/article/details/5120158 osg漫游器原理:http://blog.csdn.net/csxiaosh ...
- 最简单的基于DirectShow的示例:视频播放器自定义版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
随机推荐
- 管理mycat命令详解
mycat监听两个端口,分别为8066和9066:mycat服务默认的数据端口是8066,而9066端口则是mycat管理端口,用于管理mycat的整个集群状态.监听的端口可以在server.xml配 ...
- Docker学习笔记之运行和管理容器
0x00 概述 容器是基于容器技术所建立和运行的轻量级应用运行环境,它是 Docker 封装和管理应用程序或微服务的“集装箱”.在 Docker 中,容器算是最核心的部分了,掌握容器的操作也是 Doc ...
- RadioButton在数据列表中实现单选功能
在服务器端动态生成的name总是不断变化,故需手动实现单选 ; <html xmlns="http://www.w3.org/1999/xhtml"> <head ...
- 快速阅读《QT5.9 c++开发指南》2
1.sample2_2 信号和槽 MFC中最让人印象深刻的就是"消息映射",这里有理由相信,"信号和槽"是这种功能的发扬和扩展.通过简单的 connect(ui ...
- ODAC(V9.5.15) 学习笔记(八)TOraScript
名称 类型 说明 DataSet 如果脚本中返回了数据结果,则通过该数据集进行获取 Delimiter string 脚本语句之间的分隔符 EndLine Integer 脚本中最后一行的行号 End ...
- ODAC(V9.5.15) 学习笔记(三)TOraSession(3)
3. 选项 TOraSession的Options有如下内容 名称 类型 说明 CharLength TCharLength 单个字符的长度,缺省0,表示从服务器获取对应的字符集中单个字符长度 Cha ...
- 2015,3,10 1(南阳理工ACM)
描述输入三个字符(可以重复)后,按各字符的ASCII码从小到大的顺序输出这三个字符. 输入 第一行输入一个数N,表示有N组测试数据.后面的N行输入多组数据,每组输入数据都是占一行,有三个字符组成, ...
- JXOI2018守卫 区间DP
链接 https://loj.ac/problem/2545 思路 f[i][j]表示i到j区间的最小监视人数 可以预处理出来g[i][j],表示i能否监视到j (其实预处理的关系不大,完全可以直接判 ...
- POJ 1191 棋盘分割(区间DP)题解
题意:中文题面 思路:不知道直接暴力枚举所有情况行不行... 我们可以把答案转化为 所以答案就是求xi2的最小值,那么我们可以直接用区间DP来写.设dp[x1][y1][x2][y2][k]为x1 y ...
- Shiro源码分析
1.入口类:AbstractAuthenticator 用户输入的登录信息经过其authenticate方法: public final AuthenticationInfo authenticate ...