babylon.boneIKController.ts 8.7 KB

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