OGRE SampleBrowser框架解析

OGRE簡析(一)

                                                                             ------OGRE SampleBrowser框架解析

“偉大航路,我把世界上的一切都放在了那裏,有種的話就去領取吧”

這是OGRE中文網的一則廣告,我想,無論作爲OGRE的學習者還是漫漫人生的一名旅人,這句話都是非常不錯的激勵語。放在這,是否能夠讓你隱約看到屬於自己的新世界?


簡介

Ogre(Object-oriented Graphics Rendering Engine)是一款優秀的C++開源圖形渲染引擎。OGRE主要提供渲染引擎,但是在系統API,文件管理以及範例中都提供的非常豐富的接口和範例,在設計模式上也有很多考究,代碼書寫的也比較規範,無論是作爲使用還是學習,都有着非常不錯的價值。

       OGRE整體不算小,目前支持Windows、Linux、IPHONE、MAC、SYMBIAN五個平臺,作爲一個學習三維的新手來說,個人認爲難度還算不小。當你運行範例框架時,在驚詫其界面絢麗之餘,多少很有一點無從下手。而且OGRE也藉助了不少第三方庫,其範例界面儼然就是一個典型的Windows遊戲界面, 對於沒有接觸過的人們來說,和在.Net下的界面開發有很大的不同,這也加大的初學的難度。如果僅看一個一個的局部案例而缺乏對整體框架的理解,又難免有管中窺豹之遺憾。

       本文主要是針對範例框架部分的介紹,涵蓋範例框架啓動、顯示和其後的UI界面操作部分。針對範例框架,分析了OGRE在初始化、創建窗口、鼠標鍵盤事件響應、資源加載以及範例加載、渲染顯示這幾個模塊的技術實現,另外對這幾塊所用到的框架和設計模式進行了總結。算是對所學知識的總結,也方便接下來對案例所涉及的三維細節技術的研究。

備註:OGRE下載編譯參考


SampleBrowser範例

Ogre範例寫的很簡單,main函數中僅有如下兩行

OgreBites::SampleBrowser sb;   sb.go();

可見,範例完全封裝在SampleBrowser類中,只需要調用一下go函數即可。但這兩句話的效果卻非常豐富,展現給我們一個交互式的範例展現界面,期間經過了root的初始化、窗口的創建、鼠標鍵盤事件的綁定和監聽,系統資源的加載、範例程序的加載等,旅途可謂豐富多彩,期間無論是框架還是技術細節實現,都值得學習和推薦。不妨現在就開啓此次旅途第一站。


範例簡析
createRoot

Ogre::Root* mRoot是SanmpleBrowser最重要的成員變量,和三維相關的渲染引擎、窗口、以及事件監聽都是有其實現的,並完成整個過程的驅動,數據更新和渲染。

SanmpleBrowse啓動的第一步,就是Root類的構造,Root相當於OGRE的地基,渲染場景和引擎、以及各種文件系統的管理和加載都是在Root構造函數完成的,代碼相對簡單明瞭,如果對UGC插件機制瞭解的話,插件加載等方式也基本一致,相對難度不大。

Root構造函數主要進行了:

1.      Manager初始化(DynLibManager插件管理、ArchiveManager文件管理、
ResourceGroupManager資源文件管理、OverlayManager管理)

2.      具體文件系統的加載(普通文件、zip)

3.      窗口的初始化(mAutoWindow = 0)

4.      插件加載(loadPlugins(pluginFileName),渲染引擎的加載)

其後會根據配置文件設置Root的屬性,最關鍵的是設置渲染引擎類型(OpenGL、D3D)


createWindow

在Root構造之後,便開始窗口的初始化創建過程,其本質是調用Root函數的initialise()函數,返回RenderWindow的窗口指針。

Initialize函數調用非常方便,但內部處理還是非常複雜,關鍵成員對象如下:

l  Rendersystem(GLRenderSystem)

l  GLSupport(Win32GLSupport)

l  RenderWindow(Win32Window)

