为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

MD2帧动画模型载入

2019-01-16 8页 doc 25KB 40阅读

用户头像

is_005190

暂无简介

举报
MD2帧动画模型载入1.MD2文件简介 MD2 文件是Quake2 专用模型文件。他是基于帧动画实现模型的动态活动的(播放多个连续的帧来实现3D模型的动态展示)。因此,一个MD2文件,实际上是有多个帧组成的MD2模型文件(*. md2)以及对应的纹理文件(*. pcx ,*.bmp等)组成。 如图: 其中MD2模型文件(*. md2)又有两部分组成,头文件和数据区。头文件的格式是固定的,定义了MD2文件的基本信息,如文件的标志,版本号,MD2文件中含有几个帧等信息。头文件结构如下(对每个MD2文件都是一样的): /** MD2文件头 */ st...
MD2帧动画模型载入
1.MD2文件简介 MD2 文件是Quake2 专用模型文件。他是基于帧动画实现模型的动态活动的(播放多个连续的帧来实现3D模型的动态展示)。因此,一个MD2文件,实际上是有多个帧组成的MD2模型文件(*. md2)以及对应的纹理文件(*. pcx ,*.bmp等)组成。 如图: 其中MD2模型文件(*. md2)又有两部分组成,头文件和数据区。头文件的格式是固定的,定义了MD2文件的基本信息,如文件的标志,版本号,MD2文件中含有几个帧等信息。头文件结构如下(对每个MD2文件都是一样的): /** MD2文件头 */ struct tMd2Header { int magic;                    /**< 文件标志 */ 其值必须为IDP2 int version;                /**< 文件版本号 */ 其值为8 int skinWidth;                /**< 纹理宽度 */ int skinHeight;                /**< 纹理高度 */ int frameSize;                /**< 每一帧的字节数 */ int numSkins;                /**< 纹理数目 */ int numVertices;            /**< 顶点数目(每一帧中都是一样的) */ int numTexCoords;            /**< 纹理坐标数目 */ int numTriangles;            /**< 三角行数目 */ int numGlCommands;            /**< gl命令数目 */ int numFrames;                /**< 总帧数 */ int offsetSkins;            /**< 纹理的偏移位置 */ int offsetTexCoords;            /**< 纹理坐标的偏移位置 */ int offsetTriangles;            /**< 三角形索引的偏移位置 */ int offsetFrames;            /**< 第一帧的偏移位置 */ int offsetGlCommands;        /**< OPenGL命令的偏移位置 */ int offsetEnd;                /**< 文件结尾偏移位置 */ }; 而对于MD2文件的数据区,则是不同的MD2有不同的大小(很明显,不同的模型所含的帧数,纹理数目等数据是不同的)。对于读取MD2的数据区时还应该注意,由于MD2原文件对帧的顶点信息(将float存储为 BYTE 型),纹理坐标信息(int 存储为 short)都进行了压缩,因此在读取上面两个信息时,都要进行解压缩。 他们的解压公式为: 帧的顶点解压: x = 缩放比例 * v[0] + 偏移量; y = 缩放比例 * v[1] + 偏移量 z = 缩放比例 * v[2] + 偏移量 其中缩放比例,偏移量在帧结构体中定义。 纹理坐标解压: Like for vertices, data is compresed. Here we use short (2 bytes) instead of float (4 bytes) for storing texture coordinates. But to use them, we must convert 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 intermediate value! So how to uncompress them? It's quite simple. Divide the short value by the texture size : 公式如下: RealST[i].s = (float)texCoord[i].s / header.skinwidth; RealST[i].t = (float)texCoord[i].t / header.skinheight; 2.读取MD2文件 前面说过,MD2文件是基于帧动画的模型文件,因此,一个*.md2文件实际上是一个有许多帧的集合体(每个帧又由许多三角形组成一个网络,每个三角形又由3的顶点组成,每个顶点又由(x,y,z)组成)。对于MD2文件的读取,实质上是我们把MD2文件中的帧一个个读取到我们自定义的MD2文件对象中。当我们把所有的帧都统一存储在我们定义的MD2文件对象(*pModel)后,我们对于MD2文件的读取就完成了。但事实是这样的吗,当然不是!我们此时只是存储了一个个静止的帧(其实就是一个个摆出静止动作的3D模型),我们下面的任务,就是区分这些帧都是属于那些动作的,(如0~16帧属于跑步的动作,17~20帧属于射击的动作,20~32帧属于敬礼的动作)并将它们都链接到MD2文件对象(*pModel)的帧信息链表中(在程序中我们使用ParseAnimations(t3Dmodel *pModel)来完成对帧分类的功能)。完成了对帧分类的任务后,我们就可以在程序中运用特定的算法,让MD2文件对象对特定的动作命令做出响应。(如对射击命令,他会自动的找到射击的开始帧17,并播放17~20帧)。 此处对于播放帧动画,还有一点要注意,由于每个帧都是一个个静止的3D模型,因此在播放动画时,帧之间在切换时可能会产生抖动或很僵硬的感觉,因此需要在帧之间进行插值运算,即在开始帧与结束帧之间自动生成新的帧(类似flash里自动生成的补间动画)。 帧间的插值数学公式为(在程序中,重点是获得t值) p(t) = p(0) + t*(p(1) – p(0)) 其中: p(t) 为时刻t时模型上各点的位置 p(0) 为动作开始(如动作跑步)时模型上各点的位置 p(1) 为动作结束时模型上各点的位置 t是0~1 之间的数 至此,我们已经完成了对帧的导入,以及播放连续帧以实现动画的功能。但此时帧中的3D模型还没有进行纹理贴图!此时的动画,只是运动的灰突突的模型,因此还要给MD2文件对象贴图。 由此,总结出载入MD2模型文件的大体: 1. 将每个帧载入到MD2模型文件对象t3DModle中 2. 对已载入的帧按照动作进行分类,并连接在t3Dmodle的帧信息链表中,为将来响应各种动作命令做准备 3. 对帧中的模型贴图(因为MD2每一帧中模型的面和纹理坐标都是以索引的形式提供的,所以我们可以只对第一帧中的模型面,纹理坐标信息进行计算和保存,对于其他帧可以引用第一帧的信息,这样可以节省很多内存) 3.MD2文件载入的代码实现 MD2数据区由四部分构成:纹理数据,纹理坐标,三角形面,帧。 因此对MD2数据区的读取,要分别定义指向这四块数据区域的指针及代表这四块数据组成结构的结构体。 ● 读取帧数据 首先完成对帧数据区的读取工作,要定义帧的结构体。又由于帧是由三角形构成的网络,而三角形又是由顶点构成的,因此要定义顶点结构体和向量结构体(Vector原来已经定义过,此处直接用)。注意原数据中的顶点信息,和纹理坐标信息都需要解压缩, 先定义顶点, 顶点有两种: 由MD2文件中读出的未解压的顶点,解压后转换为程序中帧顶点格式的顶点 未解压的顶点结构:(未解压用 _t表示,同样的对于纹理坐标) struct tMd2Vertex_t { BYTE vertex[3]; //顶点坐标 BYTE normalIndex; //顶点的法向量(此处MD2文件没有定义法向//量信息) } 解压后的顶点结构: struct tVertex { float vertex[3]; float normal[3]; } 有了以上对顶点信息进行描述的准备,我们就可以构建帧结构体了。帧结构体也分为两类:从MD2读取出的原始帧结构以及经过解压缩等操作后我们在程序中实际用到的自定义帧结构。 原始帧结构:(其实更应该是帧中一个顶点的结构。一帧中顶点的总数等于头文件中的frameSize。因此一帧的大小为:sizeof(tMd2Frame) 乘以frameSize  MD2文件的命名规则在这里有点乱……) struct tMd2Frame { float scale[3];                        //解压因子 float translate[3];                    //解压因子 char name[16];                    //帧名字 tMd2Vertex_t  md2Vertices[1]; //由于是原始帧数据,此处的顶点 //结构还是未解压的结构 } 我们在程序中用到的自定义帧结构 struct tFrame { char name[16];  //帧名 tVertex *pVertices;    //解压后的顶点 } 至此,已经完成了对帧的结构体定义的工作,下面就是对帧信息进行载入。 void ReadMD2Data() { //定义数据缓冲区,来存储帧 unsigned char buffer[MD2_MAX_FRAMESIZE]; //先对四个数据区分配内存 m_pSkins = new tMd2Skin[m_Header.numSkins]; m_pTexCoords = new tMd2TexCoord [m_Header.numTexCoords]; m_pTriangles = new tMd2Face[m_Header.numTriangles]; m_pFrame = new tFrame[m_Header.numFrames]; //程序中实际用到//的帧结构指针 …… …… //将指针定位到帧数据区 fseek(m_FilePointer, m_Header.offsetFrames, SEEK_SET); //循环读取每个帧,将原文件中的帧信息转存至我们自定义的帧中 for(int i = 0; i< m_Header.numFrames; i + +) { //给第i帧分配内存
/
本文档为【MD2帧动画模型载入】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索