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

VPM矩陣

1、V 表示攝像機(jī)的觀察矩陣(View Matrix),它的作用是把對象從世界坐標(biāo)系變換到攝像機(jī)坐標(biāo)系。因此,對于世界坐標(biāo)系下的坐標(biāo)值 worldCoord(x0, y0, z0),如果希望使用觀察矩陣 VM 將其變換為攝像機(jī)相對坐標(biāo)系下的坐標(biāo)值 localCoord(x’, y’, z’),則有:

localCoord = worldCoord * VM

此外,觀察矩陣可以理解為“攝像機(jī)在世界坐標(biāo)系下的變換矩陣的逆矩陣”,因此 Camera類也專門提供了 getInverseViewMatrix 這樣一個函數(shù),它的實(shí)際意義是表示攝像機(jī)在世界坐標(biāo)系下的位置。

2、P 表示投影矩陣(Projection Matrix),當(dāng)我們使用 setProjectionMatrixAsPerspective之類的函數(shù)設(shè)置攝像機(jī)的投影矩陣時,我們相當(dāng)于創(chuàng)建了一個視截錐體,并嘗試把包含在其中的場景對象投影到鏡頭平面上來。如果投影矩陣為 PM,而得到的投影坐標(biāo)為 projCoord(x”,y”, 0)的話,那么:

projCoord = localCoord * PM

3、W 表示視口矩陣(Window Matrix),它負(fù)責(zé)把投影坐標(biāo)變換到指定的二維視口中去,對于視口矩陣 WM,通過下面的公式可以得到最終的窗口坐標(biāo) windowCoord(x, y, 0):

windowCoord = projCoord * WM

將所有的公式整合之后,得到:

windowCoord = worldCoord * VM * PM * WM

而這個所謂的窗口坐標(biāo) windowCoord,實(shí)際上也就是世界坐標(biāo)系下的坐標(biāo)值 worldCoord在指定的攝像機(jī)視口中(也就是我們的屏幕上)對應(yīng)的平面位置。怎么樣,不知不覺中,我們已經(jīng)實(shí)現(xiàn)了 gluProject 函數(shù)所完成的功能了,而反轉(zhuǎn)這三個步驟就可以得到視口中指定位置所對應(yīng)的世界坐標(biāo)了(也就是 gluUnProject 的工作)。

CheckEvent與takeEvents

上一節(jié)我們遺漏了GraphicsWindowWin32::checkEventsosgGA::EventQueue::takeEvents的關(guān)系。我們現(xiàn)在來講解一下。先看一下checkEvents函數(shù),這個函數(shù)的內(nèi)容對于熟悉 Win32 SDK 編程的朋友一定非常熟悉,其中的TranslateMessage,DispatchMessage都是windows的消息傳遞函數(shù),而它們的工作就是:通知 Windows 執(zhí)行窗口的消息回調(diào)函數(shù),進(jìn)而執(zhí)行用戶交互和系統(tǒng)消息的檢查函數(shù)GraphicsWindowWin32::handleNativeWindowingEvent。而這個函數(shù)的作用是把Win32 SDK 編程中常見的窗口消息(WM_*)轉(zhuǎn)化并傳遞給osgGA::EventQueue 消息隊(duì)列。而osgGA::EventQueue 消息隊(duì)列通過takeEvents得到所有的windows窗口消息,并進(jìn)行處理,以及清空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()中,我們繼續(xù)向下else也就是事件中的鼠標(biāo)位置多于兩個就會調(diào)用reprojectPointerData函數(shù),它也是用來把鼠標(biāo)從window屏幕坐標(biāo)轉(zhuǎn)換到主相機(jī)視口內(nèi)坐標(biāo),和上一節(jié)內(nèi)容基本相同。大家可以參照上一節(jié)內(nèi)容進(jìn)行理解。


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):

????????????????????{

????????????????????????boolwasThreading = areThreadsRunning();

????????????????????????if(wasThreading) stopThreading();


????????????????????????gw->close();

????????????????????????_currentContext = NULL;


????????????????????????if(wasThreading) startThreading();


????????????????????????break;

????????????????????}

????????????????????default:

????????????????????????break;

????????????????}

????????????}

模模糊糊朦朦朧朧,我們也算是跳出了處理所有事件中鼠標(biāo)坐標(biāo)的for循環(huán)。我們只能繼續(xù)向下前行。我們又遇到了一個for循環(huán),這個for循環(huán)簡單來說就是處理當(dāng)窗口關(guān)閉消息osgGA::GUIEventAdapter::CLOSE_WINDOW發(fā)生時,osg會做什么樣的工作,使其更加體面的離開。當(dāng)我們選擇關(guān)閉一個 GraphicsWindow 窗口 gw 時,OSG 系統(tǒng)必須首先嘗試終止所有的渲染線程,然后關(guān)閉窗口,之后再打開所有的渲染線程。事實(shí)上,當(dāng)我們試圖在運(yùn)行時開啟一個新的 OSG 圖形窗口時,也必須使用相同的線程控制步驟,即,關(guān)閉線程,創(chuàng)建新渲染窗口,開啟線程。否則很可能造成系統(tǒng)的崩潰。

再往下我們也要針對目前幀的狀態(tài)新建一個幀事件(也就是每一幀都會調(diào)用的事件),并添加到事件隊(duì)列_evnetQuene中,然后同樣得把這個幀事件中的鼠標(biāo)坐標(biāo)轉(zhuǎn)化到主相機(jī)的視口坐標(biāo)。再遍歷一遍windows消息事件,添加到events中,并清空eventQuene隊(duì)列。這樣我們的events中就把所有來自圖形窗口和視景器的事件都添加到一個 std::list 鏈表(event)當(dāng)中, 下一步我們可以統(tǒng)一處理這些交互事件了.

歡迎大家來我的新家看一看?3wwang個人博客-記錄走過的技術(shù)之路

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容