下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、1. MD2 文件簡介MD2 文件是 Quake2 專用模型文件。他是基于幀動畫實現(xiàn)模型的 動態(tài)活動的(播放多個連續(xù)的幀來實現(xiàn) 3D 模型的動態(tài)展示)。因此, 一個MD2 文件,實際上是有多個幀組成的 MD2 模型文件(* md2) 以及對應(yīng)的紋理文件(*. pcx ,*bmp 等)組成。如圖:模型tris. ID2砧圖嗣.xh 完藝業(yè)示的模型其中 MD2 模型文件(*. md2)又有兩部分組成,頭文件和數(shù)據(jù)區(qū)頭文件的格式是固定的,定義了 MD2 文件的基本信息,如文件的標(biāo)志,版本號,MD2 文件中含有幾個幀等信息。頭文件結(jié)構(gòu)如下(對每個 MD2 文件都是一樣的):/* MD2 文件頭*/st
2、ruct tMd2Headerintmagic;/*文件標(biāo)志*/其值必須為 IDP2intversion;/*文件版本號*/其值為 8intskinWidth;/*紋理寬度*/intskinHeight;/*紋理高度*/intframeSize;/*每一幀的字節(jié)數(shù)*/intnumSkins;/*紋理數(shù)目*/intnumVertices;/*頂點數(shù)目(每一幀中都是一樣的)*/intnumTexCoords;/*紋理坐標(biāo)數(shù)目*/intnumTriangles;/*三角行數(shù)目*/intnumGlCommands;/* gl 命令數(shù)目*/intnumFrames;/*總幀數(shù)*/int offsetSk
3、ins;/* 紋理的偏移位置 */int offsetTexCoords;/* 紋理坐標(biāo)的偏移位置 */int offsetTriangles;/* 三角形索引的偏移位置 */int offsetFrames;/* 第一幀的偏移位置 */int offsetGlCommands;/* OPenGL 命令的偏移位置 */int offsetEnd;/* 文件結(jié)尾偏移位置 */;而對于 MD2 文件的數(shù)據(jù)區(qū),則是不同的 MD2 有不同的大?。ê苊?顯,不同的模型所含的幀數(shù),紋理數(shù)目等數(shù)據(jù)是不同的)。對于讀取 MD2 的數(shù)據(jù)區(qū)時還應(yīng)該注意,由于MD2 原文件對幀的頂點信息(將float 存儲為 BY
4、TE 型 ) , 紋理坐標(biāo)信息 (int 存儲為 short) 都進(jìn)行 了壓縮,因此在讀取上面兩個信息時,都要進(jìn)行解壓縮。他們的解壓公式為:幀的頂點解壓 :x = 縮放比例 * v0 + 偏移量;y = 縮放比例 * v1 + 偏移量z = 縮放比例 * v2 + 偏移量 其中縮放比例,偏移量在幀結(jié)構(gòu)體中定義。紋理坐標(biāo)解壓 :Like for vertices, data is compresed. Here we use short (2 bytes) instead offloat (4 bytes) for storing texture coordinates. But to use
5、them, we mustconvert them to float because texture coordinates range from 0.0 to 1.0,and if we kept short values, we could have only 0 or 1 and any intermediatevalue! So howto uncompress them? Its quite simple. Divide the short value by the texturesize :公式如下: RealSTi.s = (float) texCoordi.s / header
6、.skinwidth; RealSTi.t= (float)texCoordi.t / header.skinheight;2. 讀取 MD2 文件前面說過,MD2 文件是基于幀動畫的模型文件,因此,一個 *.md2 文件實際上是一個有許多幀的集合體(每個幀又由許多三角形組成一 個網(wǎng)絡(luò),每個三角形又由 3 的頂點組成,每個頂點又由 (x,y,z) 組成)。 對于MD2 文件的讀取,實質(zhì)上是我們把 MD2 文件中的幀一個個讀取到 我們自定義的 MD2 文件對象中。 當(dāng)我們把所有的幀都統(tǒng)一存儲在我們 定義的 MD2文件對象(*pModel)后,我們對于 MD2 文件的讀取就完成 了。但事實是這樣的
7、嗎,當(dāng)然不是!我們此時只是存儲了一個個靜止 的幀(其實就是一個個擺出靜止動作的 3D 模型),我們下面的任務(wù), 就是區(qū)分這些幀都是屬于那些動作的, (如 016 幀屬于跑步的動作, 1720 幀屬于射擊的動作, 2032 幀屬于敬禮的動作) 并將它們都鏈 接到MD2文件對象 (*pModel)的幀信息鏈表中(在程序中我們使用 ParseAnimations (t3Dmodel *pModel)來完成對幀分類的功能 )。完成 了對幀分類的任務(wù)后,我們就可以在程序中運用特定的算法,讓 MD2 文件對象對特定的動作命令做出響應(yīng)。(如對射擊命令,他會自動的找到射擊的開始幀 17,并播放 1720 幀)
8、。此處對于播放幀動畫,還有一點要注意,由于每個幀都是一個個 靜止的 3D 模型,因此在播放動畫時,幀之間在切換時可能會產(chǎn)生抖 動或很僵硬的感覺, 因此需要 在幀之間進(jìn)行插值運算 ,即在開始幀與 結(jié)束幀之間自動生成新的幀 (類似 flash 里自動生成的補間動畫 ) 。幀間的插值數(shù)學(xué)公式為 ( 在程序中,重點是獲得 t 值)p(t) = p(0) + t*(p(1)-p(0)其中: p(t) 為時刻 t 時模型上各點的位置p(0) 為動作開始 ( 如動作跑步 ) 時模型上各點的位置p(1)為動作結(jié)束時模型上各點的位置t 是 01 之間的數(shù)至此,我們已經(jīng)完成了對幀的導(dǎo)入,以及播放連續(xù)幀以實現(xiàn)動畫
9、的功能。但此時幀中的 3D 模型還沒有進(jìn)行紋理貼圖!此時的動畫, 只是運動的灰突突的模型,因此還要給MD2 文件對象貼圖。由此,總結(jié)出載入 MD2 莫型文件的大體流程:1. 將每個幀載入到 MD2 莫型文件對象 t3DModle 中2. 對已載入的幀按照動作進(jìn)行分類,并連接在 t3Dmodle 的幀信息鏈表中,為將來響應(yīng)各種動作命令做準(zhǔn)備3. 對幀中的模型貼圖(因為 MD2 每一幀中模型的面和紋理坐標(biāo)都 是以索引的形式提供的,所以 我們可以只對第一幀中的模型 面,紋理坐標(biāo)信息進(jìn)行計算和保存 ,對于其他幀可以引用第一幀的信息,這樣可以節(jié)省很多內(nèi)存 )3. MD2 文件載入的代碼實現(xiàn)MD2 數(shù)據(jù)區(qū)
10、由四部分構(gòu)成: 紋理數(shù)據(jù), 紋理坐標(biāo), 三角形面,幀。因此對 MD2 數(shù)據(jù)區(qū)的讀取,要分別定義指向這四塊數(shù)據(jù)區(qū)域的指針 及代表這四塊數(shù)據(jù)組成結(jié)構(gòu)的結(jié)構(gòu)體。讀取幀數(shù)據(jù) 首先完成對幀數(shù)據(jù)區(qū)的讀取工作,要定義幀的結(jié)構(gòu)體。又由于幀 是由三角形構(gòu)成的網(wǎng)絡(luò), 而三角形又是由頂點構(gòu)成的, 因此要定義頂 點結(jié)構(gòu)體和向量結(jié)構(gòu)體 (Vector 原來已經(jīng)定義過,此處直接用 )。注意 原數(shù)據(jù)中的頂點信息,和紋理坐標(biāo)信息都需要解壓縮, 先定義頂點,頂點有兩種:由 MD2 文件中讀出的未解壓的頂點,解壓后轉(zhuǎn)換為程序中幀頂點格 式的頂點未解壓的頂點結(jié)構(gòu) :(未解壓用 _t 表示,同樣的對于紋理坐標(biāo) )struct tMd
11、2Vertex_tBYTE vertex3; / 頂點坐標(biāo)BYTE normalIndex; / 頂點的法向量 (此處 MD2 文件沒有定義法向 /量信息)解壓后的頂點結(jié)構(gòu) :struct tVertexfloat vertex3;float normal3;有了以上對頂點信息進(jìn)行描述的準(zhǔn)備,我們就可以構(gòu)建幀結(jié)構(gòu)體了。 幀結(jié)構(gòu)體也分為兩類:從 MD2 讀取出的原始幀結(jié)構(gòu)以及經(jīng)過解壓縮 等操作后我們在程序中實際用到的自定義幀結(jié)構(gòu)。原始幀結(jié)構(gòu) : (其實更應(yīng)該是幀中一個頂點的結(jié)構(gòu)。一幀中頂點的總數(shù)等于頭文件中的 frameSizeo 因此一幀的大小為:sizeof(tMd2Frame)乘以 fra
12、meSize MD2 文件的命名規(guī)則在這里有點亂.)struct tMd2Framefloat scale3;/解壓因子float translate3;/解壓因子char name16;/幀名字tMd2Vertex_t md2Vertices1; /由于是原始幀數(shù)據(jù),此處的頂點/結(jié)構(gòu)還是未解壓的結(jié)構(gòu)我們在程序中用到的自定義幀結(jié)構(gòu)struct tFramechar name16; /幀名tVertex *pVertices; / 解壓后的頂點至此,已經(jīng)完成了對幀的結(jié)構(gòu)體定義的工作, 下面就是對幀信息進(jìn) 行載入。void ReadMD2Data()/定義數(shù)據(jù)緩沖區(qū),來存儲幀unsigned ch
13、ar bufferMD2_MAX_FRAMESIZE;/先對四個數(shù)據(jù)區(qū)分配內(nèi)存m_pSkins = new tMd2Skinm_Header.numSkins;m_pTexCoords = new tMd2TexCoord m_Header.numTexCoords;m_pTriangles = new tMd2Facem_Header.numTriangles;m_pFrame = new tFramem_Header.numFrames; /程/ 序中實際用到/的幀結(jié)構(gòu)指針/將指針定位到幀數(shù)據(jù)區(qū)fseek(m_FilePointer, m_Header.offsetFrames, SEEK
14、_SET);/循環(huán)讀取每個幀 ,將原文件中的幀信息轉(zhuǎn)存至我們自定義的幀中for(int i = 0; iname);/* 下面幾行代碼就是對幀頂點的解壓縮與轉(zhuǎn)換操作 */ /為自定義的i 幀的頂點分配內(nèi)存,為下一步解壓頂點做準(zhǔn)備m_pFramei.pVertices = new tVertex m_Header.numVertices;/并定義指針指向自定義的 i 幀頂點tVertex* pVertices = m_pFramei.pVertices;/循環(huán)讀取幀中的每個頂點進(jìn)行解壓縮和坐標(biāo)轉(zhuǎn)換操作for(j = 0; jmd2Verticesj.vertex0 *pFrame-scale0
15、+ pFrame-translate0;/*注意要交換 y, z 軸并將 z 軸反向(也許不用反向)*/pVerticesj.vertex2 = -1* (pFrame-md2Verticesj.vertex1* pFrame-scale1 + pFrame-translate1);pVerticesj.vertex1 = pFrame-md2Verticesj.vertex2 *pFrame-scale2 + pFrame-tra nslate2;OK!至吐匕為止,我們已經(jīng)把所有的幀信息都存儲到我們自定義的 幀結(jié)構(gòu)了。將幀按不同動作分類上一步我們已經(jīng)把幀的信息都載入到了m_pFrame 中,
16、為了實現(xiàn)幀動畫的播放,現(xiàn)在就對 m_pFrame 指針指向的幀進(jìn)行分類,將它們 分解為不同的動作序列,并記錄開始幀與結(jié)束幀。對幀進(jìn)行分類是根據(jù)幀的名字來進(jìn)行的(上一步已通過strcpy(m_pF, pFrame-name 實現(xiàn)了對幀名字的存儲)。幀的名字結(jié)構(gòu)如下:動作名動作序號(2 位數(shù))例如:幀 0run 01 從 1 開始幀 1run 02幀 2run 03幀 3run 04幀 4fire 01幀 5fire 02幀 6fire 03那么在對幀進(jìn)行分類時,只需要分析幀的名字即可,將動作名相 同的幀歸為一類,并記錄下開始幀和結(jié)束幀。此處為了記錄下動作信息,需要定義一個動
17、作信息結(jié)構(gòu)體struct tAn imatio nlnfo char strName256; /動作名稱int startFrame;起始幀int en dFrame;結(jié)束幀/*下面是分類幀的函數(shù)*/void ParseAnimation(t3Dmodel *pModle) /pModle 為最終的 3D 模型象tAnimationInfo animation; / 用來存儲動作信息string strLastName = “”/* 現(xiàn)在開始依次分析每個幀的名字 */for(int i = 0 ;i m_Header.numFrame;i+)/將 m_pFrame 指針?biāo)赶虻膸拿帜贸鰜硪?/p>
18、次分析 stringstrName = m_pF;/* 分析該名字 */for(int j= 0; j = strName.length() - 2)/將字符串轉(zhuǎn)換為數(shù)字 frame = atoi(&strNamej);/清除數(shù)字 strName.erase(j, strName.length - j);break; /跳出循環(huán)/* 如果該幀的名字與前一個不同或該幀為最后一幀 */if(strName != strLastName | i = = pModel-numObject -1)/* 檢查是否為 0 號幀*/if(strLastName != “”) /如果
19、不是 0 號幀/復(fù)制幀的名稱strcpy(animation.strName, strLastName.c_str(); /設(shè)置動作結(jié)束幀為 i-1ani mati on.en dFrame = i -1; /將該動作信息添加到動作信息列表中 pModel-pAnimation.push_back(animation);memet(&animation , 0 , sizeof(tAnimationInfo);/動作數(shù)加一pModel-numOfAnimations+;/if/ 設(shè)置開始幀為 i animation.startFrame = I;/if strLastName = st
20、rName;inttexureId;/紋理 ID自此,我們又完成了把動作信息加入到了模型中的函數(shù)。下面剩下的,就是將剛才的幀信息, 動作信息這些數(shù)據(jù)都保存到模型對象中, 而且 還要進(jìn)行紋理坐標(biāo)和頂點對應(yīng)的處理。 這些最后的整合功能都被寫在 了一個函數(shù)中,該函數(shù)調(diào)用了前面兩個函數(shù)。將信息保存到模型結(jié)構(gòu)中 在將信息保存到模型結(jié)構(gòu)中前,要先定義一個對象信息結(jié)構(gòu)體,其實就是幀結(jié)構(gòu)的加強版,在對象信息結(jié)構(gòu)體中,不光有幀信息,還 包括有紋理,面信息。對象信息結(jié)構(gòu)體 :struct t3Dobjectint numOfVerts; /模型中頂點的數(shù)目int numOfFaces; /模型中面的數(shù)目int n
21、umTexVertex; / 模型中紋理坐標(biāo)的數(shù)目int materialID;/紋理 IDbool bHasTexture; /該模型是否有紋理映射char strName256; /對象名稱Vector3 *pVerts;/對象的頂點Vector3 *pNormals; / 對象的法向量Vector2 *pFace;/對象的面下面是我們最終的 模型信息結(jié)構(gòu)體 struct t3DModelint numOfObjects;/模型中對象數(shù)int numOfMaterials;/模型中材質(zhì)的數(shù)目int numOfAnimations;/模型中動作的數(shù)目int currentAnim;/動作索引
22、int currentFrame;/幀索引vector pAnimations; / 動作信息鏈表vectorpMaterials; /材質(zhì)信息鏈表vectorp3DObject;/對象信息鏈表關(guān)于材質(zhì)信息結(jié)構(gòu)體 (tMaterialInfo )的定義struct tMaterialInfochar strName255; / 紋理名稱char strFile255; /紋理文件名稱BYTE color3;/對象的 RGB 顏色inttexureId;/紋理 ID下面,就開始構(gòu)造將各種數(shù)據(jù)保存在模型信息中的函數(shù)void ConvertDataStructures(t3DModel *pMode
23、l)int j = 0, i = 0;/先給模型結(jié)構(gòu)對象分配內(nèi)存memset(pModel, 0 , sizeof(t3DModel);/* 下面開始填充模型信息對象 */pModel-numOfObjects = m_Header.numFrames;/產(chǎn)生動作信息ParseAnimations(pModel);/* 下面填充對象結(jié)構(gòu),最后再把對象結(jié)構(gòu)加到模型對象鏈表中 */ for(i= 0; inumOfObjects; i +)/先定義對象結(jié)構(gòu) t3DObject currentFrame = 0;float uTile;float vTile;float uOffset;float
24、vOffset;/u 重復(fù)/v 重復(fù)/u 紋理偏移/v 紋理偏移/填充基本的信息currentFrame.numOfVerts = m_Header.numVertices;currentFrame.numOfTexVertex = m_Header.numTexCoords;currentFrame.numFaces = m_Header.numTriangles;/* 將幀的頂點信息讀入到對象結(jié)構(gòu)中 */先分配內(nèi)存currentFrame.pVerts = new Vector3currentFrame.numOfVerts; /*將 前 面 存 儲 在 m_pFrame 中 的 幀 的 頂 點 信 息 轉(zhuǎn) 存 到 currentFrame 中 */for(j = 0; j 0) / 超出了第一幀/將對象信息添加到模型對象鏈表中pModel-pObject.push_back(currentFrame);continue;/* 以下的內(nèi)容是對于紋理坐標(biāo)與面的操作, 僅對第一幀才會 執(zhí)行*/先分配內(nèi)存currentFrame.pTexVerts=newVector2currentFrame.numTexVertex;currentFrame.pFaces = new tFacecurrentFrame.numOfFaces;/* 解壓紋理坐標(biāo) */for(j =
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度網(wǎng)絡(luò)虛擬物品買賣合同范本4篇
- 二零二五年度環(huán)保設(shè)備研發(fā)與銷售合同范本3篇
- 二零二五年拉森鋼板樁租賃合同日期與租金核算標(biāo)準(zhǔn)3篇
- 2025版城市綠地修復(fù)與植被重建工程承包合同4篇
- 二零二五年度文化娛樂活動贊助合同模板3篇
- 二零二五版按份額擔(dān)保的航空運輸合作協(xié)議2篇
- 二零二五版人力資源顧問服務(wù)合同范本6篇
- 國際貿(mào)易第六章出口合同訂立2025年國際貿(mào)易信用評估體系2篇
- 二零二五年餐飲服務(wù)業(yè)員工勞動合同標(biāo)準(zhǔn)制定3篇
- 二零二五年路燈照明設(shè)施維護保養(yǎng)合同6篇
- 新版DFMEA基礎(chǔ)知識解析與運用-培訓(xùn)教材
- 制氮機操作安全規(guī)程
- 衡水市出租車駕駛員從業(yè)資格區(qū)域科目考試題庫(全真題庫)
- 護理安全用氧培訓(xùn)課件
- 《三國演義》中人物性格探析研究性課題報告
- 注冊電氣工程師公共基礎(chǔ)高數(shù)輔導(dǎo)課件
- 土方勞務(wù)分包合同中鐵十一局
- 乳腺導(dǎo)管原位癌
- 冷庫管道應(yīng)急預(yù)案
- 司法考試必背大全(涵蓋所有法律考點)
- 公共部分裝修工程 施工組織設(shè)計
評論
0/150
提交評論