Browse Source

Merge remote-tracking branch 'upstream/master' into ColorGrading

Sébastien Vandenberghe 9 years ago
parent
commit
325776311b

+ 13 - 13
Tools/Gulp/config.json

@@ -43,19 +43,19 @@
       "../../src/Collisions/babylon.collider.js",
       "../../src/Collisions/babylon.collider.js",
       "../../src/Collisions/babylon.collisionCoordinator.js",
       "../../src/Collisions/babylon.collisionCoordinator.js",
       "../../src/Cameras/babylon.camera.js",
       "../../src/Cameras/babylon.camera.js",
-      "../../src/cameras/babylon.camerainputsmanager.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.mouse.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.keyboard.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.touch.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.deviceorientation.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.vrdeviceorientation.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.gamepad.js",
-      "../../src/cameras/inputs/babylon.freecamera.input.virtualjoystick.js",
-      "../../src/cameras/inputs/babylon.arcrotatecamera.input.keyboard.js",
-      "../../src/cameras/inputs/babylon.arcrotatecamera.input.mousewheel.js",
-      "../../src/cameras/inputs/babylon.arcrotatecamera.input.pointers.js",
-      "../../src/cameras/inputs/babylon.arcrotatecamera.input.gamepad.js",
-      "../../src/cameras/inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js",
+      "../../src/Cameras/babylon.cameraInputsManager.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.mouse.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.keyboard.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.touch.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.deviceorientation.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.vrdeviceorientation.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.gamepad.js",
+      "../../src/Cameras/Inputs/babylon.freecamera.input.virtualjoystick.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.keyboard.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.mousewheel.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.pointers.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.gamepad.js",
+      "../../src/Cameras/Inputs/babylon.arcrotatecamera.input.vrdeviceorientation.js",
       "../../src/Cameras/babylon.targetCamera.js",
       "../../src/Cameras/babylon.targetCamera.js",
       "../../src/Cameras/babylon.freeCamera.js",
       "../../src/Cameras/babylon.freeCamera.js",
       "../../src/Cameras/babylon.freeCameraInputsManager.js",
       "../../src/Cameras/babylon.freeCameraInputsManager.js",

File diff suppressed because it is too large
+ 20 - 20
dist/preview release/babylon.core.js


File diff suppressed because it is too large
+ 3388 - 3386
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 28 - 28
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 46 - 18
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 27 - 27
dist/preview release/babylon.noworker.js


+ 2 - 0
dist/preview release/what's new.md

