文章來源: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文件裏的數據存儲到實際內存中的:
- //上有CVector3D,CVector2D類用於保存一個頂點和一個紋理座標,這是底層的存儲結構。
- //這裏給出了這麼一個事實:一個模型由好幾部分組成,譬如一個人體由手腳頭身等等部分組成,每個部分就是3DS中單獨命名的一個對象;因此說,模型由一系列對象組成,每個對象由一系列三角面片組成
- // 面的結構定義《-由頂點構
- struct tFace
- {
- int vertIndex[3]; // 頂點索引
- int coordIndex[3]; // 紋理座標索引
- };
- // 對象信息結構體《-由面構
- struct t3DObject
- {
- int numOfVerts; // 模型中頂點的數目
- int numOfFaces; // 模型中面的數目
- int numTexVertex; // 模型中紋理座標的數目
- int materialID; // 紋理ID
- bool bHasTexture; // 是否具有紋理映射
- char strName[255]; // 對象的名稱
- CVector3D *pVerts; // 對象的頂點
- CVector3D *pNormals; // 對象的法向量
- CVector2D *pTexVerts; // 紋理UV座標
- tFace *pFaces; // 對象的面信息
- };
- // 模型信息結構體《-由對象構,包含材質
- struct t3DModel
- {
- UINT texture[MAX_TEXTURES];
- bool Textured; //是否使用紋理
- int numOfObjects; // 模型中對象的數目
- int numOfMaterials; // 模型中材質的數目
- vector<tMaterialInfo> pMaterials; // 材質鏈表信息
- vector<t3DObject> pObject; // 模型中對象鏈表信息
- };
- // 接下來是材質信息結構體,描述材質
- struct tMaterialInfo
- {
- char strName[255]; // 紋理名稱
- char strFile[255]; // 如果存在紋理映射,則表示紋理文件名稱
- BYTE color[3]; // 對象的RGB顏色
- int texureId; // 紋理ID
- float uTile; // u 重複
- float vTile; // v 重複
- float uOffset; // u 紋理偏移
- float vOffset; // v 紋理偏移
- } ;
- // 這個與前面的不同,它是針對3DS文件而非模型實體。也就是描述塊。你將看到bytesRead的精確計算對獲得塊內正確數據的重要性
- //保存塊信息的結構
- struct tChunk
- {
- unsigned short int ID; // 塊的ID
- unsigned int length; // 塊的長度
- unsigned int bytesRead; // 需要讀的塊數據的字節數
- };
- //實現中我們就用以上數據結構描述整個模型和讀取過程了:
- //構造一個臨時模型對象,它僅存在於讀取過程中
- t3DModel Model3DS;
- //構造兩個臨時存放chunk的結構
- tChunk *m_CurrentChunk;
- tChunk *m_TempChunk;
對模型的操作分爲兩部分:裝載模型(初始化時把3DS文件中我們所需數據,通過上述數據結構讀入內存供程序隨時調用)和渲染模型(把模型畫出來,並進行移轉縮等調整)。核心分別爲ImportModel函數和RenderModel函數。先看前者:
- // 打開一個3ds文件,讀出其中的內容
- //省略了非主要的內容,你現在可以看到一個初始化步驟做了哪些事情:
- bool CLoad3DS::ImportModel(GLuint Model_id, char *strFileName)
- { .........
- m_FilePointer = fopen(strFileName, "rb");//1.打開文件,讓文件指針指向
- ......
- // 2.將文件的第一塊讀出並判斷是否是3ds文件(0x4D4D)
- ReadChunk(m_CurrentChunk);
- ........
- // 3.通過調用下面的遞歸函數,將對象讀出
- ProcessNextChunk(&Model3DS, m_CurrentChunk);
- // 4.在讀完整個3ds文件之後,計算頂點的法線
- ComputeNormals(&Model3DS);
- .......
- return true;
- }
其中的核心當然是第3步了。在進入這個核心之前,看看CLoad3DS類是怎樣讀數據的:
- // 下面函數讀入塊的ID號和它的字節長度
- void CLoad3DS::ReadChunk(tChunk *pChunk)
- {
- // 讀入塊的ID號,佔用了2個字節。塊的ID號象OBJECT或MATERIAL一樣,說明了在塊中所包含的內容
- pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);
- // 然後讀入塊佔用的長度,包含了四個字節
- pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
- }
- //fread函數,針對每次函數調用,4參數分別表示:讀入的數據所存入的位置,每次讀多少字節,讀多少次,文件指針(所以中間兩參數的乘積就是調用一次fread要讀入的數據量了);返回實際成功讀入了的字節數。
- //因此,一次成功的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