|
@@ -3,114 +3,168 @@ module BABYLON {
|
|
|
|
|
|
private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(),Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
|
|
private static _tmpVecs: Vector3[] = [Vector3.Zero(), Vector3.Zero(), Vector3.Zero(),Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero(), Vector3.Zero()];
|
|
private static _tmpQuat = Quaternion.Identity();
|
|
private static _tmpQuat = Quaternion.Identity();
|
|
- private static _tmpMat1 = Matrix.Identity();
|
|
|
|
- private static _tmpMat2 = Matrix.Identity();
|
|
|
|
-
|
|
|
|
|
|
+ private static _tmpMats: Matrix[] = [Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity(), Matrix.Identity()];
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The target Vector3 that the bone will look at.
|
|
|
|
+ */
|
|
public target: Vector3;
|
|
public target: Vector3;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The mesh that the bone is attached to.
|
|
|
|
+ */
|
|
public mesh: AbstractMesh;
|
|
public mesh: AbstractMesh;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The bone that will be looking to the target.
|
|
|
|
+ */
|
|
public bone: Bone;
|
|
public bone: Bone;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The up axis of the coordinate system that is used when the bone is rotated.
|
|
|
|
+ */
|
|
public upAxis: Vector3 = Vector3.Up();
|
|
public upAxis: Vector3 = Vector3.Up();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The space that the up axis is in - BABYLON.Space.BONE, BABYLON.Space.LOCAL (default), or BABYLON.Space.WORLD.
|
|
|
|
+ */
|
|
|
|
+ public upAxisSpace: Space = Space.LOCAL;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used to make an adjustment to the yaw of the bone.
|
|
|
|
+ */
|
|
|
|
+ public adjustYaw = 0;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used to make an adjustment to the pitch of the bone.
|
|
|
|
+ */
|
|
|
|
+ public adjustPitch = 0;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used to make an adjustment to the roll of the bone.
|
|
|
|
+ */
|
|
|
|
+ public adjustRoll = 0;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The amount to slerp (spherical linear interpolation) to the target. Set this to a value between 0 and 1 (a value of 1 disables slerp).
|
|
|
|
+ */
|
|
public slerpAmount = 1;
|
|
public slerpAmount = 1;
|
|
|
|
|
|
- private _adjustRotY = 0;
|
|
|
|
- private _adjustRotX = 0;
|
|
|
|
- private _adjustRotZ = 0;
|
|
|
|
- private _minRotY:number;
|
|
|
|
- private _maxRotY:number;
|
|
|
|
- private _minRotX:number;
|
|
|
|
- private _maxRotX:number;
|
|
|
|
- private _minRotYSin:number;
|
|
|
|
- private _minRotYCos:number;
|
|
|
|
- private _maxRotYSin:number;
|
|
|
|
- private _maxRotYCos:number;
|
|
|
|
- private _minRotXTan:number;
|
|
|
|
- private _maxRotXTan:number;
|
|
|
|
- private _minRotZ:number;
|
|
|
|
- private _maxRotZ:number;
|
|
|
|
- private _minRotZSin:number;
|
|
|
|
- private _minRotZCos:number;
|
|
|
|
- private _maxRotZSin:number;
|
|
|
|
- private _maxRotZCos:number;
|
|
|
|
|
|
+ private _minYaw:number;
|
|
|
|
+ private _maxYaw:number;
|
|
|
|
+ private _minPitch:number;
|
|
|
|
+ private _maxPitch:number;
|
|
|
|
+ private _minYawSin:number;
|
|
|
|
+ private _minYawCos:number;
|
|
|
|
+ private _maxYawSin:number;
|
|
|
|
+ private _maxYawCos:number;
|
|
|
|
+ private _midYawConstraint:number;
|
|
|
|
+ private _minPitchTan:number;
|
|
|
|
+ private _maxPitchTan:number;
|
|
|
|
+
|
|
private _boneQuat:Quaternion = Quaternion.Identity();
|
|
private _boneQuat:Quaternion = Quaternion.Identity();
|
|
private _slerping = false;
|
|
private _slerping = false;
|
|
-
|
|
|
|
- get minRotationY():number{
|
|
|
|
- return this._minRotY - this._adjustRotY;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- set minRotationY(value:number){
|
|
|
|
- this._minRotY = value + this._adjustRotY;
|
|
|
|
- this._minRotYSin = Math.sin(this._minRotY);
|
|
|
|
- this._minRotYCos = Math.cos(this._minRotY);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- get maxRoationY():number{
|
|
|
|
- return this._maxRotY - this._adjustRotY;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- set maxRotationY(value:number){
|
|
|
|
- this._maxRotY = value + this._adjustRotY;
|
|
|
|
- this._maxRotYSin = Math.sin(this._maxRotY);
|
|
|
|
- this._maxRotYCos = Math.cos(this._maxRotY);
|
|
|
|
|
|
+ private _transformYawPitch:Matrix;
|
|
|
|
+ private _transformYawPitchInv:Matrix;
|
|
|
|
+ private _firstFrameSkipped = false;
|
|
|
|
+ private _yawRange:number;
|
|
|
|
+ private _fowardAxis: Vector3 = Vector3.Forward();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Get/set the minimum yaw angle that the bone can look to.
|
|
|
|
+ */
|
|
|
|
+ get minYaw():number{
|
|
|
|
+ return this._minYaw;
|
|
}
|
|
}
|
|
|
|
|
|
- get minRotationX():number{
|
|
|
|
- return this._minRotX - this._adjustRotX;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- set minRotationX(value:number){
|
|
|
|
- this._minRotX = value + this._adjustRotX;
|
|
|
|
- this._minRotXTan = Math.tan(this._minRotX);
|
|
|
|
|
|
+ set minYaw(value:number){
|
|
|
|
+ this._minYaw = value;
|
|
|
|
+ this._minYawSin = Math.sin(value);
|
|
|
|
+ this._minYawCos = Math.cos(value);
|
|
|
|
+ if(this._maxYaw != null){
|
|
|
|
+ this._midYawConstraint = this._getAngleDiff(this._minYaw, this._maxYaw)*.5 + this._minYaw;
|
|
|
|
+ this._yawRange = this._maxYaw - this._minYaw;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- get maxRotationX():number{
|
|
|
|
- return this._maxRotX - this._adjustRotX;
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get/set the maximum yaw angle that the bone can look to.
|
|
|
|
+ */
|
|
|
|
+ get maxYaw():number{
|
|
|
|
+ return this._maxYaw;
|
|
}
|
|
}
|
|
|
|
|
|
- set maxRotationX(value:number){
|
|
|
|
- this._maxRotX = value + this._adjustRotX;
|
|
|
|
- this._maxRotXTan = Math.tan(this._maxRotX);
|
|
|
|
|
|
+ set maxYaw(value:number){
|
|
|
|
+ this._maxYaw = value;
|
|
|
|
+ this._maxYawSin = Math.sin(value);
|
|
|
|
+ this._maxYawCos = Math.cos(value);
|
|
|
|
+ if(this._minYaw != null){
|
|
|
|
+ this._midYawConstraint = this._getAngleDiff(this._minYaw, this._maxYaw)*.5 + this._minYaw;
|
|
|
|
+ this._yawRange = this._maxYaw - this._minYaw;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- get minRotationZ():number{
|
|
|
|
- return this._minRotZ - this._adjustRotZ;
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get/set the minimum pitch angle that the bone can look to.
|
|
|
|
+ */
|
|
|
|
+ get minPitch():number{
|
|
|
|
+ return this._minPitch;
|
|
}
|
|
}
|
|
|
|
|
|
- set minRotationZ(value:number){
|
|
|
|
- this._minRotZ = value + this._adjustRotZ;
|
|
|
|
- this._minRotZSin = Math.sin(this._minRotZ);
|
|
|
|
- this._minRotZCos = Math.cos(this._minRotZ);
|
|
|
|
|
|
+ set minPitch(value:number){
|
|
|
|
+ this._minPitch = value;
|
|
|
|
+ this._minPitchTan = Math.tan(value);
|
|
}
|
|
}
|
|
|
|
|
|
- get maxRotationZ():number{
|
|
|
|
- return this._maxRotZ - this._adjustRotZ;
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Get/set the maximum pitch angle that the bone can look to.
|
|
|
|
+ */
|
|
|
|
+ get maxPitch():number{
|
|
|
|
+ return this._maxPitch;
|
|
}
|
|
}
|
|
|
|
|
|
- set maxRotationZ(value:number){
|
|
|
|
- this._maxRotZ = value + this._adjustRotZ;
|
|
|
|
- this._maxRotZSin = Math.sin(this._maxRotZ);
|
|
|
|
- this._maxRotZCos = Math.cos(this._maxRotZ);
|
|
|
|
|
|
+ set maxPitch(value:number){
|
|
|
|
+ this._maxPitch = value;
|
|
|
|
+ this._maxPitchTan = Math.tan(value);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Create a BoneLookController
|
|
|
|
+ * @param mesh the mesh that the bone belongs to
|
|
|
|
+ * @param bone the bone that will be looking to the target
|
|
|
|
+ * @param target the target Vector3 to look at
|
|
|
|
+ * @param settings optional settings:
|
|
|
|
+ * - maxYaw: the maximum angle the bone will yaw to
|
|
|
|
+ * - minYaw: the minimum angle the bone will yaw to
|
|
|
|
+ * - maxPitch: the maximum angle the bone will pitch to
|
|
|
|
+ * - minPitch: the minimum angle the bone will yaw to
|
|
|
|
+ * - slerpAmount: set the between 0 and 1 to make the bone slerp to the target.
|
|
|
|
+ * - upAxis: the up axis of the coordinate system
|
|
|
|
+ * - upAxisSpace: the space that the up axis is in - BABYLON.Space.BONE, BABYLON.Space.LOCAL (default), or BABYLON.Space.WORLD.
|
|
|
|
+ * - yawAxis: set yawAxis if the bone does not yaw on the y axis
|
|
|
|
+ * - pitchAxis: set pitchAxis if the bone does not pitch on the x axis
|
|
|
|
+ * - adjustYaw: used to make an adjustment to the yaw of the bone
|
|
|
|
+ * - adjustPitch: used to make an adjustment to the pitch of the bone
|
|
|
|
+ * - adjustRoll: used to make an adjustment to the roll of the bone
|
|
|
|
+ **/
|
|
constructor(mesh: AbstractMesh,
|
|
constructor(mesh: AbstractMesh,
|
|
bone: Bone,
|
|
bone: Bone,
|
|
target: Vector3,
|
|
target: Vector3,
|
|
- options?: {
|
|
|
|
- adjustRotationX?: number,
|
|
|
|
- adjustRotationY?: number,
|
|
|
|
- adjustRotationZ?: number,
|
|
|
|
- slerpAmount?: number,
|
|
|
|
- maxRotationY?:number,
|
|
|
|
- minRotationY?:number,
|
|
|
|
- maxRotationX?:number,
|
|
|
|
- minRotationX?:number,
|
|
|
|
- maxRotationZ?:number,
|
|
|
|
- minRotationZ?:number,
|
|
|
|
|
|
+ options?: {
|
|
adjustYaw?: number,
|
|
adjustYaw?: number,
|
|
adjustPitch?: number,
|
|
adjustPitch?: number,
|
|
- adjustRoll?: number
|
|
|
|
- }
|
|
|
|
- ){
|
|
|
|
|
|
+ adjustRoll?: number,
|
|
|
|
+ slerpAmount?: number,
|
|
|
|
+ maxYaw?:number,
|
|
|
|
+ minYaw?:number,
|
|
|
|
+ maxPitch?:number,
|
|
|
|
+ minPitch?:number,
|
|
|
|
+ upAxis?:Vector3,
|
|
|
|
+ upAxisSpace?:Space,
|
|
|
|
+ yawAxis?:Vector3,
|
|
|
|
+ pitchAxis?:Vector3,
|
|
|
|
+ showSpaceAxes?:boolean
|
|
|
|
+ }){
|
|
|
|
|
|
this.mesh = mesh;
|
|
this.mesh = mesh;
|
|
this.bone = bone;
|
|
this.bone = bone;
|
|
@@ -119,158 +173,280 @@ module BABYLON {
|
|
if(options){
|
|
if(options){
|
|
|
|
|
|
if(options.adjustYaw){
|
|
if(options.adjustYaw){
|
|
- this._adjustRotY = options.adjustYaw;
|
|
|
|
|
|
+ this.adjustYaw = options.adjustYaw;
|
|
}
|
|
}
|
|
|
|
|
|
if(options.adjustPitch){
|
|
if(options.adjustPitch){
|
|
- this._adjustRotX = options.adjustPitch;
|
|
|
|
|
|
+ this.adjustPitch = options.adjustPitch;
|
|
}
|
|
}
|
|
|
|
|
|
if(options.adjustRoll){
|
|
if(options.adjustRoll){
|
|
- this._adjustRotZ = options.adjustRoll;
|
|
|
|
|
|
+ this.adjustRoll = options.adjustRoll;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.adjustRotationY){
|
|
|
|
- this._adjustRotY = options.adjustRotationY;
|
|
|
|
|
|
+ if(options.maxYaw != null){
|
|
|
|
+ this.maxYaw = options.maxYaw;
|
|
|
|
+ }else{
|
|
|
|
+ this.maxYaw = Math.PI;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.adjustRotationX){
|
|
|
|
- this._adjustRotX = options.adjustRotationX;
|
|
|
|
|
|
+ if(options.minYaw != null){
|
|
|
|
+ this.minYaw = options.minYaw;
|
|
|
|
+ }else{
|
|
|
|
+ this.minYaw = -Math.PI;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.adjustRotationZ){
|
|
|
|
- this._adjustRotZ = options.adjustRotationZ;
|
|
|
|
|
|
+ if(options.maxPitch != null){
|
|
|
|
+ this.maxPitch = options.maxPitch;
|
|
|
|
+ }else{
|
|
|
|
+ this.maxPitch = Math.PI;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.maxRotationY != undefined){
|
|
|
|
- this.maxRotationY = options.maxRotationY;
|
|
|
|
|
|
+ if(options.minPitch != null){
|
|
|
|
+ this.minPitch = options.minPitch;
|
|
|
|
+ }else{
|
|
|
|
+ this.minPitch = -Math.PI;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.minRotationY != undefined){
|
|
|
|
- this.minRotationY = options.minRotationY;
|
|
|
|
|
|
+ if(options.slerpAmount != null){
|
|
|
|
+ this.slerpAmount = options.slerpAmount;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.maxRotationX != undefined){
|
|
|
|
- this.maxRotationX = options.maxRotationX;
|
|
|
|
|
|
+ if(options.upAxis != null){
|
|
|
|
+ this.upAxis = options.upAxis;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.minRotationX != undefined){
|
|
|
|
- this.minRotationX = options.minRotationX;
|
|
|
|
|
|
+ if(options.upAxisSpace != null){
|
|
|
|
+ this.upAxisSpace = options.upAxisSpace;
|
|
}
|
|
}
|
|
|
|
|
|
- if(options.maxRotationZ != undefined){
|
|
|
|
- this.maxRotationZ = options.maxRotationZ;
|
|
|
|
- }
|
|
|
|
|
|
+ if(options.yawAxis != null || options.pitchAxis != null){
|
|
|
|
|
|
- if(options.minRotationZ != undefined){
|
|
|
|
- this.minRotationZ = options.minRotationZ;
|
|
|
|
- }
|
|
|
|
|
|
+ var newYawAxis = Axis.Y;
|
|
|
|
+ var newPitchAxis = Axis.X;
|
|
|
|
|
|
- if(options.slerpAmount != undefined){
|
|
|
|
- this.slerpAmount = options.slerpAmount;
|
|
|
|
|
|
+ if(options.yawAxis != null){
|
|
|
|
+ newYawAxis = options.yawAxis.clone();
|
|
|
|
+ newYawAxis.normalize();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(options.pitchAxis != null){
|
|
|
|
+ newPitchAxis = options.pitchAxis.clone();
|
|
|
|
+ newPitchAxis.normalize();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var newRollAxis = Vector3.Cross(newPitchAxis, newYawAxis);
|
|
|
|
+
|
|
|
|
+ this._transformYawPitch = Matrix.Identity();
|
|
|
|
+ Matrix.FromXYZAxesToRef(newPitchAxis, newYawAxis, newRollAxis, this._transformYawPitch);
|
|
|
|
+
|
|
|
|
+ this._transformYawPitchInv = this._transformYawPitch.clone();
|
|
|
|
+ this._transformYawPitch.invert();
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(!bone.getParent() && this.upAxisSpace == Space.BONE){
|
|
|
|
+ this.upAxisSpace = Space.LOCAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Update the bone to look at the target. This should be called before the scene is rendered (use scene.registerBeforeRender()).
|
|
|
|
+ */
|
|
public update (): void {
|
|
public update (): void {
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ //skip the first frame when slerping so that the mesh rotation is correct
|
|
|
|
+ if(this.slerpAmount < 1 && !this._firstFrameSkipped){
|
|
|
|
+ this._firstFrameSkipped = true;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
var bone = this.bone;
|
|
var bone = this.bone;
|
|
- var target = this.target;
|
|
|
|
- var mat1 = BoneLookController._tmpMat1;
|
|
|
|
- var mat2 = BoneLookController._tmpMat2;
|
|
|
|
|
|
+ var bonePos = BoneLookController._tmpVecs[0];
|
|
|
|
+ bone.getAbsolutePositionToRef(this.mesh, bonePos);
|
|
|
|
|
|
|
|
+ var target = this.target;
|
|
|
|
+ var _tmpMat1 = BoneLookController._tmpMats[0];
|
|
|
|
+ var _tmpMat2 = BoneLookController._tmpMats[1];
|
|
|
|
+
|
|
|
|
+ var mesh = this.mesh;
|
|
var parentBone = bone.getParent();
|
|
var parentBone = bone.getParent();
|
|
|
|
|
|
- if(parentBone){
|
|
|
|
- if(this._maxRotX != undefined || this._minRotX != undefined){
|
|
|
|
- var localTarget = BoneLookController._tmpVecs[4];
|
|
|
|
- var _tmpVec5 = BoneLookController._tmpVecs[5];
|
|
|
|
- parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
|
|
|
|
- bone.getPositionToRef(Space.LOCAL, null, _tmpVec5);
|
|
|
|
- localTarget.x -= _tmpVec5.x;
|
|
|
|
- localTarget.y -= _tmpVec5.y;
|
|
|
|
- localTarget.z -= _tmpVec5.z;
|
|
|
|
- var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
|
|
|
|
- var rotX = Math.atan2(localTarget.y, xzlen);
|
|
|
|
-
|
|
|
|
- if(rotX > this._maxRotX){
|
|
|
|
- localTarget.y = this._maxRotXTan*xzlen + _tmpVec5.y;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
- target = localTarget;
|
|
|
|
- }else if(rotX < this._minRotX){
|
|
|
|
- localTarget.y = this._minRotXTan*xzlen + _tmpVec5.y;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
- target = localTarget;
|
|
|
|
- }
|
|
|
|
|
|
+ var upAxis = BoneLookController._tmpVecs[1];
|
|
|
|
+ upAxis.copyFrom(this.upAxis);
|
|
|
|
+
|
|
|
|
+ if(this.upAxisSpace == Space.BONE){
|
|
|
|
+ if (this._transformYawPitch){
|
|
|
|
+ Vector3.TransformCoordinatesToRef(upAxis, this._transformYawPitchInv, upAxis);
|
|
}
|
|
}
|
|
|
|
+ parentBone.getDirectionToRef(upAxis, this.mesh, upAxis);
|
|
|
|
+ }else if(this.upAxisSpace == Space.LOCAL){
|
|
|
|
+ mesh.getDirectionToRef(upAxis, upAxis);
|
|
|
|
+ if(mesh.scaling.x != 1 || mesh.scaling.y != 1 || mesh.scaling.z != 1){
|
|
|
|
+ upAxis.normalize();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var checkYaw = false;
|
|
|
|
+ var checkPitch = false;
|
|
|
|
|
|
- if(this._maxRotY != undefined || this._minRotY != undefined){
|
|
|
|
- var localTarget = BoneLookController._tmpVecs[6];
|
|
|
|
- var _tmpVec7 = BoneLookController._tmpVecs[7];
|
|
|
|
- parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
|
|
|
|
- bone.getPositionToRef(Space.LOCAL, null, _tmpVec7);
|
|
|
|
- localTarget.x -= _tmpVec7.x;
|
|
|
|
- localTarget.z -= _tmpVec7.z;
|
|
|
|
- var rotY = Math.atan2(localTarget.x, localTarget.z);
|
|
|
|
|
|
+ if(this._maxYaw != Math.PI || this._minYaw != -Math.PI){
|
|
|
|
+ checkYaw = true;
|
|
|
|
+ }
|
|
|
|
+ if(this._maxPitch != Math.PI || this._minPitch != -Math.PI){
|
|
|
|
+ checkPitch = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(checkYaw || checkPitch){
|
|
|
|
+
|
|
|
|
+ var _tmpMat3 = BoneLookController._tmpMats[2];
|
|
|
|
+ var _tmpMat3Inv = BoneLookController._tmpMats[3];
|
|
|
|
+
|
|
|
|
+ if(this.upAxisSpace == Space.BONE && upAxis.y == 1){
|
|
|
|
+
|
|
|
|
+ parentBone.getRotationMatrixToRef(Space.WORLD, this.mesh, _tmpMat3);
|
|
|
|
|
|
- if(rotY > this._maxRotY){
|
|
|
|
- var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
|
|
|
|
- localTarget.z = this._maxRotYCos*xzlen;
|
|
|
|
- localTarget.x = this._maxRotYSin*xzlen;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
- target = localTarget;
|
|
|
|
- }else if(rotY < this._minRotY){
|
|
|
|
- var xzlen = Math.sqrt(localTarget.x*localTarget.x + localTarget.z*localTarget.z);
|
|
|
|
- localTarget.z = this._minRotYCos*xzlen;
|
|
|
|
- localTarget.x = this._minRotYSin*xzlen;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
- target = localTarget;
|
|
|
|
|
|
+ }else if(this.upAxisSpace == Space.LOCAL && upAxis.y == 1 && !parentBone){
|
|
|
|
+
|
|
|
|
+ _tmpMat3.copyFrom(mesh.getWorldMatrix());
|
|
|
|
+
|
|
|
|
+ }else{
|
|
|
|
+
|
|
|
|
+ var forwardAxis = BoneLookController._tmpVecs[2];
|
|
|
|
+ forwardAxis.copyFrom(this._fowardAxis);
|
|
|
|
+
|
|
|
|
+ if (this._transformYawPitch) {
|
|
|
|
+ Vector3.TransformCoordinatesToRef(forwardAxis, this._transformYawPitchInv, forwardAxis);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if(parentBone){
|
|
|
|
+ parentBone.getDirectionToRef(forwardAxis, this.mesh, forwardAxis);
|
|
|
|
+ }else{
|
|
|
|
+ mesh.getDirectionToRef(forwardAxis, forwardAxis);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var rightAxis = Vector3.Cross(upAxis, forwardAxis);
|
|
|
|
+ rightAxis.normalize();
|
|
|
|
+ var forwardAxis = Vector3.Cross(rightAxis, upAxis);
|
|
|
|
+
|
|
|
|
+ Matrix.FromXYZAxesToRef(rightAxis, upAxis, forwardAxis, _tmpMat3);
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
- if(this._maxRotZ != undefined || this._minRotZ != undefined){
|
|
|
|
- var localTarget = BoneLookController._tmpVecs[8];
|
|
|
|
- var _tmpVec9 = BoneLookController._tmpVecs[9];
|
|
|
|
- parentBone.getLocalPositionFromAbsoluteToRef(target, this.mesh, localTarget);
|
|
|
|
- bone.getPositionToRef(Space.LOCAL, null, _tmpVec9);
|
|
|
|
- localTarget.x -= _tmpVec9.x;
|
|
|
|
- localTarget.y -= _tmpVec9.y;
|
|
|
|
- var rotZ = Math.atan2(localTarget.y, localTarget.x);
|
|
|
|
|
|
+ _tmpMat3.invertToRef(_tmpMat3Inv);
|
|
|
|
+
|
|
|
|
+ var xzlen:number;
|
|
|
|
+
|
|
|
|
+ if(checkPitch){
|
|
|
|
+ var localTarget = BoneLookController._tmpVecs[3];
|
|
|
|
+ Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
|
|
|
|
+
|
|
|
|
+ var xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
|
|
|
|
+ var pitch = Math.atan2(localTarget.y, xzlen);
|
|
|
|
+ var newPitch = pitch;
|
|
|
|
+
|
|
|
|
+ if(pitch > this._maxPitch){
|
|
|
|
+ localTarget.y = this._maxPitchTan*xzlen;
|
|
|
|
+ newPitch = this._maxPitch;
|
|
|
|
+ }else if(pitch < this._minPitch){
|
|
|
|
+ localTarget.y = this._minPitchTan*xzlen;
|
|
|
|
+ newPitch = this._minPitch;
|
|
|
|
+ }
|
|
|
|
|
|
- if(rotZ > this._maxRotZ){
|
|
|
|
- var xylen = Math.sqrt(localTarget.x*localTarget.x + localTarget.y*localTarget.y);
|
|
|
|
- localTarget.x = this._maxRotZCos*xylen;
|
|
|
|
- localTarget.y = this._maxRotZSin*xylen;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
- target = localTarget;
|
|
|
|
- }else if(rotZ < this._minRotZ){
|
|
|
|
- var xylen = Math.sqrt(localTarget.x*localTarget.x + localTarget.y*localTarget.y);
|
|
|
|
- localTarget.x = this._minRotZCos*xylen;
|
|
|
|
- localTarget.y = this._minRotZSin*xylen;
|
|
|
|
- parentBone.getAbsolutePositionFromLocalToRef(localTarget, this.mesh, localTarget);
|
|
|
|
|
|
+ if(pitch != newPitch){
|
|
|
|
+ Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
|
|
|
|
+ localTarget.addInPlace(bonePos);
|
|
target = localTarget;
|
|
target = localTarget;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if(checkYaw){
|
|
|
|
+ var localTarget = BoneLookController._tmpVecs[4];
|
|
|
|
+ Vector3.TransformCoordinatesToRef(target.subtract(bonePos), _tmpMat3Inv, localTarget);
|
|
|
|
+
|
|
|
|
+ var yaw = Math.atan2(localTarget.x, localTarget.z);
|
|
|
|
+ var newYaw = yaw;
|
|
|
|
+
|
|
|
|
+ if(yaw > this._maxYaw || yaw < this._minYaw){
|
|
|
|
+
|
|
|
|
+ if(xzlen == null){
|
|
|
|
+ xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(yaw > this._maxYaw){
|
|
|
|
+ localTarget.z = this._maxYawCos*xzlen;
|
|
|
|
+ localTarget.x = this._maxYawSin*xzlen;
|
|
|
|
+ newYaw = this._maxYaw;
|
|
|
|
+ }else if(yaw < this._minYaw){
|
|
|
|
+ localTarget.z = this._minYawCos*xzlen;
|
|
|
|
+ localTarget.x = this._minYawSin*xzlen;
|
|
|
|
+ newYaw = this._minYaw;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(this._slerping && this._yawRange > Math.PI){
|
|
|
|
+ //are we going to be crossing into the min/max region
|
|
|
|
+ var _tmpVec8 = BoneLookController._tmpVecs[8];
|
|
|
|
+ _tmpVec8.copyFrom(Axis.Z);
|
|
|
|
+ if (this._transformYawPitch) {
|
|
|
|
+ Vector3.TransformCoordinatesToRef(_tmpVec8, this._transformYawPitchInv, _tmpVec8);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var boneRotMat = BABYLON.BoneLookController._tmpMats[4];
|
|
|
|
+ this._boneQuat.toRotationMatrix(boneRotMat);
|
|
|
|
+ this.mesh.getWorldMatrix().multiplyToRef(boneRotMat, boneRotMat);
|
|
|
|
+ BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, boneRotMat, _tmpVec8);
|
|
|
|
+ BABYLON.Vector3.TransformCoordinatesToRef(_tmpVec8, _tmpMat3Inv, _tmpVec8);
|
|
|
|
+
|
|
|
|
+ var boneYaw = Math.atan2(_tmpVec8.x, _tmpVec8.z);
|
|
|
|
+ var ang1 = this._getAngleBetween(boneYaw, yaw);
|
|
|
|
+ var ang2 = this._getAngleBetween(boneYaw, this._midYawConstraint);
|
|
|
|
+
|
|
|
|
+ if(ang1 > ang2){
|
|
|
|
+
|
|
|
|
+ if (xzlen == null) {
|
|
|
|
+ xzlen = Math.sqrt(localTarget.x * localTarget.x + localTarget.z * localTarget.z);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var ang3 = this._getAngleBetween(boneYaw, this._maxYaw);
|
|
|
|
+ var ang4 = this._getAngleBetween(boneYaw, this._minYaw);
|
|
|
|
+
|
|
|
|
+ if(ang4 < ang3){
|
|
|
|
+ newYaw = boneYaw+Math.PI*.75;
|
|
|
|
+ localTarget.z = Math.cos(newYaw) * xzlen;
|
|
|
|
+ localTarget.x = Math.sin(newYaw) * xzlen;
|
|
|
|
+ }else{
|
|
|
|
+ newYaw = boneYaw-Math.PI*.75;
|
|
|
|
+ localTarget.z = Math.cos(newYaw) * xzlen;
|
|
|
|
+ localTarget.x = Math.sin(newYaw) * xzlen;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(yaw != newYaw){
|
|
|
|
+ Vector3.TransformCoordinatesToRef(localTarget, _tmpMat3, localTarget);
|
|
|
|
+ localTarget.addInPlace(bonePos);
|
|
|
|
+ target = localTarget;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- var bonePos = BoneLookController._tmpVecs[0];
|
|
|
|
- var zaxis = BoneLookController._tmpVecs[1];
|
|
|
|
- var xaxis = BoneLookController._tmpVecs[2];
|
|
|
|
- var yaxis = BoneLookController._tmpVecs[3];
|
|
|
|
|
|
+ var zaxis = BoneLookController._tmpVecs[5];
|
|
|
|
+ var xaxis = BoneLookController._tmpVecs[6];
|
|
|
|
+ var yaxis = BoneLookController._tmpVecs[7];
|
|
var _tmpQuat = BoneLookController._tmpQuat;
|
|
var _tmpQuat = BoneLookController._tmpQuat;
|
|
|
|
|
|
- bone.getAbsolutePositionToRef(this.mesh, bonePos);
|
|
|
|
target.subtractToRef(bonePos, zaxis);
|
|
target.subtractToRef(bonePos, zaxis);
|
|
zaxis.normalize();
|
|
zaxis.normalize();
|
|
- Vector3.CrossToRef(this.upAxis, zaxis, xaxis);
|
|
|
|
|
|
+ Vector3.CrossToRef(upAxis, zaxis, xaxis);
|
|
xaxis.normalize();
|
|
xaxis.normalize();
|
|
Vector3.CrossToRef(zaxis, xaxis, yaxis);
|
|
Vector3.CrossToRef(zaxis, xaxis, yaxis);
|
|
yaxis.normalize();
|
|
yaxis.normalize();
|
|
- Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, mat1);
|
|
|
|
|
|
+ Matrix.FromXYZAxesToRef(xaxis, yaxis, zaxis, _tmpMat1);
|
|
|
|
|
|
if(xaxis.x === 0 && xaxis.y === 0 && xaxis.z === 0){
|
|
if(xaxis.x === 0 && xaxis.y === 0 && xaxis.z === 0){
|
|
return;
|
|
return;
|
|
@@ -284,25 +460,69 @@ module BABYLON {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- if (this._adjustRotY || this._adjustRotX || this._adjustRotZ) {
|
|
|
|
- Matrix.RotationYawPitchRollToRef(this._adjustRotY, this._adjustRotX, this._adjustRotZ, mat2);
|
|
|
|
- mat2.multiplyToRef(mat1, mat1);
|
|
|
|
|
|
+ if (this.adjustYaw || this.adjustPitch || this.adjustRoll) {
|
|
|
|
+ Matrix.RotationYawPitchRollToRef(this.adjustYaw, this.adjustPitch, this.adjustRoll, _tmpMat2);
|
|
|
|
+ _tmpMat2.multiplyToRef(_tmpMat1, _tmpMat1);
|
|
}
|
|
}
|
|
|
|
|
|
if (this.slerpAmount < 1) {
|
|
if (this.slerpAmount < 1) {
|
|
if (!this._slerping) {
|
|
if (!this._slerping) {
|
|
this.bone.getRotationQuaternionToRef(Space.WORLD, this.mesh, this._boneQuat);
|
|
this.bone.getRotationQuaternionToRef(Space.WORLD, this.mesh, this._boneQuat);
|
|
}
|
|
}
|
|
- Quaternion.FromRotationMatrixToRef(mat1, _tmpQuat);
|
|
|
|
|
|
+ if(this._transformYawPitch){
|
|
|
|
+ this._transformYawPitch.multiplyToRef(_tmpMat1, _tmpMat1);
|
|
|
|
+ }
|
|
|
|
+ Quaternion.FromRotationMatrixToRef(_tmpMat1, _tmpQuat);
|
|
Quaternion.SlerpToRef(this._boneQuat, _tmpQuat, this.slerpAmount, this._boneQuat);
|
|
Quaternion.SlerpToRef(this._boneQuat, _tmpQuat, this.slerpAmount, this._boneQuat);
|
|
|
|
+
|
|
this.bone.setRotationQuaternion(this._boneQuat, Space.WORLD, this.mesh);
|
|
this.bone.setRotationQuaternion(this._boneQuat, Space.WORLD, this.mesh);
|
|
this._slerping = true;
|
|
this._slerping = true;
|
|
} else {
|
|
} else {
|
|
- this.bone.setRotationMatrix(mat1, Space.WORLD, this.mesh);
|
|
|
|
|
|
+ if(this._transformYawPitch){
|
|
|
|
+ this._transformYawPitch.multiplyToRef(_tmpMat1, _tmpMat1);
|
|
|
|
+ }
|
|
|
|
+ this.bone.setRotationMatrix(_tmpMat1, Space.WORLD, this.mesh);
|
|
this._slerping = false;
|
|
this._slerping = false;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private _getAngleDiff(ang1, ang2):number {
|
|
|
|
+
|
|
|
|
+ var angDiff = ang2 - ang1;
|
|
|
|
+ angDiff %= Math.PI*2;
|
|
|
|
+
|
|
|
|
+ if(angDiff > Math.PI){
|
|
|
|
+ angDiff -= Math.PI*2;
|
|
|
|
+ }else if (angDiff < -Math.PI){
|
|
|
|
+ angDiff += Math.PI*2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return angDiff;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private _getAngleBetween(ang1, ang2):number {
|
|
|
|
+
|
|
|
|
+ ang1 %= (2 * Math.PI);
|
|
|
|
+ ang1 = (ang1 < 0) ? ang1 + (2 * Math.PI) : ang1;
|
|
|
|
+
|
|
|
|
+ ang2 %= (2 * Math.PI);
|
|
|
|
+ ang2 = (ang2 < 0) ? ang2 + (2 * Math.PI) : ang2;
|
|
|
|
+
|
|
|
|
+ var ab = 0;
|
|
|
|
+
|
|
|
|
+ if(ang1 < ang2){
|
|
|
|
+ ab = ang2 - ang1;
|
|
|
|
+ }else{
|
|
|
|
+ ab = ang1 - ang2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(ab > Math.PI){
|
|
|
|
+ ab = Math.PI*2 - ab;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ab;
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|