cocos2dx blender 骨骼动画实现

前言 cocos2d-x 中相关部分代码介绍  背景知识介绍php

参考html

http://www.3dkingdoms.com/weekly/weekly.php?a=4python

一 简单3d 模型支持数组

第一步实现对3d 模型的简单支持,完成一个CCSprite3D 类dom

参考CCSprite 类 以及 CCGLProgram 代码 主要修改 draw 方法。测试

添加了定点数组pos  绘制索引数组index. 以及若干 3d 变换相关的成员方法 平移 旋转 缩放。动画

对draw方法的改造,首先增长对opengl 矩阵进行计算的stdTransform, 将3d空间中的变换 矩阵乘到 MV 矩阵上面。spa

注意cocos2d 使用了两种投影方式,一种是 平行投影,一种是3d 透视投影,默认使用的3d 投影, 这种方式下MV矩阵也被修改,将坐标原点移动到了屏幕的右下角。3d

3d绘制须要 开启depth_test 深度测试。调试

以后只须要将顶点数组传入vertexAttribPointer 中 将索引数组传给glDrawElements 中便可.

测试时能够手动写一个 正方体的 顶点数组数据。

注意要对模型进行必定的缩放,不然屏幕上面会看不到。

使用 画 line 以及 画顶点 方式 绘制 能够用来调试。


二 3d 模型 基本变换支持

http://en.wikipedia.org/wiki/Transformation_matrix

cocos2dx 中使用kazmath 这个数学库,这个库中的矩阵kmMat4使用列优先的方式存储,即0 1 2 3 存储的是 矩阵第一列数据。

对应平移变换只须要修改 最后一列的 前3行数据便可,分别对应x y z 平移。

http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation

对于旋转,通常使用四元式进行计算,所以对于旋转能够先按照四元式进行计算,最后转化成一个矩阵便可。

四元式 经过对旋转轴和相对于轴的旋转角度来表示(经过一些sin cos计算),两个四元式之间的插值使用圆插值(slerp).

基本的 x y z 轴的旋转矩阵 能够参考2维度旋转矩阵的构造方法。

http://onlinemca.com/mca_course/kurukshetra_university/semester5/computergraphics/three_d_transformation.php

对于缩放直接修改矩阵主对角线上面的值便可。


下面这些矩阵对顶点的计算 都是按照 行优先矩阵 左乘以 顶点列向量, 至关于列优先矩阵 右乘以 顶点行向量 来计算结果的。在给opengl 传入矩阵的时候 是以 列优先的方式传入数据的。  http://www.opengl.org/archives/resources/faq/technical/transformations.htm

在kazmath 这个库里面 矩阵是以列优先方式存储,矩阵相乘的时候第一个矩阵的第一行 乘以 第二个矩阵的第一列 获得第一个元素,便是第一个矩阵左乘第二个矩阵。 

http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html

貌似在direct3d中传入的矩阵数据是按照行优先的顺序的,所以在direct中若是要作两个矩阵的乘法,第一个矩阵左乘第二个矩阵,则选取的矩阵元素和opengl是不一样的。

固然这里使用的左乘 是数学上面的左乘的概念,即用一个矩阵的 第一行 乘以 第二个矩阵的第一列 获得第一个元素。


注意矩阵乘法是不能够交换了,所以对于这三种变换,不一样的乘顺序会产生不一样的结果。举例以下:

旋转矩阵 左乘 平移矩阵,则旋转矩阵中的值将会影响到平移的值,而平移的数值不会影响结果中的旋转部分的值,结果就是在世界空间中 对象是旋转必定角度以后,沿着这个角度进行平移的。

若是平移矩阵 左乘 旋转矩阵, 平移的值不会影响结果中的旋转部分, 旋转也不会影响平移。结果就是物体如今本地旋转,可是以后 仍是沿着世界坐标中原来的轴进行平移。

先考虑 缩放矩阵 左乘 旋转矩阵 结果就是 至关于在原来的旋转矩阵上面 同一行 乘以一个相同的系数, 这个矩阵在做用到顶点的时候  这个 系数能够提取出来,则至关于 对顶点先进行了旋转 接着 仍是按照原来的 世界坐标的方向 进行缩放, 这样获得的是一个 切拉伸的效果,这样物体会变形。

那么 旋转矩阵 左乘 缩放 矩阵 获得的结果就和上面不一样,所以应该是物体旋转以后,相应的缩放轴也跟着旋转了,所以缩放 不是沿着世界轴进行的,而是沿着物体自己的本地坐标轴进行的,这样物体不会边形。

接着考虑缩放左乘 平移矩阵 , 结果中的缩放部分没有变化,可是平移部分会被改变,结果就是 物体仍是按照原来的比例缩放,可是 新的平移位移的时候相对于 原来的平移位移会产生必定比例的缩放。

若是是 平移 左乘 缩放矩阵  结果中平移部分 和 缩放部分都不会发生改变, 结果就是 物体在世界坐标空间中 按照原来的比例 缩放 , 接着平移正常的位移。


能够总结出来 平移 左乘 另外的矩阵 不过影响原来矩阵的结果, 而别的两种矩阵左乘平移矩阵 会影响平移的结果。缩放 左乘 旋转 会产生物体的边形, 而旋转左乘缩放 会保持物体的形状和单纯的进行缩放的物体形状是一致的。


