babylon.boneIKController.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. module BABYLON {
  2. export class BoneIKController {
  3. public target: AbstractMesh;
  4. public poleTarget: AbstractMesh;
  5. public poleAngle = 0;
  6. public mesh: AbstractMesh;
  7. private _bone1: Bone;
  8. private _bone2: Bone;
  9. private _bone1Length: number;
  10. private _bone2Length: number;
  11. private _maxAngle = Math.PI;
  12. private _maxReach: number;
  13. private _tmpVec1 = Vector3.Zero();
  14. private _tmpVec2 = Vector3.Zero();
  15. private _tmpVec3 = Vector3.Zero();
  16. private _tmpVec4 = Vector3.Zero();
  17. private _tmpVec5 = Vector3.Zero();
  18. private _tmpMat1 = Matrix.Identity();
  19. private _tmpMat2 = Matrix.Identity();
  20. private _rightHandedSystem = false;
  21. get maxAngle(): number {
  22. return this._maxAngle;
  23. }
  24. set maxAngle(value: number) {
  25. this._setMaxAngle(value);
  26. }
  27. constructor(mesh: AbstractMesh, bone: Bone, target: AbstractMesh, poleTarget: AbstractMesh, poleAngle: number = 0){
  28. target.computeWorldMatrix(true);
  29. poleTarget.computeWorldMatrix(true);
  30. this._bone2 = bone;
  31. this._bone1 = bone.getParent();
  32. this.target = target;
  33. this.poleTarget = poleTarget;
  34. this.poleAngle = poleAngle;
  35. this.mesh = mesh;
  36. if(bone.getAbsoluteTransform().determinant() > 0){
  37. this._rightHandedSystem = true;
  38. }
  39. if (this._bone1.length) {
  40. var boneScale1 = this._bone1.getScale();
  41. var boneScale2 = this._bone2.getScale();
  42. this._bone1Length = this._bone1.length * boneScale1.y;
  43. this._bone2Length = this._bone2.length * boneScale2.y;
  44. } else if (this._bone1.children[0]) {
  45. mesh.computeWorldMatrix(true);
  46. var pos1 = this._bone2.children[0].getAbsolutePosition(mesh);
  47. var pos2 = this._bone2.getAbsolutePosition(mesh);
  48. var pos3 = this._bone1.getAbsolutePosition(mesh);
  49. this._bone1Length = Vector3.Distance(pos1, pos2);
  50. this._bone2Length = Vector3.Distance(pos2, pos3);
  51. }
  52. this.maxAngle = Math.PI;
  53. }
  54. private _setMaxAngle(ang: number): void{
  55. if (ang < 0) {
  56. ang = 0;
  57. }
  58. if (ang > Math.PI || ang == undefined) {
  59. ang = Math.PI;
  60. }
  61. this._maxAngle = ang;
  62. var a = this._bone1Length;
  63. var b = this._bone2Length;
  64. this._maxReach = Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(ang));
  65. }
  66. public update (): void {
  67. var bone1 = this._bone1;
  68. var target = this.target.getAbsolutePosition();
  69. var poleTarget = this.poleTarget.getAbsolutePosition();
  70. var bonePos = this._tmpVec1;
  71. var zaxis = this._tmpVec2;
  72. var xaxis = this._tmpVec3;
  73. var yaxis = this._tmpVec4;
  74. var upAxis = this._tmpVec5;
  75. var mat1 = this._tmpMat1;
  76. var mat2 = this._tmpMat2;
  77. bone1.getAbsolutePositionToRef(this.mesh, bonePos);
  78. poleTarget.subtractToRef(bonePos, upAxis);
  79. if (upAxis.x == 0 && upAxis.y == 0 && upAxis.z == 0) {
  80. upAxis.y = 1;
  81. } else {
  82. upAxis.normalize();
  83. }
  84. target.subtractToRef(bonePos, yaxis);
  85. yaxis.normalize();
  86. Vector3.CrossToRef(yaxis, upAxis, zaxis);
  87. zaxis.normalize();
  88. Vector3.CrossToRef(yaxis, zaxis, xaxis);
  89. xaxis.normalize();
  90. Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, mat1);
  91. var a = this._bone1Length;
  92. var b = this._bone2Length;
  93. var c = Vector3.Distance(bonePos, target);
  94. if (this._maxReach > 0) {
  95. c = Math.min(this._maxReach, c);
  96. }
  97. var acosa = (b * b + c * c - a * a) / (2 * b * c);
  98. var acosb = (c * c + a * a - b * b) / (2 * c * a);
  99. if (acosa > 1) {
  100. acosa = 1;
  101. }
  102. if (acosb > 1) {
  103. acosb = 1;
  104. }
  105. if (acosa < -1) {
  106. acosa = -1;
  107. }
  108. if (acosb < -1) {
  109. acosb = -1;
  110. }
  111. var angA = Math.acos(acosa);
  112. var angB = Math.acos(acosb);
  113. var angC = -angA - angB;
  114. var bendAxis = this._tmpVec1;
  115. bendAxis.x = 0;
  116. bendAxis.y = 0;
  117. bendAxis.z = 0;
  118. if (this._rightHandedSystem) {
  119. bendAxis.z = 1;
  120. Matrix.RotationYawPitchRollToRef(0, 0, angB + Math.PI*.5, mat2);
  121. mat2.multiplyToRef(mat1, mat1);
  122. Matrix.RotationAxisToRef(yaxis, this.poleAngle + Math.PI, mat2);
  123. mat1.multiplyToRef(mat2, mat1);
  124. } else {
  125. bendAxis.x = 1;
  126. Matrix.RotationYawPitchRollToRef(0, angB, 0, mat2);
  127. mat2.multiplyToRef(mat1, mat1);
  128. if (this.poleAngle) {
  129. Matrix.RotationAxisToRef(yaxis, this.poleAngle, mat2);
  130. mat1.multiplyToRef(mat2, mat1);
  131. }
  132. }
  133. this._bone1.setRotationMatrix(mat1, Space.WORLD, this.mesh);
  134. this._bone2.setAxisAngle(bendAxis, angC, Space.LOCAL);
  135. }
  136. }
  137. }