一個讀取3DS文件的類CLoad3DS淺析Ⅱ

文章來源: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)這個函數做了模型載入部分最重要的東西。

  1. // 下面的函數讀出3ds文件的主要部分
  2. //注意傳入的後一個參數是剛被ReadChunk過的m_CurrentChunk,也就是說它從0x4D4D塊(樹幹)後開始繼續處理,並把0x4D4D塊作爲pPreviousChunk(前一個塊)
  3. //處理樹結構的常用手法就是遞歸
  4. void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
  5. {
  6.   ..........
  7.   m_CurrentChunk = new tChunk;        // 爲新的塊分配空間    
  8.  
  9. //因爲父塊的length是子塊length總和,而又由0x4D4D塊開始,故這個while會遍歷整個3DS文件數據
  10.  
  11. //然後我們在“case OBJECTINFO”中找到了遞歸,因爲OBJECTINFO(0x3D3D,3D editor chunk)就是父塊0x4D4D的最直接子塊,這次遞歸中的ProcessNextChunk函數中,while中的pPreviousChunk是遞歸前(上一層)的m_CurrentChunk,因此switch中尋覓的將是上一層所進入的這個OBJECTINFO塊下的子塊(找到MATERIAL或OBJECT來處理直至該OBJECTINFO的遞歸完結,回來繼續0x4D4D下的尋覓)。
  12.  
  13. //總覺得說着說着自己也濛濛的(這就是遞歸!),事實上EDITKEYFRAME跟OBJECTINFO是同級的,不過我們本來就沒用到EDITKEYFRAME這種塊,故遇到它只是略過(單純用它所“擁有”的length來增加0x4D4D的bytesRead)
  14. //總之呢,你打開某殺毒軟件從“我的電腦”開始殺一次毒,觀察一下查殺順序能加深理解恩
  15.  
  16.   while (pPreviousChunk->bytesRead < pPreviousChunk->length)
  17.   {
  18.         ReadChunk(m_CurrentChunk);// 讀入下一個塊
  19.  
  20.     switch (m_CurrentChunk->ID)
  21.     {
  22.     case VERSION:       ...     // 文件版本號
  23.       break;
  24.     case OBJECTINFO:     .... // 網格對象信息(3D editor chunk)
  25.      ProcessNextChunk(pModel, m_CurrentChunk);//!!!
  26.       break;
  27.     case MATERIAL:      ....        // 材質信息
  28.        break;
  29.     case OBJECT:        ....      // 對象的名稱
  30.        break;
  31.     case EDITKEYFRAME: .....
  32.       break;
  33.     default:    
  34.       // 跳過所有忽略的塊的內容的讀入,增加需要讀入的字節數
  35.       m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
  36.       break;
  37.     }
  38.     // 增加從最後塊讀入的字節數
  39.     pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
  40.   }
  41.  
  42.   // 釋放當前塊的內存空間
  43.   delete m_CurrentChunk;
  44.   m_CurrentChunk = pPreviousChunk;
  45. }

case語句中的處理函數隨chunk的ID(種類)不同而不同,但這些處理函數多少也是遞歸函數。分配存儲空間後,從文件讀入後存入相應的數據結構中,並增加該chunk的bytesRead。最需要注意的是,一般由3DS MAX導出的3ds文件的模型座標跟OPENGL中不同,在讀入頂點時要處理(swap)一下。

  1. // 讀下一個塊
  2.  void ProcessNextChunk(t3DModel *pModel, tChunk *);
  3.  // 讀下一個對象塊
  4.  void ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *);
  5.  // 讀下一個材質塊
  6.  void ProcessNextMaterialChunk(t3DModel *pModel, tChunk *);
  7.  // 讀對象顏色的RGB值
  8.  void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk);
  9.  // 讀對象的頂點
  10.  void ReadVertices(t3DObject *pObject, tChunk *);
  11.  // 讀對象的面信息
  12.  void ReadVertexIndices(t3DObject *pObject, tChunk *);
  13.  // 讀對象的紋理座標
  14.  void ReadUVCoordinates(t3DObject *pObject, tChunk *);
  15.  // 讀賦予對象的材質名稱
  16.  void ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk);
  17.  
另外還有讀入字符串,各種向量等通用計算函數等等,就不介紹了。在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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章