魔兽世界客户端数据研究(一)

终于决定,还是通过wow model viewer起手,研究一下WOW的数据类型,从另一个角度,体验一把这个唯一让我充过值的游戏。

这将是一系列随笔,即在读代码的时候,顺便记录,以理清思路和加深映象。 其中会有很多让人费解的地方,如果有幸被某位兄弟看见,请勿见笑。

我们从读取模型数据开始。。。 
下面是这是顶点结构体 这是wow model viewer中的定义 
struct ModelVertex 

    Vec3D pos; //顶点位置 
    uint8 weights[4];//骨骼权重 
    uint8 bones[4];//受影响的骨骼索引 
    Vec3D normal;//法线 
    Vec2D texcoords;//纹理坐标,只有一层 
    int unk1, unk2; // 总是0,0  可能没有被使用到 
};

读完顶点数据后,我们需要对坐标系做一点修正,因为WOW用的是Z轴向上, Y轴向里(依稀记得torque也是这样子) 
很多人用得不是太习惯 
若要转换为GL中的坐标(Z向外),则 pos = vec3D(pos.x,pos.z,-pos.y); 
若要转换为D3D中的坐标(Z向里),则pos = vec3D(pos.x,pos.z,pos.y); 
法线转换方式和坐标一样

转换为了我们想要的坐标数据以后。我们还要强制对法线进行单位化。在这里,为了对法线进行压缩,其实我们可以仅存储X,Y分量就可以了。 
不知WOW为什么没有这样子。

同时,在进行模型顶点数据读取的时候,由于我们本来就要进行顶点数据遍历,所以我们可以顺便得出这个模型的半径,用来做球形检测

模型数据读完了,紧接着是BoundingMesh(想说是包围网格,又不太对,又或者,叫碰撞网格,这是一个简化的网格,用于碰撞检测和拾取之类的)数据 
它由两个部分组成BoundingVertices & BoundingTriangles (我又词穷了,都懂的。) 
BoundingVertices由一串float3组成,顺序读取即可,读取完了后,如果上面的MESH做了坐标系统转换,那这里也得做。 
BoundingTriangles由一串uint16索引组成,顺序读取即可。

读取完上面的模型数据后,接下来就是纹理数据。 
在WMV中的定义如下

#define    TEXTURE_MAX    32  //最大纹理数 
struct ModelTextureDef 

    uint32 type;  //纹理类型 
    uint32 flags; //纹理标记 
    uint32 nameLen; //名字长度 
    uint32 nameOfs; //名字在DBC中的偏移 
};

搞笑得很啊,在结构体定义的时候,没有对上面字段说明,在使用的地方,却有一段描述。不过想想也是,用的时候方便查看嘛。 
/* 
Texture Types 
Texture type is 0 for regular textures, nonzero for skinned textures (filename not referenced in the M2 file!) 
For instance, in the NightElfFemale model, her eye glow is a type 0 texture and has a file name, 
the other 3 textures have types of 1, 2 and 6. The texture filenames for these come from client database files:

DBFilesClient\CharSections.dbc 
DBFilesClient\CreatureDisplayInfo.dbc 
DBFilesClient\ItemDisplayInfo.dbc 
(possibly more) 
0     Texture given in filename 
1     Body + clothes   身体和布料 
2    Cape 肩膀 
6    Hair, beard 头发,胡子 
8    Tauren fur 牛头人的皮毛 
11    Skin for creatures #1 
12    Skin for creatures #2 
13    Skin for creatures #3

Texture Flags 
Value     Meaning 
1    Texture wrap X X方向环绕 
2    Texture wrap Y Y方向环绕 
*/

下面是我对这段说明的理解 
0 表示是普通纹理 并且,可以直接获取它的纹理名字 
非0表示是皮肤 值得说明的是,纹理名字不包含在M2文件中。 
比如说,在暗夜男模型中,他的眼睛发光就是一个类型为0的纹理,并且,有一个文件名(这个文件名就存在本文件中)。其它3个纹理类型是1,2和6. 纹理名字是从客户端数据库文件中提取。nameOfs就是表示其位置

额,写到这里的时候,突然发现,其实是有宏定义的

