David Catuhe 7 роки тому
батько
коміт
a2a5cfbc68

Різницю між файлами не показано, бо вона завелика
+ 10920 - 10880
Playground/babylon.d.txt


Різницю між файлами не показано, бо вона завелика
+ 9742 - 9721
dist/preview release/babylon.d.ts


Різницю між файлами не показано, бо вона завелика
+ 24 - 24
dist/preview release/babylon.js


+ 107 - 33
dist/preview release/babylon.max.js

@@ -7315,26 +7315,39 @@ var BABYLON;
         };
         /**
          * Returns a Curve3 object along a CatmullRom Spline curve :
-         * @param points (array of Vector3) the points the spline must pass through. At least, four points required.
-         * @param nbPoints (integer) the wanted number of points between each curve control points.
-         */
-        Curve3.CreateCatmullRomSpline = function (points, nbPoints) {
-            var totalPoints = new Array();
-            totalPoints.push(points[0].clone());
-            Array.prototype.push.apply(totalPoints, points);
-            totalPoints.push(points[points.length - 1].clone());
+         * @param points (array of Vector3) the points the spline must pass through. At least, four points required
+         * @param nbPoints (integer) the wanted number of points between each curve control points
+         * @param closed (boolean) optional with default false, when true forms a closed loop from the points
+         */
+        Curve3.CreateCatmullRomSpline = function (points, nbPoints, closed) {
             var catmullRom = new Array();
             var step = 1.0 / nbPoints;
             var amount = 0.0;
-            for (var i = 0; i < totalPoints.length - 3; i++) {
-                amount = 0;
-                for (var c = 0; c < nbPoints; c++) {
-                    catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
-                    amount += step;
+            if (closed) {
+                var pointsCount = points.length;
+                for (var i = 0; i < pointsCount; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(points[i % pointsCount], points[(i + 1) % pointsCount], points[(i + 2) % pointsCount], points[(i + 3) % pointsCount], amount));
+                        amount += step;
+                    }
+                }
+            }
+            else {
+                var totalPoints = new Array();
+                totalPoints.push(points[0].clone());
+                Array.prototype.push.apply(totalPoints, points);
+                totalPoints.push(points[points.length - 1].clone());
+                for (var i = 0; i < totalPoints.length - 3; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
+                        amount += step;
+                    }
                 }
+                i--;
+                catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             }
-            i--;
-            catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             return new Curve3(catmullRom);
         };
         /**
@@ -12039,7 +12052,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.2.0";
+                return "3.3.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -30577,6 +30590,18 @@ var BABYLON;
             _this.uAng = 0;
             _this.vAng = 0;
             _this.wAng = 0;
+            /**
+             * Defines the center of rotation (U)
+             */
+            _this.uRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (V)
+             */
+            _this.vRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (W)
+             */
+            _this.wRotationCenter = 0.5;
             _this._isBlocking = true;
             _this.name = url || "";
             _this.url = url;
@@ -30705,13 +30730,13 @@ var BABYLON;
         Texture.prototype._prepareRowForTextureGeneration = function (x, y, z, t) {
             x *= this.uScale;
             y *= this.vScale;
-            x -= 0.5 * this.uScale;
-            y -= 0.5 * this.vScale;
-            z -= 0.5;
+            x -= this.uRotationCenter * this.uScale;
+            y -= this.vRotationCenter * this.vScale;
+            z -= this.wRotationCenter;
             BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, this._rowGenerationMatrix, t);
-            t.x += 0.5 * this.uScale + this.uOffset;
-            t.y += 0.5 * this.vScale + this.vOffset;
-            t.z += 0.5;
+            t.x += this.uRotationCenter * this.uScale + this.uOffset;
+            t.y += this.vRotationCenter * this.vScale + this.vOffset;
+            t.z += this.wRotationCenter;
         };
         Texture.prototype.getTextureMatrix = function () {
             var _this = this;
@@ -31007,6 +31032,15 @@ var BABYLON;
         ], Texture.prototype, "wAng", void 0);
         __decorate([
             BABYLON.serialize()
+        ], Texture.prototype, "uRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "vRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "wRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
         ], Texture.prototype, "isBlocking", null);
         return Texture;
     }(BABYLON.BaseTexture));
@@ -52352,11 +52386,22 @@ var BABYLON;
                 var hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
                 currentFrame = from + (to - from) * hostNormalizedFrame;
             }
+            // Reset events if looping
+            var events = this._animation.getEvents();
+            if (range > 0 && this.currentFrame > currentFrame ||
+                range < 0 && this.currentFrame < currentFrame) {
+                // Need to reset animation events
+                for (var index = 0; index < events.length; index++) {
+                    if (!events[index].onlyOnce) {
+                        // reset event, the animation is looping
+                        events[index].isDone = false;
+                    }
+                }
+            }
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
             this.setValue(currentValue, weight);
             // Check events
-            var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
                 // Make sure current frame has passed event frame and that event frame is within the current range
                 // Also, handle both forward and reverse animations
@@ -52373,10 +52418,6 @@ var BABYLON;
                         event.action();
                     } // Don't do anything if the event has already be done.
                 }
