Browse Source

Merge pull request #371 from kpko/master

Decomposition and interpolation methods for matrices
David Catuhe 10 years ago
parent
commit
532bceedf4

+ 21 - 0
Babylon/Animations/babylon.animation.js

@@ -82,6 +82,26 @@
             return BABYLON.Color3.Lerp(startValue, endValue, gradient);
         };
 
+        Animation.prototype.matrixInterpolateFunction = function (startValue, endValue, gradient) {
+            var startScale = new BABYLON.Vector3(0, 0, 0);
+            var startRotation = new BABYLON.Quaternion();
+            var startTranslation = new BABYLON.Vector3(0, 0, 0);
+            startValue.decompose(startScale, startRotation, startTranslation);
+
+            var endScale = new BABYLON.Vector3(0, 0, 0);
+            var endRotation = new BABYLON.Quaternion();
+            var endTranslation = new BABYLON.Vector3(0, 0, 0);
+            endValue.decompose(endScale, endRotation, endTranslation);
+
+            var resultScale = this.vector3InterpolateFunction(startScale, endScale, gradient);
+            var resultRotation = this.quaternionInterpolateFunction(startRotation, endRotation, gradient);
+            var resultTranslation = this.vector3InterpolateFunction(startTranslation, endTranslation, gradient);
+
+            var result = BABYLON.Matrix.Compose(resultScale, resultRotation, resultTranslation);
+
+            return result;
+        };
+
         Animation.prototype.clone = function () {
             var clone = new Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
 
@@ -181,6 +201,7 @@
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
+                                    return this.matrixInterpolateFunction(startValue, endValue, gradient);
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return startValue;
                             }

+ 21 - 0
Babylon/Animations/babylon.animation.ts

@@ -88,6 +88,26 @@
             return Color3.Lerp(startValue, endValue, gradient);
         }
 
+        public matrixInterpolateFunction(startValue: Matrix, endValue: Matrix, gradient: number): Matrix {
+            var startScale = new Vector3(0, 0, 0);
+            var startRotation = new Quaternion();
+            var startTranslation = new Vector3(0, 0, 0);
+            startValue.decompose(startScale, startRotation, startTranslation);
+
+            var endScale = new Vector3(0, 0, 0);
+            var endRotation = new Quaternion();
+            var endTranslation = new Vector3(0, 0, 0);
+            endValue.decompose(endScale, endRotation, endTranslation);
+
+            var resultScale = this.vector3InterpolateFunction(startScale, endScale, gradient);
+            var resultRotation = this.quaternionInterpolateFunction(startRotation, endRotation, gradient);
+            var resultTranslation = this.vector3InterpolateFunction(startTranslation, endTranslation, gradient);
+
+            var result = Matrix.Compose(resultScale, resultRotation, resultTranslation);
+
+            return result;
+        }
+
         public clone(): Animation {
             var clone = new Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
 
@@ -189,6 +209,7 @@
                             switch (loopMode) {
                                 case Animation.ANIMATIONLOOPMODE_CYCLE:
                                 case Animation.ANIMATIONLOOPMODE_CONSTANT:
+                                    return this.matrixInterpolateFunction(startValue, endValue, gradient);
                                 case Animation.ANIMATIONLOOPMODE_RELATIVE:
                                     return startValue;
                             }

+ 44 - 0
Babylon/Math/babylon.math.js

@@ -1417,6 +1417,10 @@
             return new Quaternion(-q.x, -q.y, -q.z, q.w);
         };
 
+        Quaternion.Identity = function () {
+            return new Quaternion(0, 0, 0, 1);
+        };
+
         Quaternion.RotationAxis = function (axis, angle) {
             var result = new Quaternion();
             var sin = Math.sin(angle / 2);
@@ -1684,6 +1688,34 @@
             return Matrix.FromValues(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5], this.m[6], this.m[7], this.m[8], this.m[9], this.m[10], this.m[11], this.m[12], this.m[13], this.m[14], this.m[15]);
         };
 
