OpenGL系统设计-高级3D模型接口之MD2模型(2)

了解了 md2文件的结构后,我们可以来构造一个加载 md2模型的类 CLoadMD2

class CLoadMD2

{

 

public:

    CLoadMD2();

~CLoadMD2();   

 

    // 加载MD2 模型

    bool ImportMD2(Model3D_t *pModel, char *strFileName, char *strTexture);

 

private:

 

    // MD2 文件读取数据并存放在成员变量中

    void ReadMD2Data();

    // 将成员变量数据转换成我们的模型结构

    void ConvertDataStructures(Model3D_t *pModel);

    // 当使用光照时,计算顶点法向量

    void ComputeNormals(Model3D_t *pModel);

    void CleanUp();

       

    FILE *m_FilePointer;                // MD2 文件指针

    md2_header_t        m_Header;       // 文件头

    md2skin             *m_pSkins;      // 皮肤数据

    textureCoordinate_t *m_pTexCoords;  // 纹理坐标

    md2triangle_t       *m_pTriangles;  // 三角形索引数据

    postframe_t         *m_pFrames;     // 帧数据

};

 

CLoadMD2类中使用了一个 Model3D_t的结构,它是我们用于渲染 MD2模型的结构,其定义如下:

 

typedef struct

{

    int numOfObjects;                   // 模型中3D 物体的数目

    int numOfMaterials;                 // 模型中材质的数目

    int *m_glCommandBuffer;             //gl 命令缓存

    vector<tMaterialInfo> pMaterials;   // 材质信息,包括纹理、颜色

                                        // 这里的定义用到了STL

    vector<Object3D_t> pObject;         // 模型中3D 物体列表

}  Model3D_t;

 

3D物体的结构定义如下

 

typedef struct

{

    int  numOfVerts;            // 模型中顶点的数目

    int  numOfFaces;            // 模型中三角形的数目

    int  numTexVertex;          // 纹理坐标的数目

    int  materialID;            // 纹理ID

    bool bHasTexture;           // 是否有纹理

    char strName[255];          // 3D 物体名字

    Vector3  *pVerts;           // 物体的顶点数据

    Vector3  *pNormals;         // 物体的法向量数据

    Vector2  *pTexVerts;        // 纹理的坐标数据

    face_t *pFaces;             // 物体的三角形信息

} Object3D_t;

 

接下来看加载 MD2的最重要的函数 ImportMD2,函数的说明包含在代码的注释中。

 

bool CLoadMD2::ImportMD2(Model3D_t *pModel, char *strFileName, char *strTexture)

