哈... 最近正着手进行Android 3D游戏... 有些心得会陆续在后面陆续与大家分享.....
首先看看構成MD2的幾種基本結構
typedef struct
{
float X,Y,Z;
}tVector;
這個相信不用多說,凡是3D遊戲編程必然會有的一個結構--矢量;
typedef struct
{
float U;
float V;
}tTexCoord;
typedef struct
{
short U;
short V;
}tUVIndex;
這兩個幾乎一樣的結構,存儲了一個頂點的紋理座標--UV座標;不同之處在於一個是用於讀取MD2的,另一個是放入內存的,因此數據類型不一樣;
typedef struct
{
unsigned short MeshIndex[3];
unsigned short UVIndex[3];
}tMesh;
這個結構表示了一個多邊形,因為MD2是由Triangle構成的,所以每個多邊形需要有三個頂點.而tMesh結構僅僅存放了頂點和UV座標的索引,即需要時再到頂點列表(tVector * VertexList)和UV列表(tTexCoord * UV)查詢;
typedef struct
{
unsigned char Vertex[3];
unsigned char NormalIndex;
}tFramePoint;
這是一個頂點的結構,類似tVector;不同的是數據類型並不是float,unsigned char應該是MD2的規範,讀取時應用這種格式;
MD2模型是有動畫的,當然也就有關鍵幀了.MD2模型應該有一個總的頂點列表,存放所有幀的所有頂點,每一幀的頂點數和多邊形數都是一樣的.每一幀中都有一個頂點列表首地址,各幀的頂點列表內,頂點的順序都是相同的,因此多邊形列表(TriangleIndex)隻需要一個,當要顯示不同幀時,隻需要改變頂點列表的首地址即可顯示;UV列表也是一樣的道理;
typedef struct
{
float Scale[3];
float Translate[3];
char Name[16];
tFramePoint pFramePoint[1];
}tFrame;
這就是一幀的結構了,可以看到pFramePoint[1]即是幀內頂點列表的首地址;而Scale和Translate則用於拉伸移動變換,載入MD2文件時應當先載入一幀,再根據pFramePoint[J],Scale和Translate的關係把幀內每一個頂點數據存放到總的頂點列表內;
typedef struct
{
tTexTypes TextureType;
int Width;
int Height;
long int ScaleWidth;
long int ScaleHeight;
unsigned int TexIde;
unsigned char * Data;
unsigned char * Palette;
}tTexture;
紋理貼圖結構;重點理解的是TexIde與Data,使用gluBuild2DMidmaps()函數進行貼圖的載入;
typedef struct
{
int NumFrames;
int NumVertices;
int NumTriangles;
int NumUV;
int FrameSize;
int TexWidth,TexHeight;
int CurrentFrame;
int NextFrame;
float Interpol;
tMesh * TriIndex;
tTexCoord * UV;
tVector * VertexList;
tTexture * ModelTexture;
}tModelData;
這就是MD2文件的結構了,一開始需要重點理解的是tMesh * TriIndex,tTexCoord * UV,tVector * VertexList和tTexture * ModelTexture這四個結構:TriIndex即多邊形列表,存放了一幀的所有頂點的空間座標索引和UV座標索引,當繪製某個頂點,如第J個頂點,則根據索引值,向幀內頂點列表和UV列表查詢該點信息:
{
....
tVector * VertexList=new tVector[NumFrames*NumVertices];//為頂點列表分配內存空間;
tFrame * Frame=(tFrame *)&Buffer[OffsetFrame+FrameSize*KeyFrame];//填充某幀的結構;
.....
tVector * TmpVertexList=(tVector *)&VertexList[NumVertices*KeyFrame];
glBegin(0X0004)//0X0004是OpenGL的TRIANGLE模式
for(int J=0;J<NumTriangles;J++)
{
glTexCoord2fv((GLfloat *)&UV[TriIndex[J].UVIndex[2]]);
glVertex3fv((GLfloat *)&TmpVertexList[TriIndex[J].MeshIndex[2]]);
glTexCoord2fv((GLfloat *)&UV[TriIndex[J].UVIndex[1]]);
glVertex3fv((GLfloat *)&TmpVertexList[TriIndex[J].MeshIndex[1]]);
glTexCoord2fv((GLfloat *)&UV[TriIndex[J].UVIndex[0]]);
glVertex3fv((GLfloat *)&TmpVertexList[TriIndex[J].MeshIndex[0]]);
}
glEnd();
}