MD2 文件读取

MD2 文件是3D关键帧动画文件。
任何文件都有自己的格式,MD2也有自己组织数据的格式,要想正确读取MD2中大量的数据,首先弄清楚文件的格式,MD2文件分为两部分,①文件头 ②文件数据。
文件头部分描述了MD2 文件的基本信息
文件数据部分才是真正数据源。
格式如下(做了部分注释):

文件头:
Offset Data type Name Description
0 int ident Magic number. Must be equal to “IDP2”
4 int version MD2 version. Must be equal to 8 版本号
8 int skinwidth Width of the texture 纹理宽度
12 int skinheight Height of the texture纹理高度
16 int framesize Size of one frame in bytes每帧大小
20 int num_skins Number of textures 纹理图片数量
24 int num_xyz Number of vertices 顶点数量
28 int num_st Number of texture coordinates 纹理坐标数量
32 int num_tris Number of triangles 三角面片数量
36 int num_glcmds Number of OpenGL commands
40 int num_frames Total number of frames 关键帧数量
44 int ofs_skins Offset to skin names (each skin name is an unsigned char[64] and are null terminated)
48 int ofs_st Offset to s-t texture coordinates纹理坐标偏移量
52 int ofs_tris Offset to triangles三角面片偏移量
56 int ofs_frames Offset to frame data帧偏移量
60 int ofs_glcmds Offset to OpenGL commands
64 int ofs_end Offset to end of file

这里偏移量是指改纹理坐标、关键帧等数据是从哪里开始的,相对于文件头。

文件数据部分:
其实就是按照文件头的结构来组织数据,里面存放了纹理、纹理坐标、顶点坐标、帧顶点索引、三角面片的顶点索引等等。

MD2Model* MD2Model::load(const char* filename) {
    ifstream input;
    input.open(filename, istream::binary);

    char buffer[64];
    input.read(buffer, 4); //Should be "IPD2", if this is an MD2 file
    if (buffer[0] != 'I' || buffer[1] != 'D' ||
        buffer[2] != 'P' || buffer[3] != '2') {
        return NULL;
    }
    if (readInt(input) != 8) { //版本号The version number
        return NULL;
    }

    int textureWidth = readInt(input);   //纹理宽度The width of the textures
    int textureHeight = readInt(input);  //纹理高度The height of the textures
    readInt(input);                      //每帧字节数The number of bytes per frame
    int numTextures = readInt(input);    //纹理数The number of textures
    if (numTextures != 1) {
        return NULL;
    }
    int numVertices = readInt(input);    //顶点数The number of vertices
    int numTexCoords = readInt(input);   //纹理坐标数The number of texture coordinates
    int numTriangles = readInt(input);   //三角面片数The number of triangles
    readInt(input);                      //GL命令数The number of OpenGL commands
    int numFrames = readInt(input);      //关键帧数The number of frames

    //Offsets (number of bytes after the beginning of the file to the beginning
    //of where certain data appear)
    int textureOffset = readInt(input);  //纹理(即bmp图片名字)偏移量The offset to the textures
    int texCoordOffset = readInt(input); //纹理坐标偏移量The offset to the texture coordinates
    int triangleOffset = readInt(input); //三角面片偏移量The offset to the triangles
    int frameOffset = readInt(input);    //关键帧偏移量The offset to the frames
    readInt(input);                      //The offset to the OpenGL commands
    readInt(input);                      //The offset to the end of the file

    //Load the texture
    input.seekg(textureOffset, ios_base::beg);
    input.read(buffer, 64);
    //纹理图片是否是bmp格式 
    if (strlen(buffer) < 5 ||
        strcmp(buffer + strlen(buffer) - 4, ".bmp") != 0) {
        return NULL;
    }
    Image* image = loadBMP(buffer);
    GLuint textureId = loadTexture(image);
    delete image;
    MD2Model* model = new MD2Model();
    model->textureId = textureId;

    //Load the texture coordinates
    input.seekg(texCoordOffset, ios_base::beg);
    model->texCoords = new MD2TexCoord[numTexCoords];
    for(int i = 0; i < numTexCoords; i++) {
        MD2TexCoord* texCoord = model->texCoords + i;
        texCoord->texCoordX = (float)readShort(input) / textureWidth;
        texCoord->texCoordY = 1 - (float)readShort(input) / textureHeight;// opengl coordinate different from texture coordinate
    }

    //Load the triangles
    input.seekg(triangleOffset, ios_base::beg);
    model->triangles = new MD2Triangle[numTriangles];
    model->numTriangles = numTriangles;
    for(int i = 0; i < numTriangles; i++) {
        MD2Triangle* triangle = model->triangles + i;
        for(int j = 0; j < 3; j++) {
            triangle->vertices[j] = readUShort(input);
        }
        for(int j = 0; j < 3; j++) {
            triangle->texCoords[j] = readUShort(input);
        }
    }

    //Load the frames
    input.seekg(frameOffset, ios_base::beg);
    model->frames = new MD2Frame[numFrames];
    model->numFrames = numFrames;
    for(int i = 0; i < numFrames; i++) {
        MD2Frame* frame = model->frames + i;
        frame->vertices = new MD2Vertex[numVertices];
        Vec3f scale = readVec3f(input);
        Vec3f translation = readVec3f(input);
        input.read(frame->name, 16);

        for(int j = 0; j < numVertices; j++) {
            MD2Vertex* vertex = frame->vertices + j;
            input.read(buffer, 3);
            Vec3f v((unsigned char)buffer[0],
                    (unsigned char)buffer[1],
                    (unsigned char)buffer[2]);
            vertex->pos = translation + Vec3f(scale[0] * v[0],
                                              scale[1] * v[1],
                                              scale[2] * v[2]);
            input.read(buffer, 1);
            int normalIndex = (int)((unsigned char)buffer[0]);
            vertex->normal = Vec3f(NORMALS[3 * normalIndex],
                                   NORMALS[3 * normalIndex + 1],
                                   NORMALS[3 * normalIndex + 2]);
        }
    }

    model->startFrame = 0;
    model->endFrame = numFrames - 1;
    return model;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值