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

 场景漫游

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

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

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

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

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

图8-17简单碰撞检测

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

        viewer->setCameraManipulator(camera):;

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

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

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

/******************************************* 自定义漫游器示例 *************************************/
/*编码时遇到无法打开文件osgGA / MatrixManipulator错误,无法打开包括文件 : “osgGA / MatrixManipulator” : No such file or directory解决办法:新版本中已经改名为CameraManipulator将MatrixManipulator改成CameraManipulator即可并且要#include <osgGA/CameraManipulator>
*/
class TravelManipulator : public osgGA::CameraManipulator
{
public:// 构造函数TravelManipulator();// 析构函数~TravelManipulator(void);// 把漫游加入到场景中static TravelManipulator *TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer);private:osg::ref_ptr<osgViewer::Viewer> m_pHostViewer;// 移动速度float m_fMoveSpeed;osg::Vec3 m_vPosition;osg::Vec3 m_vRotation;public:// 鼠标左键是否按下bool m_bLeftButtonDown;// 鼠标XYfloat m_fpushY;float m_fpushX;// 设置矩阵virtual void setByMatrix(const osg::Matrixd &matrix);// 设置逆矩阵virtual void setByInverseMatrix(const osg::Matrixd &matrix);// 得到矩阵virtual osg::Matrixd getMatrix(void) const;// 得到逆矩阵virtual osg::Matrixd getInverseMatrix(void)const;// 事件处理函数virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa);// 屏幕角度float m_fAngle;// 位置变换函数void ChangePosition(osg::Vec3 &delta);// 碰撞检测是否开启bool m_bPeng;// 设置速度float getSpeed();void setSpeed(float &);// 设置起始位置void SetPosition(osg::Vec3 &position);osg::Vec3 GetPosition();
};void travelManipulator_8_8(const string &strDataFolder);/******************************************* 自定义漫游器示例 *************************************/
TravelManipulator::TravelManipulator() :m_fMoveSpeed(1.0f), m_bLeftButtonDown(false), m_fpushX(0), m_fAngle(2.5), m_bPeng(true), m_fpushY(0)
{m_vPosition = osg::Vec3(-22.0f, -274.0f, 100.0f);m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);
}TravelManipulator::~TravelManipulator()
{
}// 把漫游器加入到场景中
TravelManipulator* TravelManipulator::TravelToScene(osg::ref_ptr<osgViewer::Viewer> viewer)
{TravelManipulator *camera = new TravelManipulator;viewer->setCameraManipulator(camera);camera->m_pHostViewer = viewer;return camera;
}// 设置矩阵
void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)
{}// 设置逆矩阵
void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{}// 得到矩阵
osg::Matrixd TravelManipulator::getMatrix()const
{osg::Matrixd mat;mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f), m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));return mat * osg::Matrixd::translate(m_vPosition);
}// 得到逆矩阵
osg::Matrixd TravelManipulator::getInverseMatrix()const
{osg::Matrixd mat;mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));
}// 事件处理函数
bool TravelManipulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
{// 得到鼠标的位置float mouseX = ea.getX();float mouseY = ea.getY();int iEventType = ea.getEventType();switch (iEventType){case (osgGA::GUIEventAdapter::KEYDOWN) :{// 空格键if (ea.getKey() == 0x20){//us.requestRedraw();//us.requestContinuousUpdate(false);return true;}// 上移动if (ea.getKey() == 0xFF50){ChangePosition(osg::Vec3(0, 0, m_fMoveSpeed));return true;}// 下移动if (ea.getKey() == 0xFF57){ChangePosition(osg::Vec3(0, 0, -m_fMoveSpeed));return true;}// 增加速度if (ea.getKey() == 0x2B){m_fMoveSpeed += 1.0f;return true;}// 减少速度if (ea.getKey() == 0x2D){m_fMoveSpeed -= 1.0f;if (m_fMoveSpeed < 1.0f){m_fMoveSpeed = 1.0f;}return true;}// 前进if (ea.getKey() == 0xFF52 || ea.getKey() == 0x57 || ea.getKey() == 0x77)//up{ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));return true;}// 后退if (ea.getKey() == 0xFF54 || ea.getKey() == 0x53 || ea.getKey() == 0x73)//down{ChangePosition(osg::Vec3(0, -m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));return true;}// 向左if (ea.getKey() == 0x41 || ea.getKey() == 0x61){ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));return true;}// 向右if (ea.getKey() == 0x44 || ea.getKey() == 0x64){ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0));ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0, 0));return true;}// Rightif (ea.getKey() == 0xFF53){m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle);}// Leftif (ea.getKey() == 0xFF51){m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);}// 改变屏角if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F{m_fAngle -= 0.2;return true;}if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G{m_fAngle += 0.2;return true;}return false;}// 鼠标按下case (osgGA::GUIEventAdapter::PUSH):{if (ea.getButton() == 1){m_fpushX = mouseX;m_fpushY = mouseY;m_bLeftButtonDown = true;}return false;}// 拖动case (osgGA::GUIEventAdapter::DRAG) :{if (m_bLeftButtonDown){m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle *(mouseX - m_fpushX));m_vRotation._v[0] += osg::DegreesToRadians(1.1 *(mouseY - m_fpushY));if (m_vRotation._v[0] >= 3.14){m_vRotation._v[0] = 3.14;}if (m_vRotation._v[0] <= 0){m_vRotation._v[0] = 0;}}return false;}// 鼠标释放case (osgGA::GUIEventAdapter::RELEASE) :{if (ea.getButton() == 1){m_bLeftButtonDown = false;}return false;}default:{return false;}}
}// 位置变换函数
void TravelManipulator::ChangePosition(osg::Vec3 &delta)
{// 碰撞检测if (m_bPeng){// 得到新的位置osg::Vec3 newPos1 = m_vPosition + delta;osgUtil::IntersectVisitor ivXY;// 根据新的位置得到两条线段检测osg::ref_ptr<osg::LineSegment> lineXY = new osg::LineSegment(newPos1, m_vPosition);osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPos1 + osg::Vec3(0.0f, 0.0f, 10.0f), newPos1 - osg::Vec3(0.0f, 0.0f, -10.0f));ivXY.addLineSegment(lineZ.get());ivXY.addLineSegment(lineXY.get());// 结构交集检测m_pHostViewer->getSceneData()->accept(ivXY);// 如果没有碰撞检测if (!ivXY.hits()){m_vPosition += delta;}}else{m_vPosition += delta;}
}// 设置速度
void TravelManipulator::setSpeed(float &sp)
{m_fMoveSpeed = sp;
}// 得到当前速度
float TravelManipulator::getSpeed()
{return m_fMoveSpeed;
}// 设置其实的位置
void TravelManipulator::SetPosition(osg::Vec3 &position)
{m_vPosition = position;
}// 得到当前位置
osg::Vec3 TravelManipulator::GetPosition()
{return m_vPosition;
}void travelManipulator_8_8(const string &strDataFolder)
{// 创建Viewer对象,场景浏览器osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();// 把漫游器加入到场景中TravelManipulator::TravelToScene(viewer.get());osg::ref_ptr<osg::Group> root = new osg::Group();// 读取地形模型string strDataPath = strDataFolder + "lz.osg";osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);// 添加到场景root->addChild(node.get());// 优化场景数据osgUtil::Optimizer optimizer;optimizer.optimize(root.get());viewer->setSceneData(root.get());viewer->realize();viewer->run();
}

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/196010.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue+element实现多级表头加树结构