/* 
Texture Types 
Texture type is 0 for regular textures, nonzero for skinned textures (filename not referenced in the M2 file!) For instance, in the NightElfFemale model, her eye glow is a type 0 texture and has a file name, the other 3 textures have types of 1, 2 and 6. The texture filenames for these come from client database files: 
DBFilesClient\CharSections.dbc 
DBFilesClient\CreatureDisplayInfo.dbc 
DBFilesClient\ItemDisplayInfo.dbc 
(possibly more) 
*/ 
enum TextureTypes 

    TEXTURE_FILENAME=0,            // Texture given in filename 
    TEXTURE_BODY,                // Body + clothes 
    TEXTURE_CAPE,                // Item, Capes ("Item\ObjectComponents\Cape\*.blp") 
    TEXTURE_ITEM=TEXTURE_CAPE, 
    TEXTURE_ARMORREFLECT,        // 
    TEXTURE_HAIR=6,                // Hair, bear 
    TEXTURE_FUR=8,                // Tauren fur 
    TEXTURE_INVENTORY_ART1,        // Used on inventory art M2s (1): inventoryartgeometry.m2 and inventoryartgeometryold.m2 
    TEXTURE_QUILL,                // Only used in quillboarpinata.m2. I can't even find something referencing that file. Oo Is it used? 
    TEXTURE_GAMEOBJECT1,        // Skin for creatures or gameobjects #1 
    TEXTURE_GAMEOBJECT2,        // Skin for creatures or gameobjects #2 
    TEXTURE_GAMEOBJECT3,        // Skin for creatures or gameobjects #3 
    TEXTURE_INVENTORY_ART2,        // Used on inventory art M2s (2): ui-buffon.m2 and forcedbackpackitem.m2 (LUA::Model:ReplaceIconTexture("texture")) 
    TEXTURE_15,                    // Patch 12857, Unknown 
    TEXTURE_16,                    // 
    TEXTURE_17,                    // 
};

enum TextureFlags 

    TEXTURE_WRAPX=1, 
    TEXTURE_WRAPY 
};

总之,就是如果遇上是0号类型,则直接读文件名,否则就去DBC中取公共纹理数据。 
比如头发什么的,而上面牛头人的毛发单独定义,可能是因为毛发和一般人型生物不一样吧。 
另外,从TEXTURE_ARMORREFLECT中可以看出,WOW中的武器和盔甲是加上了反射纹理的,这样才看起来有高光的感觉。

------------------------------------------------------------------------ 
------------------------------------------------------------------------ 
读完模型,碰撞网格,纹理数据,接下来,就要读取挂接物了,最常见的挂接物,就是WOW中的肩膀,头盔或者武器上的一些粒子效果。

WMV中,挂接物的定义如下 
/* 
* This block specifies a bunch of locations on the body - hands, shoulders, head, back, 
* knees etc. It is used to put items on a character. This seems very likely as this block 
* also contains positions for sheathed weapons, a shield, etc. 
*/ 
struct ModelAttachmentDef 

    uint32 id; // Just an id. Is referenced in the enum POSITION_SLOTS. 
    uint32 bone; // Somewhere it has to be attached. 
    Vec3D pos; // Relative to that bone of course. 
    AnimationBlock unk; // (Int32) Its an integer in the data. It has been 1 on all models I saw. Whatever. 
};

无非就是定义了挂接的骨骼索引,偏移位置等。  最后一个参数,是动画块数据。定义如下

// sub-block in block E - animation data, size 28 bytes, WotLK 20 bytes 
struct AnimationBlock 

    int16 type;        // 插值类型 (0=none, 1=linear, 2=hermite) 
    int16 seq;        // 全局队列ID,-1表示无

    //下面的就是数据个数+数据在缓冲区中的偏移 
    #ifndef WotLK 
    uint32 nRanges; 
    uint32 ofsRanges; 
    #endif 
    uint32 nTimes;  // 
    uint32 ofsTimes; 
    uint32 nKeys; 
    uint32 ofsKeys; 
};

上面的定义可以看中,WLK版本中,BLZ对文件进行了改动,加入了一个范围数据。

读取完上面的挂接头信息以后,就可以根据这个信息,实例化一个挂接物,添加到模型身上。

下面是一个模型挂接物的信息 
struct ModelAttachment 

    int id;  //ID 
    Vec3D pos; 位置 
    int bone; //撞接的骨骼 
    Model *model; //挂接的模型

    void init(MPQFile &f, ModelAttachmentDef &mad, uint32 *global); 
    void setup(); 
    void setupParticle(); 
};

读完上面的信息后,我发现,还有一个诡异的attLookup数据, 单看字面上意思,应该是拿来装一个供挂接物ID查询的数据的。 
就是ModelAttachment中的ID作为下标,进行查询。 目前还没有搞明白。 
本来想继续写下去,但发现寸步难行了,后面的数据都没看明白是什么意思,只好留到下次了。 
睡觉了,晚安!!!!!

作者:码瘾少年·麒麟子 
出处:http://www.cnblogs.com/geniusalex/ 
蛮牛专栏:麒麟子 
简介:09年入行,喜欢游戏和编程,对3D游戏和引擎尤其感兴趣。 
版权声明:本文版权归作者和博客园共有,欢迎转载。转载必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载:http://www.cnblogs.com/geniusalex/archive/2013/04/20/3031866.html

