Procházet zdrojové kódy

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 před 7 roky
rodič
revize
6ee7cd3313
37 změnil soubory, kde provedl 975782 přidání a 42799 odebrání
  1. 13681 13529
      Playground/babylon.d.txt
  2. 930590 0
      Playground/scenes/dummy.babylon
  3. 14381 14228
      dist/preview release/babylon.d.ts
  4. 52 52
      dist/preview release/babylon.js
  5. 440 102
      dist/preview release/babylon.max.js
  6. 53 53
      dist/preview release/babylon.worker.js
  7. 14187 14034
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  8. 54 54
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  9. 440 102
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  10. 440 102
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  11. 440 102
      dist/preview release/es6.js
  12. 3 3
      dist/preview release/gui/babylon.gui.min.js
  13. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  14. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  15. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  16. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  17. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  18. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  19. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  20. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  21. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  22. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  23. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  24. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  25. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  26. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  27. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  28. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  29. 2 119
      dist/preview release/typedocValidationBaseline.json
  30. 68 67
      dist/preview release/viewer/babylon.viewer.js
  31. 440 102
      dist/preview release/viewer/babylon.viewer.max.js
  32. 13 11
      dist/preview release/what's new.md
  33. 24 2
      src/Animations/babylon.animatable.ts
  34. 111 22
      src/Animations/babylon.runtimeAnimation.ts
  35. 3 3
      src/Engine/babylon.engine.ts
  36. 221 69
      src/Math/babylon.math.ts
  37. 110 14
      src/babylon.scene.ts

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 13681 - 13529
Playground/babylon.d.txt


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 930590 - 0
Playground/scenes/dummy.babylon


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 14381 - 14228
dist/preview release/babylon.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 52 - 52
dist/preview release/babylon.js


+ 440 - 102
dist/preview release/babylon.max.js

@@ -1572,7 +1572,7 @@ var BABYLON;
         /**
          * Multiplies in place each rgb value by scale
          * @param scale defines the scaling factor
-         * @returns the updated Color3.
+         * @returns the updated Color3
          */
         Color3.prototype.scale = function (scale) {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -1581,7 +1581,7 @@ var BABYLON;
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.
+         * @returns the unmodified current Color3
          */
         Color3.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1590,6 +1590,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3
+         */
+        Color3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1957,7 +1969,7 @@ var BABYLON;
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.
+         * @returns the current unmodified Color4
          */
         Color4.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1967,6 +1979,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4
+         */
+        Color4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2410,7 +2435,31 @@ var BABYLON;
          * Returns a new Vector2 scaled by "scale" from the current Vector2.
          */
         Vector2.prototype.scale = function (scale) {
-            return new Vector2(this.x * scale, this.y * scale);
+            var result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        };
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
         };
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.
@@ -2850,6 +2899,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3
+         */
+        Vector3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        };
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -3794,6 +3855,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4
+         */
+        Vector4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.
          */
         Vector4.prototype.equals = function (otherVector) {
@@ -4320,6 +4394,32 @@ var BABYLON;
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };
         /**
+         * Scale the current Quaternion values by a factor to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        };
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".
          */
         Quaternion.prototype.multiply = function (q1) {
@@ -5066,6 +5166,99 @@ var BABYLON;
             return true;
         };
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.
+         */
+        Matrix.prototype.getRow = function (index) {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRow = function (index, row) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns a new Matrix.
+         */
+        Matrix.prototype.transpose = function () {
+            return Matrix.Transpose(this);
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns the current matrix.
+         */
+        Matrix.prototype.transposeToRef = function (result) {
+            Matrix.TransposeToRef(this, result);
+            return this;
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        Matrix.prototype.scale = function (scale) {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleAndAddToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).
          * @param ref matrix to store the result
          */
@@ -5150,63 +5343,6 @@ var BABYLON;
             result.m[15] = initialM44;
             result._markAsUpdated();
         };
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.
-         */
-        Matrix.prototype.getRow = function (index) {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRow = function (index, row) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-            this._markAsUpdated();
-            return this;
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns a new Matrix.
-         */
-        Matrix.prototype.transpose = function () {
-            return Matrix.Transpose(this);
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns the current matrix.
-         */
-        Matrix.prototype.transposeToRef = function (result) {
-            Matrix.TransposeToRef(this, result);
-            return this;
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-            this._markAsUpdated();
-            return this;
-        };
         Object.defineProperty(Matrix, "IdentityReadOnly", {
             /**
              * Static identity matrix to be used as readonly matrix
@@ -12499,7 +12635,7 @@ var BABYLON;
             this.applyStates();
             this._drawCalls.addCount(1, false);
             // Render
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -12513,7 +12649,7 @@ var BABYLON;
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             }
@@ -12521,7 +12657,7 @@ var BABYLON;
                 this._gl.drawArrays(drawMode, verticesStart, verticesCount);
             }
         };
-        Engine.prototype.DrawMode = function (fillMode) {
+        Engine.prototype._drawMode = function (fillMode) {
             switch (fillMode) {
                 // Triangle views
                 case BABYLON.Material.TriangleFillMode:
@@ -21648,6 +21784,7 @@ var BABYLON;
             this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             this.animations = [];
+            this._registeredForLateAnimationBindings = new BABYLON.SmartArrayNoDuplicate(256);
             /**
              * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).
              * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
@@ -23168,22 +23305,46 @@ var BABYLON;
         // Animations
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
-         */
-        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) {
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginWeightedAnimation = function (target, from, to, weight, loop, speedRatio, onAnimationEnd, animatable) {
+            if (weight === void 0) { weight = 1.0; }
             if (speedRatio === void 0) { speedRatio = 1.0; }
+            var returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+            return returnedAnimatable;
+        };
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent) {
+            if (speedRatio === void 0) { speedRatio = 1.0; }
+            if (stopCurrent === void 0) { stopCurrent = true; }
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
             if (!animatable) {
                 animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
             }
@@ -23195,10 +23356,12 @@ var BABYLON;
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
             return animatable;
         };
         /**
@@ -23296,6 +23459,62 @@ var BABYLON;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        };
+        /** @ignore */
+        Scene.prototype._registerTargetForLateAnimationBinding = function (runtimeAnimation) {
+            var target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};
+            }
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                };
+            }
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        };
+        Scene.prototype._processLateAnimationBindings = function () {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+                    var normalizer = 1.0;
+                    var finalValue = void 0;
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        var originalValue = holder.animations[0].originalValue;
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                    }
+                    else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        }
+                        else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+                    runtimeAnimation.target[path] = finalValue;
+                }
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         };
         // Matrix
         Scene.prototype._switchToAlternateCameraConfiguration = function (active) {
@@ -24925,6 +25144,7 @@ var BABYLON;
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();
             }
