第十四回 Mesh
这回说说Mesh,Mesh是又一种最基本的资源,说到基本资源,引擎中目前还有些更为基本的资源,比如ITexture,IVertexBuffer,IIndexBuffer,ISurface,这些基本是对D3D9提供的资源的封装,这里就不多说了.
Mesh资源里包含的东西有些杂乱,有:
1). 一个aabb,表示这个mesh所有顶点的包围盒(当然是在局部空间里的)
2). 顶点中包含的骨骼权重的个数,也就是每个顶点受几根骨骼影响.我们根据这个值来决定绘制这个mesh要使用哪个shader.
3). 骨骼数量,这个Mesh绑定的骨架系统包含多少根骨骼,注意这个值不是Mesh实际使用到的骨骼,一般某
个Mesh绑定到一个骨架系统上,它只会使用这个骨架系统上的某一部分骨骼.我们用这个值来做参数校验,如果在绘制Mesh时,传入的骨骼矩阵数组的大小和这个值不一致的话,我们认为参数错误.
4). VertexBuffer,记录了所有的顶点数据,(所有LOD的顶点数据都放在同一个vertex buffer里).目前顶点格式有 Position,Normal,Binormal,Tangent,BoneWeight,BoneIndex,以及多个channel的UV Coordinate,目前还不支持 Morph动画,所以还不支持相关的顶点格式
5). LOD(Level of Detail)信息,一个记录各个LOD数据的数组,每个LOD包含:
a) 距离值,在多远的情况下切换到这个LOD
b) IndexBuffer,记录这个LOD所有三角形对vertex buffer的索引值
c) 骨骼索引数组,记录了对骨骼矩阵数组的索引
d) Segment(段)信息,每个Segment对应IndexBuffer的一个范围和一个骨骼索引数组的范围
LOD的数据关系见下图:
之所以要采取这种数据保存方式,是因为在模型绘制时,受shader的寄存器限制,支持的骨骼数量是有限的,
所以我们必须把每个LOD分成多个Segment,并且保证每个Segment用到的骨骼数量不超过骨骼数量的限制,目前这个限制值是23(对目前的显卡来说小了点).
Mesh的绘制过程:
*. 绑定VertexBuffer
*. 根据Mesh的距离决定绘制哪个LOD
*. 绑定这个LOD的IndexBuffer
*. 对于这个LOD的每个Segment:
**. 根据Segment在骨骼索引数组中的范围,从传入的骨骼矩阵数组中提取出这个Segment会用到的骨骼矩阵,组成一个(子的)骨骼矩阵数组,把它绑定到shader中去.
**. 调用DrawIndexPrimitive(..),绘制这个Segment对应的primitives.
当然对于骨骼数量的限制,有一种简单的解决方式就是由美术手工切割,使单个的mesh用到的骨骼数量不超 过上限,这样在代码上就不用搞的那么复杂了.不过为了这个Engine使用起来更为方便,还是提供这方面的支 持.
Mesh资源的内容大致就是这样,为了更方便的使用Mesh资源,我还写了一个辅助的工具类,叫作IMeshSnapshot,
主要功能有:
1.) 为Mesh绑定一个世界空间矩阵或一套骨骼矩阵,然后计算出各个顶点的实际数据.这些数据可以用在一些调试功能,或者用于非常精确的HitTest
2.) 使用指定的UV channel,计算MeshSample.对于某套UV channel,有时候我们需要把贴图上的某个像素对应到Mesh上的一个3D位置,我叫它MeshSample,这个在生成LightMap时是很重要的步骤.也可以用于在一个Mesh的表面上得到分布均匀的采样点,可以用于一些特效.
Mesh资源就说到这里,下回说说动画树.