123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- module BABYLON {
- export class BoneIKController {
- public target: AbstractMesh;
- public poleTarget: AbstractMesh;
- public poleAngle = 0;
- public mesh: AbstractMesh;
- private _bone1: Bone;
- private _bone2: Bone;
- private _bone1Length: number;
- private _bone2Length: number;
- private _maxAngle = Math.PI;
- private _maxReach: number;
- private _tmpVec1 = Vector3.Zero();
- private _tmpVec2 = Vector3.Zero();
- private _tmpVec3 = Vector3.Zero();
- private _tmpVec4 = Vector3.Zero();
- private _tmpVec5 = Vector3.Zero();
- private _tmpMat1 = Matrix.Identity();
- private _tmpMat2 = Matrix.Identity();
- private _rightHandedSystem = false;
- get maxAngle(): number {
- return this._maxAngle;
- }
- set maxAngle(value: number) {
-
- this._setMaxAngle(value);
- }
- constructor(mesh: AbstractMesh, bone: Bone, target: AbstractMesh, poleTarget: AbstractMesh, poleAngle: number = 0){
- target.computeWorldMatrix(true);
- poleTarget.computeWorldMatrix(true);
- this._bone2 = bone;
- this._bone1 = bone.getParent();
- this.target = target;
- this.poleTarget = poleTarget;
- this.poleAngle = poleAngle;
- this.mesh = mesh;
- if(bone.getAbsoluteTransform().determinant() > 0){
- this._rightHandedSystem = true;
- }
- if (this._bone1.length) {
- var boneScale1 = this._bone1.getScale();
- var boneScale2 = this._bone2.getScale();
-
- this._bone1Length = this._bone1.length * boneScale1.y;
- this._bone2Length = this._bone2.length * boneScale2.y;
- } else if (this._bone1.children[0]) {
-
- mesh.computeWorldMatrix(true);
- var pos1 = this._bone2.children[0].getAbsolutePosition(mesh);
- var pos2 = this._bone2.getAbsolutePosition(mesh);
- var pos3 = this._bone1.getAbsolutePosition(mesh);
- this._bone1Length = Vector3.Distance(pos1, pos2);
- this._bone2Length = Vector3.Distance(pos2, pos3);
- }
- this.maxAngle = Math.PI;
- }
- private _setMaxAngle(ang: number): void{
- if (ang < 0) {
- ang = 0;
- }
- if (ang > Math.PI || ang == undefined) {
- ang = Math.PI;
- }
- this._maxAngle = ang;
- var a = this._bone1Length;
- var b = this._bone2Length;
- this._maxReach = Math.sqrt(a * a + b * b - 2 * a * b * Math.cos(ang));
- }
- public update (): void {
-
- var bone1 = this._bone1;
- var target = this.target.getAbsolutePosition();
- var poleTarget = this.poleTarget.getAbsolutePosition();
- var bonePos = this._tmpVec1;
- var zaxis = this._tmpVec2;
- var xaxis = this._tmpVec3;
- var yaxis = this._tmpVec4;
- var upAxis = this._tmpVec5;
- var mat1 = this._tmpMat1;
- var mat2 = this._tmpMat2;
- bone1.getAbsolutePositionToRef(this.mesh, bonePos);
- poleTarget.subtractToRef(bonePos, upAxis);
- if (upAxis.x == 0 && upAxis.y == 0 && upAxis.z == 0) {
- upAxis.y = 1;
- } else {
- upAxis.normalize();
- }
- target.subtractToRef(bonePos, yaxis);
- yaxis.normalize();
- Vector3.CrossToRef(yaxis, upAxis, zaxis);
- zaxis.normalize();
- Vector3.CrossToRef(yaxis, zaxis, xaxis);
- xaxis.normalize();
- Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, mat1);
- var a = this._bone1Length;
- var b = this._bone2Length;
- var c = Vector3.Distance(bonePos, target);
- if (this._maxReach > 0) {
- c = Math.min(this._maxReach, c);
- }
- var acosa = (b * b + c * c - a * a) / (2 * b * c);
- var acosb = (c * c + a * a - b * b) / (2 * c * a);
- if (acosa > 1) {
- acosa = 1;
- }
- if (acosb > 1) {
- acosb = 1;
- }
- if (acosa < -1) {
- acosa = -1;
- }
- if (acosb < -1) {
- acosb = -1;
- }
- var angA = Math.acos(acosa);
- var angB = Math.acos(acosb);
- var angC = -angA - angB;
-
- var bendAxis = this._tmpVec1;
- bendAxis.x = 0;
- bendAxis.y = 0;
- bendAxis.z = 0;
- if (this._rightHandedSystem) {
- bendAxis.z = 1;
- Matrix.RotationYawPitchRollToRef(0, 0, angB + Math.PI*.5, mat2);
- mat2.multiplyToRef(mat1, mat1);
-
- Matrix.RotationAxisToRef(yaxis, this.poleAngle + Math.PI, mat2);
- mat1.multiplyToRef(mat2, mat1);
- } else {
- bendAxis.x = 1;
- Matrix.RotationYawPitchRollToRef(0, angB, 0, mat2);
- mat2.multiplyToRef(mat1, mat1);
- if (this.poleAngle) {
- Matrix.RotationAxisToRef(yaxis, this.poleAngle, mat2);
- mat1.multiplyToRef(mat2, mat1);
- }
- }
- this._bone1.setRotationMatrix(mat1, Space.WORLD, this.mesh);
- this._bone2.setAxisAngle(bendAxis, angC, Space.LOCAL);
- }
- }
- }
|