-                else if (events[index].isDone && !events[index].onlyOnce) {
-                    // reset event, the animation is looping
-                    events[index].isDone = false;
-                }
             }
             if (!returnValue) {
                 this._stopped = true;
@@ -76107,13 +76148,16 @@ var BABYLON;
         __extends(DefaultRenderingPipeline, _super);
         /**
          * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline
+         * @param {string} name - The rendering pipeline name (default: "")
+         * @param {boolean} hdr - If high dynamic range textures should be used (default: true)
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline (default: the last created scene)
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to (default: scene.cameras)
+         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline (default: true)
          */
         function DefaultRenderingPipeline(name, hdr, scene, cameras, automaticBuild) {
+            if (name === void 0) { name = ""; }
+            if (hdr === void 0) { hdr = true; }
+            if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (automaticBuild === void 0) { automaticBuild = true; }
             var _this = _super.call(this, scene.getEngine(), name) || this;
             _this._originalCameras = [];
@@ -76138,6 +76182,10 @@ var BABYLON;
              */
             _this.GrainPostProcessId = "GrainPostProcessEffect";
             /**
+             * Glow post process which adds a glow to emmisive areas of the image
+             */
+            _this._glowLayer = null;
+            /**
              * Animations which can be used to tweak settings over a period of time
              */
             _this.animations = [];
@@ -76168,7 +76216,7 @@ var BABYLON;
             _this._hasCleared = false;
             _this._prevPostProcess = null;
             _this._prevPrevPostProcess = null;
-            _this._cameras = cameras || [];
+            _this._cameras = cameras || scene.cameras;
             _this._originalCameras = _this._cameras.slice();
             _this._buildAllowed = automaticBuild;
             // Initialize
@@ -76415,6 +76463,25 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(DefaultRenderingPipeline.prototype, "glowLayerEnabled", {
+            get: function () {
+                return this._glowLayer == null;
+            },
+            /**
+             * If glow layer is enabled. (Adds a glow effect to emmissive materials)
+             */
+            set: function (enabled) {
+                if (enabled && !this._glowLayer) {
+                    this._glowLayer = new BABYLON.GlowLayer("", this._scene);
+                }
+                else if (!enabled && this._glowLayer) {
+                    this._glowLayer.dispose();
+                    this._glowLayer = null;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", {
             get: function () {
                 return this._chromaticAberrationEnabled;
@@ -76584,6 +76651,9 @@ var BABYLON;
                     if (this.grain) {
                         this.grain.dispose(camera);
                     }
+                    if (this._glowLayer) {
+                        this._glowLayer.dispose();
+                    }
                 }
             }
             this.imageProcessing = null;
@@ -76597,6 +76667,7 @@ var BABYLON;
                 this._chromaticAberrationEffect = null;
                 this.grain = null;
                 this._grainEffect = null;
+                this._glowLayer = null;
             }
         };
         /**
@@ -76676,6 +76747,9 @@ var BABYLON;
         ], DefaultRenderingPipeline.prototype, "imageProcessingEnabled", null);
         __decorate([
             BABYLON.serialize()
+        ], DefaultRenderingPipeline.prototype, "glowLayerEnabled", null);
+        __decorate([
+            BABYLON.serialize()
         ], DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", null);
         __decorate([
             BABYLON.serialize()

+ 107 - 33
dist/preview release/babylon.no-module.max.js

@@ -7282,26 +7282,39 @@ var BABYLON;
         };
         /**
          * Returns a Curve3 object along a CatmullRom Spline curve :
-         * @param points (array of Vector3) the points the spline must pass through. At least, four points required.
-         * @param nbPoints (integer) the wanted number of points between each curve control points.
-         */
-        Curve3.CreateCatmullRomSpline = function (points, nbPoints) {
-            var totalPoints = new Array();
-            totalPoints.push(points[0].clone());
-            Array.prototype.push.apply(totalPoints, points);
-            totalPoints.push(points[points.length - 1].clone());
+         * @param points (array of Vector3) the points the spline must pass through. At least, four points required
+         * @param nbPoints (integer) the wanted number of points between each curve control points
+         * @param closed (boolean) optional with default false, when true forms a closed loop from the points
+         */
+        Curve3.CreateCatmullRomSpline = function (points, nbPoints, closed) {
             var catmullRom = new Array();
             var step = 1.0 / nbPoints;
             var amount = 0.0;
-            for (var i = 0; i < totalPoints.length - 3; i++) {
-                amount = 0;
-                for (var c = 0; c < nbPoints; c++) {
-                    catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
-                    amount += step;
+            if (closed) {
+                var pointsCount = points.length;
+                for (var i = 0; i < pointsCount; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(points[i % pointsCount], points[(i + 1) % pointsCount], points[(i + 2) % pointsCount], points[(i + 3) % pointsCount], amount));
+                        amount += step;
+                    }
+                }
+            }
+            else {
+                var totalPoints = new Array();
+                totalPoints.push(points[0].clone());
+                Array.prototype.push.apply(totalPoints, points);
+                totalPoints.push(points[points.length - 1].clone());
+                for (var i = 0; i < totalPoints.length - 3; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
+                        amount += step;
+                    }
                 }
+                i--;
+                catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             }
-            i--;
-            catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             return new Curve3(catmullRom);
         };
         /**
@@ -12006,7 +12019,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.2.0";
+                return "3.3.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -30544,6 +30557,18 @@ var BABYLON;
             _this.uAng = 0;
             _this.vAng = 0;
             _this.wAng = 0;
+            /**
+             * Defines the center of rotation (U)
+             */
+            _this.uRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (V)
+             */
+            _this.vRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (W)
+             */
+            _this.wRotationCenter = 0.5;
             _this._isBlocking = true;
             _this.name = url || "";
             _this.url = url;
@@ -30672,13 +30697,13 @@ var BABYLON;
         Texture.prototype._prepareRowForTextureGeneration = function (x, y, z, t) {
             x *= this.uScale;
             y *= this.vScale;
-            x -= 0.5 * this.uScale;
-            y -= 0.5 * this.vScale;
-            z -= 0.5;
+            x -= this.uRotationCenter * this.uScale;
+            y -= this.vRotationCenter * this.vScale;
+            z -= this.wRotationCenter;
             BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, this._rowGenerationMatrix, t);
-            t.x += 0.5 * this.uScale + this.uOffset;
-            t.y += 0.5 * this.vScale + this.vOffset;
-            t.z += 0.5;
+            t.x += this.uRotationCenter * this.uScale + this.uOffset;
+            t.y += this.vRotationCenter * this.vScale + this.vOffset;
+            t.z += this.wRotationCenter;
         };
         Texture.prototype.getTextureMatrix = function () {
             var _this = this;
@@ -30974,6 +30999,15 @@ var BABYLON;
         ], Texture.prototype, "wAng", void 0);
         __decorate([
             BABYLON.serialize()
+        ], Texture.prototype, "uRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "vRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "wRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
         ], Texture.prototype, "isBlocking", null);
         return Texture;
     }(BABYLON.BaseTexture));
@@ -52319,11 +52353,22 @@ var BABYLON;
                 var hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
                 currentFrame = from + (to - from) * hostNormalizedFrame;
             }
+            // Reset events if looping
+            var events = this._animation.getEvents();
+            if (range > 0 && this.currentFrame > currentFrame ||
+                range < 0 && this.currentFrame < currentFrame) {
+                // Need to reset animation events
+                for (var index = 0; index < events.length; index++) {
+                    if (!events[index].onlyOnce) {
+                        // reset event, the animation is looping
+                        events[index].isDone = false;
+                    }
+                }
+            }
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
             this.setValue(currentValue, weight);
             // Check events
-            var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
                 // Make sure current frame has passed event frame and that event frame is within the current range
                 // Also, handle both forward and reverse animations
@@ -52340,10 +52385,6 @@ var BABYLON;
                         event.action();
                     } // Don't do anything if the event has already be done.
                 }