所以若是你的目标是保证世界空间中平移不变则用平移矩阵左乘其它矩阵,若是是要保证物体的缩放形状不变则 用 旋转矩阵左乘 缩放矩阵。

若是要保持这两个不变性的话 矩阵乘法的顺序就是 平移 * 旋转 * 缩放

http://gamedev.stackexchange.com/questions/16719/what-is-the-correct-order-to-multiply-scale-rotation-and-translation-matrices-f

固然要根据自身想要的结果来调整矩阵的乘法顺序,而且能够经过增长父子变换的关系来控制矩阵乘法顺序。

通常状况是 父亲矩阵 左乘于 孩子矩阵 则结果就是 父亲在世界空间的平移 获得保持, 父亲缩放会致使旋转的孩子发生变形,父亲的旋转 会影响孩子自身的平移方向。

按照专业的说法叫作 孩子的变换矩阵做用在孩子节点自身的局部空间 而 父亲矩阵 会对孩子局部空间进行变换。


三 骨骼动画

本质上骨骼只是一个矩阵变换,若是要查看一个骨骼则观察其对应的矩阵便可。可是这种方式很是不直观,如何经过图像直观表现这种矩阵变换呢?

这里首先要明确表现和本质之间的区别,矩阵变换及其对应的3d骨骼对象不能等价。骨骼的做用只是施展一种变换到一个对象身上,至于这个对象当前的状态是什么并不关心,所以须要手动的对对象设定一个初始化的状态,然后续的状态经过这种骨骼矩阵变换来生成。

所以问题分红两个部分,如何描述这种初始化状态,如何描述这个矩阵变换。


骨骼分红两个端点 头和 尾部,之间有必定长度链接,而且这两个点之间有必定的旋转方向。

矩阵变换比较简单,能够经过一个四元式和一个3维向量, 以及一个骨骼长度来描述。

将骨骼的一端作为原点,这里我设定骨骼沿着x 轴方向,而骨骼长度就是lenght,offset表示孩子骨骼相对于父亲骨骼的 结束端点的 位置偏移,一般这个偏移量为0.

这样矩阵变换的计算方法就是 

外部矩阵 * 父亲骨骼平移矩阵 * 父亲骨骼旋转矩阵 * x轴方向 length长度 平移矩阵 * 孩子骨骼的平移矩阵 * 孩子骨骼旋转矩阵 

上面就能计算到 一个孩子骨骼的变换矩阵了。抽取其中的元素,能够获得每根骨骼的变换矩阵的计算方法是

外部矩阵 * 平移矩阵 * 旋转矩阵 

而传入给孩子骨骼的 矩阵就是  外部矩阵 * 平移矩阵 * 旋转矩阵 * x轴方向长度length 平移矩阵

这里的length存在的主要目的是为了方便的描述旋转,由于对于长度0的骨骼来说 就没办法指定其旋转方向了。


解决了矩阵变换的描述方法 接着须要描述骨骼初始状态以及和mesh绑定时的初始状态

首先建模的时候会把骨骼的父子关系肯定每一个骨骼初始的旋转 长度 平移这些参数肯定, 这里咱们假设骨骼动画只有旋转, 这样的话 长度能够存储到上面提到的length里面。

这时候如何存储初始的旋转矩阵呢? 咱们为每个骨骼分配了一个额外的矩阵,这个矩阵里面存放 骨骼初始 骨骼的初始平移矩阵 左乘 旋转矩阵  的逆 矩阵。

这样在对一个骨骼上面的定点进行变换的时候,若是骨骼在初始状态,那么对定点的变换就是 单位矩阵,经过上面计算的逆矩阵 * 骨骼当前的变换矩阵 就会获得一个单位矩阵 而这个单位矩阵 再做用到 定点上 定点就不会运动了。这样就保证了 在骨骼的初始状态下 骨骼上绑定的 顶点 也是在初始状态, 不会运动。


上面计算的骨骼逆矩阵是骨骼局部空间的逆矩阵 所以是不够用的,对于子骨骼来说 其变换矩阵是通过父亲层层传递的, 所以一个子骨骼的逆矩阵实际的逆向矩阵是 子局部逆向矩阵 * 父亲逆向矩阵

这时候 对于 计算孩子骨骼的实际变换矩阵就是   子局部逆向矩阵 * 父亲逆向矩阵 * 父亲传到的变换矩阵 * 子局部变化矩阵

这样若是 父亲 孩子骨骼都在bind位置时候,孩子上面的mesh 定点也是在bind位置的。

所以对于一个骨骼描述的数据就包括

rotate 四元式骨骼局部旋转

offset 3维度向量 骨骼局部偏移

length 长度 骨骼长度

reverse  kmMat4 局部逆矩阵

mat 计算的实际变换矩阵 用于给mesh定点使用 

child 骨骼的孩子骨骼

parent 骨骼的父亲

id 骨骼的编号

name 骨骼的名字


四:blender中的骨骼动画导出 并在cocos2dx 中导入 

blender 支持python脚本有比较好的扩展性 所以尝试导出blender中的模型和动画数据 在游戏引擎中使用

须要导出的数据包括

定点数据 包括 定点位置 定点绑定的骨骼编号 以及权重

面数据 每一个三角面 由哪几个编号的定点构成

骨骼数据 骨骼在bind姿式下面 每一个骨骼的旋转值, 偏移值, 长度信息, 骨骼的父亲信息

动画信息 不一样frame下 每一个骨骼的 旋转 长度 偏移 信息

相关文章
相关标签/搜索