麒麟子

~~

导航

<2013年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

统计

常用链接

留言簿(12)

随笔分类

随笔档案

Friends

WebSites

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜

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

终于决定,还是通过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作为下标,进行查询。 目前还没有搞明白。
本来想继续写下去,但发现寸步难行了,后面的数据都没看明白是什么意思,只好留到下次了。
睡觉了,晚安!!!!!

posted on 2013-04-20 00:53 麒麟子 阅读(750) 评论(0)  编辑 收藏 引用 所属分类: BLIZZARD


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理