浏览代码

Merge branch 'master' into gltf-ktx2

Gary Hsu 5 年之前
父节点
当前提交
9196df8bb6
共有 45 个文件被更改,包括 271 次插入169 次删除
  1. 2 2
      dist/preview release/babylon.js
  2. 12 5
      dist/preview release/babylon.max.js
  3. 1 1
      dist/preview release/babylon.max.js.map
  4. 2 1
      dist/preview release/documentation.d.ts
  5. 1 1
      dist/preview release/glTF2Interface/package.json
  6. 2 2
      dist/preview release/gui/package.json
  7. 7 7
      dist/preview release/inspector/package.json
  8. 37 22
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  9. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  10. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  11. 37 22
      dist/preview release/loaders/babylon.glTFFileLoader.js
  12. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  13. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  14. 2 1
      dist/preview release/loaders/babylonjs.loaders.d.ts
  15. 37 22
      dist/preview release/loaders/babylonjs.loaders.js
  16. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  17. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  18. 4 2
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  19. 3 3
      dist/preview release/loaders/package.json
  20. 2 2
      dist/preview release/materialsLibrary/package.json
  21. 1 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  22. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  23. 13 11
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  24. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  25. 3 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  26. 2 2
      dist/preview release/nodeEditor/package.json
  27. 1 1
      dist/preview release/package.json
  28. 1 1
      dist/preview release/packagesSizeBaseLine.json
  29. 2 2
      dist/preview release/postProcessesLibrary/package.json
  30. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  31. 3 3
      dist/preview release/serializers/package.json
  32. 3 3
      dist/preview release/viewer/babylon.viewer.js
  33. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  34. 4 2
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  35. 2 1
      dist/preview release/what's new.md
  36. 40 20
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  37. 1 1
      nodeEditor/src/components/propertyTab/properties/floatPropertyTabComponent.tsx
  38. 1 1
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  39. 2 2
      nodeEditor/src/diagram/properties/clampNodePropertyComponent.tsx
  40. 2 2
      nodeEditor/src/diagram/properties/inputNodePropertyComponent.tsx
  41. 4 4
      nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx
  42. 8 1
      nodeEditor/src/sharedComponents/floatLineComponent.tsx
  43. 1 1
      package.json
  44. 5 5
      src/Engines/thinEngine.ts
  45. 10 0
      src/Lights/spotLight.ts

文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/babylon.js


+ 12 - 5
dist/preview release/babylon.max.js

@@ -36710,7 +36710,7 @@ var ThinEngine = /** @class */ (function () {
          */
         // Not mixed with Version for tooling purpose.
         get: function () {
-            return "babylonjs@4.1.0-beta.25";
+            return "babylonjs@4.1.0-beta.27";
         },
         enumerable: true,
         configurable: true
@@ -36720,7 +36720,7 @@ var ThinEngine = /** @class */ (function () {
          * Returns the current version of the framework
          */
         get: function () {
-            return "4.1.0-beta.25";
+            return "4.1.0-beta.27";
         },
         enumerable: true,
         configurable: true
@@ -39081,15 +39081,15 @@ var ThinEngine = /** @class */ (function () {
         if (wrapV === void 0) { wrapV = null; }
         if (wrapR === void 0) { wrapR = null; }
         var target = this._getTextureTarget(texture);
-        if (wrapU) {
+        if (wrapU !== null) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_S, this._getTextureWrapMode(wrapU), texture);
             texture._cachedWrapU = wrapU;
         }
-        if (wrapV) {
+        if (wrapV !== null) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_T, this._getTextureWrapMode(wrapV), texture);
             texture._cachedWrapV = wrapV;
         }
-        if ((texture.is2DArray || texture.is3D) && wrapR) {
+        if ((texture.is2DArray || texture.is3D) && (wrapR !== null)) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_R, this._getTextureWrapMode(wrapR), texture);
             texture._cachedWrapR = wrapR;
         }
@@ -58335,6 +58335,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _node__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../node */ "./node.ts");
 /* harmony import */ var _light__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./light */ "./Lights/light.ts");
 /* harmony import */ var _shadowLight__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./shadowLight */ "./Lights/shadowLight.ts");
+/* harmony import */ var _Materials_Textures_texture__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../Materials/Textures/texture */ "./Materials/Textures/texture.ts");
+
 
 
 
