探索未知种族之osg类生物---呼吸分解之事件循环二
VPM矩阵
1、V 表示摄像机的观察矩阵(View Matrix),它的作用是把对象从世界坐标系变换到摄像机坐标系。因此,对于世界坐标系下的坐标值 worldCoord(x0, y0, z0),如果希望使用观察矩阵 VM 将其变换为摄像机相对坐标系下的坐标值 localCoord(x’, y’, z’),则有:
localCoord = worldCoord * VM
此外,观察矩阵可以理解为“摄像机在世界坐标系下的变换矩阵的逆矩阵”,因此 Camera类也专门提供了 getInverseViewMatrix 这样一个函数,它的实际意义是表示摄像机在世界坐标系下的位置。
2、P 表示投影矩阵(Projection Matrix),当我们使用 setProjectionMatrixAsPerspective之类的函数设置摄像机的投影矩阵时,我们相当于创建了一个视截锥体,并尝试把包含在其中的场景对象投影到镜头平面上来。如果投影矩阵为 PM,而得到的投影坐标为 projCoord(x”,y”, 0)的话,那么:
projCoord = localCoord * PM
3、W 表示视口矩阵(Window Matrix),它负责把投影坐标变换到指定的二维视口中去,对于视口矩阵 WM,通过下面的公式可以得到最终的窗口坐标 windowCoord(x, y, 0):
windowCoord = projCoord * WM
将所有的公式整合之后,得到:
windowCoord = worldCoord * VM * PM * WM
而这个所谓的窗口坐标 windowCoord,实际上也就是世界坐标系下的坐标值 worldCoord在指定的摄像机视口中(也就是我们的屏幕上)对应的平面位置。怎么样,不知不觉中,我们已经实现了 gluProject 函数所完成的功能了,而反转这三个步骤就可以得到视口中指定位置所对应的世界坐标了(也就是 gluUnProject 的工作)。
CheckEvent与takeEvents
上一节我们遗漏了GraphicsWindowWin32::checkEvents和osgGA::EventQueue::takeEvents的关系。我们现在来讲解一下。先看一下checkEvents函数,这个函数的内容对于熟悉 Win32 SDK 编程的朋友一定非常熟悉,其中的TranslateMessage,DispatchMessage都是windows的消息传递函数,而它们的工作就是:通知 Windows 执行窗口的消息回调函数,进而执行用户交互和系统消息的检查函数GraphicsWindowWin32::handleNativeWindowingEvent。而这个函数的作用是把Win32 SDK 编程中常见的窗口消息(WM_*)转化并传递给osgGA::EventQueue 消息队列。而osgGA::EventQueue 消息队列通过takeEvents得到所有的windows窗口消息,并进行处理,以及清空EventQueue。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
switch(event->getEventType()) { case(osgGA::GUIEventAdapter::PUSH): case(osgGA::GUIEventAdapter::RELEASE): case(osgGA::GUIEventAdapter::DOUBLECLICK): case(osgGA::GUIEventAdapter::MOVE): case(osgGA::GUIEventAdapter::DRAG): { if (event->getEventType()!=osgGA::GUIEventAdapter::DRAG || eventState->getGraphicsContext()!=event->getGraphicsContext() || eventState->getNumPointerData()<2) { generatePointerData(*event); } else { reprojectPointerData(*eventState, *event); } eventState->copyPointerDataFrom(*event); break; } default: event->copyPointerDataFrom(*eventState); break; } |
回到osgViewer:: Viewer::eventTraversal()中,我们继续向下else也就是事件中的鼠标位置多于两个就会调用reprojectPointerData函数,它也是用来把鼠标从window屏幕坐标转换到主相机视口内坐标,和上一节内容基本相同。大家可以参照上一节内容进行理解。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
for(itr = gw_events.begin(); itr != gw_events.end(); ++itr) { osgGA::GUIEventAdapter* event = (*itr)->asGUIEventAdapter(); if (!event) continue; switch(event->getEventType()) { case(osgGA::GUIEventAdapter::CLOSE_WINDOW): { bool wasThreading = areThreadsRunning(); if (wasThreading) stopThreading(); gw->close(); _currentContext = NULL; if (wasThreading) startThreading(); break; } default: break; } } |
模模糊糊朦朦胧胧,我们也算是跳出了处理所有事件中鼠标坐标的for循环。我们只能继续向下前行。我们又遇到了一个for循环,这个for循环简单来说就是处理当窗口关闭消息osgGA::GUIEventAdapter::CLOSE_WINDOW发生时,osg会做什么样的工作,使其更加体面的离开。当我们选择关闭一个 GraphicsWindow 窗口 gw 时,OSG 系统必须首先尝试终止所有的渲染线程,然后关闭窗口,之后再打开所有的渲染线程。事实上,当我们试图在运行时开启一个新的 OSG 图形窗口时,也必须使用相同的线程控制步骤,即,关闭线程,创建新渲染窗口,开启线程。否则很可能造成系统的崩溃。
再往下我们也要针对目前帧的状态新建一个帧事件(也就是每一帧都会调用的事件),并添加到事件队列_evnetQuene中,然后同样得把这个帧事件中的鼠标坐标转化到主相机的视口坐标。再遍历一遍windows消息事件,添加到events中,并清空eventQuene队列。这样我们的events中就把所有来自图形窗口和视景器的事件都添加到一个 std::list 链表(event)当中, 下一步我们可以统一处理这些交互事件了.
欢迎大家来我的新家看一看 3wwang个人博客-记录走过的技术之路
探索未知种族之osg类生物---呼吸分解之事件循环二的更多相关文章
- 探索未知种族之osg类生物---呼吸分解之事件循环一
事件循环和更新循环 终于到了我们嘴里经常念叨的事件循环.更新循环以及渲染循环了.首先我们来区分一下事件循环和渲染循环,他们两个首先是两个不同顺序执行的过程,我们有时候会用到任意node的updateC ...
- 探索未知种族之osg类生物---呼吸分解之事件循环三
那我们就开始处理这些事件中得到的所有的交互事件,首先我们要判断这些事件是否包含osg的退出事件,那什么情况下会触发这个退出事件呢?如果您运行过osg中example中的小例子的,聪明的你一定就会发现当 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环二
_scene->updateSceneGraph(*_updateVisitor); 我们用了前面4节才刚刚算是完成对DatabasePager::DatabaseThread::run()函数 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环一
上节总结 前几天我们大体上介绍完成了osg的事件循环的介绍,总结一下osg的时间循环主要就是得到平台(windows)的所有消息,并遍历所有的node的eventCallback,并对他们进行处理.接 ...
- 探索未知种族之osg类生物---呼吸分解之渲染遍历二
那么今天我们就正式进入osg整个呼吸动作之中最复杂的一个动作,ViewerBase::renderingTraversals(),我们先介绍renderingTraversals的开头的简单的几步操作 ...
- 探索未知种族之osg类生物---呼吸分解之更新循环三
补充 当然细心的你会发现,_scene->updateSceneGraph(*_updateVisitor)中还有一个imagePager::UpdateSceneGraph()还没有进行讲解, ...
- 探索未知种族之osg类生物---呼吸分解之advance
回顾 我们用了两节的内容才堪堪讲解完ViewerBase::frame()函数中调用的realize()---Viewer:: realize()函数.我们简单的总结就是Viewer:: realiz ...
- 探索未知种族之osg类生物---呼吸分解之渲染遍历一
总结 前面我们基本上已经完成对ViewerBase::frame()函数的探究,只剩下renderingTraversals()渲染遍历的探究,虽然就剩下了一个函数,但是这却是最重要的,不可少的一个步 ...
- 《探索未知种族之osg类生物》目录
精力有限,博客园不在更新<探索未知种族之osg类生物>.在这里列出所有文章目录(持续更新)有兴趣的同学可以看看. 探索未知种族之osg类生物[目录] 前序 探索未知种族之osg类生物--- ...
随机推荐
- Redis Cluster在线迁移
由于之前的redis cluster物理硬件性能不足.决定升级到更好的服务器上.考虑到redis是核心生产数据库,决定在线迁移,迁移过程,不中断服务. 下面是测试环境的完成迁移步骤:1. 原环境(测试 ...
- spring 解耦
spring之后不用在类中new一个实体,而是在类中申明接口类:当真正使用的时候是注入相应的实现类,要什么类注入申明类:那么这样就面向接口编程了:耦合度大大降低: 同时spring有面向切面编程,其实 ...
- Steering Behaviors
[Steering Behaviors] 1.Seek 下述的算法是一个基本Seek行为,但不带任何Steering输出的力.在该公式作用下,游戏个体的移动方式是直线型的,如果target的位置变了的 ...
- javascript学习笔记(五):异常捕获和事件处理
异常捕获 Try{ 发生异常的代码块 }catch(err){ 异常信息处理 } <!DOCTYPE html> <html> <head lang="en&q ...
- nutch笔记
1.Nutch 是一个开源Java实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫.
- numpy的使用数组的创建2
随机创建了长度为十的数组 获得十以类的随机整数 快速获取数组2乘3维的数组 生成20个1到10之间的数组 通过reshape 将这些数变成二位数组 shape这个方法可以查看数组中的元素是几行几列的
- 解决IDEA查看源码时提示:Library source does not match the bytecode for class的问题分析
解决方法:
- MYSQL启用日志,和查看日志
mysql有以下几种日志: 错误日志: -log-err 查询日志: -log 慢查询日志: -log-slow-queries 更新日志: ...
- [剑指Offer]47-礼物的最大价值(DP)
题目描述 在一个m*n的棋盘每个格有一个礼物,每个礼物有一定价值(>0).从棋盘左上角到右下角,只能向下或向右走,问能拿到的礼物最大价值. 解题思路 dp. 可将二维数组版优化为一维数组版. 代 ...
- [剑指Offer]34-二叉树中和为某一值的路径
题目链接 https://www.nowcoder.com/practice/b736e784e3e34731af99065031301bca?tpId=13&tqId=11177&t ...
