The md2 file format of quake2

Source: Internet
Author: User

Original article: http://blog.csdn.net/ouyang2008/archive/2007/04/01/1548504.aspx

 

The md2 file format of quake2
       
Introduction: "Well, a new md2 Bible :)". Although the md2 guide is full, I will present a new way to render it this time. What is md2? In fact, he is one of the first 3D model formats used in Q2 engine. Next I will introduce how to load and use OpenGL for real-time rendering. Maybe you don't think it is necessary to pick up this old form, but we do have a reason to understand his true meaning. First, md2 is a file format suitable for beginners ..... Then, it is completely free !!! Haha. The content of this article includes: md2 file format development of a javas2model class to access an md2 model display model animation. In particular, the source code here is completely free of charge, if you "accidentally" read this article, I hope you will come from the wonderful C ++ jungle, and of course you will also have experience in the OpenGL realm. Okay. Let's get started. The md2 file format is the same as other file formats. The md2 file consists of two parts: the file header and data area.
The file header contains a lot of important information, such as the size of the data area, the magic mark, and the version number. Of course, the size of the file is determined, therefore, we usually have a structure in the program. The data zone is very different. Because each file contains different images and textures, they are generally very different. The specific structure is as follows: the definition of the md2 file header is as follows:
// md2 header
typedef struct
{
Int ident; // File ID. It must be "ipd2"
Int version; // md2 version. equal to 8
 
Int skinwidth; // The texture width.
Int skinheight; // texture height
Int framesize; // The number of bytes per frame
 
Int num_skins; // Number of textures
Int num_xyz; // number of points in 3D space
Int num_st; // Number of texture coordinates
Int num_tris; // Number of triangles
Int num_glcmds; // Number of OpenGL commands
Int num_frames; // Number of frames contained in the file
 
Int ofs_skins; // the offset of the texture name (64 bytes each)
Int ofs_st; // stores the texture coordinate offset.
Int ofs_tris; // store the triangle address offset.
Int ofs_frames; // address offset of the stored Frame
Int ofs_glcmds; // address offset for storing OpenGL commands
Int ofs_end; // The offset at the end of the file
 
} md2_t;
So, I will briefly explain the purpose of the variable: first, prepare the light... Please refer to "ident", also known as "magic number". Q: Do you have any understanding of your responsibilities in md2? A: Cough. Due to time constraints, I will make a short speech. The more vivid statement is: when the md2 loader is about to pull people to the dance venue (memory), will you ask "ipd2? If not, there will be no tango behind it. It seems that in the next program, time is a factor we have to consider. Next I will introduce it full-time: "version", the version of the md2 file, the value is equal to the width and length of 8 "skinwidth" and "skinheight" textures. Because the texture of md2 is separated from the model, the data here is basically useless. "Framesize" specifies the number of bytes a frame occupies. What is a frame? If you have some knowledge about the animation principle, I will not go any further. A frame is an image at a specific time point. In 3D scenarios, all images are represented by elements, and these elements require a certain amount of storage space, which is the work of framesize. Most of the md2 files have 199 frames. These 199 frames are combined to indicate 21 types of animations. The number of textures for the "num_skins" md2 model. As I have explained above, I will not describe others one by one. For more information, see the original English version. I will provide a link at the end of the article. Next let's take a look at num_frames. He points out how many frames the md2 phantoms have. In fact, they have key frames at a certain interval. Because files need to be read, such as memory, it is not realistic for an action to contain 200 to 300 frames. If you have special requirements, you can also do this, huh, huh. Since the key frames are discontinuous, how can we ensure the continuity of the animation? The solution is to use linear interpolation to dynamically generate intermediate frames. For example, after the file header is completed, we will continue to describe and represent the remaining content of the file in detail: like the header file, we still use struct to represent frames, vectors, and OpenGL commands. First, let's introduce the vector. We don't need a complicated class to represent it, but just select a simple array.
typedef float vec3_t[3];
Each phantoms has num_frame * num_xyz vectors. The following is the structure of a single vector:
// Vertex
typedef struct
{
Unsigned char V [3]; // coordinate of the compressed vector (x, y, z)
Unsigned char lightnormalindex; // vector index
} vertex_t;
You may have noticed that unsigned char V [3]; yes, this vector represents the compressed data (which sounds very professional :)), in computing, we extract the data and then smoke and dye it, so the model will not be greatly affected.
Lightnormalindex is a vector index.
There is also a texture coordinate for the vector of A phantoms:
// Texture coordinates
typedef struct
{
    short    s;
    short    t;
 
} texCoord_t;
Like vector representation, texture data is also compressed. During graphic rendering, we extract the data. 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 cocould 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: the formula is as follows:
RealST[i].s = (float)texCoord[i].s / header.skinwidth;
RealST[i].t = (float)texCoord[i].t / header.skinheight;
 
 
The key frame structure is as follows:
// frame
typedef struct
{
Float scale [3]; // compress and decompress the code
Float translate [3]; // translation vector
Char name [16]; // frame name
Vertex_t Verts [1]; // place where the frame vector starts
 
} frame_t;
Scale [3] is the key role we mentioned above for decompression. This array stores a scaling multiple, And the translate is mainly used to store the scaled translation volume. The actual value of a key frame is represented as follows:
vertex.x = (frame.verts[i].v[0] * frame.scale[0]) + frame.translate[0]
vertex.y = (frame.verts[i].v[1] * frame.scale[1]) + frame.translate[1]
vertex.z = (frame.verts[i].v[2] * frame.scale[2]) + frame.translate[2]
Vertex is the actual Vector Value in the Phantoms. The index range of the frame. Verts array is: 0-(num_xyz-1). Let's list the relationships between them:
In the real rendering process, we need to associate the triangle vertex vector with the texture coordinate, then we will create a struct, considering the md2 file structure, the struct is as follows:
// triangle
typedef struct
{
Short index_xyz [3]; // vector index
Short index_st [3]; // texture Index
 
} triangle_t;
 
You may have noticed that we have now mapped the fixed point of each triangle to the texture of the triangle. The rendering code is as follows:
glBegin( GL_TRIANGLES );
 
// draw each triangle
for( int i = 0; i < header.num_tris; i++ )
{
    // draw triangle #i
    for( int j = 0; j < 3; j++ )
    {
        // k is the frame to draw
        // i is the current triangle of the frame
        // j is the current vertex of the triangle
 
        glTexCoord2f( (float)TexCoord[ Meshes[i].index_st[j] ].s / header.skinwidth,
                           (float)TexCoord[ Meshes[i].index_st[j] ].t / header.skinheight );
 
        glNormal3fv( anorms[ Vertices[ Meshes[i].index_xyz[j] ].lightnormalindex ] );
        
        glVertex3f( (Vertices[ Meshes[i].index_xyz[j] ].v[0] * frame[k].scale[0]) + frame[k].translate[0],
                        (Vertices[ Meshes[i].index_xyz[j] ].v[1] * frame[k].scale[1]) + frame[k].translate[1],
                        (Vertices[ Meshes[i].index_xyz[j] ].v[2] * frame[k].scale[2]) + frame[k].translate[2] );
    }
}
 
glEnd();
 
 
OpenGL command application. I am not translating it. Refer to the original version.
 
The structure of the entire file is as follows:
 
       http://tfc.duke.free.fr/old/models/md2.htm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.