-                else if (events[index].isDone && !events[index].onlyOnce) {
-                    // reset event, the animation is looping
-                    events[index].isDone = false;
-                }
             }
             if (!returnValue) {
                 this._stopped = true;
@@ -76074,13 +76115,16 @@ var BABYLON;
         __extends(DefaultRenderingPipeline, _super);
         /**
          * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline
+         * @param {string} name - The rendering pipeline name (default: "")
+         * @param {boolean} hdr - If high dynamic range textures should be used (default: true)
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline (default: the last created scene)
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to (default: scene.cameras)
+         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline (default: true)
          */
         function DefaultRenderingPipeline(name, hdr, scene, cameras, automaticBuild) {
+            if (name === void 0) { name = ""; }
+            if (hdr === void 0) { hdr = true; }
+            if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (automaticBuild === void 0) { automaticBuild = true; }
             var _this = _super.call(this, scene.getEngine(), name) || this;
             _this._originalCameras = [];
@@ -76105,6 +76149,10 @@ var BABYLON;
              */
             _this.GrainPostProcessId = "GrainPostProcessEffect";
             /**
+             * Glow post process which adds a glow to emmisive areas of the image
+             */
+            _this._glowLayer = null;
+            /**
              * Animations which can be used to tweak settings over a period of time
              */
             _this.animations = [];
@@ -76135,7 +76183,7 @@ var BABYLON;
             _this._hasCleared = false;
             _this._prevPostProcess = null;
             _this._prevPrevPostProcess = null;
-            _this._cameras = cameras || [];
+            _this._cameras = cameras || scene.cameras;
             _this._originalCameras = _this._cameras.slice();
             _this._buildAllowed = automaticBuild;
             // Initialize
@@ -76382,6 +76430,25 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(DefaultRenderingPipeline.prototype, "glowLayerEnabled", {
+            get: function () {
+                return this._glowLayer == null;
+            },
+            /**
+             * If glow layer is enabled. (Adds a glow effect to emmissive materials)
+             */
+            set: function (enabled) {
+                if (enabled && !this._glowLayer) {
+                    this._glowLayer = new BABYLON.GlowLayer("", this._scene);
+                }
+                else if (!enabled && this._glowLayer) {
+                    this._glowLayer.dispose();
+                    this._glowLayer = null;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", {
             get: function () {
                 return this._chromaticAberrationEnabled;
@@ -76551,6 +76618,9 @@ var BABYLON;
                     if (this.grain) {
                         this.grain.dispose(camera);
                     }
+                    if (this._glowLayer) {
+                        this._glowLayer.dispose();
+                    }
                 }
             }
             this.imageProcessing = null;
@@ -76564,6 +76634,7 @@ var BABYLON;
                 this._chromaticAberrationEffect = null;
                 this.grain = null;
                 this._grainEffect = null;
+                this._glowLayer = null;
             }
         };
         /**
@@ -76643,6 +76714,9 @@ var BABYLON;
         ], DefaultRenderingPipeline.prototype, "imageProcessingEnabled", null);
         __decorate([
             BABYLON.serialize()
+        ], DefaultRenderingPipeline.prototype, "glowLayerEnabled", null);
+        __decorate([
+            BABYLON.serialize()
         ], DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", null);
         __decorate([
             BABYLON.serialize()

Різницю між файлами не показано, бо вона завелика
+ 25 - 25
dist/preview release/babylon.worker.js


+ 107 - 33
dist/preview release/es6.js

@@ -7282,26 +7282,39 @@ var BABYLON;
         };
         /**
          * Returns a Curve3 object along a CatmullRom Spline curve :
-         * @param points (array of Vector3) the points the spline must pass through. At least, four points required.
-         * @param nbPoints (integer) the wanted number of points between each curve control points.
-         */
-        Curve3.CreateCatmullRomSpline = function (points, nbPoints) {
-            var totalPoints = new Array();
-            totalPoints.push(points[0].clone());
-            Array.prototype.push.apply(totalPoints, points);
-            totalPoints.push(points[points.length - 1].clone());
+         * @param points (array of Vector3) the points the spline must pass through. At least, four points required
+         * @param nbPoints (integer) the wanted number of points between each curve control points
+         * @param closed (boolean) optional with default false, when true forms a closed loop from the points
+         */
+        Curve3.CreateCatmullRomSpline = function (points, nbPoints, closed) {
             var catmullRom = new Array();
             var step = 1.0 / nbPoints;
             var amount = 0.0;
-            for (var i = 0; i < totalPoints.length - 3; i++) {
-                amount = 0;
-                for (var c = 0; c < nbPoints; c++) {
-                    catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
-                    amount += step;
+            if (closed) {
+                var pointsCount = points.length;
+                for (var i = 0; i < pointsCount; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(points[i % pointsCount], points[(i + 1) % pointsCount], points[(i + 2) % pointsCount], points[(i + 3) % pointsCount], amount));
+                        amount += step;
+                    }
+                }
+            }
+            else {
+                var totalPoints = new Array();
+                totalPoints.push(points[0].clone());
+                Array.prototype.push.apply(totalPoints, points);
+                totalPoints.push(points[points.length - 1].clone());
+                for (var i = 0; i < totalPoints.length - 3; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
+                        amount += step;
+                    }
                 }
+                i--;
+                catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             }
-            i--;
-            catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             return new Curve3(catmullRom);
         };
         /**
@@ -12006,7 +12019,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.2.0";
+                return "3.3.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -30544,6 +30557,18 @@ var BABYLON;
             _this.uAng = 0;
             _this.vAng = 0;
             _this.wAng = 0;
+            /**
+             * Defines the center of rotation (U)
+             */
+            _this.uRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (V)
+             */
+            _this.vRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (W)
+             */
+            _this.wRotationCenter = 0.5;
             _this._isBlocking = true;
             _this.name = url || "";
             _this.url = url;
@@ -30672,13 +30697,13 @@ var BABYLON;
         Texture.prototype._prepareRowForTextureGeneration = function (x, y, z, t) {
             x *= this.uScale;
             y *= this.vScale;
-            x -= 0.5 * this.uScale;
-            y -= 0.5 * this.vScale;
-            z -= 0.5;
+            x -= this.uRotationCenter * this.uScale;
+            y -= this.vRotationCenter * this.vScale;
+            z -= this.wRotationCenter;
             BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, this._rowGenerationMatrix, t);
-            t.x += 0.5 * this.uScale + this.uOffset;
-            t.y += 0.5 * this.vScale + this.vOffset;
-            t.z += 0.5;
+            t.x += this.uRotationCenter * this.uScale + this.uOffset;
+            t.y += this.vRotationCenter * this.vScale + this.vOffset;
+            t.z += this.wRotationCenter;
         };
         Texture.prototype.getTextureMatrix = function () {
             var _this = this;
@@ -30974,6 +30999,15 @@ var BABYLON;
         ], Texture.prototype, "wAng", void 0);
         __decorate([
             BABYLON.serialize()
+        ], Texture.prototype, "uRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "vRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "wRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
         ], Texture.prototype, "isBlocking", null);
         return Texture;
     }(BABYLON.BaseTexture));
@@ -52319,11 +52353,22 @@ var BABYLON;
                 var hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
                 currentFrame = from + (to - from) * hostNormalizedFrame;
             }