+        Matrix.prototype.decompose = function (scale, rotation, translation) {
+            translation.x = this.m[12];
+            translation.y = this.m[13];
+            translation.z = this.m[14];
+
+            var xs = BABYLON.Tools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
+            var ys = BABYLON.Tools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
+            var zs = BABYLON.Tools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
+
+            scale.x = xs * Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1] + this.m[2] * this.m[2]);
+            scale.y = ys * Math.sqrt(this.m[4] * this.m[4] + this.m[5] * this.m[5] + this.m[6] * this.m[6]);
+            scale.z = zs * Math.sqrt(this.m[8] * this.m[8] + this.m[9] * this.m[9] + this.m[10] * this.m[10]);
+
+            if (scale.x == 0 || scale.y == 0 || scale.z == 0) {
+                rotation.x = 0;
+                rotation.y = 0;
+                rotation.z = 0;
+                rotation.w = 1;
+                return false;
+            }
+
+            var rotationMatrix = BABYLON.Matrix.FromValues(this.m[0] / scale.x, this.m[1] / scale.x, this.m[2] / scale.x, 0, this.m[4] / scale.y, this.m[5] / scale.y, this.m[6] / scale.y, 0, this.m[8] / scale.z, this.m[9] / scale.z, this.m[10] / scale.z, 0, 0, 0, 0, 1);
+
+            rotation.fromRotationMatrix(rotationMatrix);
+
+            return true;
+        };
+
         // Statics
         Matrix.FromArray = function (array, offset) {
             var result = new Matrix();
@@ -1745,6 +1777,18 @@
             return result;
         };
 
+        Matrix.Compose = function (scale, rotation, translation) {
+            var result = Matrix.FromValues(scale.x, 0, 0, 0, 0, scale.y, 0, 0, 0, 0, scale.z, 0, 0, 0, 0, 1);
+
+            var rotationMatrix = Matrix.Identity();
+            rotation.toRotationMatrix(rotationMatrix);
+            result = result.multiply(rotationMatrix);
+
+            result.setTranslation(translation);
+
+            return result;
+        };
+
         Matrix.Identity = function () {
             return Matrix.FromValues(1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0);
         };

+ 56 - 5
Babylon/Math/babylon.math.ts

@@ -1378,6 +1378,10 @@
             return new Quaternion(-q.x, -q.y, -q.z, q.w);
         }
 
+        public static Identity(): Quaternion {
+            return new Quaternion(0, 0, 0, 1);
+        }
+
         public static RotationAxis(axis: Vector3, angle: number): Quaternion {
             var result = new Quaternion();
             var sin = Math.sin(angle / 2);
@@ -1660,6 +1664,38 @@
                 this.m[12], this.m[13], this.m[14], this.m[15]);
         }
 
+        public decompose(scale: Vector3, rotation: Quaternion, translation: Vector3) {
+            translation.x = this.m[12];
+            translation.y = this.m[13];
+            translation.z = this.m[14];
+
+            var xs = Tools.Sign(this.m[0] * this.m[1] * this.m[2] * this.m[3]) < 0 ? -1 : 1;
+            var ys = Tools.Sign(this.m[4] * this.m[5] * this.m[6] * this.m[7]) < 0 ? -1 : 1;
+            var zs = Tools.Sign(this.m[8] * this.m[9] * this.m[10] * this.m[11]) < 0 ? -1 : 1;
+
+            scale.x = xs * Math.sqrt(this.m[0] * this.m[0] + this.m[1] * this.m[1] + this.m[2] * this.m[2]);
+            scale.y = ys * Math.sqrt(this.m[4] * this.m[4] + this.m[5] * this.m[5] + this.m[6] * this.m[6]);
+            scale.z = zs * Math.sqrt(this.m[8] * this.m[8] + this.m[9] * this.m[9] + this.m[10] * this.m[10]);
+
+            if (scale.x == 0 || scale.y == 0 || scale.z == 0) {
+                rotation.x = 0;
+                rotation.y = 0;
+                rotation.z = 0;
+                rotation.w = 1;
+                return false;
+            }
+
+            var rotationMatrix = BABYLON.Matrix.FromValues(
+                this.m[0] / scale.x, this.m[1] / scale.x, this.m[2] / scale.x, 0,
+                this.m[4] / scale.y, this.m[5] / scale.y, this.m[6] / scale.y, 0,
+                this.m[8] / scale.z, this.m[9] / scale.z, this.m[10] / scale.z, 0,
+                0, 0, 0, 1);
+
+            rotation.fromRotationMatrix(rotationMatrix);
+
+            return true;
+        }
+
         // Statics
         public static FromArray(array: number[], offset?: number): Matrix {
             var result = new Matrix();
@@ -1730,6 +1766,21 @@
             return result;
         }
 