@@ -47568,16 +47788,74 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var RuntimeAnimation = /** @class */ (function () {
-        function RuntimeAnimation(target, animation) {
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        function RuntimeAnimation(target, animation, scene) {
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
             this._blendingFactor = 0;
+            this._weight = 1.0;
             this._ratioOffset = 0;
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
             animation._runtimeAnimations.push(this);
         }
+        Object.defineProperty(RuntimeAnimation.prototype, "weight", {
+            /**
+             * Gets the weight of the runtime animation
+             */
+            get: function () {
+                return this._weight;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "originalValue", {
+            /**
+             * Gets the original value of the runtime animation
+             */
+            get: function () {
+                return this._originalValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "currentValue", {
+            /**
+             * Gets the current value of the runtime animation
+             */
+            get: function () {
+                return this._currentValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "targetPath", {
+            /**
+             * Gets the path where to store the animated value in the target
+             */
+            get: function () {
+                return this._targetPath;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "target", {
+            /**
+             * Gets the actual target of the runtime animation
+             */
+            get: function () {
+                return this._activeTarget;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RuntimeAnimation.prototype, "animation", {
             get: function () {
                 return this._animation;
@@ -47590,7 +47868,7 @@ var BABYLON;
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         };
         RuntimeAnimation.prototype.isStopped = function () {
             return this._stopped;
@@ -47718,8 +47996,13 @@ var BABYLON;
             }
             return this._getKeyValue(keys[keys.length - 1].value);
         };
-        RuntimeAnimation.prototype.setValue = function (currentValue, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        RuntimeAnimation.prototype.setValue = function (currentValue, weight) {
+            if (weight === void 0) { weight = 1.0; }
             // Set value
             var path;
             var destination;
@@ -47729,43 +48012,62 @@ var BABYLON;
                 for (var index = 1; index < targetPropertyPath.length - 1; index++) {
                     property = property[targetPropertyPath[index]];
                 }
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path = [targetPropertyPath.length - 1];
                 destination = property;
             }
             else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
             // Blending
             var enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             var blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    var originalValue = void 0;
+                    if (destination.getRestPose) {
+                        originalValue = destination.getRestPose();
                     }
                     else {
-                        this._originalBlendValue = destination[path];
+                        originalValue = destination[path];
+                    }
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
+                    }
+                    else {
+                        this._originalValue = originalValue;
                     }
                 }
-                if (this._originalBlendValue.prototype) {
-                    if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+            }
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) {
+                    if (this._originalValue.prototype.Lerp) {
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     }
                     else {
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
                 }
-                else if (this._originalBlendValue.m) {
-                    destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                else if (this._originalValue.m) {
+                    this._currentValue = BABYLON.Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 }
                 else {
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                destination[path] = this._currentValue;
             }
             else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                }
+                else {
+                    destination[path] = this._currentValue;
+                }
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this._animation.targetProperty);
@@ -47777,6 +48079,10 @@ var BABYLON;
             }
             return this._animation.loopMode;
         };
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         RuntimeAnimation.prototype.goToFrame = function (frame) {
             var keys = this._animation.getKeys();
             if (frame < keys[0].frame) {
@@ -47786,14 +48092,24 @@ var BABYLON;
                 frame = keys[keys.length - 1].frame;
             }
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         };
         RuntimeAnimation.prototype._prepareForSpeedRatioChange = function (newSpeedRatio) {
             var newRatio = this._previousDelay * (this._animation.framePerSecond * newSpeedRatio) / 1000.0;
             this._ratioOffset = this._previousRatio - newRatio;
         };
-        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, weight) {
+            if (weight === void 0) { weight = -1.0; }
             var targetPropertyPath = this._animation.targetPropertyPath;
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -47903,7 +48219,7 @@ var BABYLON;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
             // Check events
             var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
@@ -47957,6 +48273,7 @@ var BABYLON;
             this._runtimeAnimations = new Array();
             this._paused = false;
             this._speedRatio = 1;
+            this._weight = -1.0;
             this.animationStarted = false;
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -47965,7 +48282,28 @@ var BABYLON;
             this._scene = scene;
             scene._activeAnimatables.push(this);
         }
+        Object.defineProperty(Animatable.prototype, "weight", {
+            /**
+             * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+             */
+            get: function () {
+                return this._weight;
+            },
+            set: function (value) {
+                if (value === -1) {
+                    this._weight = -1;
+                    return;
+                }
+                // Else weight must be in [0, 1] range
+                this._weight = Math.min(Math.max(value, 0), 1.0);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animatable.prototype, "speedRatio", {
+            /**
+             * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+             */
             get: function () {
                 return this._speedRatio;
             },
@@ -47986,7 +48324,7 @@ var BABYLON;
         Animatable.prototype.appendAnimations = function (target, animations) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
-                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation, this._scene));
             }
         };
         Animatable.prototype.getAnimationByTargetProperty = function (property) {
@@ -48114,7 +48452,7 @@ var BABYLON;
             var index;
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
             this.animationStarted = running;

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 53 - 53
dist/preview release/babylon.worker.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 14187 - 14034
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 54 - 54
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 440 - 102
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -1572,7 +1572,7 @@ var BABYLON;
         /**
          * Multiplies in place each rgb value by scale
          * @param scale defines the scaling factor
-         * @returns the updated Color3.
+         * @returns the updated Color3
          */
         Color3.prototype.scale = function (scale) {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -1581,7 +1581,7 @@ var BABYLON;
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.
+         * @returns the unmodified current Color3
          */
         Color3.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1590,6 +1590,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3
+         */
+        Color3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1957,7 +1969,7 @@ var BABYLON;
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.
+         * @returns the current unmodified Color4
          */
         Color4.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1967,6 +1979,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4
+         */
+        Color4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2410,7 +2435,31 @@ var BABYLON;
          * Returns a new Vector2 scaled by "scale" from the current Vector2.
          */
         Vector2.prototype.scale = function (scale) {
-            return new Vector2(this.x * scale, this.y * scale);
+            var result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        };
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
         };
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.
@@ -2850,6 +2899,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3
+         */
+        Vector3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        };
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -3794,6 +3855,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4
+         */
+        Vector4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.
          */
         Vector4.prototype.equals = function (otherVector) {
@@ -4320,6 +4394,32 @@ var BABYLON;
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };
         /**
+         * Scale the current Quaternion values by a factor to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        };
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".
          */
         Quaternion.prototype.multiply = function (q1) {
@@ -5066,6 +5166,99 @@ var BABYLON;
             return true;
         };
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.
+         */
+        Matrix.prototype.getRow = function (index) {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRow = function (index, row) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns a new Matrix.
+         */
+        Matrix.prototype.transpose = function () {
+            return Matrix.Transpose(this);
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns the current matrix.
+         */
+        Matrix.prototype.transposeToRef = function (result) {
+            Matrix.TransposeToRef(this, result);
+            return this;
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        Matrix.prototype.scale = function (scale) {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleAndAddToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).
          * @param ref matrix to store the result
          */
@@ -5150,63 +5343,6 @@ var BABYLON;
             result.m[15] = initialM44;
             result._markAsUpdated();
         };
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.
-         */
-        Matrix.prototype.getRow = function (index) {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRow = function (index, row) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-            this._markAsUpdated();
-            return this;
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns a new Matrix.
-         */
-        Matrix.prototype.transpose = function () {
-            return Matrix.Transpose(this);
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns the current matrix.
-         */
-        Matrix.prototype.transposeToRef = function (result) {
-            Matrix.TransposeToRef(this, result);
-            return this;
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-            this._markAsUpdated();
-            return this;
-        };
         Object.defineProperty(Matrix, "IdentityReadOnly", {
             /**
              * Static identity matrix to be used as readonly matrix
@@ -12499,7 +12635,7 @@ var BABYLON;
             this.applyStates();
             this._drawCalls.addCount(1, false);
             // Render
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -12513,7 +12649,7 @@ var BABYLON;
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             }
@@ -12521,7 +12657,7 @@ var BABYLON;
                 this._gl.drawArrays(drawMode, verticesStart, verticesCount);
             }
         };
-        Engine.prototype.DrawMode = function (fillMode) {
+        Engine.prototype._drawMode = function (fillMode) {
             switch (fillMode) {
                 // Triangle views
                 case BABYLON.Material.TriangleFillMode:
@@ -21648,6 +21784,7 @@ var BABYLON;
             this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             this.animations = [];
+            this._registeredForLateAnimationBindings = new BABYLON.SmartArrayNoDuplicate(256);
             /**
              * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).
              * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
@@ -23168,22 +23305,46 @@ var BABYLON;
         // Animations
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
-         */
-        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) {
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginWeightedAnimation = function (target, from, to, weight, loop, speedRatio, onAnimationEnd, animatable) {
+            if (weight === void 0) { weight = 1.0; }
             if (speedRatio === void 0) { speedRatio = 1.0; }
+            var returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+            return returnedAnimatable;
+        };
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent) {
+            if (speedRatio === void 0) { speedRatio = 1.0; }
+            if (stopCurrent === void 0) { stopCurrent = true; }
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
             if (!animatable) {
                 animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
             }
@@ -23195,10 +23356,12 @@ var BABYLON;
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
             return animatable;
         };
         /**
@@ -23296,6 +23459,62 @@ var BABYLON;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        };
+        /** @ignore */
+        Scene.prototype._registerTargetForLateAnimationBinding = function (runtimeAnimation) {
+            var target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};
+            }
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                };
+            }
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        };
+        Scene.prototype._processLateAnimationBindings = function () {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+                    var normalizer = 1.0;
+                    var finalValue = void 0;
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        var originalValue = holder.animations[0].originalValue;
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                    }
+                    else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        }
+                        else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+                    runtimeAnimation.target[path] = finalValue;
+                }
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         };
         // Matrix
         Scene.prototype._switchToAlternateCameraConfiguration = function (active) {
@@ -24925,6 +25144,7 @@ var BABYLON;
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();
             }
@@ -47568,16 +47788,74 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var RuntimeAnimation = /** @class */ (function () {
-        function RuntimeAnimation(target, animation) {
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        function RuntimeAnimation(target, animation, scene) {
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
             this._blendingFactor = 0;
+            this._weight = 1.0;
             this._ratioOffset = 0;
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
             animation._runtimeAnimations.push(this);
         }
+        Object.defineProperty(RuntimeAnimation.prototype, "weight", {
+            /**
+             * Gets the weight of the runtime animation
+             */
+            get: function () {
+                return this._weight;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "originalValue", {
+            /**
+             * Gets the original value of the runtime animation
+             */
+            get: function () {
+                return this._originalValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "currentValue", {
+            /**
+             * Gets the current value of the runtime animation
+             */
+            get: function () {
+                return this._currentValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "targetPath", {
+            /**
+             * Gets the path where to store the animated value in the target
+             */
+            get: function () {
+                return this._targetPath;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "target", {
+            /**
+             * Gets the actual target of the runtime animation
+             */
+            get: function () {
+                return this._activeTarget;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RuntimeAnimation.prototype, "animation", {
             get: function () {
                 return this._animation;
@@ -47590,7 +47868,7 @@ var BABYLON;
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         };
         RuntimeAnimation.prototype.isStopped = function () {
             return this._stopped;
@@ -47718,8 +47996,13 @@ var BABYLON;
             }
             return this._getKeyValue(keys[keys.length - 1].value);
         };
-        RuntimeAnimation.prototype.setValue = function (currentValue, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        RuntimeAnimation.prototype.setValue = function (currentValue, weight) {
+            if (weight === void 0) { weight = 1.0; }
             // Set value
             var path;
             var destination;
@@ -47729,43 +48012,62 @@ var BABYLON;
                 for (var index = 1; index < targetPropertyPath.length - 1; index++) {
                     property = property[targetPropertyPath[index]];
                 }
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path = [targetPropertyPath.length - 1];
                 destination = property;
             }
             else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
             // Blending
             var enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             var blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    var originalValue = void 0;
+                    if (destination.getRestPose) {
+                        originalValue = destination.getRestPose();
                     }
                     else {
-                        this._originalBlendValue = destination[path];
+                        originalValue = destination[path];
+                    }
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
+                    }
+                    else {
+                        this._originalValue = originalValue;
                     }
                 }
-                if (this._originalBlendValue.prototype) {
-                    if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+            }
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) {
+                    if (this._originalValue.prototype.Lerp) {
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     }
                     else {
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
                 }
-                else if (this._originalBlendValue.m) {
-                    destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                else if (this._originalValue.m) {
+                    this._currentValue = BABYLON.Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 }
                 else {
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                destination[path] = this._currentValue;
             }
             else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                }
+                else {
+                    destination[path] = this._currentValue;
+                }
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this._animation.targetProperty);
@@ -47777,6 +48079,10 @@ var BABYLON;
             }
             return this._animation.loopMode;
         };
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         RuntimeAnimation.prototype.goToFrame = function (frame) {
             var keys = this._animation.getKeys();
             if (frame < keys[0].frame) {
@@ -47786,14 +48092,24 @@ var BABYLON;
                 frame = keys[keys.length - 1].frame;
             }
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         };
         RuntimeAnimation.prototype._prepareForSpeedRatioChange = function (newSpeedRatio) {
             var newRatio = this._previousDelay * (this._animation.framePerSecond * newSpeedRatio) / 1000.0;
             this._ratioOffset = this._previousRatio - newRatio;
         };
-        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, weight) {
+            if (weight === void 0) { weight = -1.0; }
             var targetPropertyPath = this._animation.targetPropertyPath;
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -47903,7 +48219,7 @@ var BABYLON;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
             // Check events
             var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
@@ -47957,6 +48273,7 @@ var BABYLON;
             this._runtimeAnimations = new Array();
             this._paused = false;
             this._speedRatio = 1;
+            this._weight = -1.0;
             this.animationStarted = false;
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -47965,7 +48282,28 @@ var BABYLON;
             this._scene = scene;
             scene._activeAnimatables.push(this);
         }
+        Object.defineProperty(Animatable.prototype, "weight", {
+            /**
+             * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+             */
+            get: function () {
+                return this._weight;
+            },
+            set: function (value) {
+                if (value === -1) {
+                    this._weight = -1;
+                    return;
+                }
+                // Else weight must be in [0, 1] range
+                this._weight = Math.min(Math.max(value, 0), 1.0);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animatable.prototype, "speedRatio", {
+            /**
+             * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+             */
             get: function () {
                 return this._speedRatio;
             },
@@ -47986,7 +48324,7 @@ var BABYLON;
         Animatable.prototype.appendAnimations = function (target, animations) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
-                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation, this._scene));
             }
         };
         Animatable.prototype.getAnimationByTargetProperty = function (property) {
@@ -48114,7 +48452,7 @@ var BABYLON;
             var index;
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
             this.animationStarted = running;

+ 440 - 102
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js

@@ -1545,7 +1545,7 @@ var BABYLON;
         /**
          * Multiplies in place each rgb value by scale
          * @param scale defines the scaling factor
-         * @returns the updated Color3.
+         * @returns the updated Color3
          */
         Color3.prototype.scale = function (scale) {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -1554,7 +1554,7 @@ var BABYLON;
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.
+         * @returns the unmodified current Color3
          */
         Color3.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1563,6 +1563,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3
+         */
+        Color3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1930,7 +1942,7 @@ var BABYLON;
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.
+         * @returns the current unmodified Color4
          */
         Color4.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1940,6 +1952,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4
+         */
+        Color4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2383,7 +2408,31 @@ var BABYLON;
          * Returns a new Vector2 scaled by "scale" from the current Vector2.
          */
         Vector2.prototype.scale = function (scale) {
-            return new Vector2(this.x * scale, this.y * scale);
+            var result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        };
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
         };
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.
@@ -2823,6 +2872,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3
+         */
+        Vector3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        };
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -3767,6 +3828,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4
+         */
+        Vector4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.
          */
         Vector4.prototype.equals = function (otherVector) {
@@ -4293,6 +4367,32 @@ var BABYLON;
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };
         /**
+         * Scale the current Quaternion values by a factor to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        };
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".
          */
         Quaternion.prototype.multiply = function (q1) {
@@ -5039,6 +5139,99 @@ var BABYLON;
             return true;
         };
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.
+         */
+        Matrix.prototype.getRow = function (index) {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRow = function (index, row) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns a new Matrix.
+         */
+        Matrix.prototype.transpose = function () {
+            return Matrix.Transpose(this);
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns the current matrix.
+         */
+        Matrix.prototype.transposeToRef = function (result) {
+            Matrix.TransposeToRef(this, result);
+            return this;
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        Matrix.prototype.scale = function (scale) {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleAndAddToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).
          * @param ref matrix to store the result
          */
@@ -5123,63 +5316,6 @@ var BABYLON;
             result.m[15] = initialM44;
             result._markAsUpdated();
         };
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.
-         */
-        Matrix.prototype.getRow = function (index) {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRow = function (index, row) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-            this._markAsUpdated();
-            return this;
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns a new Matrix.
-         */
-        Matrix.prototype.transpose = function () {
-            return Matrix.Transpose(this);
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns the current matrix.
-         */
-        Matrix.prototype.transposeToRef = function (result) {
-            Matrix.TransposeToRef(this, result);
-            return this;
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-            this._markAsUpdated();
-            return this;
-        };
         Object.defineProperty(Matrix, "IdentityReadOnly", {
             /**
              * Static identity matrix to be used as readonly matrix
@@ -12472,7 +12608,7 @@ var BABYLON;
             this.applyStates();
             this._drawCalls.addCount(1, false);
             // Render
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -12486,7 +12622,7 @@ var BABYLON;
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             }
@@ -12494,7 +12630,7 @@ var BABYLON;
                 this._gl.drawArrays(drawMode, verticesStart, verticesCount);
             }
         };
-        Engine.prototype.DrawMode = function (fillMode) {
+        Engine.prototype._drawMode = function (fillMode) {
             switch (fillMode) {
                 // Triangle views
                 case BABYLON.Material.TriangleFillMode:
@@ -21621,6 +21757,7 @@ var BABYLON;
             this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             this.animations = [];
+            this._registeredForLateAnimationBindings = new BABYLON.SmartArrayNoDuplicate(256);
             /**
              * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).
              * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
@@ -23141,22 +23278,46 @@ var BABYLON;
         // Animations
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
-         */
-        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) {
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginWeightedAnimation = function (target, from, to, weight, loop, speedRatio, onAnimationEnd, animatable) {
+            if (weight === void 0) { weight = 1.0; }
             if (speedRatio === void 0) { speedRatio = 1.0; }
+            var returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+            return returnedAnimatable;
+        };
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent) {
+            if (speedRatio === void 0) { speedRatio = 1.0; }
+            if (stopCurrent === void 0) { stopCurrent = true; }
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
             if (!animatable) {
                 animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
             }
@@ -23168,10 +23329,12 @@ var BABYLON;
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
             return animatable;
         };
         /**
@@ -23269,6 +23432,62 @@ var BABYLON;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        };
+        /** @ignore */
+        Scene.prototype._registerTargetForLateAnimationBinding = function (runtimeAnimation) {
+            var target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};
+            }
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                };
+            }
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        };
+        Scene.prototype._processLateAnimationBindings = function () {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+                    var normalizer = 1.0;
+                    var finalValue = void 0;
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        var originalValue = holder.animations[0].originalValue;
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                    }
+                    else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        }
+                        else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+                    runtimeAnimation.target[path] = finalValue;
+                }
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         };
         // Matrix
         Scene.prototype._switchToAlternateCameraConfiguration = function (active) {
@@ -24898,6 +25117,7 @@ var BABYLON;
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();
             }
@@ -47541,16 +47761,74 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var RuntimeAnimation = /** @class */ (function () {
-        function RuntimeAnimation(target, animation) {
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        function RuntimeAnimation(target, animation, scene) {
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
             this._blendingFactor = 0;
+            this._weight = 1.0;
             this._ratioOffset = 0;
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
             animation._runtimeAnimations.push(this);
         }
+        Object.defineProperty(RuntimeAnimation.prototype, "weight", {
+            /**
+             * Gets the weight of the runtime animation
+             */
+            get: function () {
+                return this._weight;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "originalValue", {
+            /**
+             * Gets the original value of the runtime animation
+             */
+            get: function () {
+                return this._originalValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "currentValue", {
+            /**
+             * Gets the current value of the runtime animation
+             */
+            get: function () {
+                return this._currentValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "targetPath", {
+            /**
+             * Gets the path where to store the animated value in the target
+             */
+            get: function () {
+                return this._targetPath;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "target", {
+            /**
+             * Gets the actual target of the runtime animation
+             */
+            get: function () {
+                return this._activeTarget;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RuntimeAnimation.prototype, "animation", {
             get: function () {
                 return this._animation;
@@ -47563,7 +47841,7 @@ var BABYLON;
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         };
         RuntimeAnimation.prototype.isStopped = function () {
             return this._stopped;
@@ -47691,8 +47969,13 @@ var BABYLON;
             }
             return this._getKeyValue(keys[keys.length - 1].value);
         };
-        RuntimeAnimation.prototype.setValue = function (currentValue, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        RuntimeAnimation.prototype.setValue = function (currentValue, weight) {
+            if (weight === void 0) { weight = 1.0; }
             // Set value
             var path;
             var destination;
@@ -47702,43 +47985,62 @@ var BABYLON;
                 for (var index = 1; index < targetPropertyPath.length - 1; index++) {
                     property = property[targetPropertyPath[index]];
                 }
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path = [targetPropertyPath.length - 1];
                 destination = property;
             }
             else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
             // Blending
             var enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             var blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    var originalValue = void 0;
+                    if (destination.getRestPose) {
+                        originalValue = destination.getRestPose();
                     }
                     else {
-                        this._originalBlendValue = destination[path];
+                        originalValue = destination[path];
+                    }
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
+                    }
+                    else {
+                        this._originalValue = originalValue;
                     }
                 }
-                if (this._originalBlendValue.prototype) {
-                    if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+            }
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) {
+                    if (this._originalValue.prototype.Lerp) {
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     }
                     else {
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
                 }
-                else if (this._originalBlendValue.m) {
-                    destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                else if (this._originalValue.m) {
+                    this._currentValue = BABYLON.Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 }
                 else {
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                destination[path] = this._currentValue;
             }
             else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                }
+                else {
+                    destination[path] = this._currentValue;
+                }
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this._animation.targetProperty);
@@ -47750,6 +48052,10 @@ var BABYLON;
             }
             return this._animation.loopMode;
         };
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         RuntimeAnimation.prototype.goToFrame = function (frame) {
             var keys = this._animation.getKeys();
             if (frame < keys[0].frame) {
@@ -47759,14 +48065,24 @@ var BABYLON;
                 frame = keys[keys.length - 1].frame;
             }
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         };
         RuntimeAnimation.prototype._prepareForSpeedRatioChange = function (newSpeedRatio) {
             var newRatio = this._previousDelay * (this._animation.framePerSecond * newSpeedRatio) / 1000.0;
             this._ratioOffset = this._previousRatio - newRatio;
         };
-        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, weight) {
+            if (weight === void 0) { weight = -1.0; }
             var targetPropertyPath = this._animation.targetPropertyPath;
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -47876,7 +48192,7 @@ var BABYLON;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
             // Check events
             var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
@@ -47930,6 +48246,7 @@ var BABYLON;
             this._runtimeAnimations = new Array();
             this._paused = false;
             this._speedRatio = 1;
+            this._weight = -1.0;
             this.animationStarted = false;
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -47938,7 +48255,28 @@ var BABYLON;
             this._scene = scene;
             scene._activeAnimatables.push(this);
         }
+        Object.defineProperty(Animatable.prototype, "weight", {
+            /**
+             * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+             */
+            get: function () {
+                return this._weight;
+            },
+            set: function (value) {
+                if (value === -1) {
+                    this._weight = -1;
+                    return;
+                }
+                // Else weight must be in [0, 1] range
+                this._weight = Math.min(Math.max(value, 0), 1.0);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animatable.prototype, "speedRatio", {
+            /**
+             * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+             */
             get: function () {
                 return this._speedRatio;
             },
@@ -47959,7 +48297,7 @@ var BABYLON;
         Animatable.prototype.appendAnimations = function (target, animations) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
-                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation, this._scene));
             }
         };
         Animatable.prototype.getAnimationByTargetProperty = function (property) {
@@ -48087,7 +48425,7 @@ var BABYLON;
             var index;
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
             this.animationStarted = running;

+ 440 - 102
dist/preview release/es6.js

@@ -1545,7 +1545,7 @@ var BABYLON;
         /**
          * Multiplies in place each rgb value by scale
          * @param scale defines the scaling factor
-         * @returns the updated Color3.
+         * @returns the updated Color3
          */
         Color3.prototype.scale = function (scale) {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -1554,7 +1554,7 @@ var BABYLON;
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.
+         * @returns the unmodified current Color3
          */
         Color3.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1563,6 +1563,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3
+         */
+        Color3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1930,7 +1942,7 @@ var BABYLON;
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.
+         * @returns the current unmodified Color4
          */
         Color4.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1940,6 +1952,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4
+         */
+        Color4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2383,7 +2408,31 @@ var BABYLON;
          * Returns a new Vector2 scaled by "scale" from the current Vector2.
          */
         Vector2.prototype.scale = function (scale) {
-            return new Vector2(this.x * scale, this.y * scale);
+            var result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        };
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
         };
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.
@@ -2823,6 +2872,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3
+         */
+        Vector3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        };
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -3767,6 +3828,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4
+         */
+        Vector4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.
          */
         Vector4.prototype.equals = function (otherVector) {
@@ -4293,6 +4367,32 @@ var BABYLON;
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };
         /**
+         * Scale the current Quaternion values by a factor to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        };
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".
          */
         Quaternion.prototype.multiply = function (q1) {
@@ -5039,6 +5139,99 @@ var BABYLON;
             return true;
         };
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.
+         */
+        Matrix.prototype.getRow = function (index) {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRow = function (index, row) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns a new Matrix.
+         */
+        Matrix.prototype.transpose = function () {
+            return Matrix.Transpose(this);
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns the current matrix.
+         */
+        Matrix.prototype.transposeToRef = function (result) {
+            Matrix.TransposeToRef(this, result);
+            return this;
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        Matrix.prototype.scale = function (scale) {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleAndAddToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).
          * @param ref matrix to store the result
          */
@@ -5123,63 +5316,6 @@ var BABYLON;
             result.m[15] = initialM44;
             result._markAsUpdated();
         };
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.
-         */
-        Matrix.prototype.getRow = function (index) {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRow = function (index, row) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-            this._markAsUpdated();
-            return this;
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns a new Matrix.
-         */
-        Matrix.prototype.transpose = function () {
-            return Matrix.Transpose(this);
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns the current matrix.
-         */
-        Matrix.prototype.transposeToRef = function (result) {
-            Matrix.TransposeToRef(this, result);
-            return this;
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-            this._markAsUpdated();
-            return this;
-        };
         Object.defineProperty(Matrix, "IdentityReadOnly", {
             /**
              * Static identity matrix to be used as readonly matrix
@@ -12472,7 +12608,7 @@ var BABYLON;
             this.applyStates();
             this._drawCalls.addCount(1, false);
             // Render
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -12486,7 +12622,7 @@ var BABYLON;
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             }
@@ -12494,7 +12630,7 @@ var BABYLON;
                 this._gl.drawArrays(drawMode, verticesStart, verticesCount);
             }
         };
-        Engine.prototype.DrawMode = function (fillMode) {
+        Engine.prototype._drawMode = function (fillMode) {
             switch (fillMode) {
                 // Triangle views
                 case BABYLON.Material.TriangleFillMode:
@@ -21621,6 +21757,7 @@ var BABYLON;
             this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             this.animations = [];
+            this._registeredForLateAnimationBindings = new BABYLON.SmartArrayNoDuplicate(256);
             /**
              * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).
              * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
@@ -23141,22 +23278,46 @@ var BABYLON;
         // Animations
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
-         */
-        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) {
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginWeightedAnimation = function (target, from, to, weight, loop, speedRatio, onAnimationEnd, animatable) {
+            if (weight === void 0) { weight = 1.0; }
             if (speedRatio === void 0) { speedRatio = 1.0; }
+            var returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+            return returnedAnimatable;
+        };
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent) {
+            if (speedRatio === void 0) { speedRatio = 1.0; }
+            if (stopCurrent === void 0) { stopCurrent = true; }
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
             if (!animatable) {
                 animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
             }
@@ -23168,10 +23329,12 @@ var BABYLON;
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
             return animatable;
         };
         /**
@@ -23269,6 +23432,62 @@ var BABYLON;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        };
+        /** @ignore */
+        Scene.prototype._registerTargetForLateAnimationBinding = function (runtimeAnimation) {
+            var target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};
+            }
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                };
+            }
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        };
+        Scene.prototype._processLateAnimationBindings = function () {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+                    var normalizer = 1.0;
+                    var finalValue = void 0;
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        var originalValue = holder.animations[0].originalValue;
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                    }
+                    else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        }
+                        else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+                    runtimeAnimation.target[path] = finalValue;
+                }
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         };
         // Matrix
         Scene.prototype._switchToAlternateCameraConfiguration = function (active) {
@@ -24898,6 +25117,7 @@ var BABYLON;
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();
             }
@@ -47541,16 +47761,74 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var RuntimeAnimation = /** @class */ (function () {
-        function RuntimeAnimation(target, animation) {
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        function RuntimeAnimation(target, animation, scene) {
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
             this._blendingFactor = 0;
+            this._weight = 1.0;
             this._ratioOffset = 0;
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
             animation._runtimeAnimations.push(this);
         }
+        Object.defineProperty(RuntimeAnimation.prototype, "weight", {
+            /**
+             * Gets the weight of the runtime animation
+             */
+            get: function () {
+                return this._weight;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "originalValue", {
+            /**
+             * Gets the original value of the runtime animation
+             */
+            get: function () {
+                return this._originalValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "currentValue", {
+            /**
+             * Gets the current value of the runtime animation
+             */
+            get: function () {
+                return this._currentValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "targetPath", {
+            /**
+             * Gets the path where to store the animated value in the target
+             */
+            get: function () {
+                return this._targetPath;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "target", {
+            /**
+             * Gets the actual target of the runtime animation
+             */
+            get: function () {
+                return this._activeTarget;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RuntimeAnimation.prototype, "animation", {
             get: function () {
                 return this._animation;
@@ -47563,7 +47841,7 @@ var BABYLON;
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         };
         RuntimeAnimation.prototype.isStopped = function () {
             return this._stopped;
@@ -47691,8 +47969,13 @@ var BABYLON;
             }
             return this._getKeyValue(keys[keys.length - 1].value);
         };
-        RuntimeAnimation.prototype.setValue = function (currentValue, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        RuntimeAnimation.prototype.setValue = function (currentValue, weight) {
+            if (weight === void 0) { weight = 1.0; }
             // Set value
             var path;
             var destination;
@@ -47702,43 +47985,62 @@ var BABYLON;
                 for (var index = 1; index < targetPropertyPath.length - 1; index++) {
                     property = property[targetPropertyPath[index]];
                 }
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path = [targetPropertyPath.length - 1];
                 destination = property;
             }
             else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
             // Blending
             var enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             var blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    var originalValue = void 0;
+                    if (destination.getRestPose) {
+                        originalValue = destination.getRestPose();
                     }
                     else {
-                        this._originalBlendValue = destination[path];
+                        originalValue = destination[path];
+                    }
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
+                    }
+                    else {
+                        this._originalValue = originalValue;
                     }
                 }
-                if (this._originalBlendValue.prototype) {
-                    if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+            }
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) {
+                    if (this._originalValue.prototype.Lerp) {
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     }
                     else {
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
                 }
-                else if (this._originalBlendValue.m) {
-                    destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                else if (this._originalValue.m) {
+                    this._currentValue = BABYLON.Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 }
                 else {
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                destination[path] = this._currentValue;
             }
             else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                }
+                else {
+                    destination[path] = this._currentValue;
+                }
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this._animation.targetProperty);
@@ -47750,6 +48052,10 @@ var BABYLON;
             }
             return this._animation.loopMode;
         };
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         RuntimeAnimation.prototype.goToFrame = function (frame) {
             var keys = this._animation.getKeys();
             if (frame < keys[0].frame) {
@@ -47759,14 +48065,24 @@ var BABYLON;
                 frame = keys[keys.length - 1].frame;
             }
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         };
         RuntimeAnimation.prototype._prepareForSpeedRatioChange = function (newSpeedRatio) {
             var newRatio = this._previousDelay * (this._animation.framePerSecond * newSpeedRatio) / 1000.0;
             this._ratioOffset = this._previousRatio - newRatio;
         };
-        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, weight) {
+            if (weight === void 0) { weight = -1.0; }
             var targetPropertyPath = this._animation.targetPropertyPath;
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -47876,7 +48192,7 @@ var BABYLON;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
             // Check events
             var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
@@ -47930,6 +48246,7 @@ var BABYLON;
             this._runtimeAnimations = new Array();
             this._paused = false;
             this._speedRatio = 1;
+            this._weight = -1.0;
             this.animationStarted = false;
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -47938,7 +48255,28 @@ var BABYLON;
             this._scene = scene;
             scene._activeAnimatables.push(this);
         }
+        Object.defineProperty(Animatable.prototype, "weight", {
+            /**
+             * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+             */
+            get: function () {
+                return this._weight;
+            },
+            set: function (value) {
+                if (value === -1) {
+                    this._weight = -1;
+                    return;
+                }
+                // Else weight must be in [0, 1] range
+                this._weight = Math.min(Math.max(value, 0), 1.0);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animatable.prototype, "speedRatio", {
+            /**
+             * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+             */
             get: function () {
                 return this._speedRatio;
             },
@@ -47959,7 +48297,7 @@ var BABYLON;
         Animatable.prototype.appendAnimations = function (target, animations) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
-                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation, this._scene));
             }
         };
         Animatable.prototype.getAnimationByTargetProperty = function (property) {
@@ -48087,7 +48425,7 @@ var BABYLON;
             var index;
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
             this.animationStarted = running;

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 2 - 119
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 7175,
+  "errors": 7154,
   "babylon.typedoc.json": {
-    "errors": 7175,
+    "errors": 7154,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -2205,11 +2205,6 @@
             "MissingText": true
           }
         },
-        "speedRatio": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "target": {
           "Comments": {
             "MissingText": true
@@ -25731,25 +25726,6 @@
           "MissingText": true
         }
       },
-      "Constructor": {
-        "new RuntimeAnimation": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "target": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "animation": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
       "Property": {
         "animation": {
           "Comments": {
@@ -25775,60 +25751,11 @@
             }
           }
         },
-        "animate": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "delay": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "from": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "to": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "loop": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "speedRatio": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "blend": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "dispose": {
           "Comments": {
             "MissingText": true
           }
         },
-        "goToFrame": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "frame": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "isStopped": {
           "Comments": {
             "MissingText": true
@@ -25838,23 +25765,6 @@
           "Comments": {
             "MissingText": true
           }
-        },
-        "setValue": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "currentValue": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "blend": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
         }
       }
     },
@@ -27161,33 +27071,6 @@
             }
           }
         },
-        "beginAnimation": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "loop": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "speedRatio": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "onAnimationEnd": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "animatable": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "beginDirectAnimation": {
           "Parameter": {
             "target": {

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 68 - 67
dist/preview release/viewer/babylon.viewer.js


+ 440 - 102
dist/preview release/viewer/babylon.viewer.max.js

@@ -1655,7 +1655,7 @@ var BABYLON;
         /**
          * Multiplies in place each rgb value by scale
          * @param scale defines the scaling factor
-         * @returns the updated Color3.
+         * @returns the updated Color3
          */
         Color3.prototype.scale = function (scale) {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -1664,7 +1664,7 @@ var BABYLON;
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.
+         * @returns the unmodified current Color3
          */
         Color3.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -1673,6 +1673,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3
+         */
+        Color3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2040,7 +2052,7 @@ var BABYLON;
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.
+         * @returns the current unmodified Color4
          */
         Color4.prototype.scaleToRef = function (scale, result) {
             result.r = this.r * scale;
@@ -2050,6 +2062,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4
+         */
+        Color4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        };
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -2493,7 +2518,31 @@ var BABYLON;
          * Returns a new Vector2 scaled by "scale" from the current Vector2.
          */
         Vector2.prototype.scale = function (scale) {
-            return new Vector2(this.x * scale, this.y * scale);
+            var result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        };
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2
+         */
+        Vector2.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
         };
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.
@@ -2933,6 +2982,18 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3
+         */
+        Vector3.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        };
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -3877,6 +3938,19 @@ var BABYLON;
             return this;
         };
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4
+         */
+        Vector4.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.
          */
         Vector4.prototype.equals = function (otherVector) {
@@ -4403,6 +4477,32 @@ var BABYLON;
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };
         /**
+         * Scale the current Quaternion values by a factor to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleToRef = function (scale, result) {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        };
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion
+         */
+        Quaternion.prototype.scaleAndAddToRef = function (scale, result) {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        };
+        /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".
          */
         Quaternion.prototype.multiply = function (q1) {
@@ -5149,6 +5249,99 @@ var BABYLON;
             return true;
         };
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.
+         */
+        Matrix.prototype.getRow = function (index) {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRow = function (index, row) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns a new Matrix.
+         */
+        Matrix.prototype.transpose = function () {
+            return Matrix.Transpose(this);
+        };
+        /**
+         * Compute the transpose of the matrix.
+         * Returns the current matrix.
+         */
+        Matrix.prototype.transposeToRef = function (result) {
+            Matrix.TransposeToRef(this, result);
+            return this;
+        };
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.
+         */
+        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+            this._markAsUpdated();
+            return this;
+        };
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        Matrix.prototype.scale = function (scale) {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        };
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix
+         */
+        Matrix.prototype.scaleAndAddToRef = function (scale, result) {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        };
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).
          * @param ref matrix to store the result
          */
@@ -5233,63 +5426,6 @@ var BABYLON;
             result.m[15] = initialM44;
             result._markAsUpdated();
         };
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.
-         */
-        Matrix.prototype.getRow = function (index) {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRow = function (index, row) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-            this._markAsUpdated();
-            return this;
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns a new Matrix.
-         */
-        Matrix.prototype.transpose = function () {
-            return Matrix.Transpose(this);
-        };
-        /**
-         * Compute the transpose of the matrix.
-         * Returns the current matrix.
-         */
-        Matrix.prototype.transposeToRef = function (result) {
-            Matrix.TransposeToRef(this, result);
-            return this;
-        };
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.
-         */
-        Matrix.prototype.setRowFromFloats = function (index, x, y, z, w) {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-            this._markAsUpdated();
-            return this;
-        };
         Object.defineProperty(Matrix, "IdentityReadOnly", {
             /**
              * Static identity matrix to be used as readonly matrix
@@ -12582,7 +12718,7 @@ var BABYLON;
             this.applyStates();
             this._drawCalls.addCount(1, false);
             // Render
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -12596,7 +12732,7 @@ var BABYLON;
             // Apply states
             this.applyStates();
             this._drawCalls.addCount(1, false);
-            var drawMode = this.DrawMode(fillMode);
+            var drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             }
@@ -12604,7 +12740,7 @@ var BABYLON;
                 this._gl.drawArrays(drawMode, verticesStart, verticesCount);
             }
         };
-        Engine.prototype.DrawMode = function (fillMode) {
+        Engine.prototype._drawMode = function (fillMode) {
             switch (fillMode) {
                 // Triangle views
                 case BABYLON.Material.TriangleFillMode:
@@ -21731,6 +21867,7 @@ var BABYLON;
             this.onRenderingGroupObservable = new BABYLON.Observable();
             // Animations
             this.animations = [];
+            this._registeredForLateAnimationBindings = new BABYLON.SmartArrayNoDuplicate(256);
             /**
              * This observable event is triggered when any ponter event is triggered. It is registered during Scene.attachControl() and it is called BEFORE the 3D engine process anything (mesh/sprite picking for instance).
              * You have the possibility to skip the process and the call to onPointerObservable by setting PointerInfoPre.skipOnPointerObservable to true
@@ -23251,22 +23388,46 @@ var BABYLON;
         // Animations
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
-         */
-        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable) {
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginWeightedAnimation = function (target, from, to, weight, loop, speedRatio, onAnimationEnd, animatable) {
+            if (weight === void 0) { weight = 1.0; }
             if (speedRatio === void 0) { speedRatio = 1.0; }
+            var returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+            return returnedAnimatable;
+        };
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        Scene.prototype.beginAnimation = function (target, from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent) {
+            if (speedRatio === void 0) { speedRatio = 1.0; }
+            if (stopCurrent === void 0) { stopCurrent = true; }
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
             if (!animatable) {
                 animatable = new BABYLON.Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
             }
@@ -23278,10 +23439,12 @@ var BABYLON;
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
             return animatable;
         };
         /**
@@ -23379,6 +23542,62 @@ var BABYLON;
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        };
+        /** @ignore */
+        Scene.prototype._registerTargetForLateAnimationBinding = function (runtimeAnimation) {
+            var target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};
+            }
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                };
+            }
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        };
+        Scene.prototype._processLateAnimationBindings = function () {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+                    var normalizer = 1.0;
+                    var finalValue = void 0;
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        var originalValue = holder.animations[0].originalValue;
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight);
+                    }
+                    else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        }
+                        else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+                    runtimeAnimation.target[path] = finalValue;
+                }
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         };
         // Matrix
         Scene.prototype._switchToAlternateCameraConfiguration = function (active) {
@@ -25008,6 +25227,7 @@ var BABYLON;
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();
             }
@@ -47651,16 +47871,74 @@ var BABYLON;
 var BABYLON;
 (function (BABYLON) {
     var RuntimeAnimation = /** @class */ (function () {
-        function RuntimeAnimation(target, animation) {
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        function RuntimeAnimation(target, animation, scene) {
             this._offsetsCache = {};
             this._highLimitsCache = {};
             this._stopped = false;
             this._blendingFactor = 0;
+            this._weight = 1.0;
             this._ratioOffset = 0;
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
             animation._runtimeAnimations.push(this);
         }
+        Object.defineProperty(RuntimeAnimation.prototype, "weight", {
+            /**
+             * Gets the weight of the runtime animation
+             */
+            get: function () {
+                return this._weight;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "originalValue", {
+            /**
+             * Gets the original value of the runtime animation
+             */
+            get: function () {
+                return this._originalValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "currentValue", {
+            /**
+             * Gets the current value of the runtime animation
+             */
+            get: function () {
+                return this._currentValue;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "targetPath", {
+            /**
+             * Gets the path where to store the animated value in the target
+             */
+            get: function () {
+                return this._targetPath;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(RuntimeAnimation.prototype, "target", {
+            /**
+             * Gets the actual target of the runtime animation
+             */
+            get: function () {
+                return this._activeTarget;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(RuntimeAnimation.prototype, "animation", {
             get: function () {
                 return this._animation;
@@ -47673,7 +47951,7 @@ var BABYLON;
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         };
         RuntimeAnimation.prototype.isStopped = function () {
             return this._stopped;
@@ -47801,8 +48079,13 @@ var BABYLON;
             }
             return this._getKeyValue(keys[keys.length - 1].value);
         };
-        RuntimeAnimation.prototype.setValue = function (currentValue, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        RuntimeAnimation.prototype.setValue = function (currentValue, weight) {
+            if (weight === void 0) { weight = 1.0; }
             // Set value
             var path;
             var destination;
@@ -47812,43 +48095,62 @@ var BABYLON;
                 for (var index = 1; index < targetPropertyPath.length - 1; index++) {
                     property = property[targetPropertyPath[index]];
                 }
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path = [targetPropertyPath.length - 1];
                 destination = property;
             }
             else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
             // Blending
             var enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             var blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    var originalValue = void 0;
+                    if (destination.getRestPose) {
+                        originalValue = destination.getRestPose();
                     }
                     else {
-                        this._originalBlendValue = destination[path];
+                        originalValue = destination[path];
+                    }
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
+                    }
+                    else {
+                        this._originalValue = originalValue;
                     }
                 }
-                if (this._originalBlendValue.prototype) {
-                    if (this._originalBlendValue.prototype.Lerp) {
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+            }
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) {
+                    if (this._originalValue.prototype.Lerp) {
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     }
                     else {
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
                 }
-                else if (this._originalBlendValue.m) {
-                    destination[path] = BABYLON.Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                else if (this._originalValue.m) {
+                    this._currentValue = BABYLON.Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 }
                 else {
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                destination[path] = this._currentValue;
             }
             else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                }
+                else {
+                    destination[path] = this._currentValue;
+                }
             }
             if (this._target.markAsDirty) {
                 this._target.markAsDirty(this._animation.targetProperty);
@@ -47860,6 +48162,10 @@ var BABYLON;
             }
             return this._animation.loopMode;
         };
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         RuntimeAnimation.prototype.goToFrame = function (frame) {
             var keys = this._animation.getKeys();
             if (frame < keys[0].frame) {
@@ -47869,14 +48175,24 @@ var BABYLON;
                 frame = keys[keys.length - 1].frame;
             }
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         };
         RuntimeAnimation.prototype._prepareForSpeedRatioChange = function (newSpeedRatio) {
             var newRatio = this._previousDelay * (this._animation.framePerSecond * newSpeedRatio) / 1000.0;
             this._ratioOffset = this._previousRatio - newRatio;
         };
-        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, blend) {
-            if (blend === void 0) { blend = false; }
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        RuntimeAnimation.prototype.animate = function (delay, from, to, loop, speedRatio, weight) {
+            if (weight === void 0) { weight = -1.0; }
             var targetPropertyPath = this._animation.targetPropertyPath;
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -47986,7 +48302,7 @@ var BABYLON;
             var currentFrame = returnValue ? from + ratio % range : to;
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
             // Check events
             var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
@@ -48040,6 +48356,7 @@ var BABYLON;
             this._runtimeAnimations = new Array();
             this._paused = false;
             this._speedRatio = 1;
+            this._weight = -1.0;
             this.animationStarted = false;
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -48048,7 +48365,28 @@ var BABYLON;
             this._scene = scene;
             scene._activeAnimatables.push(this);
         }
+        Object.defineProperty(Animatable.prototype, "weight", {
+            /**
+             * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+             */
+            get: function () {
+                return this._weight;
+            },
+            set: function (value) {
+                if (value === -1) {
+                    this._weight = -1;
+                    return;
+                }
+                // Else weight must be in [0, 1] range
+                this._weight = Math.min(Math.max(value, 0), 1.0);
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Animatable.prototype, "speedRatio", {
+            /**
+             * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+             */
             get: function () {
                 return this._speedRatio;
             },
@@ -48069,7 +48407,7 @@ var BABYLON;
         Animatable.prototype.appendAnimations = function (target, animations) {
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
-                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new BABYLON.RuntimeAnimation(target, animation, this._scene));
             }
         };
         Animatable.prototype.getAnimationByTargetProperty = function (property) {
@@ -48197,7 +48535,7 @@ var BABYLON;
             var index;
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
             this.animationStarted = running;

+ 13 - 11
dist/preview release/what's new.md

@@ -2,26 +2,28 @@
 
 ## Major updates
 
-- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles) ([deltakosh](https://github.com/deltakosh))
+- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles). Demo [here](https://www.babylonjs-playground.com/frame.html#PU4WYI#2) ([deltakosh](https://github.com/deltakosh))
 - Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
+- Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
-- `WebVRCamera` add basic support for Daydream and Gear VR ([brianzinn](https://github.com/brianzinn))
-- New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
-- Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
-- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
-- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
-- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
-- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
-- New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) Class and loading methods ([trevordev](https://github.com/trevordev))
-- Added depth of field, sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
-- Particle System SubEmitters- Spawn new Sub emitter when particles dies. Cone/Sphere shapes emitters ([IbraheemOsama](https://github.com/IbraheemOsama))
+- `WebVRCamera`: added basic support for Daydream and Gear VR ([brianzinn](https://github.com/brianzinn))
+- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture). Demo [here](https://www.babylonjs-playground.com/frame.html#CQNGRK) ([lostink](https://github.com/lostink))
+- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode). Demo [here](https://www.babylonjs-playground.com/frame.html#RNASML#4) ([deltakosh](https://github.com/deltakosh))
+- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos. Demo [here](https://www.babylonjs-playground.com/frame.html#1E9JQ8#7) ([DavidHGillen](https://github.com/DavidHGillen))
+- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
+- New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
+- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#3) ([deltakosh](https://github.com/deltakosh))
+- Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
+- New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - New [glTF exporter](http://doc.babylonjs.com/resources/3dsmax_to_gltf) for Autodesk 3dsmax ([Noalak](https://github.com/Noalak))
 
 ## Updates
 
 - Tons of functions and classes received the code comments they deserved (All the community)
+- New [particle system emitter shapes](http://doc.babylonjs.com/babylon101/particles#particles-shapes): cone and sphere ([IbraheemOsama](https://github.com/IbraheemOsama))
 - Added support for 16bits TGA ([deltakosh](https://github.com/deltakosh))
 - New `AnimationPropertiesOverride` class used to simplify setting animation properties on child animations. [Documentation](http://doc.babylonjs.com/babylon101/animations#overriding-properties) ([deltakosh](https://github.com/deltakosh))
 - New `Texture.UseSerializedUrlIfAny` static property to let textures serialize complete URL instead of using side by side loading ([deltakosh](https://github.com/deltakosh))

+ 24 - 2
src/Animations/babylon.animatable.ts

@@ -6,9 +6,30 @@
         private _paused = false;
         private _scene: Scene;
         private _speedRatio = 1;
+        private _weight = -1.0;
 
         public animationStarted = false;
 
+        /**
+         * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+         */
+        public get weight(): number {
+            return this._weight;
+        }
+
+        public set weight(value: number) {
+            if (value === -1) { // -1 is ok and means no weight
+                this._weight = -1;
+                return;
+            }
+
+            // Else weight must be in [0, 1] range
+            this._weight = Math.min(Math.max(value, 0), 1.0);
+        }
+
+        /**
+         * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+         */
         public get speedRatio(): number {
             return this._speedRatio;
         }
@@ -22,6 +43,7 @@
             this._speedRatio = value;
         }
 
+
         constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: Nullable<() => void>, animations?: any) {
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -41,7 +63,7 @@
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
 
-                this._runtimeAnimations.push(new RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new RuntimeAnimation(target, animation, this._scene));
             }
         }
 
@@ -205,7 +227,7 @@
 
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
 

+ 111 - 22
src/Animations/babylon.runtimeAnimation.ts

@@ -5,15 +5,63 @@
         private _animation: Animation;
         private _target: any;
 
-        private _originalBlendValue: any;
+        private _originalValue: any;
         private _offsetsCache: {[key: string]: any} = {};
         private _highLimitsCache: {[key: string]: any} = {};
         private _stopped = false;
         private _blendingFactor = 0;
-        
-        public constructor(target: any, animation: Animation) {
+        private _scene: Scene;
+
+        private _currentValue: any;
+        private _activeTarget: any;
+        private _targetPath: string;
+        private _weight = 1.0
+
+        /**
+         * Gets the weight of the runtime animation
+         */
+        public get weight(): number {
+            return this._weight;
+        }           
+
+        /**
+         * Gets the original value of the runtime animation
+         */
+        public get originalValue(): any {
+            return this._originalValue;
+        }        
+
+        /**
+         * Gets the current value of the runtime animation
+         */
+        public get currentValue(): any {
+            return this._currentValue;
+        }
+
+        /**
+         * Gets the path where to store the animated value in the target
+         */
+        public get targetPath(): string {
+            return this._targetPath;
+        }
+
+        /**
+         * Gets the actual target of the runtime animation
+         */
+        public get target(): any {
+            return this._activeTarget;
+        }
+
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        public constructor(target: any, animation: Animation, scene: Scene) {
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
 
             animation._runtimeAnimations.push(this);
         }
@@ -27,7 +75,7 @@
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         }
 
         public isStopped(): boolean {
@@ -175,7 +223,12 @@
             return this._getKeyValue(keys[keys.length - 1].value);
         }
 
-        public setValue(currentValue: any, blend: boolean = false): void {
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        public setValue(currentValue: any, weight = 1.0): void {
             // Set value
             var path: any;
             var destination: any;
@@ -189,42 +242,63 @@
                     property = property[targetPropertyPath[index]];
                 }
 
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path =  [targetPropertyPath.length - 1];
                 destination = property;
             } else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
 
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
+
             // Blending
             let enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
             let blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
             
-            if (enableBlending && this._blendingFactor <= 1.0) {
-                if (!this._originalBlendValue) {
-                    if (destination[path].clone) {
-                        this._originalBlendValue = destination[path].clone();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    let originalValue: any;
+
+                    if (destination.getRestPose) { // For bones
+                        originalValue = destination.getRestPose();
+                    } else {
+                        originalValue = destination[path]
+                    }
+
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
                     } else {
-                        this._originalBlendValue = destination[path];
+                        this._originalValue = originalValue;
                     }
                 }
+            }
 
-                if (this._originalBlendValue.prototype) { // Complex value
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) { // Complex value
                     
-                    if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    if (this._originalValue.prototype.Lerp) { // Lerp supported
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     } else { // Blending not supported
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
 
-                } else if (this._originalBlendValue.m) { // Matrix
-                    destination[path] = Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                } else if (this._originalValue.m) { // Matrix
+                    this._currentValue = Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 } else { // Direct value
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                
+                destination[path] = this._currentValue;
             } else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                } else {
+                    destination[path] = this._currentValue;
+                }
             }
 
             if (this._target.markAsDirty) {
@@ -240,6 +314,10 @@
             return this._animation.loopMode;
         }
 
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         public goToFrame(frame: number): void {
             let keys = this._animation.getKeys();
 
@@ -251,7 +329,7 @@
 
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
 
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         }
 
         public _prepareForSpeedRatioChange(newSpeedRatio: number): void {
@@ -264,7 +342,17 @@
         private _previousDelay: number;
         private _previousRatio: number;
 
-        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, blend: boolean = false): boolean {
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, weight = -1.0): boolean {
             let targetPropertyPath = this._animation.targetPropertyPath
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -385,7 +473,8 @@
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
+
             // Check events
             let events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {

+ 3 - 3
src/Engine/babylon.engine.ts

@@ -2634,7 +2634,7 @@
             this._drawCalls.addCount(1, false);
             // Render
 
-            const drawMode = this.DrawMode(fillMode);
+            const drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -2649,7 +2649,7 @@
             this.applyStates();
             this._drawCalls.addCount(1, false);
 
-            const drawMode = this.DrawMode(fillMode);
+            const drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             } else {
@@ -2657,7 +2657,7 @@
             }
         }
 
-        private DrawMode(fillMode: number): number {
+        private _drawMode(fillMode: number): number {
             switch (fillMode) {
                 // Triangle views
                 case Material.TriangleFillMode:

+ 221 - 69
src/Math/babylon.math.ts

@@ -148,7 +148,7 @@
         /**
          * Multiplies in place each rgb value by scale 
          * @param scale defines the scaling factor
-         * @returns the updated Color3.  
+         * @returns the updated Color3 
          */
         public scale(scale: number): Color3 {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -158,7 +158,7 @@
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor 
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.  
+         * @returns the unmodified current Color3 
          */
         public scaleToRef(scale: number, result: Color3): Color3 {
             result.r = this.r * scale;
@@ -168,6 +168,19 @@
         }
 
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3  
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3 
+         */
+        public scaleAndAddToRef(scale: number, result: Color3): Color3 {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        }          
+
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -553,7 +566,7 @@
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.  
+         * @returns the current unmodified Color4
          */
         public scaleToRef(scale: number, result: Color4): Color4 {
             result.r = this.r * scale;
@@ -564,6 +577,20 @@
         }
 
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4  
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4 
+         */
+        public scaleAndAddToRef(scale: number, result: Color4): Color4 {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        }          
+
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1026,12 +1053,40 @@
             this.y *= scale;
             return this;
         }
+
         /**
          * Returns a new Vector2 scaled by "scale" from the current Vector2.  
          */
         public scale(scale: number): Vector2 {
-            return new Vector2(this.x * scale, this.y * scale);
+            let result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
         }
+
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2  
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2 
+         */
+        public scaleToRef(scale: number, result: Vector2): Vector2 {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        }         
+
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2  
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector2): Vector2 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
+        } 
+
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.  
          */
@@ -1515,6 +1570,19 @@
         }
 
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3  
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector3): Vector3 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        }         
+
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -2554,6 +2622,20 @@
         }
 
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4  
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector4): Vector4 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        }         
+
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.  
          */
         public equals(otherVector: Vector4): boolean {
@@ -3088,6 +3170,35 @@
         public scale(value: number): Quaternion {
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         }
+
+        /**
+         * Scale the current Quaternion values by a factor to a given Quaternion  
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion 
+         */
+        public scaleToRef(scale: number, result: Quaternion): Quaternion {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        }         
+
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion  
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion 
+         */
+        public scaleAndAddToRef(scale: number, result: Quaternion): Quaternion {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        }            
+
         /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".  
          */
@@ -3899,6 +4010,111 @@
         }
 
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.  
+         */
+        public getRow(index: number): Nullable<Vector4> {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        }
+
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.    
+         */
+        public setRow(index: number, row: Vector4): Matrix {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+
+            this._markAsUpdated();
+
+            return this;
+        }
+
+        /**
+         * Compute the transpose of the matrix.  
+         * Returns a new Matrix.  
+         */
+        public transpose(): Matrix {
+            return Matrix.Transpose(this);
+        }
+
+        /**
+         * Compute the transpose of the matrix.  
+         * Returns the current matrix.  
+         */
+        public transposeToRef(result: Matrix): Matrix {
+            Matrix.TransposeToRef(this, result);
+
+            return this;
+        }
+
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.    
+         */
+        public setRowFromFloats(index: number, x: number, y: number, z: number, w: number): Matrix {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+
+            this._markAsUpdated();
+            return this;
+        }
+
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        public scale(scale: number): Matrix {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        }
+
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix  
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix  
+         */
+        public scaleToRef(scale: number, result: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        }          
+        
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix  
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix  
+         */
+        public scaleAndAddToRef(scale: number, result: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        }          
+
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).  
          * @param ref matrix to store the result
          */
@@ -4004,71 +4220,7 @@
             result.m[15] = initialM44;
 
             result._markAsUpdated();
-        }
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.  
-         */
-        public getRow(index: number): Nullable<Vector4> {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        }
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.    
-         */
-        public setRow(index: number, row: Vector4): Matrix {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-
-            this._markAsUpdated();
-
-            return this;
-        }
-
-        /**
-         * Compute the transpose of the matrix.  
-         * Returns a new Matrix.  
-         */
-        public transpose(): Matrix {
-            return Matrix.Transpose(this);
-        }
-
-        /**
-         * Compute the transpose of the matrix.  
-         * Returns the current matrix.  
-         */
-        public transposeToRef(result: Matrix): Matrix {
-            Matrix.TransposeToRef(this, result);
-
-            return this;
-        }
-
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.    
-         */
-        public setRowFromFloats(index: number, x: number, y: number, z: number, w: number): Matrix {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-
-            this._markAsUpdated();
-            return this;
-        }
+        }    
 
         /**
          * Static identity matrix to be used as readonly matrix

+ 110 - 14
src/babylon.scene.ts

@@ -467,6 +467,7 @@
 
         // Animations
         public animations: Animation[] = [];
+        private _registeredForLateAnimationBindings = new SmartArrayNoDuplicate<any>(256);
 
         // Pointers
         public pointerDownPredicate: (Mesh: AbstractMesh) => boolean;
@@ -2066,25 +2067,49 @@
         }
 
         // Animations
+
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        public beginWeightedAnimation(target: any, from: number, to: number, weight = 1.0, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
+            let returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+
+            return returnedAnimatable;
+        }
+
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
          */
-        public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
+        public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true): Animatable {
 
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
 
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
 
             if (!animatable) {
                 animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
@@ -2099,11 +2124,13 @@
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
 
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
 
             return animatable;
         }
@@ -2195,7 +2222,7 @@
             if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
                 return;
             }
-
+           
             // Getting time
             var now = Tools.Now;
             if (!this._animationTimeLast) {
@@ -2210,6 +2237,74 @@
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        }
+
+        /** @ignore */
+        public _registerTargetForLateAnimationBinding(runtimeAnimation: RuntimeAnimation): void {
+            let target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};               
+            }
+
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                }
+            }
+
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        }
+
+        private _processLateAnimationBindings(): void {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];       
+                    
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+
+                    let normalizer = 1.0;
+                    let finalValue: any;
+
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        let originalValue = holder.animations[0].originalValue;                       
+
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight)
+                    } else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];    
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        } else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+
+                    runtimeAnimation.target[path] = finalValue;
+                }
+
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         }
 
         // Matrix
@@ -4149,6 +4244,7 @@
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
 
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();