文章來源:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view-2.html
CLoad3DS類是Sourceforge中的一個開源項目,作用在於幫助開發者學會簡單的對3DS文件的載入(OpenGL)程序。雖然有更成熟更強大的3dslib庫,但是平時寫寫Demo中,對模型載入的要求一般比較低,這時候只把CLoad3DS類包含到程序就夠了。——ZwqXin.com 本文承接上篇文章:一個讀取3DS文件的類CLoad3DS淺析Ⅰ 。
本文來源於 ZwqXin (http://www.zwqxin.com/),
轉載請註明
原文地址:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view-2.html
上文提到,ProcessNextChunk(&Model3DS, m_CurrentChunk)這個函數做了模型載入部分最重要的東西。
- // 下面的函數讀出3ds文件的主要部分
- //注意傳入的後一個參數是剛被ReadChunk過的m_CurrentChunk,也就是說它從0x4D4D塊(樹幹)後開始繼續處理,並把0x4D4D塊作爲pPreviousChunk(前一個塊)
- //處理樹結構的常用手法就是遞歸
- void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
- {
- ..........
- m_CurrentChunk = new tChunk; // 爲新的塊分配空間
- //因爲父塊的length是子塊length總和,而又由0x4D4D塊開始,故這個while會遍歷整個3DS文件數據
- //然後我們在“case OBJECTINFO”中找到了遞歸,因爲OBJECTINFO(0x3D3D,3D editor chunk)就是父塊0x4D4D的最直接子塊,這次遞歸中的ProcessNextChunk函數中,while中的pPreviousChunk是遞歸前(上一層)的m_CurrentChunk,因此switch中尋覓的將是上一層所進入的這個OBJECTINFO塊下的子塊(找到MATERIAL或OBJECT來處理直至該OBJECTINFO的遞歸完結,回來繼續0x4D4D下的尋覓)。
- //總覺得說着說着自己也濛濛的(這就是遞歸!),事實上EDITKEYFRAME跟OBJECTINFO是同級的,不過我們本來就沒用到EDITKEYFRAME這種塊,故遇到它只是略過(單純用它所“擁有”的length來增加0x4D4D的bytesRead)
- //總之呢,你打開某殺毒軟件從“我的電腦”開始殺一次毒,觀察一下查殺順序能加深理解恩
- while (pPreviousChunk->bytesRead < pPreviousChunk->length)
- {
- ReadChunk(m_CurrentChunk);// 讀入下一個塊
- switch (m_CurrentChunk->ID)
- {
- case VERSION: ... // 文件版本號
- break;
- case OBJECTINFO: .... // 網格對象信息(3D editor chunk)
- ProcessNextChunk(pModel, m_CurrentChunk);//!!!
- break;
- case MATERIAL: .... // 材質信息
- break;
- case OBJECT: .... // 對象的名稱
- break;
- case EDITKEYFRAME: .....
- break;
- default:
- // 跳過所有忽略的塊的內容的讀入,增加需要讀入的字節數
- m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
- break;
- }
- // 增加從最後塊讀入的字節數
- pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
- }
- // 釋放當前塊的內存空間
- delete m_CurrentChunk;
- m_CurrentChunk = pPreviousChunk;
- }
case語句中的處理函數隨chunk的ID(種類)不同而不同,但這些處理函數多少也是遞歸函數。分配存儲空間後,從文件讀入後存入相應的數據結構中,並增加該chunk的bytesRead。最需要注意的是,一般由3DS MAX導出的3ds文件的模型座標跟OPENGL中不同,在讀入頂點時要處理(swap)一下。
- // 讀下一個塊
- void ProcessNextChunk(t3DModel *pModel, tChunk *);
- // 讀下一個對象塊
- void ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *);
- // 讀下一個材質塊
- void ProcessNextMaterialChunk(t3DModel *pModel, tChunk *);
- // 讀對象顏色的RGB值
- void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk);
- // 讀對象的頂點
- void ReadVertices(t3DObject *pObject, tChunk *);
- // 讀對象的面信息
- void ReadVertexIndices(t3DObject *pObject, tChunk *);
- // 讀對象的紋理座標
- void ReadUVCoordinates(t3DObject *pObject, tChunk *);
- // 讀賦予對象的材質名稱
- void ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk);
另外還有讀入字符串,各種向量等通用計算函數等等,就不介紹了。在ImportModel的第4步中,要計算頂點法向量(把以該點爲頂點的各個面的法向量取均值),貌似3DS文件中沒有保存法向量信息的chunk吧。因此這裏導入的模型要重新(粗略地)計算面和頂點法向量。
最後是DrawModel繪製模型(集齊了頂點,紋理或材質[難道有了紋理就不能用材質嗎,汗一個],頂點法向量,用三角面片方式按索引繪製),並在RenderModel中調用並作移轉縮等處理。總結一下:CLoad3DS類最核心的就是遞歸思想,以及它與3DS文件樹型結構的對應。
CLoad3DS類下載:點此。
本文來源於 ZwqXin (http://www.zwqxin.com/),
轉載請註明
原文地址:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view-2.html