Bone.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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.*;
  35. import com.jme3.scene.Node;
  36. import com.jme3.util.TempVars;
  37. import java.io.IOException;
  38. import java.util.ArrayList;
  39. /**
  40. * <code>Bone</code> describes a bone in the bone-weight skeletal animation
  41. * system. A bone contains a name and an index, as well as relevant
  42. * transformation data.
  43. *
  44. * @author Kirill Vainer
  45. */
  46. public final class Bone implements Savable {
  47. private String name;
  48. private Bone parent;
  49. private final ArrayList<Bone> children = new ArrayList<Bone>();
  50. /**
  51. * If enabled, user can control bone transform with setUserTransforms.
  52. * Animation transforms are not applied to this bone when enabled.
  53. */
  54. private boolean userControl = false;
  55. /**
  56. * The attachment node.
  57. */
  58. private Node attachNode;
  59. /**
  60. * Initial transform is the local bind transform of this bone.
  61. * PARENT SPACE -> BONE SPACE
  62. */
  63. private Vector3f initialPos;
  64. private Quaternion initialRot;
  65. private Vector3f initialScale;
  66. /**
  67. * The inverse world bind transform.
  68. * BONE SPACE -> MODEL SPACE
  69. */
  70. private Vector3f worldBindInversePos;
  71. private Quaternion worldBindInverseRot;
  72. private Vector3f worldBindInverseScale;
  73. /**
  74. * The local animated transform combined with the local bind transform and parent world transform
  75. */
  76. private Vector3f localPos = new Vector3f();
  77. private Quaternion localRot = new Quaternion();
  78. private Vector3f localScale = new Vector3f(1.0f, 1.0f, 1.0f);
  79. /**
  80. * MODEL SPACE -> BONE SPACE (in animated state)
  81. */
  82. private Vector3f worldPos = new Vector3f();
  83. private Quaternion worldRot = new Quaternion();
  84. private Vector3f worldScale = new Vector3f();
  85. // Used for getCombinedTransform
  86. private Transform tmpTransform = new Transform();
  87. /**
  88. * Used to handle blending from one animation to another.
  89. * See {@link #blendAnimTransforms(com.jme3.math.Vector3f, com.jme3.math.Quaternion, com.jme3.math.Vector3f, float)}
  90. * on how this variable is used.
  91. */
  92. private transient float currentWeightSum = -1;
  93. /**
  94. * Creates a new bone with the given name.
  95. *
  96. * @param name Name to give to this bone
  97. */
  98. public Bone(String name) {
  99. if (name == null)
  100. throw new IllegalArgumentException("Name cannot be null");
  101. this.name = name;
  102. initialPos = new Vector3f();
  103. initialRot = new Quaternion();
  104. initialScale = new Vector3f(1, 1, 1);
  105. worldBindInversePos = new Vector3f();
  106. worldBindInverseRot = new Quaternion();
  107. worldBindInverseScale = new Vector3f();
  108. }
  109. /**
  110. * Special-purpose copy constructor.
  111. * <p>
  112. * Only copies the name and bind pose from the original.
  113. * <p>
  114. * WARNING: Local bind pose and world inverse bind pose transforms shallow
  115. * copied. Modifying that data on the original bone will cause it to
  116. * be recomputed on any cloned bones.
  117. * <p>
  118. * The rest of the data is <em>NOT</em> copied, as it will be
  119. * generated automatically when the bone is animated.
  120. *
  121. * @param source The bone from which to copy the data.
  122. */
  123. Bone(Bone source) {
  124. this.name = source.name;
  125. userControl = source.userControl;
  126. initialPos = source.initialPos;
  127. initialRot = source.initialRot;
  128. initialScale = source.initialScale;
  129. worldBindInversePos = source.worldBindInversePos;
  130. worldBindInverseRot = source.worldBindInverseRot;
  131. worldBindInverseScale = source.worldBindInverseScale;
  132. // parent and children will be assigned manually..
  133. }
  134. /**
  135. * Serialization only. Do not use.
  136. */
  137. public Bone() {
  138. }
  139. /**
  140. * Returns the name of the bone, set in the constructor.
  141. *
  142. * @return The name of the bone, set in the constructor.
  143. */
  144. public String getName() {
  145. return name;
  146. }
  147. /**
  148. * Returns parent bone of this bone, or null if it is a root bone.
  149. * @return The parent bone of this bone, or null if it is a root bone.
  150. */
  151. public Bone getParent() {
  152. return parent;
  153. }
  154. /**
  155. * Returns all the children bones of this bone.
  156. *
  157. * @return All the children bones of this bone.
  158. */
  159. public ArrayList<Bone> getChildren() {
  160. return children;
  161. }
  162. /**
  163. * Returns the local position of the bone, relative to the parent bone.
  164. *
  165. * @return The local position of the bone, relative to the parent bone.
  166. */
  167. public Vector3f getLocalPosition() {
  168. return localPos;
  169. }
  170. /**
  171. * Returns the local rotation of the bone, relative to the parent bone.
  172. *
  173. * @return The local rotation of the bone, relative to the parent bone.
  174. */
  175. public Quaternion getLocalRotation() {
  176. return localRot;
  177. }
  178. /**
  179. * Returns the local scale of the bone, relative to the parent bone.
  180. *
  181. * @return The local scale of the bone, relative to the parent bone.
  182. */
  183. public Vector3f getLocalScale() {
  184. return localScale;
  185. }
  186. /**
  187. * Returns the position of the bone in model space.
  188. *
  189. * @return The position of the bone in model space.
  190. */
  191. public Vector3f getModelSpacePosition() {
  192. return worldPos;
  193. }
  194. /**
  195. * Returns the rotation of the bone in model space.
  196. *
  197. * @return The rotation of the bone in model space.
  198. */
  199. public Quaternion getModelSpaceRotation() {
  200. return worldRot;
  201. }
  202. /**
  203. * Returns the scale of the bone in model space.
  204. *
  205. * @return The scale of the bone in model space.
  206. */
  207. public Vector3f getModelSpaceScale() {
  208. return worldScale;
  209. }
  210. /**
  211. * Returns the inverse world bind pose position.
  212. * <p>
  213. * The bind pose transform of the bone is its "default"
  214. * transform with no animation applied.
  215. *
  216. * @return the inverse world bind pose position.
  217. */
  218. public Vector3f getWorldBindInversePosition() {
  219. return worldBindInversePos;
  220. }
  221. /**
  222. * Returns the inverse world bind pose rotation.
  223. * <p>
  224. * The bind pose transform of the bone is its "default"
  225. * transform with no animation applied.
  226. *
  227. * @return the inverse world bind pose rotation.
  228. */
  229. public Quaternion getWorldBindInverseRotation() {
  230. return worldBindInverseRot;
  231. }
  232. /**
  233. * Returns the inverse world bind pose scale.
  234. * <p>
  235. * The bind pose transform of the bone is its "default"
  236. * transform with no animation applied.
  237. *
  238. * @return the inverse world bind pose scale.
  239. */
  240. public Vector3f getWorldBindInverseScale() {
  241. return worldBindInverseScale;
  242. }
  243. /**
  244. * Returns the world bind pose position.
  245. * <p>
  246. * The bind pose transform of the bone is its "default"
  247. * transform with no animation applied.
  248. *
  249. * @return the world bind pose position.
  250. */
  251. public Vector3f getWorldBindPosition() {
  252. return initialPos;
  253. }
  254. /**
  255. * Returns the world bind pose rotation.
  256. * <p>
  257. * The bind pose transform of the bone is its "default"
  258. * transform with no animation applied.
  259. *
  260. * @return the world bind pose rotation.
  261. */
  262. public Quaternion getWorldBindRotation() {
  263. return initialRot;
  264. }
  265. /**
  266. * Returns the world bind pose scale.
  267. * <p>
  268. * The bind pose transform of the bone is its "default"
  269. * transform with no animation applied.
  270. *
  271. * @return the world bind pose scale.
  272. */
  273. public Vector3f getWorldBindScale() {
  274. return initialScale;
  275. }
  276. /**
  277. * If enabled, user can control bone transform with setUserTransforms.
  278. * Animation transforms are not applied to this bone when enabled.
  279. */
  280. public void setUserControl(boolean enable) {
  281. userControl = enable;
  282. }
  283. /**
  284. * Add a new child to this bone. Shouldn't be used by user code.
  285. * Can corrupt skeleton.
  286. *
  287. * @param bone The bone to add
  288. */
  289. public void addChild(Bone bone) {
  290. children.add(bone);
  291. bone.parent = this;
  292. }
  293. /**
  294. * Updates the world transforms for this bone, and, possibly the attach node
  295. * if not null.
  296. * <p>
  297. * The world transform of this bone is computed by combining the parent's
  298. * world transform with this bones' local transform.
  299. */
  300. public final void updateWorldVectors() {
  301. if (currentWeightSum == 1f) {
  302. currentWeightSum = -1;
  303. } else if (currentWeightSum != -1f) {
  304. // Apply the weight to the local transform
  305. if (currentWeightSum == 0) {
  306. localRot.set(initialRot);
  307. localPos.set(initialPos);
  308. localScale.set(initialScale);
  309. } else {
  310. float invWeightSum = 1f - currentWeightSum;
  311. localRot.nlerp(initialRot, invWeightSum);
  312. localPos.interpolateLocal(initialPos, invWeightSum);
  313. localScale.interpolateLocal(initialScale, invWeightSum);
  314. }
  315. // Future invocations of transform blend will start over.
  316. currentWeightSum = -1;
  317. }
  318. if (parent != null) {
  319. //rotation
  320. parent.worldRot.mult(localRot, worldRot);
  321. //scale
  322. //For scale parent scale is not taken into account!
  323. // worldScale.set(localScale);
  324. parent.worldScale.mult(localScale, worldScale);
  325. //translation
  326. //scale and rotation of parent affect bone position
  327. parent.worldRot.mult(localPos, worldPos);
  328. worldPos.multLocal(parent.worldScale);
  329. worldPos.addLocal(parent.worldPos);
  330. } else {
  331. worldRot.set(localRot);
  332. worldPos.set(localPos);
  333. worldScale.set(localScale);
  334. }
  335. if (attachNode != null) {
  336. attachNode.setLocalTranslation(worldPos);
  337. attachNode.setLocalRotation(worldRot);
  338. attachNode.setLocalScale(worldScale);
  339. }
  340. }
  341. /**
  342. * Updates world transforms for this bone and it's children.
  343. */
  344. final void update() {
  345. this.updateWorldVectors();
  346. for (int i = children.size() - 1; i >= 0; i--) {
  347. children.get(i).update();
  348. }
  349. }
  350. /**
  351. * Saves the current bone state as its binding pose, including its children.
  352. */
  353. void setBindingPose() {
  354. initialPos.set(localPos);
  355. initialRot.set(localRot);
  356. initialScale.set(localScale);
  357. if (worldBindInversePos == null) {
  358. worldBindInversePos = new Vector3f();
  359. worldBindInverseRot = new Quaternion();
  360. worldBindInverseScale = new Vector3f();
  361. }
  362. // Save inverse derived position/scale/orientation, used for calculate offset transform later
  363. worldBindInversePos.set(worldPos);
  364. worldBindInversePos.negateLocal();
  365. worldBindInverseRot.set(worldRot);
  366. worldBindInverseRot.inverseLocal();
  367. worldBindInverseScale.set(Vector3f.UNIT_XYZ);
  368. worldBindInverseScale.divideLocal(worldScale);
  369. for (Bone b : children) {
  370. b.setBindingPose();
  371. }
  372. }
  373. /**
  374. * Reset the bone and it's children to bind pose.
  375. */
  376. final void reset() {
  377. if (!userControl) {
  378. localPos.set(initialPos);
  379. localRot.set(initialRot);
  380. localScale.set(initialScale);
  381. }
  382. for (int i = children.size() - 1; i >= 0; i--) {
  383. children.get(i).reset();
  384. }
  385. }
  386. /**
  387. * Stores the skinning transform in the specified Matrix4f.
  388. * The skinning transform applies the animation of the bone to a vertex.
  389. *
  390. * This assumes that the world transforms for the entire bone hierarchy
  391. * have already been computed, otherwise this method will return undefined
  392. * results.
  393. *
  394. * @param outTransform
  395. */
  396. void getOffsetTransform(Matrix4f outTransform, Quaternion tmp1, Vector3f tmp2, Vector3f tmp3, Matrix3f tmp4) {
  397. // Computing scale
  398. Vector3f scale = worldScale.mult(worldBindInverseScale, tmp3);
  399. // Computing rotation
  400. Quaternion rotate = worldRot.mult(worldBindInverseRot, tmp1);
  401. // Computing translation
  402. // Translation depend on rotation and scale
  403. Vector3f translate = worldPos.add(rotate.mult(scale.mult(worldBindInversePos, tmp2), tmp2), tmp2);
  404. // Populating the matrix
  405. outTransform.loadIdentity();
  406. outTransform.setTransform(translate, scale, rotate.toRotationMatrix(tmp4));
  407. }
  408. /**
  409. * Sets user transform.
  410. */
  411. public void setUserTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
  412. if (!userControl) {
  413. throw new IllegalStateException("User control must be on bone to allow user transforms");
  414. }
  415. localPos.set(initialPos);
  416. localRot.set(initialRot);
  417. localScale.set(initialScale);
  418. localPos.addLocal(translation);
  419. localRot = localRot.mult(rotation);
  420. localScale.multLocal(scale);
  421. }
  422. /**
  423. * Must update all bones in skeleton for this to work.
  424. * @param translation
  425. * @param rotation
  426. */
  427. public void setUserTransformsWorld(Vector3f translation, Quaternion rotation) {
  428. if (!userControl) {
  429. throw new IllegalStateException("User control must be on bone to allow user transforms");
  430. }
  431. // TODO: add scale here ???
  432. worldPos.set(translation);
  433. worldRot.set(rotation);
  434. //if there is an attached Node we need to set it's local transforms too.
  435. if(attachNode != null){
  436. attachNode.setLocalTranslation(translation);
  437. attachNode.setLocalRotation(rotation);
  438. }
  439. }
  440. /**
  441. * Returns the local transform of this bone combined with the given position and rotation
  442. * @param position a position
  443. * @param rotation a rotation
  444. */
  445. public Transform getCombinedTransform(Vector3f position, Quaternion rotation) {
  446. rotation.mult(localPos, tmpTransform.getTranslation()).addLocal(position);
  447. tmpTransform.setRotation(rotation).getRotation().multLocal(localRot);
  448. return tmpTransform;
  449. }
  450. /**
  451. * Returns the attachment node.
  452. * Attach models and effects to this node to make
  453. * them follow this bone's motions.
  454. */
  455. Node getAttachmentsNode() {
  456. if (attachNode == null) {
  457. attachNode = new Node(name + "_attachnode");
  458. attachNode.setUserData("AttachedBone", this);
  459. }
  460. return attachNode;
  461. }
  462. /**
  463. * Used internally after model cloning.
  464. * @param attachNode
  465. */
  466. void setAttachmentsNode(Node attachNode) {
  467. this.attachNode = attachNode;
  468. }
  469. /**
  470. * Sets the local animation transform of this bone.
  471. * Bone is assumed to be in bind pose when this is called.
  472. */
  473. void setAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
  474. if (userControl) {
  475. return;
  476. }
  477. // localPos.addLocal(translation);
  478. // localRot.multLocal(rotation);
  479. //localRot = localRot.mult(rotation);
  480. localPos.set(initialPos).addLocal(translation);
  481. localRot.set(initialRot).multLocal(rotation);
  482. if (scale != null) {
  483. localScale.set(initialScale).multLocal(scale);
  484. }
  485. }
  486. /**
  487. * Blends the given animation transform onto the bone's local transform.
  488. * <p>
  489. * Subsequent calls of this method stack up, with the final transformation
  490. * of the bone computed at {@link #updateWorldVectors() } which resets
  491. * the stack.
  492. * <p>
  493. * E.g. a single transform blend with weight = 0.5 followed by an
  494. * updateWorldVectors() call will result in final transform = transform * 0.5.
  495. * Two transform blends with weight = 0.5 each will result in the two
  496. * transforms blended together (nlerp) with blend = 0.5.
  497. *
  498. * @param translation The translation to blend in
  499. * @param rotation The rotation to blend in
  500. * @param scale The scale to blend in
  501. * @param weight The weight of the transform to apply. Set to 1.0 to prevent
  502. * any other transform from being applied until updateWorldVectors().
  503. */
  504. void blendAnimTransforms(Vector3f translation, Quaternion rotation, Vector3f scale, float weight) {
  505. if (userControl) {
  506. return;
  507. }
  508. if (weight == 0) {
  509. // Do not apply this transform at all.
  510. return;
  511. }
  512. if (currentWeightSum == 1){
  513. return; // More than 2 transforms are being blended
  514. } else if (currentWeightSum == -1 || currentWeightSum == 0) {
  515. // Set the transform fully
  516. localPos.set(initialPos).addLocal(translation);
  517. localRot.set(initialRot).multLocal(rotation);
  518. if (scale != null) {
  519. localScale.set(initialScale).multLocal(scale);
  520. }
  521. // Set the weight. It will be applied in updateWorldVectors().
  522. currentWeightSum = weight;
  523. } else {
  524. // The weight is already set.
  525. // Blend in the new transform.
  526. TempVars vars = TempVars.get();
  527. Vector3f tmpV = vars.vect1;
  528. Vector3f tmpV2 = vars.vect2;
  529. Quaternion tmpQ = vars.quat1;
  530. tmpV.set(initialPos).addLocal(translation);
  531. localPos.interpolateLocal(tmpV, weight);
  532. tmpQ.set(initialRot).multLocal(rotation);
  533. localRot.nlerp(tmpQ, weight);
  534. if (scale != null) {
  535. tmpV2.set(initialScale).multLocal(scale);
  536. localScale.interpolateLocal(tmpV2, weight);
  537. }
  538. // Ensures no new weights will be blended in the future.
  539. currentWeightSum = 1;
  540. vars.release();
  541. }
  542. }
  543. /**
  544. * Sets local bind transform for bone.
  545. * Call setBindingPose() after all of the skeleton bones' bind transforms are set to save them.
  546. */
  547. public void setBindTransforms(Vector3f translation, Quaternion rotation, Vector3f scale) {
  548. initialPos.set(translation);
  549. initialRot.set(rotation);
  550. //ogre.xml can have null scale values breaking this if the check is removed
  551. if (scale != null) {
  552. initialScale.set(scale);
  553. }
  554. localPos.set(translation);
  555. localRot.set(rotation);
  556. if (scale != null) {
  557. localScale.set(scale);
  558. }
  559. }
  560. private String toString(int depth) {
  561. StringBuilder sb = new StringBuilder();
  562. for (int i = 0; i < depth; i++) {
  563. sb.append('-');
  564. }
  565. sb.append(name).append(" bone\n");
  566. for (Bone child : children) {
  567. sb.append(child.toString(depth + 1));
  568. }
  569. return sb.toString();
  570. }
  571. @Override
  572. public String toString() {
  573. return this.toString(0);
  574. }
  575. @Override
  576. @SuppressWarnings("unchecked")
  577. public void read(JmeImporter im) throws IOException {
  578. InputCapsule input = im.getCapsule(this);
  579. name = input.readString("name", null);
  580. initialPos = (Vector3f) input.readSavable("initialPos", null);
  581. initialRot = (Quaternion) input.readSavable("initialRot", null);
  582. initialScale = (Vector3f) input.readSavable("initialScale", new Vector3f(1.0f, 1.0f, 1.0f));
  583. attachNode = (Node) input.readSavable("attachNode", null);
  584. localPos.set(initialPos);
  585. localRot.set(initialRot);
  586. ArrayList<Bone> childList = input.readSavableArrayList("children", null);
  587. for (int i = childList.size() - 1; i >= 0; i--) {
  588. this.addChild(childList.get(i));
  589. }
  590. // NOTE: Parent skeleton will call update() then setBindingPose()
  591. // after Skeleton has been de-serialized.
  592. // Therefore, worldBindInversePos and worldBindInverseRot
  593. // will be reconstructed based on that information.
  594. }
  595. @Override
  596. public void write(JmeExporter ex) throws IOException {
  597. OutputCapsule output = ex.getCapsule(this);
  598. output.write(name, "name", null);
  599. output.write(attachNode, "attachNode", null);
  600. output.write(initialPos, "initialPos", null);
  601. output.write(initialRot, "initialRot", null);
  602. output.write(initialScale, "initialScale", new Vector3f(1.0f, 1.0f, 1.0f));
  603. output.writeSavableArrayList(children, "children", null);
  604. }
  605. }