引擎設計跟蹤(九.14.3.4) mile stone 2 - model和fbx導入的補漏

以前milestone2已經作完的工做, 如今趁有時間記下筆記.編輯器

1.設計工具

這裏是指兼容3ds max導出/fbx格式轉換等等一系列工做的設計.測試

最開始, Blade的3dsmax導出插件, 所有代碼都是寫在導出的DLL裏面的, 後來考慮到FBX等等其餘格式, 如今把模塊分紅兩部分:優化

  • Model/Anim Collector: 預約義的接口, 用於收集其餘模型的相關數據. 用戶負責擴展實現, 好比FBXCollector, MaxCollector, 或者其餘格式.
  • Model/Anim Builder: 負責調用Model Collector的預約義接口來生成Blade的Mesh, 內置在Model插件中並提供接口.

導入/導出之類的也天然分爲兩個phase:動畫

collecting data => building meshui

這麼作的好處是builidng mesh/animation的代碼所有能夠複用, 並且building mesh的代碼和複雜度纔是最大的. 因爲model builder內置到model模塊內部, 只要根據工廠建立出內置的對象就能夠了, 這有點像Java的風格.google

而collecting data做爲用戶可擴展的方式, 只要有定義良好的接口, 就能夠只實現model collector, 主要是使用三方SDK獲取數據, 工做量相對要小不少.spa

 

2.編輯器導入插件插件

對於編輯器來講, 設計的思路是能夠直接打開FBX文件. 好比像photoshop和3ds max這樣的軟件, 若是安裝了文件格式的插件, 就能支持打開對應格式文件.設計

以前Blade對於"文件導入"沒有任何抽象, 因而添加了下面的接口:

 1     struct SEditorImporterInfo
 2     {
 3         enum
 4         {
 5             IMPORTER_ID_TAG = 0x80000000,
 6         };
 7         TString            mName;            ///factory class
 8         TString            mTarget;        ///target IEditorFile type
 9         TString            mTargetExt;        ///target file extension
10         TStringList        mExtensions;    ///supported extensions
11         //importer type: assigned by framework
12         FileTypeID        mTypeID;        ///importer type IDs are in the same space of editor file type ids
13                                         ///FileTypeID with IMPORTER_ID_TAG represent a importer.
14         IconIndex        mIconID;
15 
16         inline bool operator<(const SEditorImporterInfo& rhs) const {return mName < rhs.mName;}
17         static inline bool comparePtr(const SEditorImporterInfo* lhs, const SEditorImporterInfo* rhs) {return *lhs < *rhs;}
18     };
19 
20     class BLADE_EDITOR_API IImporter : public TempAllocatable
21     {
22     public:
23         virtual ~IImporter() {}
24 
25         /**
26         @describe get the factory class name of the importer,
27         corresponding to SEditorImporterInfo::mName
28         @param
29         @return
30         */
31         virtual const TString&    getName() const = 0;
32 
33         /**
34         @describe 
35         @param source: input source file stream that importer can support
36         @param dest: output converted/imported format recognized by framework & plugins
37         @param params: extra parameters used for importing
38         @param extraFiles: extra file created by importer. extra files can only contains file names, files should be created at the same path/folder of input source file.
39         @param callback: callback for importing progress
40         @return
41         */
42         virtual bool    import(const HSTREAM& source, const HSTREAM& dest, const TParamList& params, TStringParam& extraFiles, CallbackRef& callback) = 0;
43     };
44 
45     extern template class BLADE_EDITOR_API Factory<IImporter>;
46     typedef Factory<IImporter> ImporterFactory;

導入信息記錄了: 支持的源文件格式(擴展名), 目標格式. 也就是說, 導入器並不提供文件格式的解析(不會根據文件內容來建立任何編輯器對象), 只是單純的轉換成(其餘插件)已經支持的其餘格式.

這樣以來, "導出"實際上作的事情就是格式轉換. 好比FBX導入插件, 是使用FBXCollector和IModelBuilder, 生成Mesh(blm)文件到一個stream裏面, 而blm文件已經有插件能夠將它打開了.

在編輯器使用的時候, 能夠直接拿memory stream做爲dest stream, 經過導入器fbx文件完成格式轉換, 而後在根據導入信息裏面的"目標格式", 用工廠建立真正要打開的文件實例來打開轉換後的stream; 等打開成功之後, 刪除掉memory stream/memory file system裏面的文件(臨時mesh文件).

 