+        public static Compose(scale: Vector3, rotation: Quaternion, translation: Vector3): Matrix {
+            var result = Matrix.FromValues(scale.x, 0, 0, 0,
+                0, scale.y, 0, 0,
+                0, 0, scale.z, 0,
+                0, 0, 0, 1);
+
+            var rotationMatrix = Matrix.Identity();
+            rotation.toRotationMatrix(rotationMatrix);
+            result = result.multiply(rotationMatrix);
+
+            result.setTranslation(translation);
+
+            return result;
+        }
+
         public static Identity(): Matrix {
             return Matrix.FromValues(1.0, 0, 0, 0,
                 0, 1.0, 0, 0,
@@ -2619,7 +2670,7 @@
     }
 
     export class PathCursor {
-        private _onchange = new Array <(cursor: PathCursor) => void>();
+        private _onchange = new Array<(cursor: PathCursor) => void>();
 
         value: number = 0;
         animations = new Array<Animation>();
@@ -2627,14 +2678,14 @@
         constructor(private path: Path2) {
         }
 
-        getPoint() : Vector3 {
+        getPoint(): Vector3 {
             var point = this.path.getPointAtLengthPosition(this.value);
             return new Vector3(point.x, 0, point.y);
         }
 
         moveAhead(step: number = 0.002) {
             this.move(step);
-            
+
         }
 
         moveBack(step: number = 0.002) {
@@ -2642,7 +2693,7 @@
         }
 
         move(step: number) {
-            
+
             if (Math.abs(step) > 1) {
                 throw "step size should be less than 1.";
             }
@@ -2655,7 +2706,7 @@
         private ensureLimits() {
             while (this.value > 1) {
                 this.value -= 1;
-            } 
+            }
             while (this.value < 0) {
                 this.value += 1;
             }

+ 11 - 0
Babylon/Tools/babylon.tools.js

@@ -280,6 +280,17 @@
             return Math.min(max, Math.max(min, value));
         };
 
+        // Returns -1 when value is a negative number and
+        // +1 when value is a positive number.
+        Tools.Sign = function (value) {
+            value = +value; // convert to a number
+
+            if (value === 0 || isNaN(value))
+                return value;
+
+            return value > 0 ? 1 : -1;
+        };
+
         Tools.Format = function (value, decimals) {
             if (typeof decimals === "undefined") { decimals = 2; }
             return value.toFixed(decimals);

+ 11 - 0
Babylon/Tools/babylon.tools.ts

@@ -311,6 +311,17 @@
             return Math.min(max, Math.max(min, value));
         }
 
+        // Returns -1 when value is a negative number and
+        // +1 when value is a positive number. 
+        public static Sign(value: number): number {
+            value = +value; // convert to a number
+
+            if (value === 0 || isNaN(value))
+                return value;
+
+            return value > 0 ? 1 : -1
+        }
+
         public static Format(value: number, decimals: number = 2): string {
             return value.toFixed(decimals);
         }