• 场景交互与场景漫游-场景漫游器(6)


     场景漫游

            在浏览整个三维场景时,矩阵变换是非常关键的,通过适当的矩阵变换可以获得各种移动或者渲染效果。因此,在编写自己的场景漫游操作器时,如何作出符合逻辑的矩阵操作器是非常重要的,但这对初学者来说还是有一定难度的。在 OSG 中,已经提供了一个矩阵操作器的康的接口,即为osgGA::MatrixManipulator。在前面讲到的很多操作器都继承自osgGA:MatrixManipulator

    编写一个自己的操作器,需要处理的主要问题如下:

    • 鼠标或键盘按下时该怎么处理?
    • 如何得到当前的矩阵及其逆矩阵?
    • 如何控制当前的速度?
    • 是否开启碰撞检测?
    • 如何设置出生位置?

            这些都是做一些简单场景漫游时需要面对的问题。只有充分理解了读者需要解决什么,才会知道解决需要做什么,至于怎么做只是时间问题,只要读者肯花时间研究源代码,也可以解决。编写自定义场景漫游操作器的主要步骤如下:

    • 编写一个继承自osgGA:GUIEventHandler 类的新类
    • 重载handlel()及相关矩阵变换函数,注意在handle()中添加合适的事件处理函数,并指定执行相关的动作。
    • 进行碰撞检测。碰撞检测的方法有很多,如果读者想达到精确的碰撞检测,可以使用一些经典的物理学引擎如牛顿引擎。在第 8.2.5节的示例中只是使用一种非常简单的碰撞检测方法如图8-17所示:

    图8-17简单碰撞检测

    • 关联该操作器到当前视图场景中,没有这一步,在OSG 的场中是不会自动启动该操作器的,关联很简单,代码如下:

            viewer->setCameraManipulator(camera):;

            通过学习上面的简单步骤,相信读者也可以完成一个操作器的编写,只要明白原理是如何实现的,结果或许就不那么重要了。下面还是看一下示例,不然可能会不懂其中的一些细节。

    自定义操作器场景漫游示例

            自定义操作器场景漫游示例的代码如程序清单 8-8 所示

    1. /******************************************* 自定义漫游器示例 *************************************/
    2. /*
    3. 编码时遇到无法打开文件osgGA / MatrixManipulator错误,
    4. 无法打开包括文件 : “osgGA / MatrixManipulator” : No such file or directory
    5. 解决办法:
    6. 新版本中已经改名为CameraManipulator
    7. 将MatrixManipulator改成CameraManipulator即可
    8. 并且要#include
    9. */
    10. class TravelManipulator : public osgGA::CameraManipulator
    11. {
    12. public:
    13. // 构造函数
    14. TravelManipulator();
    15. // 析构函数
    16. ~TravelManipulator(void);
    17. // 把漫游加入到场景中
    18. static TravelManipulator *TravelToScene(osg::ref_ptr viewer);
    19. private:
    20. osg::ref_ptr m_pHostViewer;
    21. // 移动速度
    22. float m_fMoveSpeed;
    23. osg::Vec3 m_vPosition;
    24. osg::Vec3 m_vRotation;
    25. public:
    26. // 鼠标左键是否按下
    27. bool m_bLeftButtonDown;
    28. // 鼠标XY
    29. float m_fpushY;
    30. float m_fpushX;
    31. // 设置矩阵
    32. virtual void setByMatrix(const osg::Matrixd &matrix);
    33. // 设置逆矩阵
    34. virtual void setByInverseMatrix(const osg::Matrixd &matrix);
    35. // 得到矩阵
    36. virtual osg::Matrixd getMatrix(void) const;
    37. // 得到逆矩阵
    38. virtual osg::Matrixd getInverseMatrix(void)const;
    39. // 事件处理函数
    40. virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa);
    41. // 屏幕角度
    42. float m_fAngle;
    43. // 位置变换函数
    44. void ChangePosition(osg::Vec3 &delta);
    45. // 碰撞检测是否开启
    46. bool m_bPeng;
    47. // 设置速度
    48. float getSpeed();
    49. void setSpeed(float &);
    50. // 设置起始位置
    51. void SetPosition(osg::Vec3 &position);
    52. osg::Vec3 GetPosition();
    53. };
    54. void travelManipulator_8_8(const string &strDataFolder);
    55. /******************************************* 自定义漫游器示例 *************************************/
    56. TravelManipulator::TravelManipulator()
    57. :m_fMoveSpeed(1.0f)
    58. , m_bLeftButtonDown(false)
    59. , m_fpushX(0)
    60. , m_fAngle(2.5)
    61. , m_bPeng(true)
    62. , m_fpushY(0)
    63. {
    64. m_vPosition = osg::Vec3(-22.0f, -274.0f, 100.0f);
    65. m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);
    66. }
    67. TravelManipulator::~TravelManipulator()
    68. {
    69. }
    70. // 把漫游器加入到场景中
    71. TravelManipulator* TravelManipulator::TravelToScene(osg::ref_ptr viewer)
    72. {
    73. TravelManipulator *camera = new TravelManipulator;
    74. viewer->setCameraManipulator(camera);
    75. camera->m_pHostViewer = viewer;
    76. return camera;
    77. }
    78. // 设置矩阵
    79. void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)
    80. {
    81. }
    82. // 设置逆矩阵
    83. void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
    84. {
    85. }
    86. // 得到矩阵
    87. osg::Matrixd TravelManipulator::getMatrix()const
    88. {
    89. osg::Matrixd mat;
    90. mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),
    91. m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),
    92. m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
    93. return mat * osg::Matrixd::translate(m_vPosition);
    94. }
    95. // 得到逆矩阵
    96. osg::Matrixd TravelManipulator::getInverseMatrix()const
    97. {
    98. osg::Matrixd mat;
    99. mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),
    100. m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),
    101. m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));
    102. return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));
    103. }
    104. // 事件处理函数
    105. bool TravelManipulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
    106. {
    107. // 得到鼠标的位置
    108. float mouseX = ea.getX();
    109. float mouseY = ea.getY();
    110. int iEventType = ea.getEventType();
    111. switch (iEventType)
    112. {
    113. case (osgGA::GUIEventAdapter::KEYDOWN) :
    114. {
    115. // 空格键
    116. if (ea.getKey() == 0x20)
    117. {
    118. //us.requestRedraw();
    119. //us.requestContinuousUpdate(false);
    120. return true;
    121. }
    122. // 上移动
    123. if (ea.getKey() == 0xFF50)
    124. {
    125. ChangePosition(osg::Vec3(0, 0, m_fMoveSpeed));
    126. return true;
    127. }
    128. // 下移动
    129. if (ea.getKey() == 0xFF57)
    130. {
    131. ChangePosition(osg::Vec3(0, 0, -m_fMoveSpeed));
    132. return true;
    133. }
    134. // 增加速度
    135. if (ea.getKey() == 0x2B)
    136. {
    137. m_fMoveSpeed += 1.0f;
    138. return true;
    139. }
    140. // 减少速度
    141. if (ea.getKey() == 0x2D)
    142. {
    143. m_fMoveSpeed -= 1.0f;
    144. if (m_fMoveSpeed < 1.0f)
    145. {
    146. m_fMoveSpeed = 1.0f;
    147. }
    148. return true;
    149. }
    150. // 前进
    151. if (ea.getKey() == 0xFF52 || ea.getKey() == 0x57 || ea.getKey() == 0x77)//up
    152. {
    153. ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
    154. ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));
    155. return true;
    156. }
    157. // 后退
    158. if (ea.getKey() == 0xFF54 || ea.getKey() == 0x53 || ea.getKey() == 0x73)//down
    159. {
    160. ChangePosition(osg::Vec3(0, -m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
    161. ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));
    162. return true;
    163. }
    164. // 向左
    165. if (ea.getKey() == 0x41 || ea.getKey() == 0x61)
    166. {
    167. ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
    168. ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));
    169. return true;
    170. }
    171. // 向右
    172. if (ea.getKey() == 0x44 || ea.getKey() == 0x64)
    173. {
    174. ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));
    175. ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));
    176. return true;
    177. }
    178. // Right
    179. if (ea.getKey() == 0xFF53)
    180. {
    181. m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle);
    182. }
    183. // Left
    184. if (ea.getKey() == 0xFF51)
    185. {
    186. m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);
    187. }
    188. // 改变屏角
    189. if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F
    190. {
    191. m_fAngle -= 0.2;
    192. return true;
    193. }
    194. if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G
    195. {
    196. m_fAngle += 0.2;
    197. return true;
    198. }
    199. return false;
    200. }
    201. // 鼠标按下
    202. case (osgGA::GUIEventAdapter::PUSH):
    203. {
    204. if (ea.getButton() == 1)
    205. {
    206. m_fpushX = mouseX;
    207. m_fpushY = mouseY;
    208. m_bLeftButtonDown = true;
    209. }
    210. return false;
    211. }
    212. // 拖动
    213. case (osgGA::GUIEventAdapter::DRAG) :
    214. {
    215. if (m_bLeftButtonDown)
    216. {
    217. m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle *(mouseX - m_fpushX));
    218. m_vRotation._v[0] += osg::DegreesToRadians(1.1 *(mouseY - m_fpushY));
    219. if (m_vRotation._v[0] >= 3.14)
    220. {
    221. m_vRotation._v[0] = 3.14;
    222. }
    223. if (m_vRotation._v[0] <= 0)
    224. {
    225. m_vRotation._v[0] = 0;
    226. }
    227. }
    228. return false;
    229. }
    230. // 鼠标释放
    231. case (osgGA::GUIEventAdapter::RELEASE) :
    232. {
    233. if (ea.getButton() == 1)
    234. {
    235. m_bLeftButtonDown = false;
    236. }
    237. return false;
    238. }
    239. default:
    240. {
    241. return false;
    242. }
    243. }
    244. }
    245. // 位置变换函数
    246. void TravelManipulator::ChangePosition(osg::Vec3 &delta)
    247. {
    248. // 碰撞检测
    249. if (m_bPeng)
    250. {
    251. // 得到新的位置
    252. osg::Vec3 newPos1 = m_vPosition + delta;
    253. osgUtil::IntersectVisitor ivXY;
    254. // 根据新的位置得到两条线段检测
    255. osg::ref_ptr lineXY = new osg::LineSegment(newPos1, m_vPosition);
    256. osg::ref_ptr lineZ = new osg::LineSegment(newPos1 + osg::Vec3(0.0f, 0.0f, 10.0f), newPos1 - osg::Vec3(0.0f, 0.0f, -10.0f));
    257. ivXY.addLineSegment(lineZ.get());
    258. ivXY.addLineSegment(lineXY.get());
    259. // 结构交集检测
    260. m_pHostViewer->getSceneData()->accept(ivXY);
    261. // 如果没有碰撞检测
    262. if (!ivXY.hits())
    263. {
    264. m_vPosition += delta;
    265. }
    266. }
    267. else
    268. {
    269. m_vPosition += delta;
    270. }
    271. }
    272. // 设置速度
    273. void TravelManipulator::setSpeed(float &sp)
    274. {
    275. m_fMoveSpeed = sp;
    276. }
    277. // 得到当前速度
    278. float TravelManipulator::getSpeed()
    279. {
    280. return m_fMoveSpeed;
    281. }
    282. // 设置其实的位置
    283. void TravelManipulator::SetPosition(osg::Vec3 &position)
    284. {
    285. m_vPosition = position;
    286. }
    287. // 得到当前位置
    288. osg::Vec3 TravelManipulator::GetPosition()
    289. {
    290. return m_vPosition;
    291. }
    292. void travelManipulator_8_8(const string &strDataFolder)
    293. {
    294. // 创建Viewer对象,场景浏览器
    295. osg::ref_ptr viewer = new osgViewer::Viewer();
    296. // 把漫游器加入到场景中
    297. TravelManipulator::TravelToScene(viewer.get());
    298. osg::ref_ptr root = new osg::Group();
    299. // 读取地形模型
    300. string strDataPath = strDataFolder + "lz.osg";
    301. osg::ref_ptr node = osgDB::readNodeFile(strDataPath);
    302. // 添加到场景
    303. root->addChild(node.get());
    304. // 优化场景数据
    305. osgUtil::Optimizer optimizer;
    306. optimizer.optimize(root.get());
    307. viewer->setSceneData(root.get());
    308. viewer->realize();
    309. viewer->run();
    310. }

            运行程序,截图如图8-18所示:

    图8-18自定义操作器场景漫游示例截图

  • 相关阅读:
    799. 香槟塔 : 简单线性 DP 运用题
    linux网络编程之tcp
    Base64、Blob、File 三种类型的相互转换 最详细
    TensorFlow搭建LSTM实现多变量时间序列预测(负荷预测)
    html5怎么实现语音搜索
    生活中的省电小窍门
    IB心理学如何记住大量的内容?
    activemq部署
    汇编原理计算方法:物理地址=段地址*16+偏移地址
    Apache Tomcat 8.5安装配置教程
  • 原文地址:https://blog.csdn.net/liangfei868/article/details/134474076