标题两种展示方式 方式一 完整代码: <template><div class"box"><el-tableref"areaPointTable":data"tableData"border:span-method"objectSpanMethod":header-cell-style"tableHeaderMerge"><el-ta…

MHA高可用

MHA&#xff1a; 什么是MHA&#xff1a;masterhight availabulity:基于主库的高可用环境下&#xff1a;主从复制&#xff0c;故障恢复 有一个主从的架构。 MHA实验要求&#xff0c;最少有一主两从 Mysql的单点故障问题&#xff0c;一旦主库崩溃&#xff0c;MHA可以在0-30S内…

wpf devexpress 添加GanttControl到项目

这个教程示范如何添加GanttControl 到你的项目使用内置GanttControl数据类。 要求 添加 Devexpress.Wpf.Gantt Nuget包到你的项目使用GanttControl. 数据模型 GanttControl携带和内置数据对象&#xff0c;可以使用创建视图模型&#xff1a; GanttTask 呈现甘特图任务 Gan…

BUUCTF 被偷走的文件 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 一黑客入侵了某公司盗取了重要的机密文件&#xff0c;还好管理员记录了文件被盗走时的流量&#xff0c;请分析该流量&#xff0c;分析出该黑客盗走了什么文件。 密文&#xff1a; 下载附件&#xff0c;解压得到一个…

unity中的模型坐标系与3dmax导出的模型坐标系不一致的解决方案

unity中的模型坐标系与3dmax导出的模型坐标系不一致的解决方案 unity是左手坐标系&#xff0c;3dmax为右手坐标系 需要在3dmax中修改坐标系 顶视图中改成&#xff1a;X轴&#xff08;红色&#xff09;向右&#xff1a; Y轴&#xff08;蓝色&#xff09;朝向自己: Z轴&#xff…

Spring Boot 中使用 ResourceLoader 加载资源的完整示例

ResourceLoader 是 Spring 框架中用于加载资源的接口。它定义了一系列用于获取资源的方法&#xff0c;可以处理各种资源&#xff0c;包括类路径资源、文件系统资源、URL 资源等。 以下是 ResourceLoader 接口的主要方法&#xff1a; Resource getResource(String location)&am…

Linux常用命令——bzcat命令