l  Win32Context

其中,Rendersystem就是GL的渲染引擎,Win32GLSupport負責屏幕相關的大小,位深,像素等信息的傳遞,而Win32Window則負責調用Win系統函數來實現窗口的創建,以及與OpenGL建立關聯,而Win32Context則用來存儲創建窗口後的句柄等信息,函數大致過程如下:

mRoot->initialise(true, "OGRE Sample Browser");-> Rendersystem _initialise->

mGLSupport->createWindow(Win32GLSupport)-> Win32GLSupport::newWindow->

Win32Window.create-> mContext = new Win32Context(mHDC, mGlrc);

Win32Window.create函數中,在CreateWindowEx創建窗口後,通過wglCreateContext和wglMakeCurrent,將OpenGL與窗口的HDC建立關聯,而Win32Context用來存儲此句柄

如上,一個空白的Windows窗口創建完成。


setupInput

窗口創建完畢後,下一步就是鼠標鍵盤事件的處理了,在OGRE中採用了OIS開源庫來負責打理相關事務,OIS庫專門用來處理外部設備(鍵盤、鼠標、操縱桿、觸摸屏)和程序之間的,而且支持跨平臺,在遊戲程序中還是非常實用的。

另外分析一下SampleContext類,繼承自FrameListener,WindowEventListener,KeyListener,MouseListener四個類,FrameListener用來監聽OGRE三維渲染中的事件響應,WindowEventListener則用來監聽Windows消息事件,而後兩者則處理程序內部事件響應。

OIS主要文件有三類:

l  OISInputManager
統一處理外部設備的管理類

l  OISKeyboard
負責鍵盤事件的處理類

l  OISMouse
負責鼠標事件的處理類

使用時,調用OIS::InputManager::createInputSystem返回OIS::InputManager管理,核心函數爲DirectInput8Create函數,雖然在msdn中都沒有此註釋,可不要小看這個函數,用於創建和Win下外部設備交互的管理對象,封裝成OIS的InputManager返回給用戶來管理。由InputManager創建出對應的鼠標鍵盤對象。

在使用中,可大致分爲三個模塊來實現外部設備的響應:

l  外部事件的響應WindowEventUtilities::messagePump(),用來接收系統事件,比如激活當前窗口,關閉,窗口變化等等,處理程序之間的消息事件

l  在OGRE渲染過程中,之前將SampleContext類添加到Root中進行監聽
(mRoot->addFrameListener(this)),實時渲染中renderOneFrame會調用監聽類的
captureInputDevices,分別處理鍵盤和鼠標類的響應(mKeyboard->capture(),mMouse->capture();)

l  在鼠標和鍵盤監聽中,會在capture中分析當前的行爲(鼠標移動,按鍵操作等),最終在SampleBrowser中實現響應操作
如上,通過監聽類和OIS開源庫,採用回調函數,實現了外部設備和程序的交互操作


Loadresources

之後是加載範例中所用到的資源文件,也是是程序加載過程中顯示進度條的過程。此時主要是由SdkTrayManager、OverlayManager和ResourceGroupManager來處理,前者用來負責界面進度條更新,OverlayManager用來負責界面顯示部分,後者用來加載資源。首先構造進度條,進度條和其描述內容都是通過構建OverlayElement完成。

OverlayElement是一個非常有用的界面顯示元素,有點類似Dreamweaver中的層的作用,一些在屏幕中界面元素,比如遊戲視角中的駕駛艙,指南針等相對影像不變的部分,都可以以OverlayElement的形式來體現。OverlayElement本身有一些固定模板,也可以通過配置文件的形式來構建,可見,OverlayElement在遊戲中是一個非常常用的對象。

SdkTrayManager構建完界面元素對象後,則加入到ResourceGroupManager中進行監聽,而在ResourceGroupManager中會加載resources_d.cfg中包含的資源文件,分爲二進制和zip壓縮文件兩種,每次解析文件時通過監聽機制,對SdkTrayManager進行數值更新,而SdkTrayManager則驅動RenderWindow更新(renderwindow->update)

