场景交互与场景漫游-场景漫游器(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.mzph.cn/news/147789.shtml

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

相关文章

Java集合大总结——List的简单使用

List简单介绍 鉴于Java中数组用来存储数据的局限性&#xff0c;我们通常使用java.util.List替代数组List集合类中元素有序、且可重复&#xff0c;集合中的每个元素都有其对应的顺序索引。JDK API中List接口的实现类常用的有&#xff1a;ArrayList、LinkedList和Vector。 List…

【腾讯云云上实验室-向量数据库】TAI时代的数据枢纽-向量数据库 VectorDB

一、向量数据库的发展历程和时代机遇 回顾向量数据库的发展历程&#xff1a; 2012年开始&#xff0c;深度神经网络的发展催生了向量数据库的发展&#xff1b;2015年至2016年&#xff0c;Google和微软发布了标志性的论文&#xff1b;2017年&#xff0c;Facebook开源了Faiss框架…

生物信息基础:实用Git命令,掌握这些就够了

我发现有搞了几年生信的朋友还不会用Github管理代码&#xff0c;这不免令人意外。我一直强调基础知识的重要性&#xff0c;而这些知识又是可以在短时间内掌握的。Github管理平时写的代码&#xff0c;要用到Git命令。虽然官方Git命令非常多&#xff0c;但我们只要掌握常用的几个…

DRF统一返回格式

DRF中如何统一返回格式 目前在在给科室网站定义DRF的时候&#xff0c;遇到这样的一个问题&#xff0c;就是DRF的原生返回的式样是多样的&#xff0c;例如在访问成功的时候会返回这样的数据{“access”:fkasjfkljgkljgklsjgksjlksjfkljslfjs},但是在序列化器错误的时候&#xf…

PyTorch微调终极指南2:提升模型的准确性

作为一名机器学习从业者&#xff0c;你可能经常会发现自己处于这样一种情况&#xff1a;你正在针对特定任务微调预先训练的模型&#xff0c;但已经达到了无法进一步提高模型准确性的地步。 在本文中&#xff0c;我们将探讨可用于提高模型准确性的各种技术和策略。 这些方法旨在…

Python武器库开发-flask篇之session与cookie(二十六)

flask篇之session与cookie(二十六) 在 Flask 中&#xff0c;可以使用 session 来在不同请求之间存储和传递数据。Session 在客户端和服务器端之间交换&#xff0c;但是数据存储在服务器端。 Session 与 Cookie 的区别 session 和 cookie 都可以用来在不同请求之间存储和传递…

Spring底层原理学习笔记--第十一讲--(aop之proxy增强-jdk及aop之proxy增强-cglib)

AOP实现之proxy 1.jdk动态代理实现及要点 2.cglib代理实现及要点 invoke与invokeSuper区别 jdk动态代理实现及要点 package com.lucifer.itheima.a12;import java.lang.reflect.Proxy;public class JdkProxyDemo {interface Foo{void foo();}//该类可以设置成final类型 //j…

Vue3-readonly(深只读) 与 shallowReadonly(浅只读)

Vue3-readonly(深只读) 与 shallowReadonly&#xff08;浅只读&#xff09; readonly(深只读)&#xff1a;具有响应式对象中所有的属性&#xff0c;其所有值都是只读且不可修改的。shallowReadonly(浅只读)&#xff1a;具有响应式对象的第一层属性值是只读且不可修改的&#x…

使用requests库进行网络爬虫:IP请求错误的解决方法

目录 引言 一、了解requests库 二、遇到的问题 三、解决方法 1、随机化IP地址 2、减少请求频率 3、使用User Agent模拟浏览器行为 4、使用Cookies 四、注意事项 五、使用代理池 六、总结 引言 在利用Python的requests库进行网络爬虫操作时&#xff0c;我们有时会遇…

系列七、JVM的内存结构【堆(Heap)】

一、概述 一个JVM实例只存在一个堆内存&#xff0c;堆内存的大小是可以手动调节的。类加载器读取了类文件后&#xff0c;需要把类、方法、常变量放到堆内存中&#xff0c;保存所有引用类型的真实信息&#xff0c;以方便执行器执行&#xff0c;堆内存分为三个部分&#xff0c;即…

给openlab搭建web网站

1.作业的要求 2.访问www.openlab.com网站 2.1先准备好相关的包和关闭防火墙等操作 mount /dev/sr0 /mnt/ //先挂载 yum install httpd -y //下载htppd systemctl stop firewalld //关闭防火墙 setenforce 02.2然后开始配置文件和仓库 这一步比较关键,之前改了接口…

【OpenCV实现图像:OpenCV进行OCR字符分割】

文章目录 概要基本概念读入图像图像二值化小结 概要 在处理OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;时&#xff0c;利用传统的图像处理方法进行字符切分仍然是一种有效的途径。即便当前计算机视觉领域主导的是卷积神经网络&#xf…

JavaScript垃圾回收机制解析

JavaScript是一种动态语言&#xff0c;拥有自动内存管理。这意味着开发人员不需要手动分配和释放内存。在JavaScript中&#xff0c;垃圾回收器会自动处理不再需要使用的内存&#xff0c;以便重新利用。 1. 标记清除算法 JavaScript使用标记清除算法作为主要的垃圾回收机制。该…

DAO和增删改查通用方法-BasicDao

文章目录 一、BasicDao是什么&#xff1f;二、BasicDao分析三、BasicDao实现&#xff08;1&#xff09;BasicDao&#xff08;2&#xff09;ActorDao&#xff08;3&#xff09;TestDao 四、总结 一、BasicDao是什么&#xff1f; BasicDao:基础的数据对象&#xff0c;可以完成通用…

asp.net智能考试系统VS开发sqlserver数据库web结构c#编程计算机网页项目

一、源码特点 asp.net 智能考试系统 是一套完善的web设计管理系统&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 系统运行视频 https://www.bilibili.com/video/BV1gz4y1A7Qp/ 二、功能介绍 本系统使用Microsoft Visual Studio 201…

掌握键盘快捷键,在没有鼠标的情况下,也还是可以做到游刃有余,甚至可以用数字键来代替鼠标

键盘和鼠标是与计算机交互的重要外围设备。有些人可能会争辩说,你只需要这些设备中的一个,但事实上,只使用其中一个设备的电脑可能非常困难。但是,如果你的鼠标或笔记本电脑的触控板突然停止工作,而你无法修复它或无法使用备用鼠标,该怎么办? 在这种情况下,你可以使用…

树莓派4b编译FFmpeg支持硬件编解码

ffmpeg h264_omx解码器充分发挥树莓派gpu性能 准备 树莓派4b ,64位系统 修改树莓派的启动设置文件(/boot/config.txt)进行如下的调整: gpu_mem=256 framebuffer_depth=16安装依赖 常规依赖: sudo apt update sudo apt upgrade sudo apt -y install autoconf automake …

循环优先级仲裁~位屏蔽仲裁算法

参考了FPGA奇哥&#xff08;下列视频中UP主&#xff09;的讲解。 应该可以对多路读写DDR3进行操作&#xff0c;仅仲裁&#xff0c;不涉及DMA和Uibuf等。 2023年11月所写&#xff0c;暂未进行测试&#xff0c;日后补上。 第二天已完成测试&#xff0c;功能可行。 深入FPGA底层…

一生一芯18——Chisel模板与Chisel工程构建

Chisel模板链接如下&#xff1a; 链接: https://pan.baidu.com/s/1DNDKpz5VnTxPgoZBBOd-Ww?pwdrevg 提取码: revg Chisel转Verilog模板如下&#xff1a; 链接: https://pan.baidu.com/s/1T9JQL5BccxqI4bscfU-JyA?pwd7rw2 提取码: 7rw2 以下使用sbt作为构建工具 Chisel项目构…

DeepMind发布新模型Mirasol3B:更高效处理音频、视频数据

Google DeepMind日前悄然宣布了其人工智能研究的重大进展&#xff0c;推出了一款名为“Mirasol3B”的新型自回归模型&#xff0c;旨在提升对长视频输入的理解能力。该新模型展示了一种颠覆性的多模态学习方法&#xff0c;以更综合和高效的方式处理音频、视频和文本数据。 Googl…