SkeletonControl.java 21 KB

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