场景交互与场景漫游-osgGA库(5)

osgGA

        osgGA库是OSG的一个附加的工具库,它为用户提供各种事件处理及操作处理。通过osgGA库读者可以像控制Windows窗口一样来处理各种事件

        osgGA的事件处理器主要由两大部分组成,即事件适配器动作适配器。osgGA:GUIEventHandler类主要提供了窗口系统的GUI事件接口它使用osgGA::GUIEventAdapter 实例来接收更新,使用osgGA::GUIActionAdapter 实例向系统发出请求

        在osgGA::GUIEventHandler 中包含了一系列的枚举事件类型,如NONE、PUSH、RELEASE、DOUBLECLICK2、DRAG、MOVE、KEYDOWN 和KEYUP 等。但osgGA::GUIEventHandler 会根据不同的事件类型实现一些相关的操作,主要包括下面的类型:

NONE
PUSH//鼠标事件
RELEASE//松开
DOUBLECLICK//双击
DRAG//拖动
MOVE//移动
KEYDOWN//按键
KEYUP//松开
FRAME//每一帧
RESIZE//大小缩放
SCROLL//滚轮
PEN_PRESSURE/鼠标笔压力
PEN_ORIENTATION//鼠标笔的方位
PEN_PROXIMITY_ENTER //开始鼠标笔
PEN_PROXIMITY_LEAVE标笔离开
CLOSE_WINDOW//关闭窗口
QUIT_APPLICATIONG//退出程序
USER

        这些事件类型与Windows的窗口事件非常类似。但在使用这些事件类型时,需要注意,有些OSG并没有实现好,如鼠标滑轮的事件。如果读者有兴趣实现的话,可以向 OSG 官方提供读者的实现代码,读者的大名将会出现在贡献人之列。

        相对而言,osgGA::GUIActionAdapter 类就简单多了,它主要包含系统执行的动作,如重新绘制和光标重置之类的请求。

        osgGA库还包含很多操作器,主要包含一个基类osgGA::MatrixManipulator和它的一些派生类osgGA::MatrixManipulator类是一个基类,提供了各种接口,这也是漫游会用到的一个基类。它提供的接口包括矩阵变换和事件处理,编写自己的操作器需要通过继承osgGA::MatrixManipulator 来实现,需要重载里面的矩阵变换函数和时间处理函数。这里只是简单介绍,后面会有详细说明。

        从osgGA::MatrixManipulator 类派生的子类就是OSG中默认的操作器,主要包括

osgGA::AnimalionPathManipulator//动画路径操作器
osgGA::DriveManipulator//车行操作器
osgGA::FlightManipulator//飞行操作器
osgGA::KeySwitchMatrixManipulator//按键切换操作器
osgGA::NodeTrackerManipulator//节点跟踪操作器
osgGA::TerrainManipulator//地形操作器
osgGA::TrackballManipulator//跟踪球操作器
osgGA::UFOManipulator//UFO操作器

        在默认情况下,OSG通常使用的是osgGA::TrackballManipulator 操作器。在前面很多程序中,都是直接使用 viewer->run(),其实,使用的操作器就是该跟踪球操作器。当然,读者可以将其设置为其他的操作器来处理,例如:

viewer->setCameraManipulator(new osgGA::TerrainManipulator());

        OSG中预设了很多操作器,读者可以在适当的时候选择适当的操作器来完成相应的功能,这里不再赘述,因为不可能把所有操作器的源代码都拿来讲解,在实际应用中,更偏向于编写自己的操作器。

键盘事件消息处理

        在osgGA库中,存在一个事件处理器 osgGA::GUIEventHandler,可以提供窗口系统的GUI事件接口。在OSG中,默认有很多已经写好的事件处理器。在osgViewer 应用程序中添加了很多在OSG中预定义的事件处理器,实现的功能有显示帧率、操作器切换和帮助等,这些事件处理器主要包括