Root中Render渲染過程:分爲Update和Render兩部分,但均在一個線程下完成,在一系列Update後,最終調用GLRenderSystem的Render,完成此幀的渲染,其順序大致如下:renderwindow->update-> rendertarget update-> SceneManager Update RenderQueue-> SceneManager::renderSingleObject-> GLRenderSystem::_render(const RenderOperation& op),詳細的就不多說了,這也是今後研究的重點了。

最後,資源加載完,設置進度條對應了Overlay爲不可見,則資源加載過程完畢。


SampleLoad

資源加載完畢後,則開始導入具體範例,生成Sample對象來統一管理範例。

setupWidgets()則負責完成範例界面相關的部署

OGRE對範例也定義了一系列規範採用插件的方式來加載範例,最終由mLoadedSamples容積保存。mThumbs負責存儲範例的縮略圖容器,本身也是Overlay的容器集合。

在範例加載完成後,OGRE的界面顯示過程宣告結束,這時用戶通過鍵盤鼠標的外部輸入來進行範例的選擇。同樣通過OIS來進行維護,判斷鍵盤的上下移動,更新顯示內容。


框架解析

OGRE上述過程只是冰山一角,但就複雜度來說也不低,得益於OGRE的框架設計,OGRE在使用中設計的非常優良,在實現最初就做過很多好的設計模式,而且定義的很規範,這些程序員對C++編碼經驗可謂非常豐富。在如上的學習中,個人大概總結了三個模塊:

l  三維渲染框架
一個while(true)類似的循環,則開始了OGRE中每一幀的渲染。OGRE中渲染框架分爲Update和Render兩部分,均在一個線程中完成,這在遊戲中,數據量不大的情況下感覺沒有問題。通過Root驅動,最終,構造出RenderOperation來讓RenderSystem進行渲染。其渲染思路和我們的可以說完全一致,而我們則是在此思路基礎上用兩個線程來分別管理數據和渲染,在實際應用中則有更好的應用範圍。

三維渲染將渲染的核心代碼獨立,則用戶在上次則專注於業務層,最終完成RO後調用渲染引擎完成即可,降低了理解的複雜度。

這一部分在本章裏面不做過多描述,相信今後會有很多關於這最長的一幀的描述。

l  設計模式(單例(fun dllStartPlugin)、插件、封裝第三方庫、觀察者模式)
OGRE中的設計模式應用很老練,讓各種複雜的管理變得錯落有致。

n  單例模式
class Singleton
OGRE爲了保證所有管理類的唯一性,都繼承自單例模板類,所有的Manager並不以全局變量的方式在程序啓動前加載,而是作爲Root的成員,在Root初始化時構建,單例類的實現也比較簡單,但還是比較實用的,其實,最關鍵的一句個人認爲是:ms_Singleton = static_cast< T* >( this );獲取派生類的指針,進行上行轉換獲取管理類的唯一指針

n  插件機制
這個和我們的技術實現細節完全一致,但提供Plugin基類,方便插件的開發

n  封裝
和我們類似,對第三方庫的使用,OGRE封裝了一箇中間層管理,避免第三方庫和本身的過多的交涉。比如zip壓縮文件的讀取。

n  觀察者模式(監聽)

在消息傳遞中,OGRE採用監聽的方式,比如提供FrameListener類來處理消息事件,每次消息傳遞中,對關注的聽衆都進行傳遞。這種觀察者模式的技術實現不難,卻可以很靈活的解決很多棘手的問題。

在我們的類庫中,其實也有必要有一個監聽的基類,在需要時可以靈活解決問題。比如在傳統二維顯示中,都是在顯示的框架中,驅動讀取數據,然後繪製,顯示到界面的線形順序,而在讀取網絡數據時這樣的用戶效果則非常差了,一般需要以數據驅動顯示,下載完一部分數據則驅動顯示更新,由於框架依賴關係和已有代碼的限制,數據層無法直接聯繫到顯示層,通過觀察者模式,則可以在每次下載完後對聽衆發送消息,驅動更新,則非常方便的處理這種使用場景。