3.批量格式轉換(CLI)

因爲fbx文件的轉換代碼所有在編輯器的fbx importer插件裏面, 爲了模塊複用, 這裏的model converter工具其實是手動加載了fbx importer插件, 跳過編輯器的管線, 直接調用import接口完成文件格式轉換.

同時, 添加了makefile來支持批量的fbx轉換.

 

問題1: 模型/骨骼/動畫合併

這個是跟具體項目的spec相關的, 不少項目的動畫文件是拆分紅單個clip的, 每一個動畫對應一個源文件. 有的是單個文件包含全部的動畫.

blade的model converter 支持多個源文件合併, 爲了makefile可以方便處理, 只要將一組動畫/模型放入同一個子文件夾, makefile會拿到全部文件列表並調用converter來合併出最終的模型和動畫.

對於runtime, 實際項目中, 有的商業引擎沒有很好的處理和優化, 致使一個角色的全部不一樣的裝備對應的全部骨骼, 都會參與骨骼計算, 實際上有不少是無效的 - 沒有任何綁定. 並且有的引擎, 實際上想作針對性的優化, 也很難下手, 改動比較大. 由於實際項目中遇到過相似的狀況, 因此Blade以及提早考慮並作了處理: 只有在runtime具備有效綁定mesh的骨骼才參與動畫計算, 不然忽略.

 

問題2: 集成到工程

這個問題和之前的tex compressor同樣, 把makefile集成到工程, 而且把max文件轉換成fbx放入庫裏做爲源文件, 實現一鍵構建, 具體怎麼作再也不記錄了.

因爲如今的測試資源愈來愈多, 因此工程上也把美術資源和代碼分開, 單獨放到一個repo裏面去.

使用fbx的另一個好處就是, 調試和改進mesh的導入/導出, 均可以不依賴3ds max了.

 

其餘

submesh的bounding計算

在google上查到的最好方式, 是根據模型的綁定信息, 生成對應骨骼的包圍. 注意全部綁定信息都在模型上面, 只要拿到對應骨骼id全部的頂點, 就能夠計算出包圍盒; 不須要骨骼/動畫文件的任何信息.

因此包圍盒能夠只根據模型文件離線生成. 以後runtime更新時, 再根據骨骼動畫來變換包圍盒.

 

包圍盒更新和可見性依賴

Blade的動畫流程大體以下: 若是模型不可見, 那麼就不會更新動畫, submesh的包圍盒就不用更新.

這裏有一個死結, 就是模型的可見性自己也依賴包圍盒, 若是不更新骨骼動畫和包圍盒, 就可能影響可見性.

目前解決方案是: 拿模型的靜態包圍盒作粗略的視錐剔除

  • 若是所有可見, 就不更新包圍盒, 只更新骨骼動畫, 雖然這個時候可能會有不可見的submesh沒有更新到, 可是影響不大隻會有一點overdraw.
  • 若是部分可見, 那麼就更新骨骼動畫, 並根據LOD信息選擇性的更行submesh的包圍盒, 作更細粒度的剔除.
  • 若是不可見, 那麼就不更新動畫和包圍盒. 這裏有一個前提就是模型的靜態粗略的包圍盒要足夠大, 不然會影響視覺, 致使動畫中的submesh原本可見, 可是模型的粗略視錐剔除致使其不可見.

 

動畫LOD

因爲遠處的物體自己就比較小, 因此能夠不更新包圍盒. 這個能夠經過骨骼動畫的LOD來調整.

LOD的計算並不是是根據距離, 實際上應該根據屏幕上投影后的大小來, 由於遠處的動畫可能很大, 未必就應該忽略.

而骨骼動畫的計算頻率也不須要滿幀計算, 記得以前提到過, 30FPS已經到達人眼的識別上限, 實際上大部分電影24FPS就足夠, 但遊戲有不少不一樣http://www.zhihu.com/question/21081976, 並且現代電影都是48FPS, 有兩幀同樣的畫面來組成.

目前Blade會根據投影后的尺寸來調整骨骼動畫計算頻率, 好比較遠/較小的動畫就會用低頻更新, 最高頻率也不會是滿幀, 而是大約66FPS.

相關文章
相關標籤/搜索