Chinaunix首页 | 论坛 | 博客
  • 博客访问: 174301
  • 博文数量: 43
  • 博客积分: 827
  • 博客等级: 准尉
  • 技术积分: 487
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-26 19:19
文章分类

全部博文(43)

文章存档

2015年(1)

2014年(1)

2013年(5)

2012年(36)

我的朋友

分类: C/C++

2013-09-08 15:06:17

最近把Collada文件导进了Engine里面,主要是为了读取的模型和动画,有段时间没有写博客了,这里记一下。

整个这块的结构:

Collada就属于最底下的那一层,中间层包含能个构建Engine对应Resource的所有数据, 并且负责导入Engine里面。

Collada大概的结构:
在Collada里面有很多的libirary节点(比如geometry,animation等等),正如名称一样,这些是一些库节点,里面包含了各自类型的一些模板对象,这些模板对象有一个唯一id。而其他地方就通过id来实例化一个实际对象。
所以:里面实例化一个visual_scene(在中定义),visual_scene里面包含一个node graph,每一个node可以引用到其他library里面的实例。

主要过程:
1:构建visual_scene里面的node graph,对于一个node如果包含geometry_instane或者controler_instance则添加这个node下面的mesh列表,geometry_instance为static mesh,controler_instance为skin mesh。一个Node里面包含自己的所有孩子节点和mesh列表。
2:遍历node graph,构建Middle Layer上的mesh list。并且根据mesh的名字来构建mesh的LOD列表。
3:根据mesh list下面的skin mesh构建Middle Layer上的skeleton list。
4:构建mesh list上每一个mesh的geometry数据。
5:构建animation list和每一个animation上的数据。
6:导入到Engine里面。

上面skeleton list依赖mesh list创建,而animation list依赖skeleton list创建。

导入Mesh
    在node节点里面instance_geometry和instance_controler会被解析为Mesh。instance_geometry比较简单,可以直接通过url找到library_geometry的里面的geometry,然后构建mesh。instance_controler下面包含了两部分:skin,skeleton。skin里面则包含了mesh geometry数据和mesh跟skeleton联系上的skin数据(每个vertex上的weight,base pose上的joint matrix)。
    各个节点的引用关系如下:
    

   geometry 数据的解析:
   下面的是节点,mesh节点里面包含很多的节点,在collada里面表示一个数据源,包含实际的数据,这个数据的类型以及读取的格式。所以position,normal,uv等等这些数据就分别分散在各自的里面。另外的是primitive节点,他负责组装这些构造vertex数据。
    一个primitive节点:    
   
         
         
         
         
         
         

89 0 1783 0 0 1 1784 1 7 ...


   triangles>
   
   这里面

里面的数据都是在source里面的索引,里面的offset则是一个vertex在

的偏移,根据offset可以知道一个vertex在p里面要用占多少个数字,set表示一个semantic的n,比如d3d里面texcoord的texcoord0,texcoord1...。
   根据上面:一个vertex占4个。
   89 0 1783 0为一个顶点对应vertex,normal,texcoord,(textangent,texbinormal)的索引。注意textangent,texbinormal的offset一样,所以他们只占一个数字。
   

里面的数字个数/4/3 = 三角形的个数。
    
    顺便说一下,collada的格式很灵活,解析起来就很麻烦。我这里用的是dom,有的代码直接用的Torque的。

   Skin数据的解析:
   这个过程主要构建两个数据:vertex weights和bone inverse bind matrix(将vertex从model space转换到bone space)。注意:的matrix是将geometry里的local space转换到model space。

导入Skeleton
    这个过程比较简单,在mesh list里面所有的skin mesh可以拿到skeleton的root node,因此直接可以生成skeleton。
    
导入Animation
    Animation这个过程比较麻烦,在Torque里面,Animation是单独在一个.dae文件里面,而mesh和skeleton在一个.dae里面。但是Animation的.dae里面仍然有一个skeleton node结构,这个和在mesh那个文件里是保持一致的,这样Animation才能够根据bone的index来保存动画帧的数据。
   各个节点的引用关系如下:
   
   通过上面的关系图,一个channel影响一个bone(target指向的node),注意:一个bone可能被多个channel影响。把source指向的sampler里面的三个inputs : 时间线,每个时间点对应的matrix,对应的插值方法。来分别生成每一个bone对应每一帧的transform matrix,如果需要的一个时间点不是input array里面的时间点,则需要用interpolation指定的插值方法来计算。
   我是通过translation,quaternion来保存一帧的变换,scale没有保留,感觉用处不多。
  Animation里面一个bone对应一个track,这个track包含这个bone的所有帧的变换。所有的bone的帧数需要一样。

后记:
    写了骨骼动画一段时间了,单一个动画播放已经完成,但quaternion的一个问题一直不能解决。
   原因是Quaternion在差值的时候不能确定是选择长路径还是段路径,当两个动画合成的时候,就会出现某一个骨骼突然跳到另一个方向上去。

Reference :
    Torque Web :    Torque Git :

阅读(2989) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~