{

    char strMessage[255] = {0};

 

    // 首先打开一个md2 文件

    m_FilePointer = fopen(strFileName, "rb");

 

    if(!m_FilePointer)

    {

        MessageBox(NULL, “Unable to find the MD2 file!”, "Error", MB_OK);

        return false;

    }

   

    // 读取文件头

    fread(&m_Header, 1, sizeof(md2_header_t), m_FilePointer);

    // 检查文件版本

    if(m_Header.version != 8)

    {

        MessageBox(NULL, “Invalid file format strMessage”, "Error", MB_OK);

        return false;

    }

 

    // 读取md2 文件中的其他数据

    ReadMD2Data();

   

    // 将数据转换成我们定义的模型格式

    ConvertDataStructures(pModel);

 

    // 计算顶点法向量

    ComputeNormals(pModel);

 

    // 检查是否有纹理文件

    if(strTexture)

    {

        // 材质信息

        tMaterialInfo texture;

 

        strcpy(texture.strFile, strTexture);

 

        // 对于一个md2 文件,只有一个纹理,因此其ID 一直是0

        texture.texureId = 0;

 

        // 纹理平铺的比例是1

        texture.uTile = texture.uTile = 1;

 

        // 这里的模型使用一个材质

        pModel->numOfMaterials = 1;

 

        // 将材质加入到我们自己的材质列表中

        pModel->pMaterials.push_back(texture);

    }

 

    CleanUp();

    return true;

}

 

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} p.MsoBodyText, li.MsoBodyText, div.MsoBodyText {margin-top:0cm; margin-right:0cm; margin-bottom:6.0pt; margin-left:0cm; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} p.MsoBodyTextFirstIndent, li.MsoBodyTextFirstIndent, div.MsoBodyTextFirstIndent {mso-style-update:auto; mso-style-parent:正文文本; mso-style-link:" Char Char"; margin:0cm; margin-bottom:.0001pt; text-indent:19.85pt; mso-pagination:none; font-size:10.5pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-ansi-language:ZH-CN;} p.a, li.a, div.a {mso-style-name:正文(首行不缩进); margin:0cm; margin-bottom:.0001pt; line-height:150%; mso-pagination:none; mso-layout-grid-align:none; text-autospace:none; font-size:10.5pt; mso-bidi-font-size:10.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体;} span.CharChar {mso-style-name:" Char Char"; mso-style-locked:yes; mso-style-link:正文首行缩进; mso-ansi-font-size:10.5pt; mso-bidi-font-size:10.5pt; font-family:宋体; mso-fareast-font-family:宋体; mso-ansi-language:ZH-CN; mso-fareast-language:ZH-CN; mso-bidi-language:AR-SA;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

ImportMD2 是加载整个模型的过程 ReadMD2Data 则读取除了文件头之外其他数据 下面是 ReadMD2Data 的代码 通过这个函数 也可以更好地了解 md2 文件的格式。

 

void CLoadMD2::ReadMD2Data()

{

 

    unsigned char buffer[MD2_MAX_FRAMESIZE];    //8320

    int j = 0;

 

    // 先根据文件头中的信息把内存分配好

    m_pSkins     = new md2skin [m_Header.numSkins];

    m_pTexCoords = new textureCoordinate_t [m_Header.numTexCoords];

    m_pTriangles = new md2triangle_t [m_Header.numTriangles];

    m_pFrames    = new postframe_t [m_Header.numFrames];

 

    // 根据皮肤数来读取皮肤

    fseek(m_FilePointer, m_Header.offsetSkins, SEEK_SET);

    fread(m_pSkins, sizeof(md2skin), m_Header.numSkins, m_FilePointer);

 

    // 读取纹理坐标 

    fseek(m_FilePointer, m_Header.offsetTexCoords, SEEK_SET);

    fread(m_pTexCoords, sizeof(textureCoordinate_t), m_Header.numTexCoords,

            m_FilePointer);

 

// 读取三角形数据,包括顶点和纹理坐标索引

    fseek(m_FilePointer, m_Header.offsetTriangles, SEEK_SET);

    fread(m_pTriangles, sizeof(md2triangle_t), m_Header.numTriangles, m_FilePointer);

           

    fseek(m_FilePointer, m_Header.offsetFrames, SEEK_SET);

   

// 为帧缓存分配内存

    frame_t *pFrame = (frame_t *) buffer;

m_pFrames[0].pVertices = new triangle_t [m_Header.numVertices];

 

    // 读第一帧

    fread(pFrame, 1, m_Header.frameSize, m_FilePointer);

    strcpy(m_pFrames[0].strName, pFrame->name);

           

    // 第一帧的顶点

    triangle_t *pVertices = m_pFrames[0].pVertices;

 

    // 对顶点数据进行变换成真实的坐标数据

    for (j=0; j < m_Header.numVertices; j++)

    {

        pVertices[j].vertex[0] = pFrame->aliasVertices[j].vertex[0] * pFrame->scale[0]

+ pFrame->translate[0];

pVertices[j].vertex[2] = -1 * (pFrame->aliasVertices[j].vertex[1]

* pFrame->scale[1] + pFrame->translate[1]);

        pVertices[j].vertex[1] = pFrame->aliasVertices[j].vertex[2] * pFrame->scale[2]

+ pFrame->translate[2];

    }

}

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值