在线Linux命令查询工具 bzcat 解压缩指定的.bz2文件 补充说明 bzcat命令解压缩指定的.bz2文件&#xff0c;并显示解压缩后的文件内容。保留原压缩文件&#xff0c;并且不生成解压缩后的文件。 语法 bzcat(参数)参数 .bz2压缩文件&#xff1a;指定要显示内容的.bz2压缩文…

【Coppeliasim】 通过TCP与coppeliasim通信

仿真客户端&#xff0c; 代码中启动了tcp服务器。 simrequiresim socketrequiresocket-- 以下函数将数据写入套接字&#xff08;仅为简单起见只处理单个数据包&#xff09;&#xff1a; writeSocketDatafunction(client,data)local headerstring.char(59,57,math.mod(#data,25…

ubuntu20.04在docker下运行ros-noetic

经常折腾虚拟机各双系统 &#xff0c; 想着不如把docker利用起来&#xff0c;下面算是一个初学者使用docker运行ros的记录&#xff1a; 1. 安装 使用官方安装脚本自动安装 curl -fsSL https://test.docker.com -o test-docker.shsudo sh test-docker.sh验证是否安装成功 doc…

新材料企业ERP有几种?能帮助企业解决哪些问题

在我们的生活当中会遇到各种各样的新材料&#xff0c;这些新材料对应不同的制造工艺、品质检验标准、生产工序、制造设备等。有些新材料企业的营销渠道不止一个&#xff0c;各个营销平台的经营策略和商品维护流程各不相同&#xff0c;而这也使得日常的管理工作量较大。 经过多…

工业机器人“智能制造产线6”教学案例

​智能制造单元主要以智能制造技术推广应用实际与发展需求为设计依据&#xff0c;按照“设备自动化生产精益化管理信息化人工高效化”的构建理念&#xff0c;将数控加工设备、工业机器人、检测设备、数据信息采集管控设备等典型加工制造设备&#xff0c;集成为智能制造单元“硬…

HIS医疗项目

文章目录 医疗项目简介HIS项目介绍HIS架构解析HIS业务流程图HIS项目架构图 HIS组件解析——服务支撑 内存设置为4G或以上部署NGINX服务部署web安装JDK部署Elasticsearch安装ik中文分词器 部署rabbitmq部署MySQL服务安装MySQL服务建库、授权用户导入数据 部署Redis测试Redis 部署…

在线 sha1 加密

ttmd5 http://www.ttmd5.com/hash.php?type5 qqxiuzi https://www.qqxiuzi.cn/bianma/sha-1.htm jb51 http://tools.jb51.net/password/sha_encode

基于SpringBoot+Vue的新能源汽车充电桩管理系统

基于SpringBootVue的新能源汽车充电桩管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 充电桩详情 管理员界面 摘要 本项目是基于Spring Boot 和 …

解决requests库中的期限处理问题:从404到异常再到修复

目录 引言 一、了解HTTP 404错误 二、问题分析 三、解决方法 1、控制请求频率 2. 使用代理服务器 3、异常处理与重试机制 4、修复问题源头 5、联系目标网站管理员 四、总结 引言 在利用Python的requests库进行网络爬虫或API请求时&#xff0c;我们有时会遇到“HTTP …

天猫精灵/小爱同学+巴法云+Openwrt控制局电脑/群晖开关机

天猫精灵/小爱同学巴法云Openwrt控制局电脑/群晖开关机 事情的起因实战环境开始发车1.天猫精灵/小爱同学 连接 八法云 2.openwrt3.docker环节注意:sshpass 要先使用 ssh命令登陆一下你要唤醒或者远程关机的设备,不然可能因为一个登陆提示你是否登陆的yes/no导致程序没有反应,然…

(论文阅读40-45)图像描述1

40.文献阅读笔记&#xff08;m-RNN&#xff09; 简介 题目 Explain Images with Multimodal Recurrent Neural Networks 作者 Junhua Mao, Wei Xu, Yi Yang, Jiang Wang, Alan L. Yuille, arXiv:1410.1090 原文链接 http://arxiv.org/pdf/1410.1090.pdf 关键词 m-RNN、…

【Linux】Linux进程间通信(三)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…

Python:函数篇(每周练习)

编程题&#xff1a; Python第四章作业&#xff08;初级&#xff09; (educoder.net) 题一&#xff1a;无参无返回值函数 def print_hi_human(): # 函数名用小写字母print("人类&#xff0c;你好&#xff01;")if __name__ __main__:print_hi_human() 题二&#…

在python中os.chdir()的含义以及用法

文章目录 一、os.chdir() 是什么&#xff1f;二、用法注意 一、os.chdir() 是什么&#xff1f; 在Python中&#xff0c;os.chdir() 是 “change directory” 的缩写&#xff0c;意思是改变当前工作目录。这个函数是Python的 os 模块的一部分&#xff0c;允许你更改程序的工作目…