探索未知种族之osg类生物---呼吸分解之事件循环一
事件循环和更新循环
终于到了我们嘴里经常念叨的事件循环、更新循环以及渲染循环了。首先我们来区分一下事件循环和渲染循环,他们两个首先是两个不同顺序执行的过程,我们有时候会用到任意node的updateCallback函数,这个就是在更新循环的时候遍历所有的node来调用updateCallback函数的;而事件循环是与用户操作和操作系统事件想关联的,以及调用我们设置的事件回调(EventCallback)函数。而事件循环函数(viewer::eventTraversal())是我们现在要探究的内容。
osgViewer::Viewer::eventTraversal()
1
2
3
4
5
6
7
8
9
10
11
12
13
|
if (_done) return ; double cutOffTime = _frameStamp->getReferenceTime(); double beginEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); // OSG_NOTICE<<"Viewer::frameEventTraversal()."<<std::endl; // need to copy events from the GraphicsWindow's into local EventQueue; osgGA::EventQueue::Events events; Contexts contexts; getContexts(contexts); // set done if there are no windows checkWindowStatus(contexts); if (_done) return ;<br><br> |
进入这个函数,我们发现前几行都是我们以前介绍过的osg器官。首先记录了事件循环的开始时间,这样做的目的是:与这个函数最后记录的时间进行比较,然后记录在_stats记录器中,这样可以帮助开发者了解每一帧当中事件遍历,更新遍历和渲染遍历运行所占用的时间比例,以便对整个程序进行调优工作。然后得到所有的GraphicsContext,保存到contexts中,当contexts为空时,意味着没有最终的画布,osg会结束运行,通过设置_done=true;
然后的主要工作是:事件循环会得到已经发生的所有事件,并进行一定的筛选工作,最后全部都传给各自的事件处理器。所以我们首先对其中一些新成员进行简单的介绍:
- eventState事件队列的目前的状态事件,eventState的设置是通过osgGA::EventQuene::setCurrentEventState函数进行设置的。
- _eventSources 实在osgViewer::View下的成员变量,通过View::addDevice()函数来添加新的设备,他的主要作用就是在每一个帧的事件循环中便利所有的设备,然后得到通过Device :: getEventQueue收集生成的所有的事件。
搬掉了几块绊脚石,那么现在我们就可以继续前行了。osgViewer::viewer::eventTraversal()中第一个for循环的目的就是遍历所有的设备所发生的事件,并保存到viewer::events中。这些设备就包含鼠标,键盘等发生的事件。
1
2
3
4
5
6
7
8
9
10
11
12
|
for (Devices::iterator eitr = _eventSources.begin(); eitr != _eventSources.end(); ++eitr) { osgGA::Device* es = eitr->get(); if (es->getCapabilities() & osgGA::Device::RECEIVE_EVENTS) es->checkEvents(); // open question, will we need to reproject mouse coordinates into current view's coordinate frame as is down for GraphicsWindow provided events? // for now assume now and just get the events directly without any reprojection. es->getEventQueue()->takeEvents(events, cutOffTime); } |
然后再一个for循环,得到所有的GraphicsContext中的event并插入到eventQuene链表中,也就是诸如鼠标的移动,键盘上的按键被按下,窗口的尺寸被改变等动作,都会作为一个新的 GUIEventAdapter 对象插入到链表中,插入事件的方法是由图形窗口GraphicsWindow执行EventQueue类的成员函数 mouseMotion,keyPress和 windowResize,并间接地调用 EventQueue::addEvent 函数。而这些事件之间可能共通的参数和状态就从“状态事件”中读取。然后我们再会对窗口上发生的点击,释放,拖拽,双击和移动事件中的鼠标坐标进行统一的投影变换,使鼠标坐标重新投影到当前视图的坐标系中。
现在我们就主要来讲解一下鼠标坐标到视图坐标系的转换。
当鼠标只是进行单点操作,或者当然的事件的GraphicsContext不是主GraphicsContext时,需要调用generatePointerData函数来对鼠标的坐标进行转换。Viewer::generatePointerData()函数中,在这里我们要普及一点知识osg或者说opengl中屏幕坐标的原点在左下角,而windows的坐标原点在右上角,所以在这个函数中我们首先需要把判断我们所使用的平台的原点和osg的原点是否相同,如果不同则需要把鼠标坐标的y取反一下(gw->getTraits()->height - y)。然后把新的到的坐标点设置回事件信息中,并把Y轴模式改为向上增长(Y_INCREASING_UPWARDS).然后我们得到此时这个GraphicsContext下的所有的正在使用到的相机,并选出目前鼠标事件中的x,y所处在那几个相机的视口中,得到这几个相机作为活动相机。然后根据相机的先后渲染顺序进行排序,因为我们最后渲染的肯定会覆盖先前的,所以我们只需把鼠标坐标投影到最后渲染的相机的视图上就可以了。因为视口的坐标都是以0到1间的数字来表示的,所以鼠标的坐标通过一定的线性变换就可以变换到视口坐标系内
1
|
event.addPointerData( new osgGA::PointerData(camera, (x-viewport->x())/viewport->width()*2.0f-1.0f, -1.0, 1.0,(y-viewport->y())/viewport->height()*2.0f-1.0f, -1.0, 1.0));<br> |
当然上面所说的适口坐标肯定是主摄像机的视口坐标,如果是目前鼠标是在从相机中移动的,那么再转换到主摄像机坐标系中。这个过程大概可以理解成这样,我们首先要把鼠标的坐标按照从相机的MVP矩阵转换到世界坐标系中,再根据主相机的MVP矩阵把刚刚得到的世界坐标转换到主摄像机的视口中,最后完成了从相机到主相机的坐标转换。
欢迎大家来我的新家看一看 3wwang个人博客-记录走过的技术之路
探索未知种族之osg类生物---呼吸分解之事件循环一的更多相关文章
- 探索未知种族之osg类生物---呼吸分解之事件循环三
那我们就开始处理这些事件中得到的所有的交互事件,首先我们要判断这些事件是否包含osg的退出事件,那什么情况下会触发这个退出事件呢?如果您运行过osg中example中的小例子的,聪明的你一定就会发现当 ...
- 探索未知种族之osg类生物---呼吸分解之事件循环二
VPM矩阵 1.V 表示摄像机的观察矩阵(View Matrix),它的作用是把对象从世界坐标系变换到摄像机坐标系.因此,对于世界坐标系下的坐标值 worldCoord(x0, y0, z0),如果希 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环一
上节总结 前几天我们大体上介绍完成了osg的事件循环的介绍,总结一下osg的时间循环主要就是得到平台(windows)的所有消息,并遍历所有的node的eventCallback,并对他们进行处理.接 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环二
_scene->updateSceneGraph(*_updateVisitor); 我们用了前面4节才刚刚算是完成对DatabasePager::DatabaseThread::run()函数 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环三
补充 当然细心的你会发现,_scene->updateSceneGraph(*_updateVisitor)中还有一个imagePager::UpdateSceneGraph()还没有进行讲解, ...
- 探索未知种族之osg类生物---呼吸分解之渲染遍历二
那么今天我们就正式进入osg整个呼吸动作之中最复杂的一个动作,ViewerBase::renderingTraversals(),我们先介绍renderingTraversals的开头的简单的几步操作 ...
- 探索未知种族之osg类生物---呼吸分解之advance
回顾 我们用了两节的内容才堪堪讲解完ViewerBase::frame()函数中调用的realize()---Viewer:: realize()函数.我们简单的总结就是Viewer:: realiz ...
- 探索未知种族之osg类生物---呼吸分解之渲染遍历一
总结 前面我们基本上已经完成对ViewerBase::frame()函数的探究,只剩下renderingTraversals()渲染遍历的探究,虽然就剩下了一个函数,但是这却是最重要的,不可少的一个步 ...
- 《探索未知种族之osg类生物》目录
精力有限,博客园不在更新<探索未知种族之osg类生物>.在这里列出所有文章目录(持续更新)有兴趣的同学可以看看. 探索未知种族之osg类生物[目录] 前序 探索未知种族之osg类生物--- ...
随机推荐
- ADO.Net创建数据模型和数据访问类及泛型集合
数据模型和数据访问类:数据模型: 使用面向对象中的封装特性,将数据表中的行数据组成一个同样结构的对象,来单独使用: 数据访问类: 将某一个表的全部增删改查操作的方法写进去,方便统一管理和调用: 数据模 ...
- php 指定页面显示所有报错
ini_set('display_errors',1); error_reporting(E_ALL);
- lcd 控制器
1. 使用lcd 一般需要一个控制器和驱动器,控制器需要初始化以产生正确的时序,驱动器一般是和lcd基板制作在一起. LCD 控制器结构图: REGBANK 表示调色板 LCDDMA 表示DMA通道 ...
- input 文本框,对中文长度校验
在项目中,经常会遇到,对文本框进行校验. eg. 要求姓名长度为20,中文为10,只能输入中英文. <input maxlength="20" type="t ...
- vc for python2.7
https://www.microsoft.com/en-us/download/confirmation.aspx?id=44266
- windows环境安装zabbix客户端
安装windows版zabbix客户端 一.下载客户端 在数据盘新建一个zabbix_agent目录 浏览器打开 https://www.zabbix.com/download_agents 选择”z ...
- Log4j2配置及使用
Log4j2:一个日志管理工具.Log4j的升级版,需要Java6以上 一.安装log4j2依赖包 1.通过maven的pom.xml直接引入jar: log4j-api和log4j-core & ...
- JPA in
CriteriaBuilder.In in = criteriaBuilder.in(root.get("field1")); for (String str : arr) { i ...
- js keycode
参考 https://www.cnblogs.com/daysme/p/6272570.html
- 【Nodejs】ExpressのRequestとResponseの内容
Request 对象 - request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性.常见属性有: req.app:当callback为外部文件时,用req.ap ...