此次分析以0.3版本中所帶的eqPly應用為對象,從入口(main)函數入手,由外向內逐步深入,重點是流程與主要對象的結構。
一個Equalizer驅動的系統包括一個伺服器(server)與若干用戶端,其中用戶端分為兩類,一類是應用用戶端(application),一類是渲染用戶端(render client)。
用戶端的編程介面由一系列以樹狀結構管理的資來源物件實現,這些對象包括config、node、pipe、window、channel,通過一個nodeFactory對象進行封裝,並根據用戶端從伺服器擷取的compoun進行配置,同時由各個對象的可重載Task介面自動響應來自伺服器的各項指令。
main函數
1. 建立eqPly::LocalInitData對象,解析命令列參數;
2. 建立NodeFactory用於Equalizer的初始化;
3. 建立一個用戶端的子類client=eqPlay::Application對象,該對象是應用與渲染過程的主要對象;
4. 運行client對象;
5. 釋放對象並退出;
其中第2至5步為主要的工作。
一個EqPly應用用戶端中包含三個主要的對象,用於管理全部Equalizer資源的nodeFactory對象,其中的各個成員對象負責完成配置的管理以及響應來自伺服器的指令;用於應用配置的InitData對象,其中包括解析命令列所獲得的參數,從系統自動獲得的狀態資訊,以及用於進行分布式渲染的資料;用戶端client對象則用於管理整個用戶端應用。
命令列的解析
命令列的解析是由LocalInitData對象利用TCLAP命令列工具實現,該工具可直接將命令列參數解析為不同的參數。
其中以TCLAP::CmdLine作為命令列的解析器,然後將不同類型的TCLAP::Arg對象添加到該解析器內部,由TCLAP::CmdLine::parse命令完成對命令列的解析。
命令列解析後的參數作為成員變數由LocalInitData類及其父類的對象儲存,並通過公用介面擷取實際資料。
eq::init
該函數首先根據命令列參數中的“—eq-server”確定伺服器的地址,然後構造Global::_nodeFactory,最後根據命令列參數對eqNet進行初始化。
Application::run()
1. 首先根據命令列參數建立server對象並與之建立串連;
2. 然後從server擷取配置資料,即Config對象,其中包含的FrameData對象就是用於多個用戶端之間同步的幀資料;
3. 根據初始化資料對Config對象進行初始化,其中也包括FrameData對象資料的初始化,此時server會等待所有的client與renderer都完成初始化後才會返回;
4. 進入渲染迴圈,首先在config::startFrame中更新同步資料_frameData,打包並向外發送資料,;
5. 退出config對象;
6. 清空並退出;
空間資料的管理
根據Ply模型資料以頂點和面作為基本的構成元素的特點,eqPly中通過一組模板類對模型(N對象進行封裝,即typedef PlyModel< NormalFace<ColorVertex> > Model,其中face的類型ormalFace)與vertex的類型(ColorVertex)均為模板對象的執行個體類型。
PlyFileIO.h與PlyFileIO.h定義檔案操作類PlyFileIO,該類首先根據檔案名稱嘗試載入已經處理成八叉樹結構的二進位檔案,如果載入失敗則嘗試載入原始的ply檔案,注意ply檔案同樣存在ascii與二進位兩種類型。
PlyModel.h與PlyModel.cpp用於定義模板類template<class FaceType> class PlyModel,該類基於多邊形面和八叉樹的包圍盒對模型資料進行管理。“八叉樹類似於軸對齊BSP樹,沿著長方體的三條軸對長方體進行同時分割,分割點必須位於長方體的中心,這樣可以產生8個新的長方體”。每個包圍盒以其長方體的頂點座標中的最大值、最小值兩個三維向量進行描述,見PlyModel::calculateBBox()。
在直接從ply檔案中讀模數型資料時,PlyModel通過setFaces擷取面資料並根據鬆散八叉樹規則進行劃分,從而構造完整的模型對象;當以二進位形式載入已經處理好的模型資料時,PlyModel以二進位形式從緩衝中直接讀取以八叉樹形式儲存的資料來填充模型對象。
PlyModel的二進位檔案格式如下:
version (檔案版本號碼)
_nFaces (模型的總面數)
_faces (多邊形的面資料,以bbox所定義的順序進行儲存)
_bbox (包圍盒的八叉樹)
normalFace.h、colorVertex.h、Vertex.h用於定義上述模板類中所用的FaceType與VertexType類型,這裡均是以結構體形式定義,而不是類的形式,估計Eileman認為這些對象只是用於封裝資料而與操作無關。
eqPly中的模型載入,在進行包圍盒處理時由於記憶體佔用過多導致分配失敗,具體見PlyModel<FaceType>::fillBBox。因此如何解決大規模資料的載入與處理是首先需要解決的問題。
eqPly的渲染
eqPlay對模型的管理在eqPly::Node中進行,在Node::IniConig中載入模型,若命令列參數中指定了載入的模型並能夠從工作目錄中成功載入該模型,就以該模型進行渲染,否則如果是從VC中運行,則從預設路徑下擷取rockerArm.ply模型,如果直接從命令列運行或者該模型仍無法正常載入,則構造簡單的四邊形模型對象。
命令列中採用[-m string]的格式指定模型檔案,string為ply模型的檔案名稱,eqPly首先察看是否存在已經進行了格式轉換,即進行了包圍盒劃分的位元據檔案(*.b32),如果有該檔案可直接載入,否則就需要先載入ply檔案,在完成檔案解析和包圍盒劃分後建立模型對象,同時將模型資料儲存為位元據檔案(*.b32)共以後的快速載入,模型檔案的載入由PlyFileIO類實現。
載入好的模型對象由PlyModel的對象,以八叉樹的包圍盒結構進行管理,每個包圍盒節點包含包圍盒資料,包圍球以及其中的多邊形面資料。
在渲染某個節點時,首先根據該根節點的包圍球與視錐的資訊進行可視化檢測,若該包圍球完全位於視錐內則認為該包圍盒內的多邊形均為可見,則遍曆該節點下的所有節點並逐個執行各個節點的渲染指令;若包圍球只是部分的位於視錐內,則該節點為部分可見,此時需要對該節點的所有子節點進行可見度的檢測。上述迭代過程從模型對象的根節點開始,直至對模型的所有節點進行檢測和渲染後結束。
當確定某個節點可以進行渲染時,首先尋找該節點的對應顯示列表是否存在,若存在則直接採用顯示列表進行渲染,否則根據節點記憶體儲的多邊形面資料建立顯示列表並據此進行渲染。