探索未知种族之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 windowscheckWindowStatus(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类生物--- ...
随机推荐
- C# 递归获取 文件夹的 所有文件
public void Director(string dir, List<string> list) { DirectoryInfo d = new DirectoryInfo(dir) ...
- 关于ubuntu14.04,忘记root密码解决方案(经测试,内核3.13和4.2可行)。
网上已经有很多方案啦,我这里就不画蛇添足,直接上链接: http://jingyan.baidu.com/article/c843ea0b9e851077931e4aea.html 注意,有些机子没有 ...
- 最小生成树一·Prim算法
描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以拥有不止一个城市了! 但是,问题也接踵而来——小Hi现在手上拥有N座城市,且已知这N座城市中任意两座城市之间建造道 ...
- 微信小程序---模版
微信小程序用的是否娴熟,会灵活使用模版很重要. 新建一个template文件,做一个step模版. <template name="top"> <view cla ...
- 导出pdf
document.getElementById("exportSiteInfoTemp").onclick = function() { var thisMinheight=$(& ...
- 使用tor网络
在www.torproject.org/projects/torbrowser.html.en上找到合适的版本下载 下载好tor浏览器之后,解压双击Tor Browser,出现这个错误 这是因为kal ...
- Python基础之列表及元组的增删改查
定义一个列表 晚上的状态不太适合写博客,容易犯困~ 列表的增加有三种方式 第一种主流的增加 append函数 list1 = ['noevil', 'fordearme', 'city', 'cust ...
- PropertyGrid控件动态生成属性及下拉菜单 (转)
http://blog.sina.com.cn/s/blog_6f14b7010101b91b.html https://msdn.microsoft.com/zh-cn/library/ms1718 ...
- CSS3 Backgrounds相关介绍
CSS3 Backgrounds相关介绍 1.背景图片(background images)是在padding-box的左上角落脚安家的,我们可以使用background-position属性改变默认 ...
- fullCalendar插件基本使用
效果图 html代码,需要引入jquery,layui,fullCalendar <!DOCTYPE html> <html lang="en"> < ...