时间: 2024-11-02 21:49:16

魔兽世界客户端数据研究(一)的相关文章

魔兽世界客户端数据研究(三)

终于决定,还是通过wow model viewer起手,研究一下WOW的数据类型,从另一个角度,体验一把这个唯一让我充过值的游戏. 这将是一系列随笔,即在读代码的时候,顺便记录,以理清思路和加深映象. 其中会有很多让人费解的地方,如果有幸被某位兄弟看见 ,请勿见笑.   今天来说一下M2中的LOD的数据 WOW中,为了降低远处模型的渲染开销,为模型做了LOD,即远处的模型,使用更少的顶点,更粗略的材质. 比如远处的模型在渲染的时 候,面片数量减少,关闭光照,不渲染挂接的特效等等. 因此,不用证明

魔兽世界客户端数据研究(四):M2文件头分析

终于决定,还是通过wow model viewer起手,研究一下WOW的数据类型,从另一个角度,体验一把这个唯一让我充过值的游戏. 这将是一系列随笔,即在读代码的时候,顺便记录,以理清思路和加深映象. 其中会有很多让人费解的地方,如果有幸被某位兄弟看见 ,请勿见笑. 这都是第四篇关于M2文件格式的文章了,但是,对MD2文件格式的理解却还是九牛一毛,冰山一角. 仔细思考了一下,发现是不是自己一 开始走的路不对,因为是从半腰上分析的. 今天决定把文件头补上. 因为文件头可以大概看出一个文件是如何组织

魔兽世界客户端数据研究(二)

终于决定,还是通过wow model viewer起手,研究一下WOW的数据类型,从另一个角度,体验一把这 个唯一让我充过值的游戏. 这将是一系列随笔,即在读代码的时候,顺便记录,以理清思路和加深映象. 其中会有很多让人费 解的地方,如果有幸被某位兄弟看见,请勿见笑.   上次弄到nAttachLookup就不行了,这次继续弄.  最近四川地震了,所以弄得比较慢. 好吧,我们接着nAttachLookup说.  读完挂接数据后,我们接着读了堆nAttachLookup个的uint16数据.这串数

javascript进行客户端数据的校验

javascript|客户端|数据 file://如果输入的内容不满足,则不提交,并且焦点自动跳到该位置. file://比发送以后在服务器端校验数据要好用的多! 脚本代码: <script language="javascript"> <!-- function Juge(theForm) { if (theForm.title.value == "") { alert("请输入标题!"); theForm.title.foc

&amp;#106avascript进行客户端数据的校验

客户端|数据  //作者:叨叨 //email:pjzhp@263.net //客户端对用户输入数据校验 //如果输入的内容不满足,则不提交,并且焦点自动跳到该位置. //比发送以后在服务器端校验数据要好用的多! 脚本代码: <script language="javascript"> <!-- function Juge(theForm) { if (theForm.title.value == "") { alert("请输入标题!&

&amp;#106avascript进行客户端数据的校验(2)

客户端|数据 html网页代码: <html> <head> <title>文章发布</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body bgcolor=#fafee9> <center>原创文章投稿处</center> <br&

&amp;#106avascript进行客户端数据的校验(1)

客户端|数据 //客户端对用户输入数据校验 //如果输入的内容不满足,则不提交,并且焦点自动跳到该位置. //比发送以后在服务器端校验数据要好用的多! 脚本代码: <script language="JavaScript"> <!-- function Juge(theForm) { if (theForm.title.value == "") { alert("请输入标题!"); theForm.title.focus();

ASP中Request对象获取客户端数据的顺序

request|对象|客户端|数据 在ASP中Request对象是获取客户端提交数据的一个很重要的对象,大家对它也是非常熟悉了. 虽然如此,还是经常有人问我下面的几种写法有什么不同,到底应该怎么写? strMessage = Request("msg")strMessage = Request.Form("msg") 而且,我也看过好多人写的代码,一律都是Request("")的写法,当然这样的写法并没有什么错. 只是大家应该注意Request对

技巧:ASP中用Request对象获取客户端数据

request|对象|技巧|客户端|数据 在ASP中Request对象是获取客户端提交数据的一个很重要的对象,大家对他也是非常熟悉了. 虽然如此,还是经常有人问我下面的几种写法有什么不同,到底应该怎么写? strMessage = Request("msg") strMessage = Request.Form("msg") 而且,我也看过好多人写的代码,一律都是Request("")的写法,当然这样的写法并没有什么错. 只是大家应该注意 Req