babylon.boneIKController.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. module BABYLON {
  2. export class BoneIKController {
  3. private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
  4. private static _tmpQuat = Quaternion.Identity();
  5. private static _tmpMats: Matrix[] = [Matrix.Identity(), Matrix.Identity()];
  6. public targetMesh: AbstractMesh;
  7. public poleTargetMesh: AbstractMesh;
  8. public poleTargetBone: Nullable<Bone>;
  9. public targetPosition = Vector3.Zero();
  10. public poleTargetPosition = Vector3.Zero();
  11. public poleTargetLocalOffset = Vector3.Zero();
  12. public poleAngle = 0;
  13. public mesh: AbstractMesh;
  14. public slerpAmount = 1;
  15. private _bone1Quat = Quaternion.Identity();
  16. private _bone1Mat = Matrix.Identity();
  17. private _bone2Ang = Math.PI;
  18. private _bone1: Nullable<Bone>;
  19. private _bone2: Bone;
  20. private _bone1Length: number;
  21. private _bone2Length: number;
  22. private _maxAngle = Math.PI;
  23. private _maxReach: number;
  24. private _rightHandedSystem = false;
  25. private _bendAxis = Vector3.Right();
  26. private _slerping = false;
  27. private _adjustRoll = 0;
  28. get maxAngle(): number {
  29. return this._maxAngle;
  30. }
  31. set maxAngle(value: number) {
  32. this._setMaxAngle(value);
  33. }
  34. constructor(mesh: AbstractMesh,
  35. bone: Bone,
  36. options?: {
  37. targetMesh?: AbstractMesh,
  38. poleTargetMesh?: AbstractMesh,
  39. poleTargetBone?: Bone,
  40. poleTargetLocalOffset?:Vector3,
  41. poleAngle?: number,
  42. bendAxis?: Vector3,
  43. maxAngle?:number,
  44. slerpAmount?:number
  45. }){
  46. this._bone2 = bone;
  47. this._bone1 = bone.getParent();
  48. if (!this._bone1) {
  49. return;
  50. }
  51. this.mesh = mesh;
  52. var bonePos = bone.getPosition();
  53. if(bone.getAbsoluteTransform().determinant() > 0){
  54. this._rightHandedSystem = true;
  55. this._bendAxis.x = 0;
  56. this._bendAxis.y = 0;
  57. this._bendAxis.z = -1;
  58. if(bonePos.x > bonePos.y && bonePos.x > bonePos.z){
  59. this._adjustRoll = Math.PI*.5;
  60. this._bendAxis.z = 1;
  61. }
  62. }
  63. if (this._bone1.length) {
  64. var boneScale1 = this._bone1.getScale();
  65. var boneScale2 = this._bone2.getScale();
  66. this._bone1Length = this._bone1.length * boneScale1.y * this.mesh.scaling.y;
  67. this._bone2Length = this._bone2.length * boneScale2.y * this.mesh.scaling.y;
  68. } else if (this._bone1.children[0]) {
  69. mesh.computeWorldMatrix(true);
  70. var pos1 = this._bone2.children[0].getAbsolutePosition(mesh);
  71. var pos2 = this._bone2.getAbsolutePosition(mesh);
  72. var pos3 = this._bone1.getAbsolutePosition(mesh);
  73. this._bone1Length = Vector3.Distance(pos1, pos2);
  74. this._bone2Length = Vector3.Distance(pos2, pos3);
  75. }
  76. this._bone1.getRotationMatrixToRef(Space.WORLD, mesh, this._bone1Mat);
  77. this.maxAngle = Math.PI;
  78. if(options){
  79. if(options.targetMesh){
  80. this.targetMesh = options.targetMesh;
  81. this.targetMesh.computeWorldMatrix(true);
  82. }
  83. if(options.poleTargetMesh){
  84. this.poleTargetMesh = options.poleTargetMesh;
  85. this.poleTargetMesh.computeWorldMatrix(true);
  86. } else if(options.poleTargetBone){
  87. this.poleTargetBone = options.poleTargetBone;
  88. } else if(this._bone1.getParent()){
  89. this.poleTargetBone = this._bone1.getParent();
  90. }
  91. if(options.poleTargetLocalOffset){
  92. this.poleTargetLocalOffset.copyFrom(options.poleTargetLocalOffset);
  93. }
  94. if(options.poleAngle){
  95. this.poleAngle = options.poleAngle;
  96. }
  97. if(options.bendAxis){
  98. this._bendAxis.copyFrom(options.bendAxis);
  99. }
  100. if(options.maxAngle){
  101. this.maxAngle = options.maxAngle;
  102. }
  103. if(options.slerpAmount){
  104. this.slerpAmount = options.slerpAmount;
  105. }
  106. }
  107. }
  108. private _setMaxAngle(ang: number): void{
  109. if (ang < 0) {
  110. ang = 0;
  111. }
  112. if (ang > Math.PI || ang == undefined) {
  113. ang = Math.PI;
  114. }
  115. this._maxAngle = ang;
  116. var a = this._bone1Length;
  117. var b = this._bone2Length;
  118. this._maxReach = Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(ang));
  119. }
  120. public update(): void {
  121. var bone1 = this._bone1;
  122. if (!bone1) {
  123. return;
  124. }
  125. var target = this.targetPosition;
  126. var poleTarget = this.poleTargetPosition;
  127. var mat1 = BoneIKController._tmpMats[0];
  128. var mat2 = BoneIKController._tmpMats[1];
  129. if(this.targetMesh){
  130. target.copyFrom(this.targetMesh.getAbsolutePosition());
  131. }
  132. if(this.poleTargetBone){
  133. this.poleTargetBone.getAbsolutePositionFromLocalToRef(this.poleTargetLocalOffset, this.mesh, poleTarget);
  134. }else if(this.poleTargetMesh){
  135. Vector3.TransformCoordinatesToRef(this.poleTargetLocalOffset, this.poleTargetMesh.getWorldMatrix(), poleTarget);
  136. }
  137. var bonePos = BoneIKController._tmpVecs[0];
  138. var zaxis = BoneIKController._tmpVecs[1];
  139. var xaxis = BoneIKController._tmpVecs[2];
  140. var yaxis = BoneIKController._tmpVecs[3];
  141. var upAxis = BoneIKController._tmpVecs[4];
  142. var _tmpQuat = BoneIKController._tmpQuat;
  143. bone1.getAbsolutePositionToRef(this.mesh, bonePos);
  144. poleTarget.subtractToRef(bonePos, upAxis);
  145. if (upAxis.x == 0 && upAxis.y == 0 && upAxis.z == 0) {
  146. upAxis.y = 1;
  147. } else {
  148. upAxis.normalize();
  149. }
  150. target.subtractToRef(bonePos, yaxis);
  151. yaxis.normalize();
  152. Vector3.CrossToRef(yaxis, upAxis, zaxis);
  153. zaxis.normalize();
  154. Vector3.CrossToRef(yaxis, zaxis, xaxis);
  155. xaxis.normalize();
  156. Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, mat1);
  157. var a = this._bone1Length;
  158. var b = this._bone2Length;
  159. var c = Vector3.Distance(bonePos, target);
  160. if (this._maxReach > 0) {
  161. c = Math.min(this._maxReach, c);
  162. }
  163. var acosa = (b * b + c * c - a * a) / (2 * b * c);
  164. var acosb = (c * c + a * a - b * b) / (2 * c * a);
  165. if (acosa > 1) {
  166. acosa = 1;
  167. }
  168. if (acosb > 1) {
  169. acosb = 1;
  170. }
  171. if (acosa < -1) {
  172. acosa = -1;
  173. }
  174. if (acosb < -1) {
  175. acosb = -1;
  176. }
  177. var angA = Math.acos(acosa);
  178. var angB = Math.acos(acosb);
  179. var angC = -angA - angB;
  180. if (this._rightHandedSystem) {
  181. Matrix.RotationYawPitchRollToRef(0, 0, this._adjustRoll, mat2);
  182. mat2.multiplyToRef(mat1, mat1);
  183. Matrix.RotationAxisToRef(this._bendAxis, angB, mat2);
  184. mat2.multiplyToRef(mat1, mat1);
  185. } else {
  186. var _tmpVec = BoneIKController._tmpVecs[5];
  187. _tmpVec.copyFrom(this._bendAxis);
  188. _tmpVec.x *= -1;
  189. Matrix.RotationAxisToRef(_tmpVec, -angB, mat2);
  190. mat2.multiplyToRef(mat1, mat1);
  191. }
  192. if (this.poleAngle) {
  193. Matrix.RotationAxisToRef(yaxis, this.poleAngle, mat2);
  194. mat1.multiplyToRef(mat2, mat1);
  195. }
  196. if (this._bone1) {
  197. if(this.slerpAmount < 1){
  198. if(!this._slerping){
  199. Quaternion.FromRotationMatrixToRef(this._bone1Mat, this._bone1Quat);
  200. }
  201. Quaternion.FromRotationMatrixToRef(mat1, _tmpQuat);
  202. Quaternion.SlerpToRef(this._bone1Quat, _tmpQuat, this.slerpAmount, this._bone1Quat);
  203. angC = this._bone2Ang * (1.0 - this.slerpAmount) + angC * this.slerpAmount;
  204. this._bone1.setRotationQuaternion(this._bone1Quat, Space.WORLD, this.mesh);
  205. this._slerping = true;
  206. } else {
  207. this._bone1.setRotationMatrix(mat1, Space.WORLD, this.mesh);
  208. this._bone1Mat.copyFrom(mat1);
  209. this._slerping = false;
  210. }
  211. }
  212. this._bone2.setAxisAngle(this._bendAxis, angC, Space.LOCAL);
  213. this._bone2Ang = angC;
  214. }
  215. }
  216. }