魔兽世界客户端数据研究(三)
终于决定,还是通过wow model viewer起手,研究一下WOW的数据类型,从另一个角度,体验一把这个唯一让我充过值的游戏。
这将是一系列随笔,即在读代码的时候,顺便记录,以理清思路和加深映象。 其中会有很多让人费解的地方,如果有幸被某位兄弟看见
,请勿见笑。
今天来说一下M2中的LOD的数据
WOW中,为了降低远处模型的渲染开销,为模型做了LOD,即远处的模型,使用更少的顶点,更粗略的材质。 比如远处的模型在渲染的时
候,面片数量减少,关闭光照,不渲染挂接的特效等等。
因此,不用证明也知道,M2中,材质是存在每一个LOD信息中的。   
哎,也就写这几句的时候顺手些,其实不用分析,也是这个结果。因为我们自己的引擎就是这样做的,何况是WOW这种大师级的作品呢。 
从WMV的解析代码下手,看看它是如何解析的吧。   
首先,它使用了这样一行代码    
int16 *transLookup = (int16*)(f.getBuffer() + header.ofsTransparencyLookup);    
读取了一串用于透明值的查找数组。 不过暂时没有使用,后面材质构建的地方才会用到。    
接下来,就是读取相关数据了。 在WLK以后,所有的这些数据,被分离到了.skin文件里面,不知道是咱想的,以后再来作讨论。 但是在 
WLK之前,这个数据还是被放在了一起的。
通过模型的名字我们组合上.skin,就是当前所要的渲染数据了。   
这个组合是这样的。    
假如我们一个模型是 humanmale.m2    
那么它的四个LOD数据分别就是 humanmale01.skin humanmale02.skin humanmale03.skin humanmale04.skin 
当我们得到了这个数据后,就可以通过MPQFile加载想要的数据了。
OK,假设上面的过程,我们已经完全搞定了,此时,我们就得到了一个skin的数据。有了这个数据,我们就可以为所欲为了,嘿嘿。有点
夸张了。 在这个数据的最前面,肯定是数据头了。 数据头在WMV中本来一直是以xxxxHeader来定义的,不过在这里,它一改风格,定义
了一个叫ModelView的东西。
我们来看看这货的定义   
struct ModelView     
{    
#ifdef WotLK    
    char id[4]; //巫妖王版本新增的一个标记位,必须是 'S' 'K' 'I' 'N'    
#endif    
    uint32 nIndex; //这个表示此LOD有多少个INDEX    
    uint32 ofsIndex; //这个表示此LOD的INDEX从模型的哪里开始数    
    uint32 nTris; //这个表示此LOD有多少个构建成三角形的索引    
    uint32 ofsTris;     //三角形个数    
    uint32 nProps; //额外的顶点属性    
    uint32 ofsProps; //顶点属性读取    
    uint32 nSub; //有多少个子部件 后面定义的ModelGeoset表示一个子部件,其包括了MESH数据,材质,渲染状态等内容    
    uint32 ofsSub;     //    
    uint32 nTex;  //纹理    
    uint32 ofsTex;     // ModelTexUnit, material properties/textures    
    int32 lod;                 // LOD bias?  WMV作者也打了问号。    
}; 
有了这个数据头以后,我们就可以无脑的先读取上面的数据,然后再进行构建。
索引数据   
uint16 *indexLookup = (uint16*)(g.getBuffer() + view->ofsIndex);    
构成三角形的顶点索引序列    
uint16 *triangles = (uint16*)(g.getBuffer() + view->ofsTris); 
当前模型在渲染时候的索引数目   
nIndices = view->nTris;    
重新分配索引    
wxDELETEA(indices);    
indices = new uint16[nIndices]; 
将本地索引转换成全局索引   
for (size_t i = 0; i<nIndices; i++)     
{    
        indices[i] = indexLookup[triangles[i]];    
} 
索引数据总算是完了,下面就得准备子模型和材质相关的事情。   
大家都知道,在渲染管线中,一次渲染提交只能提交具有相同渲染状态和纹理的模型。 于是,我们的模型如果具有不同的材质,就需要 
先做分割处理。 这是所有WOW这样的3D MMORPG引擎都需要处理的问题。
在WMV中,模型渲染状态相关的数据,使用了ModelGeoset来表示,纹理相关的,使用了ModelTexUnit来表示   
先看看ModelGeoset的定义    
/// Lod part, One material + render operation    
struct ModelGeoset     
{    
    uint32 id;        // mesh part id?    
    uint16 vstart;    // first vertex, Starting vertex number.    
    uint16 vcount;    // num vertices, Number of vertices.    
    uint16 istart;    // first index, Starting triangle index (that's 3* the number of triangles drawn so far).    
    uint16 icount;    // num indices, Number of triangle indices.    
    uint16 nSkinnedBones;    // number of bone indices, Number of elements in the bone lookup table.    
    uint16 StartBones;        // ? always 1 to 4, Starting index in the bone lookup table.    
    uint16 rootBone;        // root bone?    
    uint16 nBones;        //     
    Vec3D BoundingBox[2];    
    float radius;    
}; 
由上可知,它定义了渲染相关的顶点,以及骨骼,和包围盒信息,最后一个是作为构建包围球用的。
/// Lod part, A texture unit (sub of material)   
struct ModelTexUnit    
{    
    // probably the texture units    
    // size always >=number of materials it seems    
    uint16 flags;        // Usually 16 for static textures, and 0 for animated textures.    
    uint16 shading;        // If set to 0x8000: shaders. Used in skyboxes to ditch the need for depth buffering. 
See below.   
    uint16 op;            // Material this texture is part of (index into mat)    
    uint16 op2;            // Always same as above?    
    int16 colorIndex;    // A Color out of the Colors-Block or -1 if none.    
    uint16 flagsIndex;    // RenderFlags (index into render flags, TexFlags)    
    uint16 texunit;        // Index into the texture unit lookup table.    
    uint16 mode;        // See below.    
    uint16 textureid;    // Index into Texture lookup table    
    uint16 texunit2;    // copy of texture unit value?    
    uint16 transid;        // Index into transparency lookup table.    
    uint16 texanimid;    // Index into uvanimation lookup table.     
};    
而上面这个结构,是纹理相关的信息。 
上面的信息,都是一些索引和ID值,真正的数据是放在全局信息中的。
读取完上面的数据后,LOD信息基本上就大功造成了。 而这些索引是如何使用的,只有下一次再研究了。今天又很晚了。
由此可知,WOW中的数据组织和一般的引擎没有太多区别。 即HEADER信息用于分割数据区域。   
整个模型要使用的数据,放在了最上层,然后,不同的LOD和子MESH要使用数据的时候,只需要保存一些索引值,再到全局数据里去查询就可以了。 
暂时到此吧,下次继续。。。。
作者:麒麟子 
出处:http://www.cnblogs.com/qilinzi/
蛮牛专栏:麒麟子 
简介:麒麟子,编程15年,科技创始人,技术作家。
09年进入游戏行业,16年创立成都幼麟科技有限公司。十年从业经验练就了游戏全栈技能,目前专注于手机游戏领域。
版权声明:本文版权归作者和博客园共有,欢迎转载。转载必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号