觀察者模式,在框架複雜的情況下,可以很好的降低耦合度,提供框架靈活性。

l  資源管理框架(配置文件、插件、cfg、文件系統)
OGRE的配置文件非常多,不論是系統級別的(日誌、插件資源、顯示效果)還是資源級別的(Overlay、zip、圖片),這都減少了不必要接口的添加,方便用戶的使用,畢竟,在遊戲中,一些顯示效果,裝備等都可以在資源文件中打包,無需在程序中進行設置,點到爲止吧,不多寫了,有點寫煩了,呵呵。


總結

l  遊戲完整性
縱觀OGRE的範例,採用插件方式集成案例,整個界面都以Overlay作爲元素展現,藉助OGRE的實時渲染引擎,達到了一個非常精緻的顯示效果,典型的遊戲畫面,另外,也很好的考慮了和外部設備的交互,一個基礎的遊戲框架在OGRE中很快捷的搭建完成。

l  設計模式優雅
OGRE不僅僅實現了3D引擎的渲染功能,也包含了很多其他功能,同時藉助了很多開源庫,也滿足使用人員的擴展,這些能夠糅合在一起,難度非常大,能將這些繽紛的功能和模塊有序的整合在一起,對開發人員的設計模式有不小的考驗,何時使用合適的設計模式達到適度的效果,這需要很好的把握,太粗獷或精緻的考慮都有可能導致不適用和易用性的考驗。
OGRE也是一款非常悠久的開源庫,採用插件的定製化方式,隨着新技術和新的設計模式的開展,也是不斷演化,本身能夠有如此豐富的擴充性,也是非常難得的,這體現了很多管理類的設計的成熟和優雅。

l  其他
OGRE有一個不錯的地方就是將所做的一切百分百的完成,很多工作儘量以擴展插件的方式完成。比如管理類,都有單例來進行控制。插件機制有了,但有基類來提供規範,方便用戶理解和擴展。配置文件也定義的很清晰。
OGRE的擴展機制也很靈活,不會出現那種要麼全要要不什麼都沒有的選擇,整合許多優秀的元素(第三方庫、物理引擎、影音套件),藉助整合更好的計劃你的方案,而不是被不喜歡的拖累着走。
誠然,OGRE本身還是有一定難度的,如果沒有豐富的編程經驗和技能,閱讀起來肯定還是有不少難度的,這也體現了OGRE開發者的能力和活力。“我們非常小心地挑選我們的團隊成員,程式技巧是最重要的能力,可以跟別人好好溝通,對於討論持著開放得心胸,可以與目前的團隊成員在設計和撰寫程式方面保持一致得概念並且可以獨立工作,這些都是必需的。”這是OGRE招募開發者的標準,而核心團隊會控制在5人以下,這也很好的保證了OGRE庫的功能,設計和品質。而作爲開源代碼,很多都是在工作之外的創作,這種發自自身的動力也是非常欽佩。

這是一個精彩的世界,無論是C、C++還有Java,還是一些新型語言Python、Silverlight、XNA,或者Go等還沒有普及的語言,無論是傳統的Windows,還是移動或者各種嵌入式終端和機器人,各種技術和領域都充斥着人類的生活和工作領域,多少有點亂花漸欲迷人眼的味道,想學的有很多,在這樣一個浮躁的世界裏,會有很多急於求成的人和事情,希望會有更多的人能夠深入研究各自領域的知識,讓自身獲取更寶貴的財富和經驗。

無論你關注底層技術還是前臺應用,無論你希望成爲管理者還是所謂的碼農,如果因爲外界而有所動搖,只能證明你對成功沒有足夠的渴望,記住,最寶貴的東西都流淌在你的血液中,不會因爲這些稱謂而改變。

發佈了3 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章