/src/away3d/animators/data/SkeletonAnimationState.as

http://github.com/away3d/away3d-core-fp11 · ActionScript · 356 lines · 266 code · 39 blank · 51 comment · 21 complexity · 1214eb867e438a05e85cd1c913a9be5c MD5 · raw file

  1. package away3d.animators.data
  2. {
  3. import away3d.animators.skeleton.JointPose;
  4. import away3d.animators.skeleton.Skeleton;
  5. import away3d.animators.skeleton.SkeletonJoint;
  6. import away3d.animators.skeleton.SkeletonPose;
  7. import away3d.animators.skeleton.SkeletonTreeNode;
  8. import away3d.arcane;
  9. import away3d.core.base.IRenderable;
  10. import away3d.core.base.SkinnedSubGeometry;
  11. import away3d.core.base.SubMesh;
  12. import away3d.core.managers.Stage3DProxy;
  13. import away3d.core.math.Quaternion;
  14. import away3d.materials.passes.MaterialPassBase;
  15. import flash.display3D.Context3D;
  16. import flash.display3D.Context3DProgramType;
  17. import flash.geom.Vector3D;
  18. import flash.utils.Dictionary;
  19. use namespace arcane;
  20. /**
  21. * SkeletonAnimationState defines the state for a given Mesh and SkeletonAnimation. The state consists of a skeleton pose.
  22. *
  23. * @see away3d.core.animation.skinned.SkinnedAnimation
  24. *
  25. */
  26. public class SkeletonAnimationState extends AnimationStateBase
  27. {
  28. private var _globalMatrices : Vector.<Number>;
  29. private var _numJoints : uint;
  30. private var _skinnedAnimation : SkeletonAnimation;
  31. private var _jointsPerVertex : uint;
  32. private var _bufferFormat : String;
  33. private var _skeleton : Skeleton;
  34. private var _blendTree : SkeletonTreeNode;
  35. private var _globalPose : SkeletonPose;
  36. private var _globalInput : Boolean;
  37. private var _buffersValid : Dictionary = new Dictionary(true);
  38. private var _globalMatricesInvalid : Boolean;
  39. /**
  40. * Creates a SkeletonAnimationState object.
  41. * @param animation The animation object the state refers to.
  42. * @param jointsPerVertex The amount of joints per vertex define
  43. */
  44. public function SkeletonAnimationState(animation : SkeletonAnimation)
  45. {
  46. super(animation);
  47. _skinnedAnimation = animation;
  48. if (animation.numJoints > 0) {
  49. init();
  50. }
  51. }
  52. private function init() : void
  53. {
  54. _jointsPerVertex = _skinnedAnimation.jointsPerVertex;
  55. _skeleton = _skinnedAnimation.skeleton;
  56. _numJoints = _skinnedAnimation.numJoints;
  57. _globalMatrices = new Vector.<Number>(_numJoints*12, true);
  58. _bufferFormat = "float"+_jointsPerVertex;
  59. _globalPose = new SkeletonPose();
  60. var j : int;
  61. for (var i : uint = 0; i < _numJoints; ++i) {
  62. _globalMatrices[j++] = 1; _globalMatrices[j++] = 0; _globalMatrices[j++] = 0; _globalMatrices[j++] = 0;
  63. _globalMatrices[j++] = 0; _globalMatrices[j++] = 1; _globalMatrices[j++] = 0; _globalMatrices[j++] = 0;
  64. _globalMatrices[j++] = 0; _globalMatrices[j++] = 0; _globalMatrices[j++] = 1; _globalMatrices[j++] = 0;
  65. }
  66. }
  67. /**
  68. * The amount of joints in the target skeleton.
  69. */
  70. public function get numJoints() : uint
  71. {
  72. return _numJoints;
  73. }
  74. /**
  75. * The chained raw data of the global pose matrices in row-major order.
  76. */
  77. public function get globalMatrices() : Vector.<Number>
  78. {
  79. return _globalMatrices;
  80. }
  81. /**
  82. * The global skeleton pose used to transform the mesh's vertices.
  83. */
  84. public function get globalPose() : SkeletonPose
  85. {
  86. if (_stateInvalid) updateGlobalPose();
  87. return _globalPose;
  88. }
  89. public function set globalPose(value : SkeletonPose) : void
  90. {
  91. if (!_globalInput) throw new Error("Cannot set global pose if globalInput is false");
  92. _globalPose = value;
  93. _globalMatricesInvalid = true;
  94. }
  95. arcane function validateGlobalMatrices() : void
  96. {
  97. _stateInvalid = false;
  98. _globalMatricesInvalid = false;
  99. }
  100. /**
  101. * The local skeleton blend tree that will be used to generate the global pose.
  102. */
  103. public function get blendTree() : SkeletonTreeNode
  104. {
  105. return _blendTree;
  106. }
  107. public function set blendTree(value : SkeletonTreeNode) : void
  108. {
  109. _blendTree = value;
  110. }
  111. /**
  112. * @inheritDoc
  113. */
  114. override public function invalidateState() : void
  115. {
  116. super.invalidateState();
  117. for (var key : Object in _buffersValid) {
  118. _buffersValid[key] = false;
  119. }
  120. }
  121. /**
  122. * @inheritDoc
  123. */
  124. override public function setRenderState(stage3DProxy : Stage3DProxy, pass : MaterialPassBase, renderable : IRenderable) : void
  125. {
  126. if (_numJoints == 0) {
  127. // delayed skeleton instantiation
  128. if (_skinnedAnimation.numJoints > 0)
  129. init();
  130. else
  131. return;
  132. }
  133. // do on request of globalPose
  134. if (_stateInvalid) updateGlobalPose();
  135. if (_globalMatricesInvalid) convertToMatrices();
  136. if (_skinnedAnimation.usesCPU) {
  137. var subGeom : SkinnedSubGeometry = SkinnedSubGeometry(SubMesh(renderable).subGeometry);
  138. if (!_buffersValid[subGeom]) {
  139. morphGeometry(subGeom);
  140. _buffersValid[subGeom] = true;
  141. }
  142. return;
  143. }
  144. var skinnedGeom : SkinnedSubGeometry = SkinnedSubGeometry(SubMesh(renderable).subGeometry);
  145. var context : Context3D = stage3DProxy._context3D;
  146. context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, pass.numUsedVertexConstants, _globalMatrices, _numJoints*3);
  147. var streamOffset : uint = pass.numUsedStreams;
  148. stage3DProxy.setSimpleVertexBuffer(streamOffset, skinnedGeom.getJointIndexBuffer(stage3DProxy), _bufferFormat);
  149. stage3DProxy.setSimpleVertexBuffer(streamOffset+1, skinnedGeom.getJointWeightsBuffer(stage3DProxy), _bufferFormat);
  150. }
  151. private function updateGlobalPose() : void
  152. {
  153. if (!_globalInput) {
  154. _blendTree.updatePose(_skeleton);
  155. _blendTree.skeletonPose.toGlobalPose(_globalPose, _skeleton);
  156. }
  157. _globalMatricesInvalid = true;
  158. _stateInvalid = false;
  159. }
  160. /**
  161. * @inheritDoc
  162. */
  163. override public function clone() : AnimationStateBase
  164. {
  165. return new SkeletonAnimationState(_skinnedAnimation);
  166. }
  167. /**
  168. * Defines whether or not to bypass the blend tree and allow setting the global skeleton pose directly.
  169. * todo: remove, use post-processing effects for global position based... stuff.
  170. */
  171. arcane function get globalInput() : Boolean
  172. {
  173. return _globalInput;
  174. }
  175. arcane function set globalInput(value : Boolean) : void
  176. {
  177. _globalInput = value;
  178. }
  179. /**
  180. * Converts the current final pose to matrices for the actual transformations
  181. */
  182. private function convertToMatrices() : void
  183. {
  184. // convert pose to matrix
  185. var mtxOffset : uint;
  186. var globalPoses : Vector.<JointPose> = _globalPose.jointPoses;
  187. var raw : Vector.<Number>;
  188. var ox : Number, oy : Number, oz : Number, ow : Number;
  189. var xy2 : Number, xz2 : Number, xw2 : Number;
  190. var yz2 : Number, yw2 : Number, zw2 : Number;
  191. var xx : Number, yy : Number, zz : Number, ww : Number;
  192. var n11 : Number, n12 : Number, n13 : Number, n14 : Number;
  193. var n21 : Number, n22 : Number, n23 : Number, n24 : Number;
  194. var n31 : Number, n32 : Number, n33 : Number, n34 : Number;
  195. var m11 : Number, m12 : Number, m13 : Number, m14 : Number;
  196. var m21 : Number, m22 : Number, m23 : Number, m24 : Number;
  197. var m31 : Number, m32 : Number, m33 : Number, m34 : Number;
  198. var joints : Vector.<SkeletonJoint> = _skeleton.joints;
  199. var pose : JointPose;
  200. var quat : Quaternion;
  201. var vec : Vector3D;
  202. for (var i : uint = 0; i < _numJoints; ++i) {
  203. pose = globalPoses[i];
  204. quat = pose.orientation;
  205. vec = pose.translation;
  206. ox = quat.x; oy = quat.y; oz = quat.z; ow = quat.w;
  207. xy2 = 2.0 * ox * oy; xz2 = 2.0 * ox * oz; xw2 = 2.0 * ox * ow;
  208. yz2 = 2.0 * oy * oz; yw2 = 2.0 * oy * ow; zw2 = 2.0 * oz * ow;
  209. xx = ox * ox; yy = oy * oy; zz = oz * oz; ww = ow * ow;
  210. n11 = xx - yy - zz + ww; n12 = xy2 - zw2; n13 = xz2 + yw2; n14 = vec.x;
  211. n21 = xy2 + zw2; n22 = -xx + yy - zz + ww; n23 = yz2 - xw2; n24 = vec.y;
  212. n31 = xz2 - yw2; n32 = yz2 + xw2; n33 = -xx - yy + zz + ww; n34 = vec.z;
  213. // prepend inverse bind pose
  214. raw = joints[i].inverseBindPose;
  215. m11 = raw[0]; m12 = raw[4]; m13 = raw[8]; m14 = raw[12];
  216. m21 = raw[1]; m22 = raw[5]; m23 = raw[9]; m24 = raw[13];
  217. m31 = raw[2]; m32 = raw[6]; m33 = raw[10]; m34 = raw[14];
  218. _globalMatrices[mtxOffset++] = n11 * m11 + n12 * m21 + n13 * m31;
  219. _globalMatrices[mtxOffset++] = n11 * m12 + n12 * m22 + n13 * m32;
  220. _globalMatrices[mtxOffset++] = n11 * m13 + n12 * m23 + n13 * m33;
  221. _globalMatrices[mtxOffset++] = n11 * m14 + n12 * m24 + n13 * m34 + n14;
  222. _globalMatrices[mtxOffset++] = n21 * m11 + n22 * m21 + n23 * m31;
  223. _globalMatrices[mtxOffset++] = n21 * m12 + n22 * m22 + n23 * m32;
  224. _globalMatrices[mtxOffset++] = n21 * m13 + n22 * m23 + n23 * m33;
  225. _globalMatrices[mtxOffset++] = n21 * m14 + n22 * m24 + n23 * m34 + n24;
  226. _globalMatrices[mtxOffset++] = n31 * m11 + n32 * m21 + n33 * m31;
  227. _globalMatrices[mtxOffset++] = n31 * m12 + n32 * m22 + n33 * m32;
  228. _globalMatrices[mtxOffset++] = n31 * m13 + n32 * m23 + n33 * m33;
  229. _globalMatrices[mtxOffset++] = n31 * m14 + n32 * m24 + n33 * m34 + n34;
  230. }
  231. _globalMatricesInvalid = false;
  232. }
  233. /**
  234. * If the animation can't be performed on cpu, transform vertices manually
  235. * @param subGeom The subgeometry containing the weights and joint index data per vertex.
  236. * @param pass The material pass for which we need to transform the vertices
  237. *
  238. * todo: we may be able to transform tangents more easily, similar to how it happens on gpu
  239. */
  240. private function morphGeometry(subGeom : SkinnedSubGeometry) : void
  241. {
  242. var verts : Vector.<Number> = subGeom.vertexData;
  243. var normals : Vector.<Number> = subGeom.vertexNormalData;
  244. var tangents : Vector.<Number> = subGeom.vertexTangentData;
  245. var targetVerts : Vector.<Number> = subGeom.animatedVertexData;
  246. var targetNormals : Vector.<Number> = subGeom.animatedNormalData;
  247. var targetTangents : Vector.<Number> = subGeom.animatedTangentData;
  248. var jointIndices : Vector.<Number> = subGeom.jointIndexData;
  249. var jointWeights : Vector.<Number> = subGeom.jointWeightsData;
  250. var i1 : uint, i2 : uint = 1, i3 : uint = 2;
  251. var j : uint, k : uint;
  252. var vx : Number, vy : Number, vz : Number;
  253. var nx : Number, ny : Number, nz : Number;
  254. var tx : Number, ty : Number, tz : Number;
  255. var len : int = verts.length;
  256. var weight : Number;
  257. var mtxOffset : uint;
  258. var vertX : Number, vertY : Number, vertZ : Number;
  259. var normX : Number, normY : Number, normZ : Number;
  260. var tangX : Number, tangY : Number, tangZ : Number;
  261. var m11 : Number, m12 : Number, m13 : Number;
  262. var m21 : Number, m22 : Number, m23 : Number;
  263. var m31 : Number, m32 : Number, m33 : Number;
  264. while (i1 < len) {
  265. vertX = verts[i1]; vertY = verts[i2]; vertZ = verts[i3];
  266. vx = 0; vy = 0; vz = 0;
  267. normX = normals[i1]; normY = normals[i2]; normZ = normals[i3];
  268. nx = 0; ny = 0; nz = 0;
  269. tangX = tangents[i1]; tangY = tangents[i2]; tangZ = tangents[i3];
  270. tx = 0; ty = 0; tz = 0;
  271. k = 0;
  272. while (k < _jointsPerVertex) {
  273. weight = jointWeights[j];
  274. if (weight == 0) {
  275. j += _jointsPerVertex - k;
  276. k = _jointsPerVertex;
  277. }
  278. else {
  279. // implicit /3*12 (/3 because indices are multiplied by 3 for gpu matrix access, *12 because it's the matrix size)
  280. mtxOffset = jointIndices[uint(j++)]*4;
  281. m11 = _globalMatrices[mtxOffset]; m12 = _globalMatrices[mtxOffset+1]; m13 = _globalMatrices[mtxOffset+2];
  282. m21 = _globalMatrices[mtxOffset+4]; m22 = _globalMatrices[mtxOffset+5]; m23 = _globalMatrices[mtxOffset+6];
  283. m31 = _globalMatrices[mtxOffset+8]; m32 = _globalMatrices[mtxOffset+9]; m33 = _globalMatrices[mtxOffset+10];
  284. vx += weight*(m11*vertX + m12*vertY + m13*vertZ + _globalMatrices[mtxOffset+3]);
  285. vy += weight*(m21*vertX + m22*vertY + m23*vertZ + _globalMatrices[mtxOffset+7]);
  286. vz += weight*(m31*vertX + m32*vertY + m33*vertZ + _globalMatrices[mtxOffset+11]);
  287. nx += weight*(m11*normX + m12*normY + m13*normZ);
  288. ny += weight*(m21*normX + m22*normY + m23*normZ);
  289. nz += weight*(m31*normX + m32*normY + m33*normZ);
  290. tx += weight*(m11*tangX + m12*tangY + m13*tangZ);
  291. ty += weight*(m21*tangX + m22*tangY + m23*tangZ);
  292. tz += weight*(m31*tangX + m32*tangY + m33*tangZ);
  293. k++;
  294. }
  295. }
  296. targetVerts[i1] = vx; targetVerts[i2] = vy; targetVerts[i3] = vz;
  297. targetNormals[i1] = nx; targetNormals[i2] = ny; targetNormals[i3] = nz;
  298. targetTangents[i1] = tx; targetTangents[i2] = ty; targetTangents[i3] = tz;
  299. i1 += 3; i2 += 3; i3 += 3;
  300. }
  301. subGeom.animatedVertexData = targetVerts;
  302. subGeom.animatedNormalData = targetNormals;
  303. subGeom.animatedTangentData = targetTangents;
  304. }
  305. public function applyRootDelta() : void
  306. {
  307. var delta : Vector3D = blendTree.rootDelta;
  308. var dist : Number = delta.length;
  309. var len : uint;
  310. if (dist > 0) {
  311. len = _owners.length;
  312. for (var i : uint = 0; i < len; ++i)
  313. _owners[i].translateLocal(delta, dist);
  314. }
  315. }
  316. }
  317. }