class HelpHandler //帮助事件处理器
class StatsHandler //状态事件处理器
class WindowSizeHandler //窗口大小事件处理器
class ThreadingHandler //线程模型设置事件处理器
class RecordCameraPathHandler //动画记录事件处理器
class LODScaleHandler//LOD缩放事件处理器
class ScrccnCaptureHandler //截屏事件处理器

        这些事件处理器的源代码可以在osgViewer目录下找到,有兴趣的读者可以去研究一下,或者改写为自己的事件处理器。

        在实际过程中,编写自己的事件处理器是一件不可避免的事情,这也是交互的重要部分之一。如果一个平台没有交互,那就只是给客户放电影,就没有必要用到3D这样充满挑战的技术。

        编写一个自己的事件处理器是非常简单的,主要操作步骤如下:

        <1> 编写一个新类,继承自osgGA:GUIEventHandler类。

        <2> 重载成员函数handle(),在osgGA::GUIEventHandler中,该函数原型如下,是一个虚函数:

   

     virtual bool handle(const GUIEventAdapter &, GUIActionAdapter &)

        这一步是非常关键的,也是十分重要的。通过重载该函数,可以根据事件的类型执行自定义动作(可参看第8.2.3节的示例)。

        <3> 将事件处理器压入处理器列表。这一步是非常必要的,如果没有这一步,所写的事件处理器将不会执行,这相当于启动该事件处理器的作用,在使用时一定要注意。

        在编写自己的事件处理器时,在事件处理函数中,事件处理函数的返回值与事件处理器列表中的当前处理器的键盘和鼠标时间相关,并保持一一对应关系。如果返回值为true,则系统会认为该事件已经处理,就不再传递给下一个事件处理器。如果返回值是false,那么它会继续传递给下一个事件处理器,执行对应事件的动作。在用户的应用程序中,可以包含多个事件处理器,在编写时要注意事件不要重复,否则可能会造成有些事件没有响应,有些事件却重复响应。

        在第8.2.3节将演示一个抓图的示例。抓图本身比较简单,可以通过下面的代码实现:

// 读取像素信息抓图image->readPixels(0, 0, width, height, GL_RGB,GL_UNSIGNED_BYTE);

        但在OSG2x系列以后,这样简单的执行会出现问题,读者会发现使用上面代码根本抓不到图片因为此时并没有得到当前的 RC 设备,这个问题曾经在邮件列表上也讨论过,最好的解决方案就是使用osg::Camera::DrawCallback,这样可以确保在当前RC设备下执行 readPixels(),从而可以保证抓取到图片。这时写一个简单的类,继承自 osg:Camera::DrawCallback类,在开始渲染前就执行绘制回调可以很容易抓到图片。

        抓图示例的代码如程序如下所示。

