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

文章來源:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view.html

CLoad3DS類是Sourceforge中的一個開源項目,作用在於幫助開發者學會簡單的對3DS文件的載入(OpenGL)程序。雖然有更成熟更強大的3dslib庫,但是平時寫寫Demo中,對模型載入的要求一般比較低,這時候只把CLoad3DS類包含到程序就夠了。——ZwqXin.com  上篇文章:3DS文件結構的初步認識 中談到的就是這個類。

本文來源於 ZwqXin (http://www.zwqxin.com/), 轉載請註明
      原文地址:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view.html

這個類只用到了3DS文件中的一小部分(chunk):頂點信息,面信息,紋理信息,材質信息,和一些標誌信息(見上篇日誌)。接下來我們首先看看它是怎樣把3DS文件裏的數據存儲到實際內存中的:

  1. //上有CVector3D,CVector2D類用於保存一個頂點和一個紋理座標,這是底層的存儲結構。
  2.  
  3. //這裏給出了這麼一個事實:一個模型由好幾部分組成,譬如一個人體由手腳頭身等等部分組成,每個部分就是3DS中單獨命名的一個對象;因此說,模型由一系列對象組成,每個對象由一系列三角面片組成
  4.  
  5. // 面的結構定義《-由頂點構
  6. struct tFace
  7. {
  8.   int vertIndex[3];      // 頂點索引
  9.   int coordIndex[3];      // 紋理座標索引
  10. };
  11.  
  12. // 對象信息結構體《-由面構
  13. struct t3DObject 
  14. {
  15.   int numOfVerts;      // 模型中頂點的數目
  16.   int numOfFaces;      // 模型中面的數目
  17.   int numTexVertex;      // 模型中紋理座標的數目
  18.   int materialID;      // 紋理ID
  19.   bool bHasTexture;      // 是否具有紋理映射
  20.   char strName[255];      // 對象的名稱
  21.   CVector3D *pVerts;      // 對象的頂點
  22.   CVector3D *pNormals;    // 對象的法向量
  23.   CVector2D *pTexVerts;    // 紋理UV座標
  24.   tFace *pFaces;        // 對象的面信息
  25. };
  26.  
  27. // 模型信息結構體《-由對象構,包含材質
  28. struct t3DModel 
  29. {
  30.   UINT texture[MAX_TEXTURES];
  31.   bool  Textured;           //是否使用紋理
  32.   int numOfObjects;          // 模型中對象的數目
  33.   int numOfMaterials;          // 模型中材質的數目
  34.   vector<tMaterialInfo> pMaterials;  // 材質鏈表信息
  35.   vector<t3DObject> pObject;      // 模型中對象鏈表信息
  36. };
  37.  
  38. // 接下來是材質信息結構體,描述材質
  39. struct tMaterialInfo
  40. {
  41.   char strName[255];      // 紋理名稱
  42.   char strFile[255];      // 如果存在紋理映射,則表示紋理文件名稱
  43.   BYTE color[3];        // 對象的RGB顏色
  44.   int texureId;        // 紋理ID
  45.   float uTile;        // u 重複
  46.   float vTile;        // v 重複
  47.   float uOffset;       // u 紋理偏移
  48.   float vOffset;        // v 紋理偏移
  49. } ;
  50.  
  51. // 這個與前面的不同,它是針對3DS文件而非模型實體。也就是描述塊。你將看到bytesRead的精確計算對獲得塊內正確數據的重要性
  52. //保存塊信息的結構
  53. struct tChunk
  54. {
  55.   unsigned short int ID;          // 塊的ID    
  56.   unsigned int length;          // 塊的長度
  57.   unsigned int bytesRead;          // 需要讀的塊數據的字節數
  58. };
  59. //實現中我們就用以上數據結構描述整個模型和讀取過程了:
  60.  //構造一個臨時模型對象,它僅存在於讀取過程中
  61. t3DModel Model3DS;
  62.  
  63. //構造兩個臨時存放chunk的結構
  64.   tChunk *m_CurrentChunk;
  65.   tChunk *m_TempChunk;

對模型的操作分爲兩部分:裝載模型(初始化時把3DS文件中我們所需數據,通過上述數據結構讀入內存供程序隨時調用)和渲染模型(把模型畫出來,並進行移轉縮等調整)。核心分別爲ImportModel函數和RenderModel函數。先看前者:

  1. // 打開一個3ds文件,讀出其中的內容
  2. //省略了非主要的內容,你現在可以看到一個初始化步驟做了哪些事情:
  3. bool CLoad3DS::ImportModel(GLuint Model_id, char *strFileName)
  4. { .........
  5.     m_FilePointer = fopen(strFileName, "rb");//1.打開文件,讓文件指針指向
  6.    ......
  7.   // 2.將文件的第一塊讀出並判斷是否是3ds文件(0x4D4D)
  8.   ReadChunk(m_CurrentChunk);
  9.   ........
  10.     // 3.通過調用下面的遞歸函數,將對象讀出
  11.   ProcessNextChunk(&Model3DS, m_CurrentChunk);
  12.  
  13.   // 4.在讀完整個3ds文件之後,計算頂點的法線
  14.   ComputeNormals(&Model3DS);
  15.    .......
  16.   return true;
  17. }

其中的核心當然是第3步了。在進入這個核心之前,看看CLoad3DS類是怎樣讀數據的:

  1. // 下面函數讀入塊的ID號和它的字節長度
  2. void CLoad3DS::ReadChunk(tChunk *pChunk)
  3. {
  4.   // 讀入塊的ID號,佔用了2個字節。塊的ID號象OBJECT或MATERIAL一樣,說明了在塊中所包含的內容
  5.   pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
  6.  
  7.   // 然後讀入塊佔用的長度,包含了四個字節
  8.   pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
  9. }
  10. //fread函數,針對每次函數調用,4參數分別表示:讀入的數據所存入的位置,每次讀多少字節,讀多少次,文件指針(所以中間兩參數的乘積就是調用一次fread要讀入的數據量了);返回實際成功讀入了的字節數。
  11. //因此,一次成功的ReadChunk將把參數(tChunk 類型的塊結構)中的bytesRead加6。這6字節包含一個塊最開頭的ID號(存入ID)和長度(存入length),這樣文件指針(fread會讓其指向下一個文件數據塊開頭)接下來將要面對的就是實際數據了。不明白者看此

請繼續收看:一個讀取3DS文件的類CLoad3DS淺析Ⅱ
 

本文參考資料(大部分中文註釋編寫者),若沒找錯的話,應該是這裏(http://blog.csdn.net/hardVB)呵呵.

本文來源於 ZwqXin (http://www.zwqxin.com/), 轉載請註明
      原文地址:http://www.zwqxin.com/archives/opengl/3ds-cload3ds-view.html


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