使用四元数来渲染蒙皮动画

原本没计划使用四元数来渲染蒙皮动画的,但是由于stage3D的限制,因此考虑在AOI3D中,使用四元数来渲染吧。

由于Adobe的畏首畏尾,尽可能的向下兼容,又不肯把兼容的选择权交给开发者,因此stage3D只提供了128个常量寄存器。
在3D程式中,一般使用 4*4 矩陣來描述骨骼的旋轉-位移-縮放。 而一個常量寄存器只能存儲 4個浮點型(在DX10中已经支持整数型了,不过stage3D只有DX9级别),
因此我们只能渲染 128/4 = 32 根骨骼, 为了确定模型的位置,我们还需要上传 ModelViewProjection 矩阵, 那么我们只能使用31根骨骼了,而且还要放弃各种灯光及滤镜效果了。

使用四元数的优势,开源引擎Ogre的模型文件就是使用四元数进行蒙皮了,这也是AOI3D能支持蒙皮动画的原因。 一个四元数使用 x,y,z,w 来表示 3个轴的旋转,因此它只需要使用1个寄存器, 之后再使用一个寄存器来存储位移即可。 对于缩放,一般蒙皮动画的缩放都是 1, 因此可以忽略。 那么我们可以渲染 124 / 2 = 62 跟骨头了。

这里不讲解四元数的原理,直接说使用。
你可以通过支持四元数的动画文件直接解析出四元数的值,也可以通过 Matrix3D 来获取四元数

[cc lang=”actionscript3″]
var datas : Vector. = matrix3D.decompose(Orientation3D.QUATERNION);
[/cc]

datas 是一个数组,其实[0]是位移,[1]是四元数,[2]是缩放
有了四元数后,我们将其通过常量上传到Shader中,然后再Shader中,重新组装成一个 3 * 4 矩阵,然后其他都和之前的一样。

四元数转换回矩阵的方式(CPU模拟)
[cc lang=”actionscript3″]
var quaIndex : uint = index / 2;
var rotation : Vector3D = m_jointConstant[quaIndex];
var translate : Vector3D = m_jointConstant[quaIndex + 1];

var mat : Matrix3D = new Matrix3D();

var vt0 : Vector3D = new Vector3D();
vt0.x = 2 * rotation.x * rotation.y;
vt0.y = 2 * rotation.x * rotation.z;
vt0.z = 2 * rotation.x * rotation.w;
vt0.w = 2 * rotation.y * rotation.z;
var vt1 : Vector3D = new Vector3D();
vt1.x = 2 * rotation.y * rotation.w;
vt1.y = 2 * rotation.z * rotation.w;
vt1.z = rotation.x * rotation.x;
vt1.w = rotation.y * rotation.y;
var vt2 : Vector3D = new Vector3D();
vt2.x = rotation.z * rotation.z;
vt2.y = rotation.w * rotation.w;

var rawData : Vector. = mat.rawData;
xx – yy – zz + ww
rawData[0] = vt1.z – vt1.w – vt2.x + vt2.y;
2xy – 2zw
rawData[1] = vt0.x – vt1.y;
2xz + 2yw
rawData[2] = vt0.y + vt1.x;
0
rawData[3] = translate.x;
2xy + 2zw
rawData[4] = vt0.x + vt1.y;
-xx + yy – zz + ww
rawData[5] = vt1.w – vt1.z – vt2.x + vt2.y;
2yz + 2xw
rawData[6] = vt0.w – vt0.z;
0
rawData[7] = translate.y;
2xz + 2yw
rawData[8] = vt0.y – vt1.x;
2yz – 2xw
rawData[9] = vt0.w + vt0.z;
-xx – yy + zz + ww
rawData[10] = vt2.x – vt1.z – vt1.w + vt2.y;
0
rawData[11] = translate.z;
0
rawData[12] = 0;
0
rawData[13] = 0;
0
rawData[14] = 0;
1
rawData[15] = 1;

mat.rawData = rawData;
[/cc]

这个矩阵的解析已经被手动转置过了,如果使用CPU渲染,需要手动转置回来,又或者在创建rawData的时候就设置好其索引。

发表评论

电子邮件地址不会被公开。 必填项已用*标注