探索未知種族之osg類生物---呼吸分解之事件循環二

探索未知種族之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。

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屏幕座標轉換到主相機視口內座標,和上一節內容基本相同。大家可以參照上一節內容進行理解。

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)當中, 下一步我們可以統一處理這些交互事件了.

歡迎大家來我的新家看一看 www.3wwang.cn

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章