babylon.boneIKController.ts 9.4 KB

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