/******************************************* 键盘事件-抓图示例 *************************************/
osg::ref_ptr<osg::Image> image_c = new osg::Image();// 定义一个全局变量// 得到抓图
struct CaptureDrawCallback :public osg::Camera::DrawCallback
{CaptureDrawCallback(osg::ref_ptr<osg::Image>image){_image = image;}~CaptureDrawCallback(){}virtual void operator()(const osg::Camera &camera) const{// 得到窗口系统接口osg::ref_ptr<osg::GraphicsContext::WindowingSystemInterface> wsi = osg::GraphicsContext::getWindowingSystemInterface();unsigned int width, height;// 得到分辨率wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);// 分配一个image_image->allocateImage(width, height, 1, GL_RGB, GL_UNSIGNED_BYTE);// 读取像素信息抓图_image->readPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE);}osg::ref_ptr<osg::Image> _image;
};// 抓图时间处理器
class ImageHandle :public osgGA::GUIEventHandler
{
public:ImageHandle(){}~ImageHandle(){}// 重置handle()函数bool ImageHandle::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa){osg::ref_ptr<osgViewer::Viewer> viewer = dynamic_cast<osgViewer::Viewer*>(&aa);if (viewer == nullptr){return false;}// 定义一个静态变量static int _screenCaptureSequence = 0;switch (ea.getEventType()){case osgGA::GUIEventAdapter::KEYDOWN:// 按键{int iValue = ea.getKey();if (ea.getKey() == 'c' || ea.getKey() == 'C'){char filename[128];// 确定一个合理的文件名,以保证能够连续抓图sprintf_s(filename, "D:\\ScreenShot%04d.bmp", _screenCaptureSequence);++_screenCaptureSequence;// 写入文件osgDB::writeImageFile(*(image_c.get()), filename);}break;}default:{return false;}}return true;}
};
// 键盘事件之抓图示例
void CaptureImage_8_7(const string &strDataFolder)
{osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();osg::ref_ptr<osg::Group> root = new osg::Group();// 读取模型string strDataPath = strDataFolder + "cow.osg";osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(strDataPath);root->addChild(node.get());// 优化场景数据osgUtil::Optimizer optimizer;optimizer.optimize(root.get());// 设置绘制回调viewer->getCamera()->setPostDrawCallback(new CaptureDrawCallback(image_c.get()));viewer->setSceneData(root.get());// 添加抓图时间viewer->addEventHandler(new ImageHandle());viewer->realize();viewer->run();
}

图8-16 抓图示例截图

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

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

相关文章

系列九、对象的生命周期和GC

一、堆细分 Java堆从GC的角度还可以细分为&#xff1a;新生代&#xff08;eden【伊甸园区】、from【幸存者0区】、to【幸存者1区】&#xff09;和老年代。 二、MinorGC的过程 复制>清空》交换 1、eden、from区中的对象复制到to区&#xff0c;年龄1 首先&#xff0c;当eden区…

我认为除了HelloWorld之外,Python的三大数据转换实例可以作为开始学习Python的入门语言。

Python的三大数据转换实例 一、反转三位数 class Solution:def funtcion(self,number):hint(number/100)tint(number%100/10)zint(number%10)return 100*z10*th if __name____main__:solution Solution()num123new_num solution.funtcion(num)print("输入:{}".fo…

【仿真动画】ABB IRB 8700 机器人搬运(ruckig在线轨迹生成)动画欣赏

场景 动画 一、IRB 8700简介 二、动画脚本重点分析 2.1 sim.moveToPose 通过在两个 poses 之间执行插值&#xff0c;使用 Ruckig 在线轨迹生成器生成对象运动数据。该函数可以通过处理 4 个运动变量&#xff08;x、y、z 和两个姿势之间的角度&#xff09;或单个运动变量&#…

深度学习数据集—细胞、微生物、显微图像数据集大合集

最近收集了一大波关于细胞、微生物、显微图像数据集&#xff0c;有细胞、微生物&#xff0c;细菌等。 接下来是每个数据的详细介绍&#xff01;&#xff01; 1、12500张血细胞增强图像&#xff08;JPEG&#xff09;数据集 该数据集包含12500张血细胞增强图像&#xff08;JPE…

vscode终端npm install报错

报错如下&#xff1a; npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion1, but package-lock.json was generated for lockfileVersion2. Ill try to do my best with it! npm ERR! code EPERM npm ERR! syscall open npm ERR! errno -4048…

视频剪辑技巧:轻松搞定视频随机合并,一篇文章告知所有秘诀

在视频制作的过程中&#xff0c;视频随机合并是一种创新的剪辑手法&#xff0c;它打破了传统的线性剪辑模式&#xff0c;使得视频剪辑更加灵活和有趣。通过将不同的视频片段随机组合在一起&#xff0c;我们可以创造出独特的视觉效果和情感氛围。这种剪辑方式让观众在观看视频时…

Hive函数

文章目录 一、Hive建表SQL二、Hive函数三、函数1、查看内置函数2、空字段赋值(nvl)3、CASE WHEN THEN ELSE END4、行转列5、列转行6、开窗函数6.1 简介6.2 语法6.3 案例6.4 LAG函数6.5 Ntile函数6.6 Rank 7、自定义函数 四、压缩和存储1、简介2、压缩简介3、Map输出阶段压缩4、…

⑧【MySQL】数据库查询:内连接、外连接、自连接、子查询、多表查询

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 内连接、外连接、自连接、子查询、多表查询 ⑧…

使用Pandas进行时间重采样,充分挖掘数据价值

大家好&#xff0c;时间序列数据蕴含着很大价值&#xff0c;通过重采样技术可以提升原始数据的表现形式。本文将介绍数据重采样方法和工具&#xff0c;提升数据可视化技巧。 在进行时间数据可视化时&#xff0c;数据重采样是至关重要且非常有用的&#xff0c;它支持控制数据的…

ControlNet原理及应用

《Adding Conditional Control to Text-to-Image Diffusion Models》 目录 1.背景介绍 2.原理详解 2.1 Controlnet 2.2 用于Stable Diffusion的ControlNet 2.3 训练 2.4 推理 3.实验结果 3.1 定性结果 3.2 消融实验 3.3 和之前结果比较 3.4 数据集大小的影响 4.结…

Vite 启动默认只能访问localhost解决方法

事情的经过是因为我需要测试本地项目的接口,然后因为burp默认不抓取localhost,127.0.0.1 .而且我也不想去修改burp. 所以我通过本地IP地址访问项目, 发现项目无法访问。 默认启动 所以特此记录一下。 在本地项目的package.json 中需要运行的脚本后 添加 --host即可。 具体如下…

rabbitMQ的扇出模式(fanout发布订阅)的生产者与消费者使用案例

扇出模式 fanout 发布订阅模式 生产者 生产者发送消息到交换机&#xff08;logs&#xff09;,控制台输入消息作为生产者的消息发送 package com.esint.rabbitmq.work03;import com.esint.rabbitmq.RabbitMQUtils; import com.rabbitmq.client.Channel;import java.util.Scanne…

使用FP8加速PyTorch训练

现代的人工智能硬件架构(例如&#xff0c;Nvidia Hopper, Nvidia Ada Lovelace和Habana Gaudi2)中&#xff0c;FP8张量内核能够显著提高每秒浮点运算(FLOPS)&#xff0c;以及为人工智能训练和推理工作负载提供内存优化和节能的机会。 在这篇文章中&#xff0c;我们将介绍如何修…

Arduino驱动LM35线性温度传感器(温湿度传感器)

目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 LM35半导体的温度传感器,可以用来对环境温度进行定性的检测。LM35半导体温度传感器是美国国家半导体公司生产的线性温度传感器。其测温范围是-40℃到150℃,灵敏度为10mV/℃,输出电压与温度成正比。

<C++> 反向迭代器

我们知道正向迭代器的设计&#xff1a;begin迭代器指向第一个数据&#xff0c;end迭代器指向最后一个数据的下一个位置 。移向下一个数据&#xff0c;解引用得到数据的值&#xff0c;并根据容器储存方式的不同&#xff0c;容器有不同类型的迭代器。 注意&#xff1a;rbegin迭代…

c语言:模拟实现qsort函数

qsort函数的功能&#xff1a; qsort相较于冒泡排序法&#xff0c;不仅效率更快&#xff0c;而且能够比较不同类型的元素&#xff0c;如&#xff1a;浮点数&#xff0c;结构体等等。这里我们来模拟下qsort是如何实现这一功能的&#xff0c;方便我们对指针数组有一个更深层次的理…

龙芯 操作系统选择和安装

龙芯3a5000及之后的cpu底层架构已经从mips64el改为了loongarch64 所以这里分了2种来说明&#xff0c;分别对应3a4000之前的和3a5000之后的 龙芯的系统安装难点在于操作系统的选取和引导 一、烧录工具 制作安装盘使用常规的烧录工具是不行滴&#xff0c;会提示没有\boot\initrd…

产品经理必备技能:如何快速锁定种子用户群体?

大家好&#xff0c;我是小米&#xff0c;一名热爱技术、热衷分享的90后小青年。今天我们要探讨的话题是一个在产品经理面试中经常被问到的问题&#xff1a;“产品上线后的种子用户该如何获取&#xff1f;”作为一个热爱挑战、乐于探讨的小伙伴&#xff0c;我将和大家分享一些我…

第七部分:Maven(项目管理工具)

目录 Maven简介 7.1&#xff1a;为什么学习Maven&#xff1f; 7.1.1、Maven是一个依赖管理工具 7.1.2&#xff1a;Maven是一个构建工具 7.1.3&#xff1a;结论 7.2&#xff1a;Maven介绍 7.3&#xff1a;Maven的优点 Maven安装和配置 7.4&#xff1a;安装教程及环境配置 …