Chinaunix首页 | 论坛 | 博客
  • 博客访问: 21628
  • 博文数量: 16
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 170
  • 用 户 组: 普通用户
  • 注册时间: 2019-02-19 14:05
文章分类

全部博文(16)

文章存档

2019年(16)

我的朋友

分类: C/C++

2019-03-01 12:36:43

    eventTravel

    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::checkEventsosgGA::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个人博客-记录走过的技术之路
阅读(638) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~