+            // Reset events if looping
+            var events = this._animation.getEvents();
+            if (range > 0 && this.currentFrame > currentFrame ||
+                range < 0 && this.currentFrame < currentFrame) {
+                // Need to reset animation events
+                for (var index = 0; index < events.length; index++) {
+                    if (!events[index].onlyOnce) {
+                        // reset event, the animation is looping
+                        events[index].isDone = false;
+                    }
+                }
+            }
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
             this.setValue(currentValue, weight);
             // Check events
-            var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
                 // Make sure current frame has passed event frame and that event frame is within the current range
                 // Also, handle both forward and reverse animations
@@ -52340,10 +52385,6 @@ var BABYLON;
                         event.action();
                     } // Don't do anything if the event has already be done.
                 }
-                else if (events[index].isDone && !events[index].onlyOnce) {
-                    // reset event, the animation is looping
-                    events[index].isDone = false;
-                }
             }
             if (!returnValue) {
                 this._stopped = true;
@@ -76074,13 +76115,16 @@ var BABYLON;
         __extends(DefaultRenderingPipeline, _super);
         /**
          * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline
+         * @param {string} name - The rendering pipeline name (default: "")
+         * @param {boolean} hdr - If high dynamic range textures should be used (default: true)
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline (default: the last created scene)
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to (default: scene.cameras)
+         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline (default: true)
          */
         function DefaultRenderingPipeline(name, hdr, scene, cameras, automaticBuild) {
+            if (name === void 0) { name = ""; }
+            if (hdr === void 0) { hdr = true; }
+            if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (automaticBuild === void 0) { automaticBuild = true; }
             var _this = _super.call(this, scene.getEngine(), name) || this;
             _this._originalCameras = [];
@@ -76105,6 +76149,10 @@ var BABYLON;
              */
             _this.GrainPostProcessId = "GrainPostProcessEffect";
             /**
+             * Glow post process which adds a glow to emmisive areas of the image
+             */
+            _this._glowLayer = null;
+            /**
              * Animations which can be used to tweak settings over a period of time
              */
             _this.animations = [];
@@ -76135,7 +76183,7 @@ var BABYLON;
             _this._hasCleared = false;
             _this._prevPostProcess = null;
             _this._prevPrevPostProcess = null;
-            _this._cameras = cameras || [];
+            _this._cameras = cameras || scene.cameras;
             _this._originalCameras = _this._cameras.slice();
             _this._buildAllowed = automaticBuild;
             // Initialize
@@ -76382,6 +76430,25 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(DefaultRenderingPipeline.prototype, "glowLayerEnabled", {
+            get: function () {
+                return this._glowLayer == null;
+            },
+            /**
+             * If glow layer is enabled. (Adds a glow effect to emmissive materials)
+             */
+            set: function (enabled) {
+                if (enabled && !this._glowLayer) {
+                    this._glowLayer = new BABYLON.GlowLayer("", this._scene);
+                }
+                else if (!enabled && this._glowLayer) {
+                    this._glowLayer.dispose();
+                    this._glowLayer = null;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", {
             get: function () {
                 return this._chromaticAberrationEnabled;
@@ -76551,6 +76618,9 @@ var BABYLON;
                     if (this.grain) {
                         this.grain.dispose(camera);
                     }
+                    if (this._glowLayer) {
+                        this._glowLayer.dispose();
+                    }
                 }
             }
             this.imageProcessing = null;
@@ -76564,6 +76634,7 @@ var BABYLON;
                 this._chromaticAberrationEffect = null;
                 this.grain = null;
                 this._grainEffect = null;
+                this._glowLayer = null;
             }
         };
         /**
@@ -76643,6 +76714,9 @@ var BABYLON;
         ], DefaultRenderingPipeline.prototype, "imageProcessingEnabled", null);
         __decorate([
             BABYLON.serialize()
+        ], DefaultRenderingPipeline.prototype, "glowLayerEnabled", null);
+        __decorate([
+            BABYLON.serialize()
         ], DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", null);
         __decorate([
             BABYLON.serialize()

+ 15 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -707,6 +707,8 @@ declare module BABYLON.GLTF2 {
         protected _loadVertexDataAsync(context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Override this method to modify the default behavior for loading materials. */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading textures. */
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading uris. */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** Helper method called by a loader extension to load an glTF extension. */
@@ -719,6 +721,8 @@ declare module BABYLON.GLTF2 {
         static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Helper method called by the loader to allow extensions to override loading materials. */
         static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading textures. */
+        static _LoadTextureAsync(loader: GLTFLoader, context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Helper method called by the loader to allow extensions to override loading uris. */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
@@ -824,3 +828,14 @@ declare module BABYLON.GLTF2.Extensions {
         private readonly _lights;
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
+     * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+     */
+    class KHR_texture_transform extends GLTFLoaderExtension {
+        readonly name: string;
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
+    }
+}

+ 74 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -616,7 +616,7 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFLoaderUtilities.js.map
 
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 
 //# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map
 
@@ -1861,6 +1861,10 @@ var BABYLON;
             /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
+                if (promise) {
+                    return promise;
+                }
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
@@ -2198,6 +2202,8 @@ var BABYLON;
             GLTFLoaderExtension.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) { return null; };
             /** Override this method to modify the default behavior for loading materials. */
             GLTFLoaderExtension.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) { return null; };
+            /** Override this method to modify the default behavior for loading textures. */
+            GLTFLoaderExtension.prototype._loadTextureAsync = function (context, textureInfo, assign) { return null; };
             /** Override this method to modify the default behavior for loading uris. */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
             // #endregion
@@ -2237,6 +2243,10 @@ var BABYLON;
             GLTFLoaderExtension._LoadMaterialAsync = function (loader, context, material, babylonMesh, babylonDrawMode, assign) {
                 return loader._applyExtensions(function (extension) { return extension._loadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign); });
             };
+            /** Helper method called by the loader to allow extensions to override loading textures. */
+            GLTFLoaderExtension._LoadTextureAsync = function (loader, context, textureInfo, assign) {
+                return loader._applyExtensions(function (extension) { return extension._loadTextureAsync(context, textureInfo, assign); });
+            };
             /** Helper method called by the loader to allow extensions to override loading uris. */
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
@@ -2910,3 +2920,66 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=KHR_lights.js.map
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var NAME = "KHR_texture_transform";
+            /**
+             * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+             */
+            var KHR_texture_transform = /** @class */ (function (_super) {
+                __extends(KHR_texture_transform, _super);
+                function KHR_texture_transform() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                KHR_texture_transform.prototype._loadTextureAsync = function (context, textureInfo, assign) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, textureInfo, function (extensionContext, extension) {
+                        return _this._loader._loadTextureAsync(context, textureInfo, function (babylonTexture) {
+                            if (extension.offset) {
+                                babylonTexture.uOffset = extension.offset[0];
+                                babylonTexture.vOffset = extension.offset[1];
+                            }
+                            // Always rotate around the origin.
+                            babylonTexture.uRotationCenter = 0;
+                            babylonTexture.vRotationCenter = 0;
+                            if (extension.rotation) {
+                                babylonTexture.wAng = -extension.rotation;
+                            }
+                            if (extension.scale) {
+                                babylonTexture.uScale = extension.scale[0];
+                                babylonTexture.vScale = extension.scale[1];
+                            }
+                            if (extension.texCoord != undefined) {
+                                babylonTexture.coordinatesIndex = extension.texCoord;
+                            }
+                            assign(babylonTexture);
+                        });
+                    });
+                };
+                return KHR_texture_transform;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHR_texture_transform = KHR_texture_transform;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_texture_transform(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=KHR_texture_transform.js.map

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 15 - 0
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -1284,6 +1284,8 @@ declare module BABYLON.GLTF2 {
         protected _loadVertexDataAsync(context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Override this method to modify the default behavior for loading materials. */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading textures. */
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading uris. */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** Helper method called by a loader extension to load an glTF extension. */
@@ -1296,6 +1298,8 @@ declare module BABYLON.GLTF2 {
         static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Helper method called by the loader to allow extensions to override loading materials. */
         static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading textures. */
+        static _LoadTextureAsync(loader: GLTFLoader, context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Helper method called by the loader to allow extensions to override loading uris. */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
@@ -1401,3 +1405,14 @@ declare module BABYLON.GLTF2.Extensions {
         private readonly _lights;
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
+     * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+     */
+    class KHR_texture_transform extends GLTFLoaderExtension {
+        readonly name: string;
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
+    }
+}

+ 72 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2832,7 +2832,7 @@ var BABYLON;
 //# sourceMappingURL=babylon.glTFLoaderUtilities.js.map
 
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 
 //# sourceMappingURL=babylon.glTFLoaderInterfaces.js.map
 
@@ -4077,6 +4077,10 @@ var BABYLON;
             /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
+                if (promise) {
+                    return promise;
+                }
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
@@ -4414,6 +4418,8 @@ var BABYLON;
             GLTFLoaderExtension.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) { return null; };
             /** Override this method to modify the default behavior for loading materials. */
             GLTFLoaderExtension.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) { return null; };
+            /** Override this method to modify the default behavior for loading textures. */
+            GLTFLoaderExtension.prototype._loadTextureAsync = function (context, textureInfo, assign) { return null; };
             /** Override this method to modify the default behavior for loading uris. */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
             // #endregion
@@ -4453,6 +4459,10 @@ var BABYLON;
             GLTFLoaderExtension._LoadMaterialAsync = function (loader, context, material, babylonMesh, babylonDrawMode, assign) {
                 return loader._applyExtensions(function (extension) { return extension._loadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign); });
             };
+            /** Helper method called by the loader to allow extensions to override loading textures. */
+            GLTFLoaderExtension._LoadTextureAsync = function (loader, context, textureInfo, assign) {
+                return loader._applyExtensions(function (extension) { return extension._loadTextureAsync(context, textureInfo, assign); });
+            };
             /** Helper method called by the loader to allow extensions to override loading uris. */
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
@@ -5122,3 +5132,64 @@ var BABYLON;
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
+
+/// <reference path="../../../../../dist/preview release/babylon.d.ts"/>
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return function (d, b) {
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var NAME = "KHR_texture_transform";
+            /**
+             * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+             */
+            var KHR_texture_transform = /** @class */ (function (_super) {
+                __extends(KHR_texture_transform, _super);
+                function KHR_texture_transform() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                KHR_texture_transform.prototype._loadTextureAsync = function (context, textureInfo, assign) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, textureInfo, function (extensionContext, extension) {
+                        return _this._loader._loadTextureAsync(context, textureInfo, function (babylonTexture) {
+                            if (extension.offset) {
+                                babylonTexture.uOffset = extension.offset[0];
+                                babylonTexture.vOffset = extension.offset[1];
+                            }
+                            // Always rotate around the origin.
+                            babylonTexture.uRotationCenter = 0;
+                            babylonTexture.vRotationCenter = 0;
+                            if (extension.rotation) {
+                                babylonTexture.wAng = -extension.rotation;
+                            }
+                            if (extension.scale) {
+                                babylonTexture.uScale = extension.scale[0];
+                                babylonTexture.vScale = extension.scale[1];
+                            }
+                            if (extension.texCoord != undefined) {
+                                babylonTexture.coordinatesIndex = extension.texCoord;
+                            }
+                            assign(babylonTexture);
+                        });
+                    });
+                };
+                return KHR_texture_transform;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHR_texture_transform = KHR_texture_transform;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_texture_transform(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));

Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 15 - 0
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -1380,6 +1380,8 @@ declare module BABYLON.GLTF2 {
         protected _loadVertexDataAsync(context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Override this method to modify the default behavior for loading materials. */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading textures. */
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading uris. */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** Helper method called by a loader extension to load an glTF extension. */
@@ -1392,6 +1394,8 @@ declare module BABYLON.GLTF2 {
         static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Helper method called by the loader to allow extensions to override loading materials. */
         static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading textures. */
+        static _LoadTextureAsync(loader: GLTFLoader, context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Helper method called by the loader to allow extensions to override loading uris. */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
@@ -1497,3 +1501,14 @@ declare module BABYLON.GLTF2.Extensions {
         private readonly _lights;
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
+     * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+     */
+    class KHR_texture_transform extends GLTFLoaderExtension {
+        readonly name: string;
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
+    }
+}

+ 62 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -5059,6 +5059,10 @@ var BABYLON;
             /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
+                if (promise) {
+                    return promise;
+                }
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
@@ -5396,6 +5400,8 @@ var BABYLON;
             GLTFLoaderExtension.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) { return null; };
             /** Override this method to modify the default behavior for loading materials. */
             GLTFLoaderExtension.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) { return null; };
+            /** Override this method to modify the default behavior for loading textures. */
+            GLTFLoaderExtension.prototype._loadTextureAsync = function (context, textureInfo, assign) { return null; };
             /** Override this method to modify the default behavior for loading uris. */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
             // #endregion
@@ -5435,6 +5441,10 @@ var BABYLON;
             GLTFLoaderExtension._LoadMaterialAsync = function (loader, context, material, babylonMesh, babylonDrawMode, assign) {
                 return loader._applyExtensions(function (extension) { return extension._loadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign); });
             };
+            /** Helper method called by the loader to allow extensions to override loading textures. */
+            GLTFLoaderExtension._LoadTextureAsync = function (loader, context, textureInfo, assign) {
+                return loader._applyExtensions(function (extension) { return extension._loadTextureAsync(context, textureInfo, assign); });
+            };
             /** Helper method called by the loader to allow extensions to override loading uris. */
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
@@ -6042,6 +6052,58 @@ var BABYLON;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
+
+
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var NAME = "KHR_texture_transform";
+            /**
+             * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+             */
+            var KHR_texture_transform = /** @class */ (function (_super) {
+                __extends(KHR_texture_transform, _super);
+                function KHR_texture_transform() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                KHR_texture_transform.prototype._loadTextureAsync = function (context, textureInfo, assign) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, textureInfo, function (extensionContext, extension) {
+                        return _this._loader._loadTextureAsync(context, textureInfo, function (babylonTexture) {
+                            if (extension.offset) {
+                                babylonTexture.uOffset = extension.offset[0];
+                                babylonTexture.vOffset = extension.offset[1];
+                            }
+                            // Always rotate around the origin.
+                            babylonTexture.uRotationCenter = 0;
+                            babylonTexture.vRotationCenter = 0;
+                            if (extension.rotation) {
+                                babylonTexture.wAng = -extension.rotation;
+                            }
+                            if (extension.scale) {
+                                babylonTexture.uScale = extension.scale[0];
+                                babylonTexture.vScale = extension.scale[1];
+                            }
+                            if (extension.texCoord != undefined) {
+                                babylonTexture.coordinatesIndex = extension.texCoord;
+                            }
+                            assign(babylonTexture);
+                        });
+                    });
+                };
+                return KHR_texture_transform;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHR_texture_transform = KHR_texture_transform;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_texture_transform(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
     
 
     return BABYLON;

Різницю між файлами не показано, бо вона завелика
+ 4 - 4
dist/preview release/loaders/babylonjs.loaders.min.js


+ 15 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1387,6 +1387,8 @@ declare module BABYLON.GLTF2 {
         protected _loadVertexDataAsync(context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Override this method to modify the default behavior for loading materials. */
         protected _loadMaterialAsync(context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Override this method to modify the default behavior for loading textures. */
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Override this method to modify the default behavior for loading uris. */
         protected _loadUriAsync(context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
         /** Helper method called by a loader extension to load an glTF extension. */
@@ -1399,6 +1401,8 @@ declare module BABYLON.GLTF2 {
         static _LoadVertexDataAsync(loader: GLTFLoader, context: string, primitive: _ILoaderMeshPrimitive, babylonMesh: Mesh): Nullable<Promise<Geometry>>;
         /** Helper method called by the loader to allow extensions to override loading materials. */
         static _LoadMaterialAsync(loader: GLTFLoader, context: string, material: _ILoaderMaterial, babylonMesh: Mesh, babylonDrawMode: number, assign: (babylonMaterial: Material) => void): Nullable<Promise<void>>;
+        /** Helper method called by the loader to allow extensions to override loading textures. */
+        static _LoadTextureAsync(loader: GLTFLoader, context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
         /** Helper method called by the loader to allow extensions to override loading uris. */
         static _LoadUriAsync(loader: GLTFLoader, context: string, uri: string): Nullable<Promise<ArrayBufferView>>;
     }
@@ -1504,3 +1508,14 @@ declare module BABYLON.GLTF2.Extensions {
         private readonly _lights;
     }
 }
+
+
+declare module BABYLON.GLTF2.Extensions {
+    /**
+     * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+     */
+    class KHR_texture_transform extends GLTFLoaderExtension {
+        readonly name: string;
+        protected _loadTextureAsync(context: string, textureInfo: ITextureInfo, assign: (texture: Texture) => void): Nullable<Promise<void>>;
+    }
+}

+ 5 - 5
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -65,7 +65,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFSerializer.js.map
 
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 /**
  * Module for the Babylon glTF 2.0 exporter.  Should ONLY be used internally
  * @hidden
@@ -1281,7 +1281,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFExporter.js.map
 
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     /**
@@ -1340,7 +1340,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFData.js.map
 
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;
@@ -2344,7 +2344,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFMaterial.js.map
 
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;
@@ -3000,7 +3000,7 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFAnimation.js.map
 
-/// <reference path="../../../../dist/babylon.glTF2Interface.d.ts"/>
+/// <reference path="../../../../dist/preview release/gltf2Interface/babylon.glTF2Interface.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
     var GLTF2;

Різницю між файлами не показано, бо вона завелика
+ 55 - 55
dist/preview release/viewer/babylon.viewer.js


+ 170 - 34
dist/preview release/viewer/babylon.viewer.max.js

@@ -7403,26 +7403,39 @@ var BABYLON;
         };
         /**
          * Returns a Curve3 object along a CatmullRom Spline curve :
-         * @param points (array of Vector3) the points the spline must pass through. At least, four points required.
-         * @param nbPoints (integer) the wanted number of points between each curve control points.
-         */
-        Curve3.CreateCatmullRomSpline = function (points, nbPoints) {
-            var totalPoints = new Array();
-            totalPoints.push(points[0].clone());
-            Array.prototype.push.apply(totalPoints, points);
-            totalPoints.push(points[points.length - 1].clone());
+         * @param points (array of Vector3) the points the spline must pass through. At least, four points required
+         * @param nbPoints (integer) the wanted number of points between each curve control points
+         * @param closed (boolean) optional with default false, when true forms a closed loop from the points
+         */
+        Curve3.CreateCatmullRomSpline = function (points, nbPoints, closed) {
             var catmullRom = new Array();
             var step = 1.0 / nbPoints;
             var amount = 0.0;
-            for (var i = 0; i < totalPoints.length - 3; i++) {
-                amount = 0;
-                for (var c = 0; c < nbPoints; c++) {
-                    catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
-                    amount += step;
+            if (closed) {
+                var pointsCount = points.length;
+                for (var i = 0; i < pointsCount; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(points[i % pointsCount], points[(i + 1) % pointsCount], points[(i + 2) % pointsCount], points[(i + 3) % pointsCount], amount));
+                        amount += step;
+                    }
+                }
+            }
+            else {
+                var totalPoints = new Array();
+                totalPoints.push(points[0].clone());
+                Array.prototype.push.apply(totalPoints, points);
+                totalPoints.push(points[points.length - 1].clone());
+                for (var i = 0; i < totalPoints.length - 3; i++) {
+                    amount = 0;
+                    for (var c = 0; c < nbPoints; c++) {
+                        catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
+                        amount += step;
+                    }
                 }
+                i--;
+                catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             }
-            i--;
-            catmullRom.push(Vector3.CatmullRom(totalPoints[i], totalPoints[i + 1], totalPoints[i + 2], totalPoints[i + 3], amount));
             return new Curve3(catmullRom);
         };
         /**
@@ -12127,7 +12140,7 @@ var BABYLON;
              * Returns the current version of the framework
              */
             get: function () {
-                return "3.2.0";
+                return "3.3.0-alpha.0";
             },
             enumerable: true,
             configurable: true
@@ -30665,6 +30678,18 @@ var BABYLON;
             _this.uAng = 0;
             _this.vAng = 0;
             _this.wAng = 0;
+            /**
+             * Defines the center of rotation (U)
+             */
+            _this.uRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (V)
+             */
+            _this.vRotationCenter = 0.5;
+            /**
+             * Defines the center of rotation (W)
+             */
+            _this.wRotationCenter = 0.5;
             _this._isBlocking = true;
             _this.name = url || "";
             _this.url = url;
@@ -30793,13 +30818,13 @@ var BABYLON;
         Texture.prototype._prepareRowForTextureGeneration = function (x, y, z, t) {
             x *= this.uScale;
             y *= this.vScale;
-            x -= 0.5 * this.uScale;
-            y -= 0.5 * this.vScale;
-            z -= 0.5;
+            x -= this.uRotationCenter * this.uScale;
+            y -= this.vRotationCenter * this.vScale;
+            z -= this.wRotationCenter;
             BABYLON.Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, this._rowGenerationMatrix, t);
-            t.x += 0.5 * this.uScale + this.uOffset;
-            t.y += 0.5 * this.vScale + this.vOffset;
-            t.z += 0.5;
+            t.x += this.uRotationCenter * this.uScale + this.uOffset;
+            t.y += this.vRotationCenter * this.vScale + this.vOffset;
+            t.z += this.wRotationCenter;
         };
         Texture.prototype.getTextureMatrix = function () {
             var _this = this;
@@ -31095,6 +31120,15 @@ var BABYLON;
         ], Texture.prototype, "wAng", void 0);
         __decorate([
             BABYLON.serialize()
+        ], Texture.prototype, "uRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "vRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
+        ], Texture.prototype, "wRotationCenter", void 0);
+        __decorate([
+            BABYLON.serialize()
         ], Texture.prototype, "isBlocking", null);
         return Texture;
     }(BABYLON.BaseTexture));
@@ -52440,11 +52474,22 @@ var BABYLON;
                 var hostNormalizedFrame = (syncRoot.masterFrame - syncRoot.fromFrame) / (syncRoot.toFrame - syncRoot.fromFrame);
                 currentFrame = from + (to - from) * hostNormalizedFrame;
             }
+            // Reset events if looping
+            var events = this._animation.getEvents();
+            if (range > 0 && this.currentFrame > currentFrame ||
+                range < 0 && this.currentFrame < currentFrame) {
+                // Need to reset animation events
+                for (var index = 0; index < events.length; index++) {
+                    if (!events[index].onlyOnce) {
+                        // reset event, the animation is looping
+                        events[index].isDone = false;
+                    }
+                }
+            }
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
             // Set value
             this.setValue(currentValue, weight);
             // Check events
-            var events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
                 // Make sure current frame has passed event frame and that event frame is within the current range
                 // Also, handle both forward and reverse animations
@@ -52461,10 +52506,6 @@ var BABYLON;
                         event.action();
                     } // Don't do anything if the event has already be done.
                 }
-                else if (events[index].isDone && !events[index].onlyOnce) {
-                    // reset event, the animation is looping
-                    events[index].isDone = false;
-                }
             }
             if (!returnValue) {
                 this._stopped = true;
@@ -76195,13 +76236,16 @@ var BABYLON;
         __extends(DefaultRenderingPipeline, _super);
         /**
          * @constructor
-         * @param {string} name - The rendering pipeline name
-         * @param {BABYLON.Scene} scene - The scene linked to this pipeline
-         * @param {any} ratio - The size of the postprocesses (0.5 means that your postprocess will have a width = canvas.width 0.5 and a height = canvas.height 0.5)
-         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to
-         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline
+         * @param {string} name - The rendering pipeline name (default: "")
+         * @param {boolean} hdr - If high dynamic range textures should be used (default: true)
+         * @param {BABYLON.Scene} scene - The scene linked to this pipeline (default: the last created scene)
+         * @param {BABYLON.Camera[]} cameras - The array of cameras that the rendering pipeline will be attached to (default: scene.cameras)
+         * @param {boolean} automaticBuild - if false, you will have to manually call prepare() to update the pipeline (default: true)
          */
         function DefaultRenderingPipeline(name, hdr, scene, cameras, automaticBuild) {
+            if (name === void 0) { name = ""; }
+            if (hdr === void 0) { hdr = true; }
+            if (scene === void 0) { scene = BABYLON.Engine.LastCreatedScene; }
             if (automaticBuild === void 0) { automaticBuild = true; }
             var _this = _super.call(this, scene.getEngine(), name) || this;
             _this._originalCameras = [];
@@ -76226,6 +76270,10 @@ var BABYLON;
              */
             _this.GrainPostProcessId = "GrainPostProcessEffect";
             /**
+             * Glow post process which adds a glow to emmisive areas of the image
+             */
+            _this._glowLayer = null;
+            /**
              * Animations which can be used to tweak settings over a period of time
              */
             _this.animations = [];
@@ -76256,7 +76304,7 @@ var BABYLON;
             _this._hasCleared = false;
             _this._prevPostProcess = null;
             _this._prevPrevPostProcess = null;
-            _this._cameras = cameras || [];
+            _this._cameras = cameras || scene.cameras;
             _this._originalCameras = _this._cameras.slice();
             _this._buildAllowed = automaticBuild;
             // Initialize
@@ -76503,6 +76551,25 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(DefaultRenderingPipeline.prototype, "glowLayerEnabled", {
+            get: function () {
+                return this._glowLayer == null;
+            },
+            /**
+             * If glow layer is enabled. (Adds a glow effect to emmissive materials)
+             */
+            set: function (enabled) {
+                if (enabled && !this._glowLayer) {
+                    this._glowLayer = new BABYLON.GlowLayer("", this._scene);
+                }
+                else if (!enabled && this._glowLayer) {
+                    this._glowLayer.dispose();
+                    this._glowLayer = null;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", {
             get: function () {
                 return this._chromaticAberrationEnabled;
@@ -76672,6 +76739,9 @@ var BABYLON;
                     if (this.grain) {
                         this.grain.dispose(camera);
                     }
+                    if (this._glowLayer) {
+                        this._glowLayer.dispose();
+                    }
                 }
             }
             this.imageProcessing = null;
@@ -76685,6 +76755,7 @@ var BABYLON;
                 this._chromaticAberrationEffect = null;
                 this.grain = null;
                 this._grainEffect = null;
+                this._glowLayer = null;
             }
         };
         /**
@@ -76764,6 +76835,9 @@ var BABYLON;
         ], DefaultRenderingPipeline.prototype, "imageProcessingEnabled", null);
         __decorate([
             BABYLON.serialize()
+        ], DefaultRenderingPipeline.prototype, "glowLayerEnabled", null);
+        __decorate([
+            BABYLON.serialize()
         ], DefaultRenderingPipeline.prototype, "chromaticAberrationEnabled", null);
         __decorate([
             BABYLON.serialize()
@@ -106443,6 +106517,10 @@ var BABYLON;
             /** @hidden */
             GLTFLoader.prototype._loadTextureAsync = function (context, textureInfo, assign) {
                 var _this = this;
+                var promise = GLTF2.GLTFLoaderExtension._LoadTextureAsync(this, context, textureInfo, assign);
+                if (promise) {
+                    return promise;
+                }
                 var texture = GLTFLoader._GetProperty(context + "/index", this._gltf.textures, textureInfo.index);
                 context = "#/textures/" + textureInfo.index;
                 var promises = new Array();
@@ -106780,6 +106858,8 @@ var BABYLON;
             GLTFLoaderExtension.prototype._loadVertexDataAsync = function (context, primitive, babylonMesh) { return null; };
             /** Override this method to modify the default behavior for loading materials. */
             GLTFLoaderExtension.prototype._loadMaterialAsync = function (context, material, babylonMesh, babylonDrawMode, assign) { return null; };
+            /** Override this method to modify the default behavior for loading textures. */
+            GLTFLoaderExtension.prototype._loadTextureAsync = function (context, textureInfo, assign) { return null; };
             /** Override this method to modify the default behavior for loading uris. */
             GLTFLoaderExtension.prototype._loadUriAsync = function (context, uri) { return null; };
             // #endregion
@@ -106819,6 +106899,10 @@ var BABYLON;
             GLTFLoaderExtension._LoadMaterialAsync = function (loader, context, material, babylonMesh, babylonDrawMode, assign) {
                 return loader._applyExtensions(function (extension) { return extension._loadMaterialAsync(context, material, babylonMesh, babylonDrawMode, assign); });
             };
+            /** Helper method called by the loader to allow extensions to override loading textures. */
+            GLTFLoaderExtension._LoadTextureAsync = function (loader, context, textureInfo, assign) {
+                return loader._applyExtensions(function (extension) { return extension._loadTextureAsync(context, textureInfo, assign); });
+            };
             /** Helper method called by the loader to allow extensions to override loading uris. */
             GLTFLoaderExtension._LoadUriAsync = function (loader, context, uri) {
                 return loader._applyExtensions(function (extension) { return extension._loadUriAsync(context, uri); });
@@ -107426,6 +107510,58 @@ var BABYLON;
     })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
 })(BABYLON || (BABYLON = {}));
 
+
+
+var BABYLON;
+(function (BABYLON) {
+    var GLTF2;
+    (function (GLTF2) {
+        var Extensions;
+        (function (Extensions) {
+            var NAME = "KHR_texture_transform";
+            /**
+             * [Specification](https://github.com/AltspaceVR/glTF/blob/avr-sampler-offset-tile/extensions/2.0/Khronos/KHR_texture_transform/README.md) (Experimental)
+             */
+            var KHR_texture_transform = /** @class */ (function (_super) {
+                __extends(KHR_texture_transform, _super);
+                function KHR_texture_transform() {
+                    var _this = _super !== null && _super.apply(this, arguments) || this;
+                    _this.name = NAME;
+                    return _this;
+                }
+                KHR_texture_transform.prototype._loadTextureAsync = function (context, textureInfo, assign) {
+                    var _this = this;
+                    return this._loadExtensionAsync(context, textureInfo, function (extensionContext, extension) {
+                        return _this._loader._loadTextureAsync(context, textureInfo, function (babylonTexture) {
+                            if (extension.offset) {
+                                babylonTexture.uOffset = extension.offset[0];
+                                babylonTexture.vOffset = extension.offset[1];
+                            }
+                            // Always rotate around the origin.
+                            babylonTexture.uRotationCenter = 0;
+                            babylonTexture.vRotationCenter = 0;
+                            if (extension.rotation) {
+                                babylonTexture.wAng = -extension.rotation;
+                            }
+                            if (extension.scale) {
+                                babylonTexture.uScale = extension.scale[0];
+                                babylonTexture.vScale = extension.scale[1];
+                            }
+                            if (extension.texCoord != undefined) {
+                                babylonTexture.coordinatesIndex = extension.texCoord;
+                            }
+                            assign(babylonTexture);
+                        });
+                    });
+                };
+                return KHR_texture_transform;
+            }(GLTF2.GLTFLoaderExtension));
+            Extensions.KHR_texture_transform = KHR_texture_transform;
+            GLTF2.GLTFLoader._Register(NAME, function (loader) { return new KHR_texture_transform(loader); });
+        })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
+    })(GLTF2 = BABYLON.GLTF2 || (BABYLON.GLTF2 = {}));
+})(BABYLON || (BABYLON = {}));
+
     
 
     return BABYLON;
@@ -110678,7 +110814,7 @@ exports.extendedConfiguration = {
         receiveShadows: true
     },
     lab: {
-        assetsRootURL: '/assets/environment/',
+        assetsRootURL: 'https://viewer.babylonjs.com/assets/environment/',
         environmentMap: {
             texture: "EnvMap_2.0-256.env",
             rotationY: 3,

+ 14 - 5
src/Animations/babylon.runtimeAnimation.ts

@@ -496,7 +496,7 @@
             // Compute value
             var repeatCount = (ratio / range) >> 0;
             var currentFrame = returnValue ? from + ratio % range : to;
-
+            
             // Need to normalize?
             if (this._host && this._host.syncRoot) {
                 let syncRoot = this._host.syncRoot;
@@ -504,13 +504,25 @@
                 currentFrame = from + (to - from) * hostNormalizedFrame;
             }
 
+            // Reset events if looping
+            let events = this._animation.getEvents();
+            if (range > 0 && this.currentFrame > currentFrame || 
+                range < 0 && this.currentFrame < currentFrame) {
+                    // Need to reset animation events
+                    for (var index = 0; index < events.length; index++) {
+                        if (!events[index].onlyOnce) {
+                            // reset event, the animation is looping
+                            events[index].isDone = false;
+                        }
+                    }                    
+                }
+
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
             // Set value
             this.setValue(currentValue, weight);
 
             // Check events
-            let events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {
                 // Make sure current frame has passed event frame and that event frame is within the current range
                 // Also, handle both forward and reverse animations
@@ -528,9 +540,6 @@
                         event.isDone = true;
                         event.action();
                     } // Don't do anything if the event has already be done.
-                } else if (events[index].isDone && !events[index].onlyOnce) {
-                    // reset event, the animation is looping
-                    events[index].isDone = false;
                 }
             }
             if (!returnValue) {