@@ -58596,6 +58598,11 @@ var SpotLight = /** @class */ (function (_super) {
     SpotLight.prototype._computeProjectionTextureMatrix = function () {
         this._projectionTextureDirty = false;
         this._projectionTextureViewLightMatrix.multiplyToRef(this._projectionTextureProjectionLightMatrix, this._projectionTextureMatrix);
+        if (this._projectionTexture instanceof _Materials_Textures_texture__WEBPACK_IMPORTED_MODULE_6__["Texture"]) {
+            var u = this._projectionTexture.uScale / 2.0;
+            var v = this._projectionTexture.vScale / 2.0;
+            _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Matrix"].FromValuesToRef(u, 0.0, 0.0, 0.0, 0.0, v, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0, this._projectionTextureScalingMatrix);
+        }
         this._projectionTextureMatrix.multiplyToRef(this._projectionTextureScalingMatrix, this._projectionTextureMatrix);
     };
     SpotLight.prototype._buildUniformLayout = function () {

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 2 - 1
dist/preview release/documentation.d.ts

@@ -76204,7 +76204,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 2 - 2
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

+ 7 - 7
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,12 +29,12 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25",
-        "babylonjs-gui": "4.1.0-beta.25",
-        "babylonjs-loaders": "4.1.0-beta.25",
-        "babylonjs-materials": "4.1.0-beta.25",
-        "babylonjs-serializers": "4.1.0-beta.25",
-        "babylonjs-gltf2interface": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27",
+        "babylonjs-gui": "4.1.0-beta.27",
+        "babylonjs-loaders": "4.1.0-beta.27",
+        "babylonjs-materials": "4.1.0-beta.27",
+        "babylonjs-serializers": "4.1.0-beta.27",
+        "babylonjs-gltf2interface": "4.1.0-beta.27"
     },
     "devDependencies": {
         "@types/react": "~16.7.3",

+ 37 - 22
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1338,7 +1338,6 @@ var MSFT_lod = /** @class */ (function () {
     }
     /** @hidden */
     MSFT_lod.prototype.dispose = function () {
-        this._disposeUnusedMaterials();
         delete this._loader;
         this._nodeIndexLOD = null;
         this._nodeSignalLODs.length = 0;
@@ -1426,9 +1425,8 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _babylonTransformNode
                         var previousNodeLOD = nodeLODs[indexLOD - 1];
                         if (previousNodeLOD._babylonTransformNode) {
-                            previousNodeLOD._babylonTransformNode.dispose();
+                            _this._disposeTransformNode(previousNodeLOD._babylonTransformNode);
                             delete previousNodeLOD._babylonTransformNode;
-                            _this._disposeUnusedMaterials();
                         }
                     }
                     babylonMesh.setEnabled(true);
@@ -1478,7 +1476,7 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _data
                         var previousDataLOD = materialLODs[indexLOD - 1]._data;
                         if (previousDataLOD[babylonDrawMode]) {
-                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                            _this._disposeMaterials([previousDataLOD[babylonDrawMode].babylonMaterial]);
                             delete previousDataLOD[babylonDrawMode];
                         }
                     }
@@ -1573,27 +1571,44 @@ var MSFT_lod = /** @class */ (function () {
         properties.push(property);
         return properties;
     };
-    MSFT_lod.prototype._disposeUnusedMaterials = function () {
-        // TODO: should not rely on _data
-        var materials = this._loader.gltf.materials;
-        if (materials) {
-            for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
-                var material = materials_1[_i];
-                if (material._data) {
-                    var _loop_5 = function (drawMode) {
-                        var data = material._data[drawMode];
-                        if (data.babylonMeshes.every(function (babylonMesh) { return babylonMesh.material !== data.babylonMaterial; })) {
-                            // TODO: check if texture is in use instead of force disposing textures
-                            data.babylonMaterial.dispose(false, true);
-                            delete material._data[drawMode];
-                        }
-                    };
-                    for (var drawMode in material._data) {
-                        _loop_5(drawMode);
-                    }
+    MSFT_lod.prototype._disposeTransformNode = function (babylonTransformNode) {
+        var _this = this;
+        var babylonMaterials = new Array();
+        var babylonMaterial = babylonTransformNode.material;
+        if (babylonMaterial) {
+            babylonMaterials.push(babylonMaterial);
+        }
+        for (var _i = 0, _a = babylonTransformNode.getChildMeshes(); _i < _a.length; _i++) {
+            var babylonMesh = _a[_i];
+            if (babylonMesh.material) {
+                babylonMaterials.push(babylonMesh.material);
+            }
+        }
+        babylonTransformNode.dispose();
+        var babylonMaterialsToDispose = babylonMaterials.filter(function (babylonMaterial) { return _this._loader.babylonScene.meshes.every(function (mesh) { return mesh.material != babylonMaterial; }); });
+        this._disposeMaterials(babylonMaterialsToDispose);
+    };
+    MSFT_lod.prototype._disposeMaterials = function (babylonMaterials) {
+        var babylonTextures = {};
+        for (var _i = 0, babylonMaterials_1 = babylonMaterials; _i < babylonMaterials_1.length; _i++) {
+            var babylonMaterial = babylonMaterials_1[_i];
+            for (var _a = 0, _b = babylonMaterial.getActiveTextures(); _a < _b.length; _a++) {
+                var babylonTexture = _b[_a];
+                babylonTextures[babylonTexture.uniqueId] = babylonTexture;
+            }
+            babylonMaterial.dispose();
+        }
+        for (var uniqueId in babylonTextures) {
+            for (var _c = 0, _d = this._loader.babylonScene.materials; _c < _d.length; _c++) {
+                var babylonMaterial = _d[_c];
+                if (babylonMaterial.hasTexture(babylonTextures[uniqueId])) {
+                    delete babylonTextures[uniqueId];
                 }
             }
         }
+        for (var uniqueId in babylonTextures) {
+            babylonTextures[uniqueId].dispose();
+        }
     };
     return MSFT_lod;
 }());

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 37 - 22
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3915,7 +3915,6 @@ var MSFT_lod = /** @class */ (function () {
     }
     /** @hidden */
     MSFT_lod.prototype.dispose = function () {
-        this._disposeUnusedMaterials();
         delete this._loader;
         this._nodeIndexLOD = null;
         this._nodeSignalLODs.length = 0;
@@ -4003,9 +4002,8 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _babylonTransformNode
                         var previousNodeLOD = nodeLODs[indexLOD - 1];
                         if (previousNodeLOD._babylonTransformNode) {
-                            previousNodeLOD._babylonTransformNode.dispose();
+                            _this._disposeTransformNode(previousNodeLOD._babylonTransformNode);
                             delete previousNodeLOD._babylonTransformNode;
-                            _this._disposeUnusedMaterials();
                         }
                     }
                     babylonMesh.setEnabled(true);
@@ -4055,7 +4053,7 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _data
                         var previousDataLOD = materialLODs[indexLOD - 1]._data;
                         if (previousDataLOD[babylonDrawMode]) {
-                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                            _this._disposeMaterials([previousDataLOD[babylonDrawMode].babylonMaterial]);
                             delete previousDataLOD[babylonDrawMode];
                         }
                     }
@@ -4150,27 +4148,44 @@ var MSFT_lod = /** @class */ (function () {
         properties.push(property);
         return properties;
     };
-    MSFT_lod.prototype._disposeUnusedMaterials = function () {
-        // TODO: should not rely on _data
-        var materials = this._loader.gltf.materials;
-        if (materials) {
-            for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
-                var material = materials_1[_i];
-                if (material._data) {
-                    var _loop_5 = function (drawMode) {
-                        var data = material._data[drawMode];
-                        if (data.babylonMeshes.every(function (babylonMesh) { return babylonMesh.material !== data.babylonMaterial; })) {
-                            // TODO: check if texture is in use instead of force disposing textures
-                            data.babylonMaterial.dispose(false, true);
-                            delete material._data[drawMode];
-                        }
-                    };
-                    for (var drawMode in material._data) {
-                        _loop_5(drawMode);
-                    }
+    MSFT_lod.prototype._disposeTransformNode = function (babylonTransformNode) {
+        var _this = this;
+        var babylonMaterials = new Array();
+        var babylonMaterial = babylonTransformNode.material;
+        if (babylonMaterial) {
+            babylonMaterials.push(babylonMaterial);
+        }
+        for (var _i = 0, _a = babylonTransformNode.getChildMeshes(); _i < _a.length; _i++) {
+            var babylonMesh = _a[_i];
+            if (babylonMesh.material) {
+                babylonMaterials.push(babylonMesh.material);
+            }
+        }
+        babylonTransformNode.dispose();
+        var babylonMaterialsToDispose = babylonMaterials.filter(function (babylonMaterial) { return _this._loader.babylonScene.meshes.every(function (mesh) { return mesh.material != babylonMaterial; }); });
+        this._disposeMaterials(babylonMaterialsToDispose);
+    };
+    MSFT_lod.prototype._disposeMaterials = function (babylonMaterials) {
+        var babylonTextures = {};
+        for (var _i = 0, babylonMaterials_1 = babylonMaterials; _i < babylonMaterials_1.length; _i++) {
+            var babylonMaterial = babylonMaterials_1[_i];
+            for (var _a = 0, _b = babylonMaterial.getActiveTextures(); _a < _b.length; _a++) {
+                var babylonTexture = _b[_a];
+                babylonTextures[babylonTexture.uniqueId] = babylonTexture;
+            }
+            babylonMaterial.dispose();
+        }
+        for (var uniqueId in babylonTextures) {
+            for (var _c = 0, _d = this._loader.babylonScene.materials; _c < _d.length; _c++) {
+                var babylonMaterial = _d[_c];
+                if (babylonMaterial.hasTexture(babylonTextures[uniqueId])) {
+                    delete babylonTextures[uniqueId];
                 }
             }
         }
+        for (var uniqueId in babylonTextures) {
+            babylonTextures[uniqueId].dispose();
+        }
     };
     return MSFT_lod;
 }());

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 2 - 1
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -1969,7 +1969,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

+ 37 - 22
dist/preview release/loaders/babylonjs.loaders.js

@@ -5294,7 +5294,6 @@ var MSFT_lod = /** @class */ (function () {
     }
     /** @hidden */
     MSFT_lod.prototype.dispose = function () {
-        this._disposeUnusedMaterials();
         delete this._loader;
         this._nodeIndexLOD = null;
         this._nodeSignalLODs.length = 0;
@@ -5382,9 +5381,8 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _babylonTransformNode
                         var previousNodeLOD = nodeLODs[indexLOD - 1];
                         if (previousNodeLOD._babylonTransformNode) {
-                            previousNodeLOD._babylonTransformNode.dispose();
+                            _this._disposeTransformNode(previousNodeLOD._babylonTransformNode);
                             delete previousNodeLOD._babylonTransformNode;
-                            _this._disposeUnusedMaterials();
                         }
                     }
                     babylonMesh.setEnabled(true);
@@ -5434,7 +5432,7 @@ var MSFT_lod = /** @class */ (function () {
                         // TODO: should not rely on _data
                         var previousDataLOD = materialLODs[indexLOD - 1]._data;
                         if (previousDataLOD[babylonDrawMode]) {
-                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                            _this._disposeMaterials([previousDataLOD[babylonDrawMode].babylonMaterial]);
                             delete previousDataLOD[babylonDrawMode];
                         }
                     }
@@ -5529,27 +5527,44 @@ var MSFT_lod = /** @class */ (function () {
         properties.push(property);
         return properties;
     };
-    MSFT_lod.prototype._disposeUnusedMaterials = function () {
-        // TODO: should not rely on _data
-        var materials = this._loader.gltf.materials;
-        if (materials) {
-            for (var _i = 0, materials_1 = materials; _i < materials_1.length; _i++) {
-                var material = materials_1[_i];
-                if (material._data) {
-                    var _loop_5 = function (drawMode) {
-                        var data = material._data[drawMode];
-                        if (data.babylonMeshes.every(function (babylonMesh) { return babylonMesh.material !== data.babylonMaterial; })) {
-                            // TODO: check if texture is in use instead of force disposing textures
-                            data.babylonMaterial.dispose(false, true);
-                            delete material._data[drawMode];
-                        }
-                    };
-                    for (var drawMode in material._data) {
-                        _loop_5(drawMode);
-                    }
+    MSFT_lod.prototype._disposeTransformNode = function (babylonTransformNode) {
+        var _this = this;
+        var babylonMaterials = new Array();
+        var babylonMaterial = babylonTransformNode.material;
+        if (babylonMaterial) {
+            babylonMaterials.push(babylonMaterial);
+        }
+        for (var _i = 0, _a = babylonTransformNode.getChildMeshes(); _i < _a.length; _i++) {
+            var babylonMesh = _a[_i];
+            if (babylonMesh.material) {
+                babylonMaterials.push(babylonMesh.material);
+            }
+        }
+        babylonTransformNode.dispose();
+        var babylonMaterialsToDispose = babylonMaterials.filter(function (babylonMaterial) { return _this._loader.babylonScene.meshes.every(function (mesh) { return mesh.material != babylonMaterial; }); });
+        this._disposeMaterials(babylonMaterialsToDispose);
+    };
+    MSFT_lod.prototype._disposeMaterials = function (babylonMaterials) {
+        var babylonTextures = {};
+        for (var _i = 0, babylonMaterials_1 = babylonMaterials; _i < babylonMaterials_1.length; _i++) {
+            var babylonMaterial = babylonMaterials_1[_i];
+            for (var _a = 0, _b = babylonMaterial.getActiveTextures(); _a < _b.length; _a++) {
+                var babylonTexture = _b[_a];
+                babylonTextures[babylonTexture.uniqueId] = babylonTexture;
+            }
+            babylonMaterial.dispose();
+        }
+        for (var uniqueId in babylonTextures) {
+            for (var _c = 0, _d = this._loader.babylonScene.materials; _c < _d.length; _c++) {
+                var babylonMaterial = _d[_c];
+                if (babylonMaterial.hasTexture(babylonTextures[uniqueId])) {
+                    delete babylonTextures[uniqueId];
                 }
             }
         }
+        for (var uniqueId in babylonTextures) {
+            babylonTextures[uniqueId].dispose();
+        }
     };
     return MSFT_lod;
 }());

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 4 - 2
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -2121,7 +2121,8 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_lod" {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_minecraftMesh" {
@@ -4556,7 +4557,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

+ 3 - 3
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.1.0-beta.25",
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs-gltf2interface": "4.1.0-beta.27",
+        "babylonjs": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

+ 1 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -341,6 +341,7 @@ declare module NODEEDITOR {
         additionalClass?: string;
         step?: string;
         digits?: number;
+        globalState: GlobalState;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.js


+ 13 - 11
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -52550,7 +52550,7 @@ var FloatPropertyTabComponent = /** @class */ (function (_super) {
     }
     FloatPropertyTabComponent.prototype.render = function () {
         var _this = this;
-        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { label: "Value", target: this.props.inputBlock, propertyName: "value", onChange: function () {
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { globalState: this.props.globalState, label: "Value", target: this.props.inputBlock, propertyName: "value", onChange: function () {
                 if (_this.props.inputBlock.isConstant) {
                     _this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                 }
@@ -52837,7 +52837,7 @@ var PropertyTabComponent = /** @class */ (function (_super) {
                                 _this.processInputBlockUpdate(block);
                             } }),
                     !block.isBoolean && cantDisplaySlider &&
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_16__["FloatLineComponent"], { key: block.uniqueId, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }),
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_16__["FloatLineComponent"], { globalState: this.props.globalState, key: block.uniqueId, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }),
                     !block.isBoolean && !cantDisplaySlider &&
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_sliderLineComponent__WEBPACK_IMPORTED_MODULE_11__["SliderLineComponent"], { key: block.uniqueId, label: block.name, target: block, propertyName: "value", step: (block.max - block.min) / 100.0, minimum: block.min, maximum: block.max, onChange: function () { return _this.processInputBlockUpdate(block); } })));
             case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Color3:
@@ -55764,8 +55764,8 @@ var ClampPropertyTabComponent = /** @class */ (function (_super) {
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_genericNodePropertyComponent__WEBPACK_IMPORTED_MODULE_4__["GenericPropertyTabComponent"], { globalState: this.props.globalState, block: this.props.block }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { title: "PROPERTIES" },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { label: "Minimum", propertyName: "minimum", target: clampBlock, onChange: function () { return _this.forceRebuild(); } }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { label: "Maximum", propertyName: "maximum", target: clampBlock, onChange: function () { return _this.forceRebuild(); } }))));
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { globalState: this.props.globalState, label: "Minimum", propertyName: "minimum", target: clampBlock, onChange: function () { return _this.forceRebuild(); } }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { globalState: this.props.globalState, label: "Maximum", propertyName: "maximum", target: clampBlock, onChange: function () { return _this.forceRebuild(); } }))));
     };
     return ClampPropertyTabComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -56101,11 +56101,11 @@ var InputPropertyTabComponent = /** @class */ (function (_super) {
                                 _this.forceUpdate();
                             } }),
                     !inputBlock.isBoolean &&
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { label: "Min", target: inputBlock, propertyName: "min", onChange: function () {
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { globalState: this.props.globalState, label: "Min", target: inputBlock, propertyName: "min", onChange: function () {
                                 _this.forceUpdate();
                             } }),
                     !inputBlock.isBoolean &&
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { label: "Max", target: inputBlock, propertyName: "max", onChange: function () {
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { globalState: this.props.globalState, label: "Max", target: inputBlock, propertyName: "max", onChange: function () {
                                 _this.forceUpdate();
                             } }),
                     !inputBlock.isBoolean && cantDisplaySlider &&
@@ -56661,19 +56661,19 @@ var TexturePropertyTabComponent = /** @class */ (function (_super) {
                             _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         } }),
                 texture && !isInReflectionMode &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { label: "Offset U", target: texture, propertyName: "uOffset", onChange: function () {
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { globalState: this.props.globalState, label: "Offset U", target: texture, propertyName: "uOffset", onChange: function () {
                             _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         } }),
                 texture && !isInReflectionMode &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { label: "Offset V", target: texture, propertyName: "vOffset", onChange: function () {
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { globalState: this.props.globalState, label: "Offset V", target: texture, propertyName: "vOffset", onChange: function () {
                             _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         } }),
                 texture && !isInReflectionMode &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { label: "Scale U", target: texture, propertyName: "uScale", onChange: function () {
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { globalState: this.props.globalState, label: "Scale U", target: texture, propertyName: "uScale", onChange: function () {
                             _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         } }),
                 texture && !isInReflectionMode &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { label: "Scale V", target: texture, propertyName: "vScale", onChange: function () {
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_8__["FloatLineComponent"], { globalState: this.props.globalState, label: "Scale V", target: texture, propertyName: "vScale", onChange: function () {
                             _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         } }),
                 texture && !isInReflectionMode &&
@@ -58462,7 +58462,9 @@ var FloatLineComponent = /** @class */ (function (_super) {
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null, react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "label" }, this.props.label),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "value" },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("input", { type: "number", step: this.props.step || "0.01", className: "numeric-input", value: this.state.value, onChange: function (evt) { return _this.updateValue(evt.target.value); } })))));
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("input", { type: "number", step: this.props.step || "0.01", className: "numeric-input", onBlur: function (evt) {
+                        _this.props.globalState.blockKeyboardEvents = false;
+                    }, onFocus: function () { return _this.props.globalState.blockKeyboardEvents = true; }, value: this.state.value, onChange: function (evt) { return _this.updateValue(evt.target.value); } })))));
     };
     return FloatLineComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


+ 3 - 0
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts

@@ -427,6 +427,7 @@ declare module "babylonjs-node-editor/sharedComponents/floatLineComponent" {
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
     import { PropertyChangedEvent } from "babylonjs-node-editor/sharedComponents/propertyChangedEvent";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
     interface IFloatLineComponentProps {
         label: string;
         target: any;
@@ -437,6 +438,7 @@ declare module "babylonjs-node-editor/sharedComponents/floatLineComponent" {
         additionalClass?: string;
         step?: string;
         digits?: number;
+        globalState: GlobalState;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
@@ -1985,6 +1987,7 @@ declare module NODEEDITOR {
         additionalClass?: string;
         step?: string;
         digits?: number;
+        globalState: GlobalState;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;

+ 2 - 2
dist/preview release/nodeEditor/package.json

@@ -4,14 +4,14 @@
     },
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27"
     },
     "files": [
         "babylon.nodeEditor.max.js.map",

+ 1 - 1
dist/preview release/package.json

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":112467,"engineOnly":148577,"sceneOnly":504040,"minGridMaterial":634667,"minStandardMaterial":774539}
+{"thinEngineOnly":112467,"engineOnly":149443,"sceneOnly":504906,"minGridMaterial":635533,"minStandardMaterial":775405}

+ 2 - 2
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

+ 3 - 3
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.25",
-        "babylonjs-gltf2interface": "4.1.0-beta.25"
+        "babylonjs": "4.1.0-beta.27",
+        "babylonjs-gltf2interface": "4.1.0-beta.27"
     },
     "engines": {
         "node": "*"

文件差异内容过多而无法显示
+ 3 - 3
dist/preview release/viewer/babylon.viewer.js


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 4 - 2
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -2121,7 +2121,8 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_lod" {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/MSFT_minecraftMesh" {
@@ -4556,7 +4557,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
          * Gets an array of LOD properties from lowest to highest.
          */
         private _getLODs;
-        private _disposeUnusedMaterials;
+        private _disposeTransformNode;
+        private _disposeMaterials;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

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

@@ -148,6 +148,7 @@
 - Added support for animations import from separate files ([noalak](https://github.com/noalak/))
 - Use web workers to validate glTF to avoid blocking the main thread. ([bghgary](https://github.com/bghgary))
 - Update glTF validator to 2.0.0-dev.3.1. ([bghgary](https://github.com/bghgary))
+- Fix an issue with disposing materials and textures too aggressively in MSFT_lod loader extension. ([bghgary](https://github.com/bghgary))
 - Added experimental support for loading KTX2 files and `KHR_texture_basisu` glTF extension. ([bghgary](https://github.com/bghgary))
 
 ### Materials
@@ -194,7 +195,7 @@
 - UI Button has options to set different session mode and reference type ([RaananW](https://github.com/RaananW/))
 - Added option to change the teleportation duration in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 - Added support to teleport the camera at constant speed in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
-- VRExperienceHelper has now an XR fallback to force XR usage (Beta) ([RaananW](https://github.com/RaananW/))
+- VRExperienceHelper has now an XR fallback to force XR usage (beta) ([RaananW](https://github.com/RaananW/))
 - Added option to change the teleportation easing function in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 - Windows motion controller mapping corrected to XR (xr-standard) ([RaananW](https://github.com/RaananW/))
 - Pointer-Event simulation for screen target ray mode ([RaananW](https://github.com/RaananW/))

+ 40 - 20
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -4,7 +4,7 @@ import { Deferred } from "babylonjs/Misc/deferred";
 import { Material } from "babylonjs/Materials/material";
 import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Mesh } from "babylonjs/Meshes/mesh";
-
+import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
 import { INode, IMaterial, IBuffer, IScene } from "../glTFLoaderInterfaces";
 import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
 import { GLTFLoader, ArrayItem } from "../glTFLoader";
@@ -75,8 +75,6 @@ export class MSFT_lod implements IGLTFLoaderExtension {
 
     /** @hidden */
     public dispose() {
-        this._disposeUnusedMaterials();
-
         delete this._loader;
 
         this._nodeIndexLOD = null;
@@ -174,9 +172,8 @@ export class MSFT_lod implements IGLTFLoaderExtension {
                         // TODO: should not rely on _babylonTransformNode
                         const previousNodeLOD = nodeLODs[indexLOD - 1];
                         if (previousNodeLOD._babylonTransformNode) {
-                            previousNodeLOD._babylonTransformNode.dispose();
+                            this._disposeTransformNode(previousNodeLOD._babylonTransformNode);
                             delete previousNodeLOD._babylonTransformNode;
-                            this._disposeUnusedMaterials();
                         }
                     }
 
@@ -235,7 +232,7 @@ export class MSFT_lod implements IGLTFLoaderExtension {
                         // TODO: should not rely on _data
                         const previousDataLOD = materialLODs[indexLOD - 1]._data!;
                         if (previousDataLOD[babylonDrawMode]) {
-                            previousDataLOD[babylonDrawMode].babylonMaterial.dispose();
+                            this._disposeMaterials([previousDataLOD[babylonDrawMode].babylonMaterial]);
                             delete previousDataLOD[babylonDrawMode];
                         }
                     }
@@ -344,23 +341,46 @@ export class MSFT_lod implements IGLTFLoaderExtension {
         return properties;
     }
 
-    private _disposeUnusedMaterials(): void {
-        // TODO: should not rely on _data
-        const materials = this._loader.gltf.materials;
-        if (materials) {
-            for (const material of materials) {
-                if (material._data) {
-                    for (const drawMode in material._data) {
-                        const data = material._data[drawMode];
-                        if (data.babylonMeshes.every((babylonMesh) => babylonMesh.material !== data.babylonMaterial)) {
-                            // TODO: check if texture is in use instead of force disposing textures
-                            data.babylonMaterial.dispose(false, true);
-                            delete material._data[drawMode];
-                        }
-                    }
+    private _disposeTransformNode(babylonTransformNode: TransformNode): void {
+        const babylonMaterials = new Array<Material>();
+        const babylonMaterial = (babylonTransformNode as Mesh).material;
+        if (babylonMaterial) {
+            babylonMaterials.push(babylonMaterial);
+        }
+        for (const babylonMesh of babylonTransformNode.getChildMeshes()) {
+            if (babylonMesh.material) {
+                babylonMaterials.push(babylonMesh.material);
+            }
+        }
+
+        babylonTransformNode.dispose();
+
+        const babylonMaterialsToDispose = babylonMaterials.filter((babylonMaterial) => this._loader.babylonScene.meshes.every((mesh) => mesh.material != babylonMaterial));
+        this._disposeMaterials(babylonMaterialsToDispose);
+    }
+
+    private _disposeMaterials(babylonMaterials: Material[]): void {
+        const babylonTextures: { [uniqueId: number]: BaseTexture } = {};
+
+        for (const babylonMaterial of babylonMaterials) {
+            for (const babylonTexture of babylonMaterial.getActiveTextures()) {
+                babylonTextures[babylonTexture.uniqueId] = babylonTexture;
+            }
+
+            babylonMaterial.dispose();
+        }
+
+        for (const uniqueId in babylonTextures) {
+            for (const babylonMaterial of this._loader.babylonScene.materials) {
+                if (babylonMaterial.hasTexture(babylonTextures[uniqueId])) {
+                    delete babylonTextures[uniqueId];
                 }
             }
         }
+
+        for (const uniqueId in babylonTextures) {
+            babylonTextures[uniqueId].dispose();
+        }
     }
 }
 

+ 1 - 1
nodeEditor/src/components/propertyTab/properties/floatPropertyTabComponent.tsx

@@ -13,7 +13,7 @@ export class FloatPropertyTabComponent extends React.Component<IFloatPropertyTab
 
     render() {
         return (
-            <FloatLineComponent label="Value" target={this.props.inputBlock} propertyName="value" onChange={() => {
+            <FloatLineComponent globalState={this.props.globalState} label="Value" target={this.props.inputBlock} propertyName="value" onChange={() => {
                 if (this.props.inputBlock.isConstant) {
                     this.props.globalState.onRebuildRequiredObservable.notifyObservers();    
                 }

+ 1 - 1
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -83,7 +83,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                             }
                             {
                                 !block.isBoolean && cantDisplaySlider &&
-                                <FloatLineComponent key={block.uniqueId} label={block.name} target={block} propertyName="value" 
+                                <FloatLineComponent globalState={this.props.globalState} key={block.uniqueId} label={block.name} target={block} propertyName="value" 
                                 onChange={() => this.processInputBlockUpdate(block)}/>
                             }        
                             {

+ 2 - 2
nodeEditor/src/diagram/properties/clampNodePropertyComponent.tsx

@@ -24,8 +24,8 @@ export class ClampPropertyTabComponent extends React.Component<IPropertyComponen
             <div>
                 <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
-                  <FloatLineComponent label="Minimum" propertyName="minimum" target={clampBlock} onChange={() => this.forceRebuild()} />
-                  <FloatLineComponent label="Maximum" propertyName="maximum" target={clampBlock} onChange={() => this.forceRebuild()} />
+                  <FloatLineComponent globalState={this.props.globalState} label="Minimum" propertyName="minimum" target={clampBlock} onChange={() => this.forceRebuild()} />
+                  <FloatLineComponent globalState={this.props.globalState} label="Maximum" propertyName="maximum" target={clampBlock} onChange={() => this.forceRebuild()} />
                 </LineContainerComponent>
             </div>
         );

+ 2 - 2
nodeEditor/src/diagram/properties/inputNodePropertyComponent.tsx

@@ -51,13 +51,13 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
                         }
                         {
                             !inputBlock.isBoolean &&
-                            <FloatLineComponent label="Min" target={inputBlock} propertyName="min" onChange={() => {
+                            <FloatLineComponent globalState={this.props.globalState} label="Min" target={inputBlock} propertyName="min" onChange={() => {
                                 this.forceUpdate();
                             }}></FloatLineComponent>
                         }
                         {
                             !inputBlock.isBoolean &&
-                            <FloatLineComponent label="Max" target={inputBlock} propertyName="max" onChange={() => {
+                            <FloatLineComponent globalState={this.props.globalState} label="Max" target={inputBlock} propertyName="max" onChange={() => {
                                     this.forceUpdate();
                                 }}></FloatLineComponent>      
                         }

+ 4 - 4
nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx

@@ -212,7 +212,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
                     }        
                     {
                         texture && !isInReflectionMode &&
-                        <FloatLineComponent label="Offset U" target={texture} propertyName="uOffset" 
+                        <FloatLineComponent globalState={this.props.globalState} label="Offset U" target={texture} propertyName="uOffset" 
                         onChange={() => {
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         }}
@@ -220,7 +220,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
                     }
                     {
                         texture && !isInReflectionMode &&
-                        <FloatLineComponent label="Offset V" target={texture} propertyName="vOffset"
+                        <FloatLineComponent globalState={this.props.globalState} label="Offset V" target={texture} propertyName="vOffset"
                         onChange={() => {
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         }}
@@ -228,14 +228,14 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
                     }
                     {
                         texture && !isInReflectionMode &&
-                        <FloatLineComponent label="Scale U" target={texture} propertyName="uScale"
+                        <FloatLineComponent globalState={this.props.globalState} label="Scale U" target={texture} propertyName="uScale"
                         onChange={() => {
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         }} />
                     }
                     {
                         texture && !isInReflectionMode &&
-                        <FloatLineComponent label="Scale V" target={texture} propertyName="vScale"
+                        <FloatLineComponent globalState={this.props.globalState} label="Scale V" target={texture} propertyName="vScale"
                         onChange={() => {
                             this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         }} />

+ 8 - 1
nodeEditor/src/sharedComponents/floatLineComponent.tsx

@@ -2,6 +2,7 @@ import * as React from "react";
 
 import { Observable } from "babylonjs/Misc/observable";
 import { PropertyChangedEvent } from "./propertyChangedEvent";
+import { GlobalState } from '../globalState';
 
 interface IFloatLineComponentProps {
     label: string;
@@ -13,6 +14,7 @@ interface IFloatLineComponentProps {
     additionalClass?: string;
     step?: string,
     digits?: number;
+    globalState: GlobalState
 }
 
 export class FloatLineComponent extends React.Component<IFloatLineComponentProps, { value: string }> {
@@ -98,7 +100,12 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
                             {this.props.label}
                         </div>
                         <div className="value">
-                            <input type="number" step={this.props.step || "0.01"} className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
+                            <input type="number" step={this.props.step || "0.01"} className="numeric-input" 
+                            onBlur={evt => {
+                                this.props.globalState.blockKeyboardEvents = false;
+                            }}
+                            onFocus={() => this.props.globalState.blockKeyboardEvents = true}
+                            value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
                         </div>
                     </div>
                 }

+ 1 - 1
package.json

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.1.0-beta.25",
+    "version": "4.1.0-beta.27",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 5 - 5
src/Engines/thinEngine.ts

@@ -132,14 +132,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.1.0-beta.25";
+        return "babylonjs@4.1.0-beta.27";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.1.0-beta.25";
+        return "4.1.0-beta.27";
     }
 
     /**
@@ -3095,15 +3095,15 @@ export class ThinEngine {
     public updateTextureWrappingMode(texture: InternalTexture, wrapU: Nullable<number>, wrapV: Nullable<number> = null, wrapR: Nullable<number> = null): void {
         const target = this._getTextureTarget(texture);
 
-        if (wrapU) {
+        if (wrapU !== null) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_S, this._getTextureWrapMode(wrapU), texture);
             texture._cachedWrapU = wrapU;
         }
-        if (wrapV) {
+        if (wrapV !== null) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_T, this._getTextureWrapMode(wrapV), texture);
             texture._cachedWrapV = wrapV;
         }
-        if ((texture.is2DArray || texture.is3D) && wrapR) {
+        if ((texture.is2DArray || texture.is3D) && (wrapR !== null)) {
             this._setTextureParameterInteger(target, this._gl.TEXTURE_WRAP_R, this._getTextureWrapMode(wrapR), texture);
             texture._cachedWrapR = wrapR;
         }

+ 10 - 0
src/Lights/spotLight.ts

@@ -302,6 +302,16 @@ export class SpotLight extends ShadowLight {
         this._projectionTextureDirty = false;
 
         this._projectionTextureViewLightMatrix.multiplyToRef(this._projectionTextureProjectionLightMatrix, this._projectionTextureMatrix);
+        if (this._projectionTexture instanceof Texture) {
+            const u = this._projectionTexture.uScale / 2.0;
+            const v = this._projectionTexture.vScale / 2.0;
+            Matrix.FromValuesToRef(
+                u,   0.0, 0.0, 0.0,
+                0.0, v,   0.0, 0.0,
+                0.0, 0.0, 0.5, 0.0,
+                0.5, 0.5, 0.5, 1.0
+            , this._projectionTextureScalingMatrix);
+        }
         this._projectionTextureMatrix.multiplyToRef(this._projectionTextureScalingMatrix, this._projectionTextureMatrix);
     }