終于決定,還是通過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作為下標,進行查詢。 目前還沒有搞明白。
本來想繼續寫下去,但發現寸步難行了,后面的數據都沒看明白是什么意思,只好留到下次了。
睡覺了,晚安?。。。?!