SkeletonControl.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * To change this template, choose Tools | Templates
  3. * and open the template in the editor.
  4. */
  5. package com.jme3.animation;
  6. import com.jme3.export.*;
  7. import com.jme3.math.FastMath;
  8. import com.jme3.math.Matrix4f;
  9. import com.jme3.renderer.RenderManager;
  10. import com.jme3.renderer.ViewPort;
  11. import com.jme3.scene.*;
  12. import com.jme3.scene.VertexBuffer.Type;
  13. import com.jme3.scene.control.AbstractControl;
  14. import com.jme3.scene.control.Control;
  15. import com.jme3.util.TempVars;
  16. import java.io.IOException;
  17. import java.nio.ByteBuffer;
  18. import java.nio.FloatBuffer;
  19. import java.util.ArrayList;
  20. /**
  21. * The Skeleton control deforms a model according to a skeleton,
  22. * It handles the computation of the deformation matrices and performs
  23. * the transformations on the mesh
  24. *
  25. * @author Rémy Bouquet Based on AnimControl by Kirill Vainer
  26. */
  27. public class SkeletonControl extends AbstractControl implements Cloneable {
  28. /**
  29. * The skeleton of the model
  30. */
  31. private Skeleton skeleton;
  32. /**
  33. * List of targets which this controller effects.
  34. */
  35. private Mesh[] targets;
  36. /**
  37. * Used to track when a mesh was updated. Meshes are only updated
  38. * if they are visible in at least one camera.
  39. */
  40. private boolean wasMeshUpdated = false;
  41. /**
  42. * Serialization only. Do not use.
  43. */
  44. public SkeletonControl() {
  45. }
  46. /**
  47. * Creates a skeleton control.
  48. * The list of targets will be acquired automatically when
  49. * the control is attached to a node.
  50. *
  51. * @param skeleton the skeleton
  52. */
  53. public SkeletonControl(Skeleton skeleton) {
  54. this.skeleton = skeleton;
  55. }
  56. /**
  57. * Creates a skeleton control.
  58. *
  59. * @param targets the meshes controlled by the skeleton
  60. * @param skeleton the skeleton
  61. */
  62. @Deprecated
  63. SkeletonControl(Mesh[] targets, Skeleton skeleton) {
  64. this.skeleton = skeleton;
  65. this.targets = targets;
  66. }
  67. private boolean isMeshAnimated(Mesh mesh) {
  68. return mesh.getBuffer(Type.BindPosePosition) != null;
  69. }
  70. private Mesh[] findTargets(Node node) {
  71. Mesh sharedMesh = null;
  72. ArrayList<Mesh> animatedMeshes = new ArrayList<Mesh>();
  73. for (Spatial child : node.getChildren()) {
  74. if (!(child instanceof Geometry)) {
  75. continue; // could be an attachment node, ignore.
  76. }
  77. Geometry geom = (Geometry) child;
  78. // is this geometry using a shared mesh?
  79. Mesh childSharedMesh = geom.getUserData(UserData.JME_SHAREDMESH);
  80. if (childSharedMesh != null) {
  81. // Don't bother with non-animated shared meshes
  82. if (isMeshAnimated(childSharedMesh)) {
  83. // child is using shared mesh,
  84. // so animate the shared mesh but ignore child
  85. if (sharedMesh == null) {
  86. sharedMesh = childSharedMesh;
  87. } else if (sharedMesh != childSharedMesh) {
  88. throw new IllegalStateException("Two conflicting shared meshes for " + node);
  89. }
  90. }
  91. } else {
  92. Mesh mesh = geom.getMesh();
  93. if (isMeshAnimated(mesh)) {
  94. animatedMeshes.add(mesh);
  95. }
  96. }
  97. }
  98. if (sharedMesh != null) {
  99. animatedMeshes.add(sharedMesh);
  100. }
  101. return animatedMeshes.toArray(new Mesh[animatedMeshes.size()]);
  102. }
  103. @Override
  104. public void setSpatial(Spatial spatial) {
  105. super.setSpatial(spatial);
  106. if (spatial != null) {
  107. Node node = (Node) spatial;
  108. targets = findTargets(node);
  109. } else {
  110. targets = null;
  111. }
  112. }
  113. @Override
  114. protected void controlRender(RenderManager rm, ViewPort vp) {
  115. if (!wasMeshUpdated) {
  116. resetToBind(); // reset morph meshes to bind pose
  117. Matrix4f[] offsetMatrices = skeleton.computeSkinningMatrices();
  118. // if hardware skinning is supported, the matrices and weight buffer
  119. // will be sent by the SkinningShaderLogic object assigned to the shader
  120. for (int i = 0; i < targets.length; i++) {
  121. // NOTE: This assumes that code higher up
  122. // Already ensured those targets are animated
  123. // otherwise a crash will happen in skin update
  124. //if (isMeshAnimated(targets[i])) {
  125. softwareSkinUpdate(targets[i], offsetMatrices);
  126. //}
  127. }
  128. wasMeshUpdated = true;
  129. }
  130. }
  131. @Override
  132. protected void controlUpdate(float tpf) {
  133. wasMeshUpdated = false;
  134. }
  135. void resetToBind() {
  136. for (Mesh mesh : targets) {
  137. if (isMeshAnimated(mesh)) {
  138. FloatBuffer bwBuff = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
  139. ByteBuffer biBuff = (ByteBuffer)mesh.getBuffer(Type.BoneIndex).getData();
  140. if (!biBuff.hasArray() || !bwBuff.hasArray()) {
  141. mesh.prepareForAnim(true); // prepare for software animation
  142. }
  143. VertexBuffer bindPos = mesh.getBuffer(Type.BindPosePosition);
  144. VertexBuffer bindNorm = mesh.getBuffer(Type.BindPoseNormal);
  145. VertexBuffer pos = mesh.getBuffer(Type.Position);
  146. VertexBuffer norm = mesh.getBuffer(Type.Normal);
  147. FloatBuffer pb = (FloatBuffer) pos.getData();
  148. FloatBuffer nb = (FloatBuffer) norm.getData();
  149. FloatBuffer bpb = (FloatBuffer) bindPos.getData();
  150. FloatBuffer bnb = (FloatBuffer) bindNorm.getData();
  151. pb.clear();
  152. nb.clear();
  153. bpb.clear();
  154. bnb.clear();
  155. //reseting bind tangents if there is a bind tangent buffer
  156. VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent);
  157. if (bindTangents != null) {
  158. VertexBuffer tangents = mesh.getBuffer(Type.Tangent);
  159. FloatBuffer tb = (FloatBuffer) tangents.getData();
  160. FloatBuffer btb = (FloatBuffer) bindTangents.getData();
  161. tb.clear();
  162. btb.clear();
  163. tb.put(btb).clear();
  164. }
  165. pb.put(bpb).clear();
  166. nb.put(bnb).clear();
  167. }
  168. }
  169. }
  170. public Control cloneForSpatial(Spatial spatial) {
  171. Node clonedNode = (Node) spatial;
  172. AnimControl ctrl = spatial.getControl(AnimControl.class);
  173. SkeletonControl clone = new SkeletonControl();
  174. clone.setSpatial(clonedNode);
  175. clone.skeleton = ctrl.getSkeleton();
  176. // Fix animated targets for the cloned node
  177. clone.targets = findTargets(clonedNode);
  178. // Fix attachments for the cloned node
  179. for (int i = 0; i < clonedNode.getQuantity(); i++) {
  180. // go through attachment nodes, apply them to correct bone
  181. Spatial child = clonedNode.getChild(i);
  182. if (child instanceof Node) {
  183. Node clonedAttachNode = (Node) child;
  184. Bone originalBone = (Bone) clonedAttachNode.getUserData("AttachedBone");
  185. if (originalBone != null) {
  186. Bone clonedBone = clone.skeleton.getBone(originalBone.getName());
  187. clonedAttachNode.setUserData("AttachedBone", clonedBone);
  188. clonedBone.setAttachmentsNode(clonedAttachNode);
  189. }
  190. }
  191. }
  192. return clone;
  193. }
  194. /**
  195. *
  196. * @param boneName the name of the bone
  197. * @return the node attached to this bone
  198. */
  199. public Node getAttachmentsNode(String boneName) {
  200. Bone b = skeleton.getBone(boneName);
  201. if (b == null) {
  202. throw new IllegalArgumentException("Given bone name does not exist "
  203. + "in the skeleton.");
  204. }
  205. Node n = b.getAttachmentsNode();
  206. Node model = (Node) spatial;
  207. model.attachChild(n);
  208. return n;
  209. }
  210. /**
  211. * returns the skeleton of this control
  212. * @return
  213. */
  214. public Skeleton getSkeleton() {
  215. return skeleton;
  216. }
  217. /**
  218. * sets the skeleton for this control
  219. * @param skeleton
  220. */
  221. // public void setSkeleton(Skeleton skeleton) {
  222. // this.skeleton = skeleton;
  223. // }
  224. /**
  225. * returns the targets meshes of this control
  226. * @return
  227. */
  228. public Mesh[] getTargets() {
  229. return targets;
  230. }
  231. /**
  232. * sets the target meshes of this control
  233. * @param targets
  234. */
  235. // public void setTargets(Mesh[] targets) {
  236. // this.targets = targets;
  237. // }
  238. /**
  239. * Update the mesh according to the given transformation matrices
  240. * @param mesh then mesh
  241. * @param offsetMatrices the transformation matrices to apply
  242. */
  243. private void softwareSkinUpdate(Mesh mesh, Matrix4f[] offsetMatrices) {
  244. VertexBuffer tb = mesh.getBuffer(Type.Tangent);
  245. if (tb == null) {
  246. //if there are no tangents use the classic skinning
  247. applySkinning(mesh, offsetMatrices);
  248. } else {
  249. //if there are tangents use the skinning with tangents
  250. applySkinningTangents(mesh, offsetMatrices, tb);
  251. }
  252. }
  253. /**
  254. * Method to apply skinning transforms to a mesh's buffers
  255. * @param mesh the mesh
  256. * @param offsetMatrices the offset matices to apply
  257. */
  258. private void applySkinning(Mesh mesh, Matrix4f[] offsetMatrices) {
  259. int maxWeightsPerVert = mesh.getMaxNumWeights();
  260. if (maxWeightsPerVert <= 0) {
  261. throw new IllegalStateException("Max weights per vert is incorrectly set!");
  262. }
  263. int fourMinusMaxWeights = 4 - maxWeightsPerVert;
  264. // NOTE: This code assumes the vertex buffer is in bind pose
  265. // resetToBind() has been called this frame
  266. VertexBuffer vb = mesh.getBuffer(Type.Position);
  267. FloatBuffer fvb = (FloatBuffer) vb.getData();
  268. fvb.rewind();
  269. VertexBuffer nb = mesh.getBuffer(Type.Normal);
  270. FloatBuffer fnb = (FloatBuffer) nb.getData();
  271. fnb.rewind();
  272. // get boneIndexes and weights for mesh
  273. ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
  274. FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
  275. ib.rewind();
  276. wb.rewind();
  277. float[] weights = wb.array();
  278. byte[] indices = ib.array();
  279. int idxWeights = 0;
  280. TempVars vars = TempVars.get();
  281. float[] posBuf = vars.skinPositions;
  282. float[] normBuf = vars.skinNormals;
  283. int iterations = (int) FastMath.ceil(fvb.limit() / ((float) posBuf.length));
  284. int bufLength = posBuf.length;
  285. for (int i = iterations - 1; i >= 0; i--) {
  286. // read next set of positions and normals from native buffer
  287. bufLength = Math.min(posBuf.length, fvb.remaining());
  288. fvb.get(posBuf, 0, bufLength);
  289. fnb.get(normBuf, 0, bufLength);
  290. int verts = bufLength / 3;
  291. int idxPositions = 0;
  292. // iterate vertices and apply skinning transform for each effecting bone
  293. for (int vert = verts - 1; vert >= 0; vert--) {
  294. float nmx = normBuf[idxPositions];
  295. float vtx = posBuf[idxPositions++];
  296. float nmy = normBuf[idxPositions];
  297. float vty = posBuf[idxPositions++];
  298. float nmz = normBuf[idxPositions];
  299. float vtz = posBuf[idxPositions++];
  300. float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0;
  301. for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
  302. float weight = weights[idxWeights];
  303. Matrix4f mat = offsetMatrices[indices[idxWeights++]];
  304. rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
  305. ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
  306. rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
  307. rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
  308. rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
  309. rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
  310. }
  311. idxWeights += fourMinusMaxWeights;
  312. idxPositions -= 3;
  313. normBuf[idxPositions] = rnx;
  314. posBuf[idxPositions++] = rx;
  315. normBuf[idxPositions] = rny;
  316. posBuf[idxPositions++] = ry;
  317. normBuf[idxPositions] = rnz;
  318. posBuf[idxPositions++] = rz;
  319. }
  320. fvb.position(fvb.position() - bufLength);
  321. fvb.put(posBuf, 0, bufLength);
  322. fnb.position(fnb.position() - bufLength);
  323. fnb.put(normBuf, 0, bufLength);
  324. }
  325. vars.release();
  326. vb.updateData(fvb);
  327. nb.updateData(fnb);
  328. }
  329. /**
  330. * Specific method for skinning with tangents to avoid cluttering the classic skinning calculation with
  331. * null checks that would slow down the process even if tangents don't have to be computed.
  332. * Also the iteration has additional indexes since tangent has 4 components instead of 3 for pos and norm
  333. * @param maxWeightsPerVert maximum number of weights per vertex
  334. * @param mesh the mesh
  335. * @param offsetMatrices the offsetMaytrices to apply
  336. * @param tb the tangent vertexBuffer
  337. */
  338. private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) {
  339. int maxWeightsPerVert = mesh.getMaxNumWeights();
  340. if (maxWeightsPerVert <= 0) {
  341. throw new IllegalStateException("Max weights per vert is incorrectly set!");
  342. }
  343. int fourMinusMaxWeights = 4 - maxWeightsPerVert;
  344. // NOTE: This code assumes the vertex buffer is in bind pose
  345. // resetToBind() has been called this frame
  346. VertexBuffer vb = mesh.getBuffer(Type.Position);
  347. FloatBuffer fvb = (FloatBuffer) vb.getData();
  348. fvb.rewind();
  349. VertexBuffer nb = mesh.getBuffer(Type.Normal);
  350. FloatBuffer fnb = (FloatBuffer) nb.getData();
  351. fnb.rewind();
  352. FloatBuffer ftb = (FloatBuffer) tb.getData();
  353. ftb.rewind();
  354. // get boneIndexes and weights for mesh
  355. ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData();
  356. FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData();
  357. ib.rewind();
  358. wb.rewind();
  359. float[] weights = wb.array();
  360. byte[] indices = ib.array();
  361. int idxWeights = 0;
  362. TempVars vars = TempVars.get();
  363. float[] posBuf = vars.skinPositions;
  364. float[] normBuf = vars.skinNormals;
  365. float[] tanBuf = vars.skinTangents;
  366. int iterations = (int) FastMath.ceil(fvb.limit() / ((float) posBuf.length));
  367. int bufLength = 0;
  368. int tanLength = 0;
  369. for (int i = iterations - 1; i >= 0; i--) {
  370. // read next set of positions and normals from native buffer
  371. bufLength = Math.min(posBuf.length, fvb.remaining());
  372. tanLength = Math.min(tanBuf.length, ftb.remaining());
  373. fvb.get(posBuf, 0, bufLength);
  374. fnb.get(normBuf, 0, bufLength);
  375. ftb.get(tanBuf, 0, tanLength);
  376. int verts = bufLength / 3;
  377. int idxPositions = 0;
  378. //tangents has their own index because of the 4 components
  379. int idxTangents = 0;
  380. // iterate vertices and apply skinning transform for each effecting bone
  381. for (int vert = verts - 1; vert >= 0; vert--) {
  382. float nmx = normBuf[idxPositions];
  383. float vtx = posBuf[idxPositions++];
  384. float nmy = normBuf[idxPositions];
  385. float vty = posBuf[idxPositions++];
  386. float nmz = normBuf[idxPositions];
  387. float vtz = posBuf[idxPositions++];
  388. float tnx = tanBuf[idxTangents++];
  389. float tny = tanBuf[idxTangents++];
  390. float tnz = tanBuf[idxTangents++];
  391. //skipping the 4th component of the tangent since it doesn't have to be transformed
  392. idxTangents++;
  393. float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0, rtx = 0, rty = 0, rtz = 0;
  394. for (int w = maxWeightsPerVert - 1; w >= 0; w--) {
  395. float weight = weights[idxWeights];
  396. Matrix4f mat = offsetMatrices[indices[idxWeights++]];
  397. rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight;
  398. ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight;
  399. rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight;
  400. rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight;
  401. rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight;
  402. rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight;
  403. rtx += (tnx * mat.m00 + tny * mat.m01 + tnz * mat.m02) * weight;
  404. rty += (tnx * mat.m10 + tny * mat.m11 + tnz * mat.m12) * weight;
  405. rtz += (tnx * mat.m20 + tny * mat.m21 + tnz * mat.m22) * weight;
  406. }
  407. idxWeights += fourMinusMaxWeights;
  408. idxPositions -= 3;
  409. normBuf[idxPositions] = rnx;
  410. posBuf[idxPositions++] = rx;
  411. normBuf[idxPositions] = rny;
  412. posBuf[idxPositions++] = ry;
  413. normBuf[idxPositions] = rnz;
  414. posBuf[idxPositions++] = rz;
  415. idxTangents -= 4;
  416. tanBuf[idxTangents++] = rtx;
  417. tanBuf[idxTangents++] = rty;
  418. tanBuf[idxTangents++] = rtz;
  419. //once again skipping the 4th component of the tangent
  420. idxTangents++;
  421. }
  422. fvb.position(fvb.position() - bufLength);
  423. fvb.put(posBuf, 0, bufLength);
  424. fnb.position(fnb.position() - bufLength);
  425. fnb.put(normBuf, 0, bufLength);
  426. ftb.position(ftb.position() - tanLength);
  427. ftb.put(tanBuf, 0, tanLength);
  428. }
  429. vars.release();
  430. vb.updateData(fvb);
  431. nb.updateData(fnb);
  432. tb.updateData(ftb);
  433. }
  434. @Override
  435. public void write(JmeExporter ex) throws IOException {
  436. super.write(ex);
  437. OutputCapsule oc = ex.getCapsule(this);
  438. oc.write(targets, "targets", null);
  439. oc.write(skeleton, "skeleton", null);
  440. }
  441. @Override
  442. public void read(JmeImporter im) throws IOException {
  443. super.read(im);
  444. InputCapsule in = im.getCapsule(this);
  445. Savable[] sav = in.readSavableArray("targets", null);
  446. if (sav != null) {
  447. targets = new Mesh[sav.length];
  448. System.arraycopy(sav, 0, targets, 0, sav.length);
  449. }
  450. skeleton = (Skeleton) in.readSavable("skeleton", null);
  451. }
  452. }