@@ -17,6 +17,7 @@
     - StandardMaterial.maxSimultaneousLights can define how many dynamic lights the material can handle ([deltakosh](https://github.com/deltakosh))
     - StandardMaterial.maxSimultaneousLights can define how many dynamic lights the material can handle ([deltakosh](https://github.com/deltakosh))
   - **Updates**
   - **Updates**
     - Added postprocess.enablePixelPerfectMode to avoid texture scaling/stretching when dealing with non-power of 2 resolutions. cannot be used on post-processes chain ([deltakosh](https://github.com/deltakosh))
     - Added postprocess.enablePixelPerfectMode to avoid texture scaling/stretching when dealing with non-power of 2 resolutions. cannot be used on post-processes chain ([deltakosh](https://github.com/deltakosh))
+    - Enabled other post processes to be used when also using a 3D Rig ([jcpalmer](https://github.com/Palmer-JC))
     - Added skeleton.getBoneIndexByName(boneName: string) ([dad72](https://github.com/dad72))
     - Added skeleton.getBoneIndexByName(boneName: string) ([dad72](https://github.com/dad72))
     - Added node._children to track children hierarchy ([deltakosh](https://github.com/deltakosh))
     - Added node._children to track children hierarchy ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
     - Added Camera.ForceAttachControlToAlwaysPreventDefault to help embedding Babylon.js in iFrames ([deltakosh](https://github.com/deltakosh))
@@ -39,6 +40,7 @@
   - **Exporters**
   - **Exporters**
     - Support for 3dsmax 2017 ([deltakosh](https://github.com/deltakosh))
     - Support for 3dsmax 2017 ([deltakosh](https://github.com/deltakosh))
     - Added support for up to 8 bones influences per vertex for 3dsmax exporter ([deltakosh](https://github.com/deltakosh))
     - Added support for up to 8 bones influences per vertex for 3dsmax exporter ([deltakosh](https://github.com/deltakosh))
+    - Added console logging for .babylon file loading ([jcpalmer](https://github.com/Palmer-JC))
   - **API doc**
   - **API doc**
     - class `SolidParticleSystem` documented ([jerome](https://github.com/jbousquie))
     - class `SolidParticleSystem` documented ([jerome](https://github.com/jbousquie))
     - class `MeshBuilder` documented ([jerome](https://github.com/jbousquie))
     - class `MeshBuilder` documented ([jerome](https://github.com/jbousquie))

+ 16 - 7
src/Animations/babylon.animation.js

@@ -155,8 +155,8 @@ var BABYLON;
                 ret += ", Ranges: {";
                 ret += ", Ranges: {";
                 var first = true;
                 var first = true;
                 for (var name in this._ranges) {
                 for (var name in this._ranges) {
-                    if (!first) {
-                        ret + ", ";
+                    if (first) {
+                        ret += ", ";
                         first = false;
                         first = false;
                     }
                     }
                     ret += name;
                     ret += name;
@@ -390,16 +390,24 @@ var BABYLON;
             // Blending
             // Blending
             if (this.enableBlending && this._blendingFactor <= 1.0) {
             if (this.enableBlending && this._blendingFactor <= 1.0) {
                 if (!this._originalBlendValue) {
                 if (!this._originalBlendValue) {
-                    this._originalBlendValue = destination[path];
+                    if (destination[path].clone) {
+                        this._originalBlendValue = destination[path].clone();
+                    }
+                    else {
+                        this._originalBlendValue = destination[path];
+                    }
                 }
                 }
                 if (this._originalBlendValue.prototype) {
                 if (this._originalBlendValue.prototype) {
                     if (this._originalBlendValue.prototype.Lerp) {
                     if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
                     }
                     }
                     else {
                     else {
                         destination[path] = currentValue;
                         destination[path] = currentValue;
                     }
                     }
                 }
                 }
+                else if (this._originalBlendValue.m) {
+                    destination[path] = BABYLON.Matrix.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                }
                 else {
                 else {
                     destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                     destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 }
@@ -642,9 +650,10 @@ var BABYLON;
             var animation = new Animation(parsedAnimation.name, parsedAnimation.property, parsedAnimation.framePerSecond, parsedAnimation.dataType, parsedAnimation.loopBehavior);
             var animation = new Animation(parsedAnimation.name, parsedAnimation.property, parsedAnimation.framePerSecond, parsedAnimation.dataType, parsedAnimation.loopBehavior);
             var dataType = parsedAnimation.dataType;
             var dataType = parsedAnimation.dataType;
             var keys = [];
             var keys = [];
-            for (var index = 0; index < parsedAnimation.keys.length; index++) {
+            var data;
+            var index;
+            for (index = 0; index < parsedAnimation.keys.length; index++) {
                 var key = parsedAnimation.keys[index];
                 var key = parsedAnimation.keys[index];
-                var data;
                 switch (dataType) {
                 switch (dataType) {
                     case Animation.ANIMATIONTYPE_FLOAT:
                     case Animation.ANIMATIONTYPE_FLOAT:
                         data = key.values[0];
                         data = key.values[0];
@@ -670,7 +679,7 @@ var BABYLON;
             }
             }
             animation.setKeys(keys);
             animation.setKeys(keys);
             if (parsedAnimation.ranges) {
             if (parsedAnimation.ranges) {
-                for (var index = 0; index < parsedAnimation.ranges.length; index++) {
+                for (index = 0; index < parsedAnimation.ranges.length; index++) {
                     data = parsedAnimation.ranges[index];
                     data = parsedAnimation.ranges[index];
                     animation.createRange(data.name, data.from, data.to);
                     animation.createRange(data.name, data.from, data.to);
                 }
                 }

+ 19 - 11
src/Animations/babylon.animation.ts

@@ -179,12 +179,12 @@
             ret += ", datatype: " + (["Float", "Vector3", "Quaternion", "Matrix", "Color3", "Vector2"])[this.dataType];
             ret += ", datatype: " + (["Float", "Vector3", "Quaternion", "Matrix", "Color3", "Vector2"])[this.dataType];
             ret += ", nKeys: " + (this._keys ? this._keys.length : "none");
             ret += ", nKeys: " + (this._keys ? this._keys.length : "none");
             ret += ", nRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
             ret += ", nRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
-            if (fullDetails){
-                ret += ", Ranges: {" 
+            if (fullDetails) {
+                ret += ", Ranges: {";
                 var first = true;
                 var first = true;
                 for (var name in this._ranges) {
                 for (var name in this._ranges) {
-                    if (!first){
-                        ret + ", ";
+                    if (first) {
+                        ret += ", ";
                         first = false; 
                         first = false; 
                     }
                     }
                     ret += name; 
                     ret += name; 
@@ -446,7 +446,7 @@
                     property = property[this.targetPropertyPath[index]];
                     property = property[this.targetPropertyPath[index]];
                 }
                 }
 
 
-                path = this.targetPropertyPath[this.targetPropertyPath.length - 1]
+                path = this.targetPropertyPath[this.targetPropertyPath.length - 1];
                 destination = property;
                 destination = property;
             } else {
             } else {
                 path = this.targetPropertyPath[0];
                 path = this.targetPropertyPath[0];
@@ -456,17 +456,23 @@
             // Blending
             // Blending
             if (this.enableBlending && this._blendingFactor <= 1.0) {
             if (this.enableBlending && this._blendingFactor <= 1.0) {
                 if (!this._originalBlendValue) {
                 if (!this._originalBlendValue) {
-                    this._originalBlendValue = destination[path];
+                    if (destination[path].clone) {
+                        this._originalBlendValue = destination[path].clone();
+                    } else {
+                        this._originalBlendValue = destination[path];
+                    }
                 }
                 }
 
 
                 if (this._originalBlendValue.prototype) { // Complex value
                 if (this._originalBlendValue.prototype) { // Complex value
                     
                     
                     if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
                     if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
-                        destination[path] = this._originalBlendValue.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
                     } else { // Blending not supported
                     } else { // Blending not supported
                         destination[path] = currentValue;
                         destination[path] = currentValue;
                     }
                     }
 
 
+                } else if (this._originalBlendValue.m) { // Matrix
+                    destination[path] = Matrix.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
                 } else { // Direct value
                 } else { // Direct value
                     destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                     destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 }
@@ -482,7 +488,7 @@
 
 
         public goToFrame(frame: number): void {
         public goToFrame(frame: number): void {
             if (frame < this._keys[0].frame) {
             if (frame < this._keys[0].frame) {
-                frame = this._keys[0].frame
+                frame = this._keys[0].frame;
             } else if (frame > this._keys[this._keys.length - 1].frame) {
             } else if (frame > this._keys[this._keys.length - 1].frame) {
                 frame = this._keys[this._keys.length - 1].frame;
                 frame = this._keys[this._keys.length - 1].frame;
             }
             }
@@ -715,10 +721,12 @@
 
 
             var dataType = parsedAnimation.dataType;
             var dataType = parsedAnimation.dataType;
             var keys = [];
             var keys = [];
-            for (var index = 0; index < parsedAnimation.keys.length; index++) {
+            var data;
+            var index: number;
+
+            for (index = 0; index < parsedAnimation.keys.length; index++) {
                 var key = parsedAnimation.keys[index];
                 var key = parsedAnimation.keys[index];
 
 
-                var data;
 
 
                 switch (dataType) {
                 switch (dataType) {
                     case Animation.ANIMATIONTYPE_FLOAT:
                     case Animation.ANIMATIONTYPE_FLOAT:
@@ -748,7 +756,7 @@
             animation.setKeys(keys);
             animation.setKeys(keys);
 
 
             if (parsedAnimation.ranges) {
             if (parsedAnimation.ranges) {
-                for (var index = 0; index < parsedAnimation.ranges.length; index++) {
+                for (index = 0; index < parsedAnimation.ranges.length; index++) {
                     data = parsedAnimation.ranges[index];
                     data = parsedAnimation.ranges[index];
                     animation.createRange(data.name, data.from, data.to);
                     animation.createRange(data.name, data.from, data.to);
                 }
                 }

+ 3 - 3
src/Bones/babylon.bone.ts

@@ -123,9 +123,9 @@
             
             
             // loop vars declaration / initialization
             // loop vars declaration / initialization
             var orig: { frame: number, value: Matrix };
             var orig: { frame: number, value: Matrix };
-            var origScale = scalingReqd ? BABYLON.Vector3.Zero() : null;
-            var origRotation = scalingReqd ? new BABYLON.Quaternion() : null;
-            var origTranslation = scalingReqd ? BABYLON.Vector3.Zero() : null;
+            var origScale = scalingReqd ? Vector3.Zero() : null;
+            var origRotation = scalingReqd ? new Quaternion() : null;
+            var origTranslation = scalingReqd ? Vector3.Zero() : null;
             var mat: Matrix;
             var mat: Matrix;
 
 
             for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {
             for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {

+ 21 - 9
src/Bones/babylon.skeleton.js

@@ -36,12 +36,12 @@ var BABYLON;
             if (fullDetails) {
             if (fullDetails) {
                 ret += ", Ranges: {";
                 ret += ", Ranges: {";
                 var first = true;
                 var first = true;
-                for (var name in this._ranges) {
-                    if (!first) {
-                        ret + ", ";
+                for (var name_1 in this._ranges) {
+                    if (first) {
+                        ret += ", ";
                         first = false;
                         first = false;
                     }
                     }
-                    ret += name;
+                    ret += name_1;
                 }
                 }
                 ret += "}";
                 ret += "}";
             }
             }
@@ -109,14 +109,16 @@ var BABYLON;
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             var boneDict = {};
             var boneDict = {};
             var sourceBones = source.bones;
             var sourceBones = source.bones;
-            for (var i = 0, nBones = sourceBones.length; i < nBones; i++) {
+            var nBones;
+            var i;
+            for (i = 0, nBones = sourceBones.length; i < nBones; i++) {
                 boneDict[sourceBones[i].name] = sourceBones[i];
                 boneDict[sourceBones[i].name] = sourceBones[i];
             }
             }
             if (this.bones.length !== sourceBones.length) {
             if (this.bones.length !== sourceBones.length) {
                 BABYLON.Tools.Warn("copyAnimationRange: this rig has " + this.bones.length + " bones, while source as " + sourceBones.length);
                 BABYLON.Tools.Warn("copyAnimationRange: this rig has " + this.bones.length + " bones, while source as " + sourceBones.length);
                 ret = false;
                 ret = false;
             }
             }
-            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+            for (i = 0, nBones = this.bones.length; i < nBones; i++) {
                 var boneName = this.bones[i].name;
                 var boneName = this.bones[i].name;
                 var sourceBone = boneDict[boneName];
                 var sourceBone = boneDict[boneName];
                 if (sourceBone) {
                 if (sourceBone) {
@@ -154,7 +156,7 @@ var BABYLON;
             if (!range) {
             if (!range) {
                 return null;
                 return null;
             }
             }
-            this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
+            return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
         };
         };
         Skeleton.prototype._markAsDirty = function () {
         Skeleton.prototype._markAsDirty = function () {
             this._isDirty = true;
             this._isDirty = true;
@@ -250,6 +252,15 @@ var BABYLON;
             this._isDirty = true;
             this._isDirty = true;
             return result;
             return result;
         };
         };
+        Skeleton.prototype.enableBlending = function (blendingSpeed) {
+            if (blendingSpeed === void 0) { blendingSpeed = 0.01; }
+            this.bones.forEach(function (bone) {
+                bone.animations.forEach(function (animation) {
+                    animation.enableBlending = true;
+                    animation.blendingSpeed = blendingSpeed;
+                });
+            });
+        };
         Skeleton.prototype.dispose = function () {
         Skeleton.prototype.dispose = function () {
             this._meshesWithPoseMatrix = [];
             this._meshesWithPoseMatrix = [];
             // Animations
             // Animations
@@ -292,7 +303,8 @@ var BABYLON;
         Skeleton.Parse = function (parsedSkeleton, scene) {
         Skeleton.Parse = function (parsedSkeleton, scene) {
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
             var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
-            for (var index = 0; index < parsedSkeleton.bones.length; index++) {
+            var index;
+            for (index = 0; index < parsedSkeleton.bones.length; index++) {
                 var parsedBone = parsedSkeleton.bones[index];
                 var parsedBone = parsedSkeleton.bones[index];
                 var parentBone = null;
                 var parentBone = null;
                 if (parsedBone.parentBoneIndex > -1) {
                 if (parsedBone.parentBoneIndex > -1) {
@@ -309,7 +321,7 @@ var BABYLON;
             }
             }
             // placed after bones, so createAnimationRange can cascade down
             // placed after bones, so createAnimationRange can cascade down
             if (parsedSkeleton.ranges) {
             if (parsedSkeleton.ranges) {
-                for (var index = 0; index < parsedSkeleton.ranges.length; index++) {
+                for (index = 0; index < parsedSkeleton.ranges.length; index++) {
                     var data = parsedSkeleton.ranges[index];
                     var data = parsedSkeleton.ranges[index];
                     skeleton.createAnimationRange(data.name, data.from, data.to);
                     skeleton.createAnimationRange(data.name, data.from, data.to);
                 }
                 }

+ 28 - 16
src/Bones/babylon.skeleton.ts

@@ -42,14 +42,14 @@
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
          * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
          */
          */
         public toString(fullDetails? : boolean) : string {
         public toString(fullDetails? : boolean) : string {
-            var ret = "Name: " + this.name + ", nBones: " + this.bones.length;
-            ret += ", nAnimationRanges: " + (this._ranges ? Object.keys(this._ranges).length : "none");
-            if (fullDetails){
-                ret += ", Ranges: {" 
-                var first = true;
-                for (var name in this._ranges) {
-                    if (!first){
-                        ret + ", ";
+            var ret = `Name: ${this.name}, nBones: ${this.bones.length}`;
+            ret += `, nAnimationRanges: ${this._ranges ? Object.keys(this._ranges).length : "none"}`;
+            if (fullDetails) {
+                ret += ", Ranges: {"; 
+                let first = true;
+                for (let name in this._ranges) {
+                    if (first) {
+                        ret += ", ";
                         first = false; 
                         first = false; 
                     }
                     }
                     ret += name; 
                     ret += name; 
@@ -125,22 +125,24 @@
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
             var boneDict = {};
             var boneDict = {};
             var sourceBones = source.bones;
             var sourceBones = source.bones;
-            for (var i = 0, nBones = sourceBones.length; i < nBones; i++) {
+            var nBones: number;
+            var i: number;
+            for (i = 0, nBones = sourceBones.length; i < nBones; i++) {
                 boneDict[sourceBones[i].name] = sourceBones[i];
                 boneDict[sourceBones[i].name] = sourceBones[i];
             }
             }
 
 
             if (this.bones.length !== sourceBones.length){
             if (this.bones.length !== sourceBones.length){
-                BABYLON.Tools.Warn("copyAnimationRange: this rig has " + this.bones.length + " bones, while source as " + sourceBones.length);
+                Tools.Warn(`copyAnimationRange: this rig has ${this.bones.length} bones, while source as ${sourceBones.length}`);
                 ret = false;
                 ret = false;
             }
             }
             
             
-            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+            for (i = 0, nBones = this.bones.length; i < nBones; i++) {
                 var boneName = this.bones[i].name;
                 var boneName = this.bones[i].name;
                 var sourceBone = boneDict[boneName];
                 var sourceBone = boneDict[boneName];
                 if (sourceBone) {
                 if (sourceBone) {
                     ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
                     ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
                 } else {
                 } else {
-                    BABYLON.Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
+                    Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
                     ret = false;
                     ret = false;
                 }
                 }
             }
             }
@@ -169,14 +171,14 @@
             return ret;
             return ret;
         }
         }
 
 
-        public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): void {
+        public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): Animatable {
             var range = this.getAnimationRange(name);
             var range = this.getAnimationRange(name);
 
 
             if (!range) {
             if (!range) {
                 return null;
                 return null;
             }
             }
 
 
-            this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
+            return this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
         }
         }
 
 
         public _markAsDirty(): void {
         public _markAsDirty(): void {
@@ -299,6 +301,15 @@
             return result;
             return result;
         }
         }
 
 
+        public enableBlending(blendingSpeed = 0.01) {
+            this.bones.forEach((bone) => {
+                bone.animations.forEach((animation: Animation) => {
+                    animation.enableBlending = true;
+                    animation.blendingSpeed = blendingSpeed;
+                });
+            });
+        }
+
         public dispose() {
         public dispose() {
             this._meshesWithPoseMatrix = [];
             this._meshesWithPoseMatrix = [];
 
 
@@ -356,7 +367,8 @@
 
 
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
             skeleton.needInitialSkinMatrix = parsedSkeleton.needInitialSkinMatrix;
 
 
-            for (var index = 0; index < parsedSkeleton.bones.length; index++) {
+            let index: number;
+            for (index = 0; index < parsedSkeleton.bones.length; index++) {
                 var parsedBone = parsedSkeleton.bones[index];
                 var parsedBone = parsedSkeleton.bones[index];
 
 
                 var parentBone = null;
                 var parentBone = null;
@@ -377,7 +389,7 @@
             
             
             // placed after bones, so createAnimationRange can cascade down
             // placed after bones, so createAnimationRange can cascade down
             if (parsedSkeleton.ranges) {
             if (parsedSkeleton.ranges) {
-                for (var index = 0; index < parsedSkeleton.ranges.length; index++) {
+                for (index = 0; index < parsedSkeleton.ranges.length; index++) {
                     var data = parsedSkeleton.ranges[index];
                     var data = parsedSkeleton.ranges[index];
                     skeleton.createAnimationRange(data.name, data.from, data.to);
                     skeleton.createAnimationRange(data.name, data.from, data.to);
                 }
                 }

+ 21 - 13
src/Cameras/babylon.arcRotateCamera.ts

@@ -514,18 +514,21 @@
          * Override Camera.createRigCamera
          * Override Camera.createRigCamera
          */
          */
         public createRigCamera(name: string, cameraIndex: number): Camera {
         public createRigCamera(name: string, cameraIndex: number): Camera {
+            var alphaShift : number;
             switch (this.cameraRigMode) {
             switch (this.cameraRigMode) {
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_VR:
                 case Camera.RIG_MODE_VR:
-                    var alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
-                    var rigCam = new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this.target, this.getScene());
-                    rigCam._cameraRigParams = {};
-                    return rigCam;
-            }
-            return null;
+                    alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
+                    break;
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                    alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? -1 : 1);
+                    break;
+           }
+            var rigCam = new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this.target, this.getScene());
+            rigCam._cameraRigParams = {};
+            return rigCam;
         }
         }
         
         
         /**
         /**
@@ -533,18 +536,23 @@
          * Override Camera._updateRigCameras
          * Override Camera._updateRigCameras
          */
          */
         public _updateRigCameras() {
         public _updateRigCameras() {
+            var camLeft  = <ArcRotateCamera>this._rigCameras[0];
+            var camRight = <ArcRotateCamera>this._rigCameras[1];
+            
+            camLeft.beta = camRight.beta = this.beta;
+            camLeft.radius = camRight.radius = this.radius;
+
             switch (this.cameraRigMode) {
             switch (this.cameraRigMode) {
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_VR:
                 case Camera.RIG_MODE_VR:
-                    var camLeft = <ArcRotateCamera>this._rigCameras[0];
-                    var camRight = <ArcRotateCamera>this._rigCameras[1];
-                    camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
+                    camLeft.alpha  = this.alpha - this._cameraRigParams.stereoHalfAngle;
                     camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
                     camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
-                    camLeft.beta = camRight.beta = this.beta;
-                    camLeft.radius = camRight.radius = this.radius;
+                    break;
+                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
+                    camLeft.alpha  = this.alpha + this._cameraRigParams.stereoHalfAngle;
+                    camRight.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
                     break;
                     break;
             }
             }
             super._updateRigCameras();
             super._updateRigCameras();

+ 70 - 116
src/Cameras/babylon.camera.ts

@@ -113,14 +113,13 @@
 
 
         public _cameraRigParams: any;
         public _cameraRigParams: any;
         public _rigCameras = new Array<Camera>();
         public _rigCameras = new Array<Camera>();
-
+        public _rigPostProcess : PostProcess;
 
 
         // Cache
         // Cache
         private _computedViewMatrix = Matrix.Identity();
         private _computedViewMatrix = Matrix.Identity();
         public _projectionMatrix = new Matrix();
         public _projectionMatrix = new Matrix();
         private _worldMatrix: Matrix;
         private _worldMatrix: Matrix;
         public _postProcesses = new Array<PostProcess>();
         public _postProcesses = new Array<PostProcess>();
-        public _postProcessesTakenIndices = [];
 
 
         public _activeMeshes = new SmartArray<Mesh>(256);
         public _activeMeshes = new SmartArray<Mesh>(256);
 
 
@@ -275,95 +274,72 @@
 
 
         public _checkInputs(): void {
         public _checkInputs(): void {
         }
         }
+        
+        private _cascadePostProcessesToRigCams() : void {
+            // invalidate framebuffer
+            if (this._postProcesses.length > 0){
+                this._postProcesses[0].markTextureDirty();
+            }
+            
+            // glue the rigPostProcess to the end of the user postprocesses & assign to each sub-camera
+            for(var i = 0, len = this._rigCameras.length; i < len; i++){
+                var cam = this._rigCameras[i];
+                var rigPostProcess = cam._rigPostProcess;
+                
+                // for VR rig, there does not have to be a post process 
+                if (rigPostProcess){
+                    var isPass = rigPostProcess instanceof PassPostProcess;
+                    if (isPass){
+                        // any rig which has a PassPostProcess for rig[0], cannot be isIntermediate when there are also user postProcesses
+                        cam.isIntermediate = this._postProcesses.length === 0;
+                    }               
+                    cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
+                    rigPostProcess.markTextureDirty();
+                }
+            }
+        }
 
 
         public attachPostProcess(postProcess: PostProcess, insertAt: number = null): number {
         public attachPostProcess(postProcess: PostProcess, insertAt: number = null): number {
             if (!postProcess.isReusable() && this._postProcesses.indexOf(postProcess) > -1) {
             if (!postProcess.isReusable() && this._postProcesses.indexOf(postProcess) > -1) {
                 Tools.Error("You're trying to reuse a post process not defined as reusable.");
                 Tools.Error("You're trying to reuse a post process not defined as reusable.");
                 return 0;
                 return 0;
             }
             }
-
+            
             if (insertAt == null || insertAt < 0) {
             if (insertAt == null || insertAt < 0) {
                 this._postProcesses.push(postProcess);
                 this._postProcesses.push(postProcess);
-                this._postProcessesTakenIndices.push(this._postProcesses.length - 1);
-
-                return this._postProcesses.length - 1;
-            }
-
-            var add = 0;
-            var i: number;
-            var start: number;
-            if (this._postProcesses[insertAt]) {
-                start = this._postProcesses.length - 1;
-                for (i = start; i >= insertAt + 1; --i) {
-                    this._postProcesses[i + 1] = this._postProcesses[i];
-                }
-
-                add = 1;
-            }
-
-            for (i = 0; i < this._postProcessesTakenIndices.length; ++i) {
-                if (this._postProcessesTakenIndices[i] < insertAt) {
-                    continue;
-                }
-
-                start = this._postProcessesTakenIndices.length - 1;
-                for (var j = start; j >= i; --j) {
-                    this._postProcessesTakenIndices[j + 1] = this._postProcessesTakenIndices[j] + add;
-                }
-                this._postProcessesTakenIndices[i] = insertAt;
-                break;
+                
+            }else{
+                this._postProcesses.splice(insertAt, 0, postProcess);
             }
             }
-
-            if (!add && this._postProcessesTakenIndices.indexOf(insertAt) === -1) {
-                this._postProcessesTakenIndices.push(insertAt);
-            }
-
-            var result = insertAt + add;
-
-            this._postProcesses[result] = postProcess;
-
-            return result;
+            this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated            
+            return this._postProcesses.indexOf(postProcess);
         }
         }
-
+        
         public detachPostProcess(postProcess: PostProcess, atIndices: any = null): number[] {
         public detachPostProcess(postProcess: PostProcess, atIndices: any = null): number[] {
             var result = [];
             var result = [];
             var i: number;
             var i: number;
             var index: number;
             var index: number;
-            if (!atIndices) {
-
-                var length = this._postProcesses.length;
 
 
-                for (i = 0; i < length; i++) {
-
-                    if (this._postProcesses[i] !== postProcess) {
-                        continue;
-                    }
-
-                    delete this._postProcesses[i];
-                    index = this._postProcessesTakenIndices.indexOf(i);
-                    this._postProcessesTakenIndices.splice(index, 1);
+            if (!atIndices) {
+                var idx = this._postProcesses.indexOf(postProcess);
+                if (idx !== -1){
+                    this._postProcesses.splice(idx, 1);
                 }
                 }
-
-            }
-            else {
+            } else {
                 atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
                 atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
-                for (i = 0; i < atIndices.length; i++) {
-                    var foundPostProcess = this._postProcesses[atIndices[i]];
-
-                    if (foundPostProcess !== postProcess) {
+                // iterate descending, so can just splice as we go
+                for (i = atIndices.length - 1; i >= 0; i--) {
+                    if ( this._postProcesses[atIndices[i]] !== postProcess) {
                         result.push(i);
                         result.push(i);
                         continue;
                         continue;
                     }
                     }
-
-                    delete this._postProcesses[atIndices[i]];
-
-                    index = this._postProcessesTakenIndices.indexOf(atIndices[i]);
-                    this._postProcessesTakenIndices.splice(index, 1);
+                    this._postProcesses.splice(index, 1);
                 }
                 }
             }
             }
+            this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
             return result;
             return result;
         }
         }
-
+        
         public getWorldMatrix(): Matrix {
         public getWorldMatrix(): Matrix {
             if (!this._worldMatrix) {
             if (!this._worldMatrix) {
                 this._worldMatrix = Matrix.Identity();
                 this._worldMatrix = Matrix.Identity();
@@ -452,8 +428,8 @@
             }
             }
 
 
             // Postprocesses
             // Postprocesses
-            for (var i = 0; i < this._postProcessesTakenIndices.length; ++i) {
-                this._postProcesses[this._postProcessesTakenIndices[i]].dispose(this);
+            for (var i = 0; i < this._postProcesses.length; ++i) {
+                this._postProcesses[i].dispose(this);
             }
             }
 
 
             super.dispose();
             super.dispose();
@@ -466,82 +442,57 @@
             }
             }
             this.cameraRigMode = mode;
             this.cameraRigMode = mode;
             this._cameraRigParams = {};
             this._cameraRigParams = {};
+            //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target, 
+            //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
+            this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
+            this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
 
 
-            switch (this.cameraRigMode) {
-                case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
-                case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
-                case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
-                    this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
-                    //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target, 
-                    //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
-                    this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
-
-                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
-                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
-                    break;
+            // create the rig cameras, unless none
+            if (this.cameraRigMode !== Camera.RIG_MODE_NONE){
+                this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
+                this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
             }
             }
 
 
-            var postProcesses = new Array<PostProcess>();
-
             switch (this.cameraRigMode) {
             switch (this.cameraRigMode) {
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
-                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]));
-                    this._rigCameras[0].isIntermediate = true;
-
-                    postProcesses.push(new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras[1]));
-                    postProcesses[1].onApply = effect => {
-                        effect.setTextureFromPostProcess("leftSampler", postProcesses[0]);
-                    };
+                    this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
+                    this._rigCameras[1]._rigPostProcess = new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras);
                     break;
                     break;
 
 
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
-                    var isStereoscopicHoriz = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED);
-                    var firstCamIndex = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? 1 : 0;
-                    var secondCamIndex = 1 - firstCamIndex;
-
-                    postProcesses.push(new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[firstCamIndex]));
-                    this._rigCameras[firstCamIndex].isIntermediate = true;
-
-                    postProcesses.push(new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras[secondCamIndex], postProcesses[0], isStereoscopicHoriz));
+                    var isStereoscopicHoriz = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
+                    
+                    this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
+                    this._rigCameras[1]._rigPostProcess = new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras, isStereoscopicHoriz);
                     break;
                     break;
 
 
                 case Camera.RIG_MODE_VR:
                 case Camera.RIG_MODE_VR:
-                    this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
-                    this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
-
-                    this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
-                    this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
-
                     var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
                     var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
+                    
                     this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
                     this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
                     this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                     this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
                     this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
                     this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
-
                     this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
                     this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
                     this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
                     this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
                     this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
                     this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
 
 
-                    if (metrics.compensateDistortion) {
-                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics));
-                    }
-
-                    this._rigCameras[1]._cameraRigParams.vrMetrics = this._rigCameras[0]._cameraRigParams.vrMetrics;
+                    this._rigCameras[1]._cameraRigParams.vrMetrics = metrics;
                     this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
                     this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
                     this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                     this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
                     this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
                     this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
                     this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
-
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
                     this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
 
 
                     if (metrics.compensateDistortion) {
                     if (metrics.compensateDistortion) {
-                        postProcesses.push(new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics));
+                        this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
+                        this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
                     }
                     }
                     break;
                     break;
             }
             }
 
 
+            this._cascadePostProcessesToRigCams(); 
             this._update();
             this._update();
         }
         }
 
 
@@ -552,6 +503,9 @@
         }
         }
 
 
         public setCameraRigParameter(name: string, value: any) {
         public setCameraRigParameter(name: string, value: any) {
+            if (!this._cameraRigParams){
+               this._cameraRigParams = {}; 
+            }
             this._cameraRigParams[name] = value;
             this._cameraRigParams[name] = value;
             //provisionnally:
             //provisionnally:
             if (name === "interaxialDistance") {
             if (name === "interaxialDistance") {
@@ -560,14 +514,14 @@
         }
         }
         
         
         /**
         /**
-         * May needs to be overridden by children so sub has required properties to be copied
+         * needs to be overridden by children so sub has required properties to be copied
          */
          */
         public createRigCamera(name: string, cameraIndex: number): Camera {
         public createRigCamera(name: string, cameraIndex: number): Camera {
-            return null;
+           return null;
         }
         }
         
         
         /**
         /**
-         * May needs to be overridden by children
+         * May need to be overridden by children
          */
          */
         public _updateRigCameras() {
         public _updateRigCameras() {
             for (var i = 0; i < this._rigCameras.length; i++) {
             for (var i = 0; i < this._rigCameras.length; i++) {

+ 18 - 17
src/Cameras/babylon.targetCamera.ts

@@ -259,31 +259,32 @@
          * Override Camera._updateRigCameras
          * Override Camera._updateRigCameras
          */
          */
         public _updateRigCameras() {
         public _updateRigCameras() {
+            var camLeft = <TargetCamera>this._rigCameras[0];
+            var camRight = <TargetCamera>this._rigCameras[1];
+
             switch (this.cameraRigMode) {
             switch (this.cameraRigMode) {
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
                 case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
+                    //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
+                    var leftSign  = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ?  1 : -1;
+                    var rightSign = (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED) ? -1 :  1;
+                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * leftSign , camLeft.position);
+                    this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle * rightSign, camRight.position);
+
+                    camLeft.setTarget(this.getTarget());
+                    camRight.setTarget(this.getTarget());
+                    break;
+                    
                 case Camera.RIG_MODE_VR:
                 case Camera.RIG_MODE_VR:
-                    var camLeft = <TargetCamera>this._rigCameras[0];
-                    var camRight = <TargetCamera>this._rigCameras[1];
-
-                    if (this.cameraRigMode === Camera.RIG_MODE_VR) {
-                        camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
-                        camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
-                        camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
-
-                        camLeft.position.copyFrom(this.position);
-                        camRight.position.copyFrom(this.position);
+                    camLeft.rotation.x = camRight.rotation.x = this.rotation.x;
+                    camLeft.rotation.y = camRight.rotation.y = this.rotation.y;
+                    camLeft.rotation.z = camRight.rotation.z = this.rotation.z;
 
 
-                    } else {
-                        //provisionnaly using _cameraRigParams.stereoHalfAngle instead of calculations based on _cameraRigParams.interaxialDistance:
-                        this._getRigCamPosition(-this._cameraRigParams.stereoHalfAngle, camLeft.position);
-                        this._getRigCamPosition(this._cameraRigParams.stereoHalfAngle, camRight.position);
+                    camLeft.position.copyFrom(this.position);
+                    camRight.position.copyFrom(this.position);
 
 
-                        camLeft.setTarget(this.getTarget());
-                        camRight.setTarget(this.getTarget());
-                    }
                     break;
                     break;
             }
             }
             super._updateRigCameras();
             super._updateRigCameras();

+ 1 - 1
src/Debug/babylon.debugLayer.js

@@ -670,7 +670,7 @@ var BABYLON;
                 + "</div><br>"
                 + "</div><br>"
                 + glInfo.renderer + "<br>";
                 + glInfo.renderer + "<br>";
             if (this.customStatsFunction) {
             if (this.customStatsFunction) {
-                this._statsSubsetDiv.innerHTML += this._statsSubsetDiv.innerHTML;
+                this._statsSubsetDiv.innerHTML += this.customStatsFunction();
             }
             }
         };
         };
         return DebugLayer;
         return DebugLayer;

+ 1 - 1
src/Debug/babylon.debugLayer.ts

@@ -826,7 +826,7 @@
                 + glInfo.renderer + "<br>";
                 + glInfo.renderer + "<br>";
 
 
             if (this.customStatsFunction) {
             if (this.customStatsFunction) {
-                this._statsSubsetDiv.innerHTML += this._statsSubsetDiv.innerHTML;
+                this._statsSubsetDiv.innerHTML += this.customStatsFunction();
             }
             }
         }
         }
     }
     }

+ 7 - 0
src/Math/babylon.math.js

@@ -2038,6 +2038,13 @@ var BABYLON;
             Matrix.FromValuesToRef(1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, x, y, z, 1.0, result);
             Matrix.FromValuesToRef(1.0, 0, 0, 0, 0, 1.0, 0, 0, 0, 0, 1.0, 0, x, y, z, 1.0, result);
         };
         };
         Matrix.Lerp = function (startValue, endValue, gradient) {
         Matrix.Lerp = function (startValue, endValue, gradient) {
+            var result = Matrix.Zero();
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = startValue.m[index] * gradient + endValue.m[index] * (1.0 - gradient);
+            }
+            return result;
+        };
+        Matrix.DecomposeLerp = function (startValue, endValue, gradient) {
             var startScale = new Vector3(0, 0, 0);
             var startScale = new Vector3(0, 0, 0);
             var startRotation = new Quaternion();
             var startRotation = new Quaternion();
             var startTranslation = new Vector3(0, 0, 0);
             var startTranslation = new Vector3(0, 0, 0);

+ 10 - 0
src/Math/babylon.math.ts

@@ -2549,6 +2549,16 @@
         }
         }
 
 
         public static Lerp(startValue: Matrix, endValue: Matrix, gradient: number): Matrix {
         public static Lerp(startValue: Matrix, endValue: Matrix, gradient: number): Matrix {
+            var result = Matrix.Zero();
+
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = startValue.m[index] * gradient + endValue.m[index] * (1.0 - gradient);
+            }
+
+            return result;
+        }
+
+        public static DecomposeLerp(startValue: Matrix, endValue: Matrix, gradient: number): Matrix {
             var startScale = new Vector3(0, 0, 0);
             var startScale = new Vector3(0, 0, 0);
             var startRotation = new Quaternion();
             var startRotation = new Quaternion();
             var startTranslation = new Vector3(0, 0, 0);
             var startTranslation = new Vector3(0, 0, 0);

+ 2 - 2
src/Mesh/babylon.mesh.ts

@@ -2158,7 +2158,7 @@
          * Detail here : http://doc.babylonjs.com/tutorials/02._Discover_Basic_Elements#side-orientation    
          * Detail here : http://doc.babylonjs.com/tutorials/02._Discover_Basic_Elements#side-orientation    
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.  
          */
          */
-        public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction, rotationFunction, ribbonCloseArray: boolean, ribbonClosePath: boolean, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh {
+        public static ExtrudeShapeCustom(name: string, shape: Vector3[], path: Vector3[], scaleFunction: Function, rotationFunction: Function, ribbonCloseArray: boolean, ribbonClosePath: boolean, cap: number, scene: Scene, updatable?: boolean, sideOrientation?: number, instance?: Mesh): Mesh {
             var options = {
             var options = {
                 shape: shape,
                 shape: shape,
                 path: path,
                 path: path,
@@ -2609,4 +2609,4 @@
             return meshSubclass;
             return meshSubclass;
         }
         }
     }
     }
-}
+}

+ 9 - 2
src/PostProcess/babylon.anaglyphPostProcess.ts

@@ -1,7 +1,14 @@
 module BABYLON {
 module BABYLON {
     export class AnaglyphPostProcess extends PostProcess {
     export class AnaglyphPostProcess extends PostProcess {
-        constructor(name: string, ratio: number, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
-            super(name, "anaglyph", null, ["leftSampler"], ratio, camera, samplingMode, engine, reusable);
+        private _passedProcess : PostProcess;
+
+        constructor(name: string, ratio: number,  rigCameras: Camera[], samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "anaglyph", null, ["leftSampler"], ratio, rigCameras[1], samplingMode, engine, reusable);
+            this._passedProcess = rigCameras[0]._rigPostProcess;
+
+            this.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("leftSampler", this._passedProcess);
+            };
         }
         }
     }
     }
 } 
 } 

+ 11 - 6
src/PostProcess/babylon.postProcess.ts

@@ -56,7 +56,7 @@
 
 
             this.updateEffect(defines);
             this.updateEffect(defines);
         }
         }
-
+        
         public updateEffect(defines?: string) {
         public updateEffect(defines?: string) {
             this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: this._fragmentUrl },
             this._effect = this._engine.createEffect({ vertex: "postprocess", fragment: this._fragmentUrl },
                 ["position"],
                 ["position"],
@@ -67,6 +67,11 @@
         public isReusable(): boolean {
         public isReusable(): boolean {
             return this._reusable;
             return this._reusable;
         }
         }
+        
+        /** invalidate frameBuffer to hint the postprocess to create a depth buffer */
+        public markTextureDirty() : void{
+            this.width = -1;
+        }
 
 
         public activate(camera: Camera, sourceTexture?: WebGLTexture): void {
         public activate(camera: Camera, sourceTexture?: WebGLTexture): void {
             camera = camera || this._camera;
             camera = camera || this._camera;
@@ -96,13 +101,13 @@
                         this._engine._releaseTexture(this._textures.data[i]);
                         this._engine._releaseTexture(this._textures.data[i]);
                     }
                     }
                     this._textures.reset();
                     this._textures.reset();
-                }
+                }         
                 this.width = desiredWidth;
                 this.width = desiredWidth;
                 this.height = desiredHeight;
                 this.height = desiredHeight;
-                this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
+                this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === 0, samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
 
 
                 if (this._reusable) {
                 if (this._reusable) {
-                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === camera._postProcessesTakenIndices[0], samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
+                    this._textures.push(this._engine.createRenderTargetTexture({ width: this.width, height: this.height }, { generateMipMaps: false, generateDepthBuffer: camera._postProcesses.indexOf(this) === 0, samplingMode: this.renderTargetSamplingMode, type: this._textureType }));
                 }
                 }
 
 
                 if (this.onSizeChanged) {
                 if (this.onSizeChanged) {
@@ -179,8 +184,8 @@
             camera.detachPostProcess(this);
             camera.detachPostProcess(this);
 
 
             var index = camera._postProcesses.indexOf(this);
             var index = camera._postProcesses.indexOf(this);
-            if (index === camera._postProcessesTakenIndices[0] && camera._postProcessesTakenIndices.length > 0) {
-                this._camera._postProcesses[camera._postProcessesTakenIndices[0]].width = -1; // invalidate frameBuffer to hint the postprocess to create a depth buffer
+            if (index === 0 && camera._postProcesses.length > 0) {
+                this._camera._postProcesses[0].markTextureDirty(); 
             }
             }
         }
         }
     }
     }

+ 7 - 10
src/PostProcess/babylon.postProcessManager.ts

@@ -39,14 +39,12 @@
         // Methods
         // Methods
         public _prepareFrame(sourceTexture?: WebGLTexture): boolean {
         public _prepareFrame(sourceTexture?: WebGLTexture): boolean {
             var postProcesses = this._scene.activeCamera._postProcesses;
             var postProcesses = this._scene.activeCamera._postProcesses;
-            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
 
 
-            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
+            if (postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
                 return false;
                 return false;
             }
             }
 
 
-            postProcesses[this._scene.activeCamera._postProcessesTakenIndices[0]].activate(this._scene.activeCamera, sourceTexture);
-
+            postProcesses[0].activate(this._scene.activeCamera, sourceTexture);
             return true;
             return true;
         }
         }
 
 
@@ -92,15 +90,14 @@
 
 
         public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture, faceIndex?: number, postProcesses?: PostProcess[]): void {
         public _finalizeFrame(doNotPresent?: boolean, targetTexture?: WebGLTexture, faceIndex?: number, postProcesses?: PostProcess[]): void {
             postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
             postProcesses = postProcesses || this._scene.activeCamera._postProcesses;
-            var postProcessesTakenIndices = this._scene.activeCamera._postProcessesTakenIndices;
-            if (postProcessesTakenIndices.length === 0 || !this._scene.postProcessesEnabled) {
+            if (postProcesses.length === 0 || !this._scene.postProcessesEnabled) {
                 return;
                 return;
             }
             }
             var engine = this._scene.getEngine();
             var engine = this._scene.getEngine();
 
 
-            for (var index = 0; index < postProcessesTakenIndices.length; index++) {
-                if (index < postProcessesTakenIndices.length - 1) {
-                    postProcesses[postProcessesTakenIndices[index + 1]].activate(this._scene.activeCamera, targetTexture);
+            for (var index = 0, len = postProcesses.length; index < len; index++) {
+                if (index < len - 1) {
+                    postProcesses[index + 1].activate(this._scene.activeCamera, targetTexture);
                 } else {
                 } else {
                     if (targetTexture) {
                     if (targetTexture) {
                         engine.bindFramebuffer(targetTexture, faceIndex);
                         engine.bindFramebuffer(targetTexture, faceIndex);
@@ -113,7 +110,7 @@
                     break;
                     break;
                 }
                 }
 
 
-                var pp = postProcesses[postProcessesTakenIndices[index]];
+                var pp = postProcesses[index];
                 var effect = pp.apply();
                 var effect = pp.apply();
 
 
                 if (effect) {
                 if (effect) {

+ 5 - 3
src/PostProcess/babylon.stereoscopicInterlacePostProcess.ts

@@ -1,17 +1,19 @@
 module BABYLON {
 module BABYLON {
     export class StereoscopicInterlacePostProcess extends PostProcess {
     export class StereoscopicInterlacePostProcess extends PostProcess {
         private _stepSize : Vector2;
         private _stepSize : Vector2;
+        private _passedProcess : PostProcess;
 
 
-        constructor(name: string, camB: Camera, postProcessA : PostProcess, isStereoscopicHoriz: boolean, samplingMode?: number) {
-            super(name, "stereoscopicInterlace", ['stepSize'], ['camASampler'], 1, camB, samplingMode, camB.getScene().getEngine(), false, isStereoscopicHoriz ? "#define IS_STEREOSCOPIC_HORIZ 1" : undefined);
+        constructor(name: string, rigCameras: Camera[], isStereoscopicHoriz: boolean, samplingMode?: number, engine?: Engine, reusable?: boolean) {
+            super(name, "stereoscopicInterlace", ['stepSize'], ['camASampler'], 1, rigCameras[1], samplingMode, engine, reusable, isStereoscopicHoriz ? "#define IS_STEREOSCOPIC_HORIZ 1" : undefined);
             
             
+            this._passedProcess = rigCameras[0]._rigPostProcess;
             this._stepSize = new Vector2(1 / this.width, 1 / this.height);
             this._stepSize = new Vector2(1 / this.width, 1 / this.height);
 
 
             this.onSizeChanged = () => {
             this.onSizeChanged = () => {
                 this._stepSize = new Vector2(1 / this.width, 1 / this.height);
                 this._stepSize = new Vector2(1 / this.width, 1 / this.height);
             };
             };
             this.onApply = (effect: Effect) => {
             this.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("camASampler", postProcessA);
+                effect.setTextureFromPostProcess("camASampler", this._passedProcess);
                 effect.setFloat2("stepSize", this._stepSize.x, this._stepSize.y);
                 effect.setFloat2("stepSize", this._stepSize.x, this._stepSize.y);
             };
             };
         }
         }