Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

Guide 7 năm trước cách đây
mục cha
commit
f1e82336a0
47 tập tin đã thay đổi với 3699 bổ sung2019 xóa
  1. 924 915
      Playground/babylon.d.txt
  2. 738 468
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 460 129
      dist/preview release/babylon.max.js
  5. 460 129
      dist/preview release/babylon.no-module.max.js
  6. 1 1
      dist/preview release/babylon.worker.js
  7. 462 131
      dist/preview release/es6.js
  8. 1 1
      dist/preview release/gui/babylon.gui.min.js.map
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  10. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js.map
  11. 2 0
      dist/preview release/inspector/babylon.inspector.d.ts
  12. 4 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  13. 8 5
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  14. 9 6
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  15. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  16. 11 7
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  17. 14 9
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  18. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  19. 11 7
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  20. 14 9
      dist/preview release/loaders/babylon.glTFFileLoader.js
  21. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  22. 31 3
      dist/preview release/loaders/babylon.objFileLoader.d.ts
  23. 31 3
      dist/preview release/loaders/babylon.objFileLoader.js
  24. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  25. 42 10
      dist/preview release/loaders/babylonjs.loaders.d.ts
  26. 45 12
      dist/preview release/loaders/babylonjs.loaders.js
  27. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  28. 42 10
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  29. 4 25
      dist/preview release/viewer/babylon.viewer.d.ts
  30. 1 1
      dist/preview release/viewer/babylon.viewer.js
  31. 4 4
      dist/preview release/viewer/babylon.viewer.max.js
  32. 5 29
      dist/preview release/viewer/babylon.viewer.module.d.ts
  33. 7 5
      dist/preview release/what's new.md
  34. 15 3
      src/Engine/babylon.engine.ts
  35. 5 11
      src/Gizmos/babylon.boundingBoxGizmo.ts
  36. 9 45
      src/Mesh/babylon.abstractMesh.ts
  37. 0 14
      src/Mesh/babylon.linesMesh.ts
  38. 106 0
      src/Particles/EmitterTypes/babylon.cylinderParticleEmitter.ts
  39. 11 0
      src/Particles/babylon.IParticleSystem.ts
  40. 15 0
      src/Particles/babylon.baseParticleSystem.ts
  41. 30 3
      src/Particles/babylon.gpuParticleSystem.ts
  42. 110 2
      src/Rendering/babylon.edgesRenderer.ts
  43. 2 2
      src/Rendering/babylon.renderingGroup.ts
  44. 42 6
      src/Shaders/gpuUpdateParticles.vertex.fx
  45. BIN
      tests/validation/ReferenceImages/edges.png
  46. 11 6
      tests/validation/config.json
  47. 4 0
      tests/validation/validation.js

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 924 - 915
Playground/babylon.d.txt


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 738 - 468
dist/preview release/babylon.d.ts


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/babylon.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 460 - 129
dist/preview release/babylon.max.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 460 - 129
dist/preview release/babylon.no-module.max.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/babylon.worker.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 462 - 131
dist/preview release/es6.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js.map


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js.map


+ 2 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -819,8 +819,10 @@ declare module INSPECTOR {
         activateNode(item: TreeItem): void;
     }
     class DDSPreview {
+        canvas: HTMLCanvasElement | null;
         constructor(AdapterItem: TextureAdapter);
         insertPreview(AdapterItem: TextureAdapter): void;
+        dispose(): void;
     }
 }
 declare module INSPECTOR {

+ 4 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -1061,8 +1061,10 @@ declare module 'babylonjs-inspector/tabs/TextureTab' {
         activateNode(item: TreeItem): void;
     }
     class DDSPreview {
+        canvas: HTMLCanvasElement | null;
         constructor(AdapterItem: TextureAdapter);
         insertPreview(AdapterItem: TextureAdapter): void;
+        dispose(): void;
     }
     export {};
 }
@@ -2157,8 +2159,10 @@ declare module INSPECTOR {
         activateNode(item: TreeItem): void;
     }
     class DDSPreview {
+        canvas: HTMLCanvasElement | null;
         constructor(AdapterItem: TextureAdapter);
         insertPreview(AdapterItem: TextureAdapter): void;
+        dispose(): void;
     }
 }
 declare module INSPECTOR {

+ 8 - 5
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,9 +262,10 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -276,18 +277,20 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         /**
          * Load into an asset container.
          * @param scene The scene to load into
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data

+ 9 - 6
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -372,14 +372,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -388,14 +389,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -404,14 +406,15 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 11 - 7
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,9 +262,10 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -276,18 +277,20 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         /**
          * Load into an asset container.
          * @param scene The scene to load into
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -568,6 +571,7 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
+        private _fullName;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -596,14 +600,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 14 - 9
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -372,14 +372,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -388,14 +389,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -404,14 +406,15 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -812,11 +815,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -850,11 +854,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -2106,7 +2111,7 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._rootUrl + (image.uri || "image" + image.index);
+                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 11 - 7
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -76,13 +76,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -262,9 +262,10 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -276,18 +277,20 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         /**
          * Load into an asset container.
          * @param scene The scene to load into
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1130,6 +1133,7 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
+        private _fullName;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1158,14 +1162,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 14 - 9
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -372,14 +372,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -388,14 +389,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -404,14 +406,15 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -3019,11 +3022,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -3057,11 +3061,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -4313,7 +4318,7 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._rootUrl + (image.uri || "image" + image.index);
+                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 31 - 3
dist/preview release/loaders/babylon.objFileLoader.d.ts

@@ -58,14 +58,42 @@ declare module BABYLON {
          * @private
          */
         private _loadMTL;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        /**
+         * Imports one or more meshes from the loaded glTF data and adds them to the scene
+         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
+         * @param scene the scene the meshes should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise containg the loaded meshes, particles, skeletons and animations
+         */
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        /**
+         * Imports all objects from the loaded glTF data and adds them to the scene
+         * @param scene the scene the objects should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise which completes when objects have been loaded to the scene
+         */
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
+         * @returns The loaded asset container
+         */
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.

+ 31 - 3
dist/preview release/loaders/babylon.objFileLoader.js

@@ -251,7 +251,17 @@ var BABYLON;
             // Loads through the babylon tools to allow fileInput search.
             BABYLON.Tools.LoadFile(pathOfFile, onSuccess, undefined, undefined, false, function () { console.warn("Error - Unable to load " + pathOfFile); });
         };
-        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        /**
+         * Imports one or more meshes from the loaded glTF data and adds them to the scene
+         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
+         * @param scene the scene the meshes should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise containg the loaded meshes, particles, skeletons and animations
+         */
+        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             //get the meshes from OBJ file
             return this._parseSolid(meshesNames, scene, data, rootUrl).then(function (meshes) {
                 return {
@@ -262,13 +272,31 @@ var BABYLON;
                 };
             });
         };
-        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        /**
+         * Imports all objects from the loaded glTF data and adds them to the scene
+         * @param scene the scene the objects should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise which completes when objects have been loaded to the scene
+         */
+        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             //Get the 3D model
             return this.importMeshAsync(null, scene, data, rootUrl, onProgress).then(function () {
                 // return void
             });
         };
-        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
+         * @returns The loaded asset container
+         */
+        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             return this.importMeshAsync(null, scene, data, rootUrl).then(function (result) {
                 var container = new BABYLON.AssetContainer(scene);
                 result.meshes.forEach(function (mesh) { return container.meshes.push(mesh); });

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


+ 42 - 10
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -76,14 +76,42 @@ declare module BABYLON {
          * @private
          */
         private _loadMTL;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        /**
+         * Imports one or more meshes from the loaded glTF data and adds them to the scene
+         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
+         * @param scene the scene the meshes should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise containg the loaded meshes, particles, skeletons and animations
+         */
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        /**
+         * Imports all objects from the loaded glTF data and adds them to the scene
+         * @param scene the scene the objects should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise which completes when objects have been loaded to the scene
+         */
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
+         * @returns The loaded asset container
+         */
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -178,13 +206,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -364,9 +392,10 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -378,18 +407,20 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         /**
          * Load into an asset container.
          * @param scene The scene to load into
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1232,6 +1263,7 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
+        private _fullName;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1260,14 +1292,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 45 - 12
dist/preview release/loaders/babylonjs.loaders.js

@@ -450,7 +450,17 @@ var BABYLON;
             // Loads through the babylon tools to allow fileInput search.
             BABYLON.Tools.LoadFile(pathOfFile, onSuccess, undefined, undefined, false, function () { console.warn("Error - Unable to load " + pathOfFile); });
         };
-        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        /**
+         * Imports one or more meshes from the loaded glTF data and adds them to the scene
+         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
+         * @param scene the scene the meshes should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise containg the loaded meshes, particles, skeletons and animations
+         */
+        OBJFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             //get the meshes from OBJ file
             return this._parseSolid(meshesNames, scene, data, rootUrl).then(function (meshes) {
                 return {
@@ -461,13 +471,31 @@ var BABYLON;
                 };
             });
         };
-        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        /**
+         * Imports all objects from the loaded glTF data and adds them to the scene
+         * @param scene the scene the objects should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise which completes when objects have been loaded to the scene
+         */
+        OBJFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             //Get the 3D model
             return this.importMeshAsync(null, scene, data, rootUrl, onProgress).then(function () {
                 // return void
             });
         };
-        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
+         * @returns The loaded asset container
+         */
+        OBJFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             return this.importMeshAsync(null, scene, data, rootUrl).then(function (result) {
                 var container = new BABYLON.AssetContainer(scene);
                 result.meshes.forEach(function (mesh) { return container.meshes.push(mesh); });
@@ -1427,14 +1455,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress);
+                return _this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -1443,14 +1472,15 @@ var BABYLON;
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress);
+                return _this._loader.loadAsync(scene, loaderData, rootUrl, onProgress, fullName);
             });
         };
         /**
@@ -1459,14 +1489,15 @@ var BABYLON;
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress) {
+        GLTFFileLoader.prototype.loadAssetContainerAsync = function (scene, data, rootUrl, onProgress, fullName) {
             var _this = this;
             return Promise.resolve().then(function () {
                 var loaderData = _this._parse(data);
                 _this._loader = _this._getLoader(loaderData);
-                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress).then(function (result) {
+                return _this._loader.importMeshAsync(null, scene, loaderData, rootUrl, onProgress, fullName).then(function (result) {
                     var container = new BABYLON.AssetContainer(scene);
                     Array.prototype.push.apply(container.meshes, result.meshes);
                     Array.prototype.push.apply(container.particleSystems, result.particleSystems);
@@ -4050,11 +4081,12 @@ var BABYLON;
                 this._parent._clear();
             };
             /** @hidden */
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     var nodes = null;
@@ -4088,11 +4120,12 @@ var BABYLON;
                 });
             };
             /** @hidden */
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onProgress, fullName) {
                 var _this = this;
                 return Promise.resolve().then(function () {
                     _this.babylonScene = scene;
                     _this._rootUrl = rootUrl;
+                    _this._fullName = fullName || "" + Date.now();
                     _this._progressCallback = onProgress;
                     _this._loadData(data);
                     return _this._loadAsync(null, function () { return undefined; });
@@ -5344,7 +5377,7 @@ var BABYLON;
                 babylonTexture.wrapV = samplerData.wrapV;
                 var image = ArrayItem.Get(context + "/source", this.gltf.images, texture.source);
                 promises.push(this.loadImageAsync("#/images/" + image.index, image).then(function (data) {
-                    var dataUrl = "data:" + _this._rootUrl + (image.uri || "image" + image.index);
+                    var dataUrl = "data:" + _this._fullName + (image.uri || "image" + image.index);
                     babylonTexture.updateURL(dataUrl, new Blob([data], { type: image.mimeType }));
                 }));
                 assign(babylonTexture);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


+ 42 - 10
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -83,14 +83,42 @@ declare module BABYLON {
          * @private
          */
         private _loadMTL;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        /**
+         * Imports one or more meshes from the loaded glTF data and adds them to the scene
+         * @param meshesNames a string or array of strings of the mesh names that should be loaded from the file
+         * @param scene the scene the meshes should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise containg the loaded meshes, particles, skeletons and animations
+         */
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
-        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        /**
+         * Imports all objects from the loaded glTF data and adds them to the scene
+         * @param scene the scene the objects should be added to
+         * @param data the glTF data to load
+         * @param rootUrl root url to load from
+         * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
+         * @returns a promise which completes when objects have been loaded to the scene
+         */
+        loadAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
+        /**
+         * Load into an asset container.
+         * @param scene The scene to load into
+         * @param data The data to import
+         * @param rootUrl The root url for scene and resources
+         * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
+         * @returns The loaded asset container
+         */
+        loadAssetContainerAsync(scene: Scene, data: string, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * Read the OBJ file and create an Array of meshes.
          * Each mesh contains all information given by the OBJ and the MTL file.
@@ -185,13 +213,13 @@ declare module BABYLON {
     /** @hidden */
     interface IGLTFLoader extends IDisposable {
         readonly state: Nullable<GLTFLoaderState>;
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<{
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void) => Promise<void>;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string) => Promise<void>;
     }
     /**
      * File loader for loading glTF files into a scene.
@@ -371,9 +399,10 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise containg the loaded meshes, particles, skeletons and animations
          */
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
@@ -385,18 +414,20 @@ declare module BABYLON {
          * @param data the glTF data to load
          * @param rootUrl root url to load from
          * @param onProgress event that fires when loading progress has occured
+         * @param fullName Defines the FQDN of the file to load
          * @returns a promise which completes when objects have been loaded to the scene
          */
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         /**
          * Load into an asset container.
          * @param scene The scene to load into
          * @param data The data to import
          * @param rootUrl The root url for scene and resources
          * @param onProgress The callback when the load progresses
+         * @param fullName Defines the FQDN of the file to load
          * @returns The loaded asset container
          */
-        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<AssetContainer>;
+        loadAssetContainerAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<AssetContainer>;
         /**
          * If the data string can be loaded directly.
          * @param data string contianing the file data
@@ -1239,6 +1270,7 @@ declare module BABYLON.GLTF2 {
         private _state;
         private _extensions;
         private _rootUrl;
+        private _fullName;
         private _rootBabylonMesh;
         private _defaultBabylonMaterialData;
         private _progressCallback?;
@@ -1267,14 +1299,14 @@ declare module BABYLON.GLTF2 {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<{
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<{
             meshes: AbstractMesh[];
             particleSystems: IParticleSystem[];
             skeletons: Skeleton[];
             animationGroups: AnimationGroup[];
         }>;
         /** @hidden */
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void): Promise<void>;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onProgress?: (event: SceneLoaderProgressEvent) => void, fullName?: string): Promise<void>;
         private _loadAsync;
         private _loadData;
         private _setupData;

+ 4 - 25
dist/preview release/viewer/babylon.viewer.d.ts

@@ -168,11 +168,11 @@ declare module BabylonViewer {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -189,11 +189,11 @@ declare module BabylonViewer {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -919,13 +919,6 @@ declare module BabylonViewer {
     }
 }
 declare module BabylonViewer {
-    /**
-      *
-      * @param name the name of the custom optimizer configuration
-      * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
-      */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
-    export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
 }
 declare module BabylonViewer {
     /**
@@ -1558,20 +1551,6 @@ declare module BabylonViewer {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 declare module BabylonViewer {
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-declare module BabylonViewer {
 }
 declare module BabylonViewer {
     export interface IEnvironmentMapConfiguration {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/viewer/babylon.viewer.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 4 - 4
dist/preview release/viewer/babylon.viewer.max.js


+ 5 - 29
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -200,11 +200,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Mainly used for help and errors
                 * @param subScreen the name of the subScreen. Those can be defined in the configuration object
                 */
-            showOverlayScreen(subScreen: string): Promise<Template> | Promise<string>;
+            showOverlayScreen(subScreen: string): Promise<string> | Promise<Template>;
             /**
                 * Hide the overlay screen.
                 */
-            hideOverlayScreen(): Promise<Template> | Promise<string>;
+            hideOverlayScreen(): Promise<string> | Promise<Template>;
             /**
                 * show the viewer (in case it was hidden)
                 *
@@ -221,11 +221,11 @@ declare module 'babylonjs-viewer/viewer/defaultViewer' {
                 * Show the loading screen.
                 * The loading screen can be configured using the configuration object
                 */
-            showLoadingScreen(): Promise<Template> | Promise<string>;
+            showLoadingScreen(): Promise<string> | Promise<Template>;
             /**
                 * Hide the loading screen
                 */
-            hideLoadingScreen(): Promise<Template> | Promise<string>;
+            hideLoadingScreen(): Promise<string> | Promise<Template>;
             dispose(): void;
             protected _onConfigurationLoaded(configuration: ViewerConfiguration): void;
     }
@@ -985,15 +985,7 @@ declare module 'babylonjs-viewer/templating/viewerTemplatePlugin' {
 }
 
 declare module 'babylonjs-viewer/optimizer/custom' {
-    import { extendedUpgrade } from "babylonjs-viewer/optimizer/custom/extended";
-    import { SceneManager } from "babylonjs-viewer/managers/sceneManager";
-    /**
-      *
-      * @param name the name of the custom optimizer configuration
-      * @param upgrade set to true if you want to upgrade optimizer and false if you want to degrade
-      */
-    export function getCustomOptimizerByName(name: string, upgrade?: boolean): typeof extendedUpgrade;
-    export function registerCustomOptimizer(name: string, optimizer: (sceneManager: SceneManager) => boolean): void;
+    
 }
 
 declare module 'babylonjs-viewer/initializer' {
@@ -1663,22 +1655,6 @@ declare module 'babylonjs-viewer/loader/plugins' {
     export function addLoaderPlugin(name: string, plugin: ILoaderPlugin): void;
 }
 
-declare module 'babylonjs-viewer/optimizer/custom/extended' {
-    import { SceneManager } from 'babylonjs-viewer/managers/sceneManager';
-    /**
-        * A custom upgrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedUpgrade(sceneManager: SceneManager): boolean;
-    /**
-        * A custom degrade-oriented function configuration for the scene optimizer.
-        *
-        * @param viewer the viewer to optimize
-        */
-    export function extendedDegrade(sceneManager: SceneManager): boolean;
-}
-
 declare module 'babylonjs-viewer/configuration/interfaces' {
     export * from 'babylonjs-viewer/configuration/interfaces/cameraConfiguration';
     export * from 'babylonjs-viewer/configuration/interfaces/colorGradingConfiguration';

+ 7 - 5
dist/preview release/what's new.md

@@ -15,6 +15,7 @@
   - Added ignoreChildren field to bounding box to save performance when using heavily nested meshes ([TrevorDev](https://github.com/TrevorDev))
   - Add uniform scaling drag support to scale gizmo ([TrevorDev](https://github.com/TrevorDev))
   - Support interacting with child elements ([TrevorDev](https://github.com/TrevorDev))
+  - BoundingBox gizmo support for including/excluding descendants when computing the bounding box ([TrevorDev](https://github.com/TrevorDev))
 - Particle system improvements ([Deltakosh](https://github.com/deltakosh))
   - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
   - Improved CPU particles rendering performance (up to x2 on low end devices)
@@ -32,11 +33,12 @@
   - Added support for size gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#size)
   - Added support for life time gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#lifetime)
   - Added support for angular speed gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#rotation)
-  - Added support for velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
-  - Added support for limit velocty gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
+  - Added support for velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#velocity-over-time)
+  - Added support for limit velocity gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time)
+  - Added support for drag gradients. [Doc](https://doc.babylonjs.com/babylon101/particles#drag-factor)
   - Added support for noise textures. [Doc](http://doc.babylonjs.com/babylon101/particles#noise-texture)
   - Added support for emit rate gradients. [Doc](http://doc.babylonjs.com/babylon101/particles#emit-rate-over-time)
-  - Start size gradient support for particles [Doc](http://doc.babylonjs.com/babylon101/particles#start-size-over-time) ([TrevorDev](https://github.com/TrevorDev))
+  - Start size gradient support for particles. [Doc](http://doc.babylonjs.com/babylon101/particles#start-size-over-time) ([TrevorDev](https://github.com/TrevorDev))
   - Cylinder particle emitter and constructor in baseParticle [Doc](https://doc.babylonjs.com/babylon101/particles#cylinder-emitter) ([TrevorDev](https://github.com/TrevorDev))
 - Added SceneComponent to help decoupling Scene from its components. ([sebavan](http://www.github.com/sebavan))
 - Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
@@ -49,7 +51,7 @@
 ## Updates
 
 - Updated TypeScript version to new major 3.0.1 ([christopherstock](https://github.com/christopherstock))
-- All NPM packages have `latest`and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
+- All NPM packages have `latest` and `preview` streams [#3055](https://github.com/BabylonJS/Babylon.js/issues/3055) ([RaananW](https://github.com/RaananW))
 - Added New Tools Tab in the inspector (env texture and screenshot tools so far) ([sebavan](http://www.github.com/sebavan))
 - Moved to gulp 4, updated dependencies to latest ([RaananW](https://github.com/RaananW))
 
@@ -62,7 +64,7 @@
 ### Core Engine
 
 - Added `scene.pickSpriteWithRay` function ([Deltakosh](https://github.com/deltakosh))
-- Added support for muyltiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
+- Added support for multiple clip planes. [Demo](https://www.babylonjs-playground.com/#Y6W087) ([Deltakosh](https://github.com/deltakosh))
 - Added new `MixMaterial` to the Materials Library allowing to mix up to 8 textures ([julien-moreau](https://github.com/julien-moreau))
 - Added new `BoundingInfo.scale()` function to let users control the size of the bounding info ([Deltakosh](https://github.com/deltakosh))
 - Added new `Animatable.waitAsync` function to use Promises with animations. Demo [Here](https://www.babylonjs-playground.com/#HZBCXR) ([Deltakosh](https://github.com/deltakosh))

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

@@ -3875,7 +3875,6 @@
                 return;
             }
             this._currentEffect = null;
-            this._unpackFlipYCached = null;
             this._viewportCached.x = 0;
             this._viewportCached.y = 0;
             this._viewportCached.z = 0;
@@ -3889,6 +3888,8 @@
                 this._depthCullingState.reset();
                 this.setDepthFunctionToLessOrEqual();
                 this._alphaState.reset();
+
+                this._unpackFlipYCached = null;
             }
 
             this._resetVertexBufferBinding();
@@ -4412,11 +4413,22 @@
         }
 
         private _unpackFlipYCached: Nullable<boolean> = null;
+
+        /**
+         * In case you are sharing the context with other applications, it might 
+         * be interested to not cache the unpack flip y state to ensure a consistent 
+         * value would be set.
+         */
+        public enableUnpackFlipYCached = true;
+
         /** @hidden */
-        public _unpackFlipY(value: boolean) {
+        public _unpackFlipY(value: boolean): void {
             if (this._unpackFlipYCached !== value) {
-                this._unpackFlipYCached = value;
                 this._gl.pixelStorei(this._gl.UNPACK_FLIP_Y_WEBGL, value ? 1 : 0);
+
+                if (this.enableUnpackFlipYCached) {
+                    this._unpackFlipYCached = value;
+                }
             }
         }
 

+ 5 - 11
src/Gizmos/babylon.boundingBoxGizmo.ts

@@ -18,6 +18,10 @@ module BABYLON {
          * If child meshes should be ignored when calculating the boudning box. This should be set to true to avoid perf hits with heavily nested meshes (Default: false)
          */
         public ignoreChildren = false;
+        /**
+         * Returns true if a descendant should be included when computing the bounding box. When null, all descendants are included. If ignoreChildren is set this will be ignored. (Default: null)
+         */
+        public includeChildPredicate: Nullable<(abstractMesh: AbstractMesh) => boolean> = null
 
         /**
          * The size of the rotation spheres attached to the bounding box (Default: 0.1)
@@ -332,15 +336,6 @@ module BABYLON {
                 })
         }
 
-        private _recurseComputeWorld(node: Node) {
-            node.computeWorldMatrix(true);
-            if(!this.ignoreChildren){
-                node.getDescendants().forEach((n) => {
-                    this._recurseComputeWorld(n);
-                });
-            }
-        }
-
         /**
          * Updates the bounding box information for the Gizmo
          */
@@ -364,7 +359,7 @@ module BABYLON {
                 this.attachedMesh.position.set(0, 0, 0);
 
                 // Update bounding dimensions/positions   
-                var boundingMinMax = this.attachedMesh.getHierarchyBoundingVectors(!this.ignoreChildren);
+                var boundingMinMax = this.attachedMesh.getHierarchyBoundingVectors(!this.ignoreChildren, this.includeChildPredicate);
                 boundingMinMax.max.subtractToRef(boundingMinMax.min, this._boundingDimensions);
 
                 // Update gizmo to match bounding box scaling and rotation
@@ -378,7 +373,6 @@ module BABYLON {
                 // restore position/rotation values
                 this.attachedMesh.rotationQuaternion.copyFrom(this._tmpQuaternion);
                 this.attachedMesh.position.copyFrom(this._tmpVector);
-                this._recurseComputeWorld(this.attachedMesh);
             }
             
             // Update rotation sphere locations

+ 9 - 45
src/Mesh/babylon.abstractMesh.ts

@@ -524,7 +524,7 @@
          */
         public edgesColor = new Color4(1, 0, 0, 1);
         /** @hidden */
-        public _edgesRenderer: Nullable<EdgesRenderer>;
+        public _edgesRenderer: Nullable<IEdgesRenderer>;
 
         // Cache
         private _collisionsTransformMatrix = Matrix.Zero();
@@ -594,6 +594,11 @@
             return this._skeleton;
         }
 
+        /**
+         * An event triggered when the mesh is rebuilt.
+         */
+        public onRebuildObservable = new Observable<AbstractMesh>();
+
         // Constructor
 
         /**
@@ -637,14 +642,12 @@
 
         /** @hidden */
         public _rebuild(): void {
+            this.onRebuildObservable.notifyObservers(this);
+
             if (this._occlusionQuery) {
                 this._occlusionQuery = null;
             }
 
-            if (this._edgesRenderer) {
-                this._edgesRenderer._rebuild();
-            }
-
             if (!this.subMeshes) {
                 return;
             }
@@ -762,40 +765,6 @@
         }
 
         // Methods
-
-        /**
-         * Disables the mesh edge rendering mode
-         * @returns the currentAbstractMesh
-         */
-        public disableEdgesRendering(): AbstractMesh {
-            if (this._edgesRenderer) {
-                this._edgesRenderer.dispose();
-                this._edgesRenderer = null;
-            }
-            return this;
-        }
-
-        /**
-         * Enables the edge rendering mode on the mesh.  
-         * This mode makes the mesh edges visible
-         * @param epsilon defines the maximal distance between two angles to detect a face
-         * @param checkVerticesInsteadOfIndices indicates that we should check vertex list directly instead of faces
-         * @returns the currentAbstractMesh 
-         * @see https://www.babylonjs-playground.com/#19O9TU#0
-         */
-        public enableEdgesRendering(epsilon = 0.95, checkVerticesInsteadOfIndices = false): AbstractMesh {
-            this.disableEdgesRendering();
-            this._edgesRenderer = new EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
-            return this;
-        }
-
-        /**
-         * Gets the edgesRenderer associated with the mesh
-         */
-        public get edgesRenderer(): Nullable<EdgesRenderer> {
-            return this._edgesRenderer;
-        }
-
         /**
          * Returns true if the mesh is blocked. Implemented by child classes
          */
@@ -1615,12 +1584,6 @@
                 }
             });
 
-            // Edges
-            if (this._edgesRenderer) {
-                this._edgesRenderer.dispose();
-                this._edgesRenderer = null;
-            }
-
             // SubMeshes
             if (this.getClassName() !== "InstancedMesh") {
                 this.releaseSubMeshes();
@@ -1674,6 +1637,7 @@
             this.onAfterWorldMatrixUpdateObservable.clear();
             this.onCollideObservable.clear();
             this.onCollisionPositionChangeObservable.clear();
+            this.onRebuildObservable.clear();
 
             super.dispose(doNotRecurse, disposeMaterialAndTextures);
         }

+ 0 - 14
src/Mesh/babylon.linesMesh.ts

@@ -139,19 +139,5 @@
         public clone(name: string, newParent?: Node, doNotCloneChildren?: boolean): LinesMesh {
             return new LinesMesh(name, this.getScene(), newParent, this, doNotCloneChildren);
         }
-
-        /**
-         * Enables the edge rendering mode on the mesh.
-         * This mode makes the mesh edges visible
-         * @param epsilon defines the maximal distance between two angles to detect a face
-         * @param checkVerticesInsteadOfIndices indicates that we should check vertex list directly instead of faces
-         * @returns the currentAbstractMesh
-         * @see https://www.babylonjs-playground.com/#19O9TU#0
-         */
-        public enableEdgesRendering(epsilon = 0.95, checkVerticesInsteadOfIndices = false): AbstractMesh {
-            this.disableEdgesRendering();
-            this._edgesRenderer = new LineEdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
-            return this;
-        }
     }
 } 

+ 106 - 0
src/Particles/EmitterTypes/babylon.cylinderParticleEmitter.ts

@@ -135,4 +135,110 @@ module BABYLON {
             this.directionRandomizer = serializationObject.directionRandomizer;
         }          
     }
+
+    /**
+     * Particle emitter emitting particles from the inside of a cylinder.
+     * It emits the particles randomly between two vectors.
+     */
+    export class CylinderDirectedParticleEmitter extends CylinderParticleEmitter {
+
+        /**
+         * Creates a new instance CylinderDirectedParticleEmitter
+         * @param radius the radius of the emission cylinder (1 by default)
+         * @param height the height of the emission cylinder (1 by default)
+         * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default) 
+         * @param direction1 the min limit of the emission direction (up vector by default)
+         * @param direction2 the max limit of the emission direction (up vector by default)
+         */
+        constructor(
+            radius = 1, 
+            height = 1,
+            radiusRange = 1,
+            /**
+             * The min limit of the emission direction.
+             */
+            public direction1 = new Vector3(0, 1, 0), 
+            /**
+             * The max limit of the emission direction.
+             */
+            public direction2 = new Vector3(0, 1, 0)) {
+            super(radius, height, radiusRange);
+        }
+
+        /**
+         * Called by the particle System when the direction is computed for the created particle.
+         * @param worldMatrix is the world matrix of the particle system
+         * @param directionToUpdate is the direction vector to update with the result
+         * @param particle is the particle we are computed the direction for
+         */
+        public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+            var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+            var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+            var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
+            Vector3.TransformNormalFromFloatsToRef(randX, randY, randZ, worldMatrix, directionToUpdate);
+        }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): CylinderDirectedParticleEmitter {
+            let newOne = new CylinderDirectedParticleEmitter(this.radius, this.height, this.radiusRange, this.direction1, this.direction2);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }     
+        
+        /**
+         * Called by the GPUParticleSystem to setup the update shader
+         * @param effect defines the update shader
+         */        
+        public applyToShader(effect: Effect): void {
+            effect.setFloat("radius", this.radius);
+            effect.setFloat("height", this.height);
+            effect.setFloat("radiusRange", this.radiusRange);
+            effect.setVector3("direction1", this.direction1);
+            effect.setVector3("direction2", this.direction2);
+        }       
+        
+        /**
+         * Returns a string to use to update the GPU particles update shader
+         * @returns a string containng the defines string
+         */
+        public getEffectDefines(): string {
+            return "#define CYLINDEREMITTER\n#define DIRECTEDCYLINDEREMITTER"
+        }    
+        
+        /**
+         * Returns the string "CylinderDirectedParticleEmitter"
+         * @returns a string containing the class name
+         */
+        public getClassName(): string {
+            return "CylinderDirectedParticleEmitter";
+        }       
+        
+        /**
+         * Serializes the particle system to a JSON object.
+         * @returns the JSON object
+         */        
+        public serialize(): any {
+            var serializationObject = super.serialize();
+
+            serializationObject.direction1 = this.direction1.asArray();
+            serializationObject.direction2 = this.direction2.asArray();
+
+            return serializationObject;
+        }    
+        
+        /**
+         * Parse properties from a JSON object
+         * @param serializationObject defines the JSON object
+         */
+        public parse(serializationObject: any): void {
+            super.parse(serializationObject);
+            this.direction1.copyFrom(serializationObject.direction1);
+            this.direction2.copyFrom(serializationObject.direction2);
+        }           
+    }
 }

+ 11 - 0
src/Particles/babylon.IParticleSystem.ts

@@ -464,6 +464,17 @@ module BABYLON {
         createCylinderEmitter(radius: number, height: number, radiusRange: number, directionRandomizer: number): CylinderParticleEmitter;
 
         /**
+         * Creates a Directed Cylinder Emitter for the particle system (emits between direction1 and direction2)
+         * @param radius The radius of the cylinder to emit from
+         * @param height The height of the emission cylinder
+         * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default) 
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the cylinder
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the cylinder
+         * @returns the emitter
+         */
+        createDirectedCylinderEmitter(radius: number, height: number, radiusRange:number , direction1:Vector3, direction2: Vector3): SphereDirectedParticleEmitter;
+
+        /**
          * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
          * @param radius The radius of the cone to emit from
          * @param angle The base angle of the cone

+ 15 - 0
src/Particles/babylon.baseParticleSystem.ts

@@ -588,6 +588,21 @@ module BABYLON {
         }
 
         /**
+         * Creates a Directed Cylinder Emitter for the particle system (emits between direction1 and direction2)
+         * @param radius The radius of the cylinder to emit from
+         * @param height The height of the emission cylinder
+         * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default) 
+         * @param direction1 Particles are emitted between the direction1 and direction2 from within the cylinder
+         * @param direction2 Particles are emitted between the direction1 and direction2 from within the cylinder
+         * @returns the emitter
+         */
+        public createDirectedCylinderEmitter(radius = 1, height = 1, radiusRange = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)): CylinderDirectedParticleEmitter {
+            var particleEmitter = new CylinderDirectedParticleEmitter(radius, height, radiusRange, direction1, direction2)
+            this.particleEmitterType = particleEmitter;
+            return particleEmitter;
+        }
+
+        /**
          * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
          * @param radius The radius of the cone to emit from
          * @param angle The base angle of the cone

+ 30 - 3
src/Particles/babylon.gpuParticleSystem.ts

@@ -519,9 +519,9 @@
                 attributes: ["position", "age", "life", "seed", "size", "color", "direction", "initialDirection", "angle", "cellIndex"],
                 uniformsNames: ["currentCount", "timeDelta", "emitterWM", "lifeTime", "color1", "color2", "sizeRange", "scaleRange","gravity", "emitPower",
                                 "direction1", "direction2", "minEmitBox", "maxEmitBox", "radius", "directionRandomizer", "height", "coneAngle", "stopFactor", 
-                                "angleRange", "radiusRange", "cellInfos", "noiseStrength"],
+                                "angleRange", "radiusRange", "cellInfos", "noiseStrength", "limitVelocityDamping"],
                 uniformBuffersNames: [],
-                samplers:["randomSampler", "randomSampler2", "sizeGradientSampler", "angularSpeedGradientSampler", "velocityGradientSampler", "noiseSampler"],
+                samplers:["randomSampler", "randomSampler2", "sizeGradientSampler", "angularSpeedGradientSampler", "velocityGradientSampler", "limitVelocityGradientSampler", "noiseSampler", "dragGradientSampler"],
                 defines: "",
                 fallbacks: null,  
                 onCompiled: null,
@@ -773,7 +773,15 @@
             
             if (this._velocityGradientsTexture) {
                 defines += "\n#define VELOCITYGRADIENTS";
-            }                    
+            }        
+
+            if (this._limitVelocityGradientsTexture) {
+                defines += "\n#define LIMITVELOCITYGRADIENTS";
+            }                
+            
+            if (this._dragGradientsTexture) {
+                defines += "\n#define DRAGGRADIENTS";
+            }              
             
             if (this.isAnimationSheetEnabled) {
                 defines += "\n#define ANIMATESHEET";
@@ -919,6 +927,14 @@
         private _createVelocityGradientTexture() {
             this._createFactorGradientTexture(this._velocityGradients, "_velocityGradientsTexture");
         }          
+
+        private _createLimitVelocityGradientTexture() {
+            this._createFactorGradientTexture(this._limitVelocityGradients, "_limitVelocityGradientsTexture");
+        }          
+
+        private _createDragGradientTexture() {
+            this._createFactorGradientTexture(this._dragGradients, "_dragGradientsTexture");
+        }            
             
         private _createColorGradientTexture() {
             if (!this._colorGradients || !this._colorGradients.length || this._colorGradientsTexture) {
@@ -959,6 +975,8 @@
             this._createSizeGradientTexture();
             this._createAngularSpeedGradientTexture();
             this._createVelocityGradientTexture();
+            this._createLimitVelocityGradientTexture();
+            this._createDragGradientTexture();
 
             this._recreateUpdateEffect();
             this._recreateRenderEffect();
@@ -1030,6 +1048,15 @@
                 this._updateEffect.setTexture("velocityGradientSampler", this._velocityGradientsTexture);      
             }
 
+            if (this._limitVelocityGradientsTexture) {      
+                this._updateEffect.setTexture("limitVelocityGradientSampler", this._limitVelocityGradientsTexture);  
+                this._updateEffect.setFloat("limitVelocityDamping", this.limitVelocityDamping);    
+            }            
+
+            if (this._dragGradientsTexture) {      
+                this._updateEffect.setTexture("dragGradientSampler", this._dragGradientsTexture);      
+            }
+
             if (this.particleEmitterType) {
                 this.particleEmitterType.applyToShader(this._updateEffect);
             }

+ 110 - 2
src/Rendering/babylon.edgesRenderer.ts

@@ -1,4 +1,67 @@
 module BABYLON {
+    export interface AbstractMesh {
+        /**
+         * Disables the mesh edge rendering mode
+         * @returns the currentAbstractMesh
+         */
+        disableEdgesRendering(): AbstractMesh;
+        
+        /**
+         * Enables the edge rendering mode on the mesh.  
+         * This mode makes the mesh edges visible
+         * @param epsilon defines the maximal distance between two angles to detect a face
+         * @param checkVerticesInsteadOfIndices indicates that we should check vertex list directly instead of faces
+         * @returns the currentAbstractMesh 
+         * @see https://www.babylonjs-playground.com/#19O9TU#0
+         */
+        enableEdgesRendering(epsilon?: number, checkVerticesInsteadOfIndices?: boolean): AbstractMesh;
+        
+        /**
+         * Gets the edgesRenderer associated with the mesh
+         */
+        edgesRenderer: Nullable<EdgesRenderer>;
+    }
+
+    AbstractMesh.prototype.disableEdgesRendering = function(): AbstractMesh {
+        if (this._edgesRenderer) {
+            this._edgesRenderer.dispose();
+            this._edgesRenderer = null;
+        }
+        return this;
+    }
+
+    AbstractMesh.prototype.enableEdgesRendering = function(epsilon = 0.95, checkVerticesInsteadOfIndices = false): AbstractMesh {
+        this.disableEdgesRendering();
+        this._edgesRenderer = new EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
+        return this;
+    }
+
+    Object.defineProperty(AbstractMesh.prototype, "edgesRenderer", {
+        get: function (this:AbstractMesh) {
+            return this._edgesRenderer;
+        },
+        enumerable: true,
+        configurable: true
+    });
+
+    export interface LinesMesh {
+        /**
+         * Enables the edge rendering mode on the mesh.
+         * This mode makes the mesh edges visible
+         * @param epsilon defines the maximal distance between two angles to detect a face
+         * @param checkVerticesInsteadOfIndices indicates that we should check vertex list directly instead of faces
+         * @returns the currentAbstractMesh
+         * @see https://www.babylonjs-playground.com/#19O9TU#0
+         */
+        enableEdgesRendering(epsilon?: number, checkVerticesInsteadOfIndices?: boolean): AbstractMesh;
+    }
+
+    LinesMesh.prototype.enableEdgesRendering = function(epsilon = 0.95, checkVerticesInsteadOfIndices = false): AbstractMesh {
+        this.disableEdgesRendering();
+        this._edgesRenderer = new LineEdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
+        return this;
+    }
+
     /**
      * FaceAdjacencies Helper class to generate edges
      */
@@ -11,9 +74,30 @@
     }
 
     /**
+     * Defines the minimum contract an Edges renderer should follow.
+     */
+    export interface IEdgesRenderer extends IDisposable {
+        /** 
+         * Gets or sets a boolean indicating if the edgesRenderer is active 
+         */
+        isEnabled: boolean;
+
+        /**
+         * Renders the edges of the attached mesh,
+         */
+        render(): void;
+
+        /**
+         * Checks wether or not the edges renderer is ready to render.
+         * @return true if ready, otherwise false.
+         */
+        isReady(): boolean;
+    }
+
+    /**
      * This class is used to generate edges of the mesh that could then easily be rendered in a scene.
      */
-    export class EdgesRenderer {
+    export class EdgesRenderer implements IEdgesRenderer {
         public edgesWidthScalerForOrthographic = 1000.0;
         public edgesWidthScalerForPerspective = 50.0;
         protected _source: AbstractMesh;
@@ -28,6 +112,9 @@
         protected _buffers: { [key: string]: Nullable<VertexBuffer> } = {};
         protected _checkVerticesInsteadOfIndices = false;
 
+        private _meshRebuildObserver: Nullable<Observer<AbstractMesh>>;
+        private _meshDisposeObserver: Nullable<Observer<Node>>;
+
         /** Gets or sets a boolean indicating if the edgesRenderer is active */
         public isEnabled = true;
 
@@ -49,6 +136,14 @@
             if(generateEdgesLines) {
                 this._generateEdgesLines();
             }
+
+            this._meshRebuildObserver = this._source.onRebuildObservable.add(() => {
+                this._rebuild();
+            });
+
+            this._meshDisposeObserver = this._source.onDisposeObservable.add(() => {
+                this.dispose();
+            });
         }
 
         protected _prepareRessources(): void {
@@ -87,6 +182,8 @@
          * Releases the required resources for the edges renderer
          */
         public dispose(): void {
+            this._source.onRebuildObservable.remove(this._meshRebuildObserver);
+            this._source.onDisposeObservable.remove(this._meshDisposeObserver);
 
             var buffer = this._buffers[VertexBuffer.PositionKind];
             if (buffer) {
@@ -332,10 +429,21 @@
             this._indicesCount = this._linesIndices.length;
         }
 
+        /**
+         * Checks wether or not the edges renderer is ready to render.
+         * @return true if ready, otherwise false.
+         */
+        public isReady(): boolean {
+            return this._lineShader.isReady();
+        }
+
+        /**
+         * Renders the edges of the attached mesh,
+         */
         public render(): void {
             var scene = this._source.getScene();
 
-            if (!this._lineShader.isReady() || !scene.activeCamera) {
+            if (!this.isReady() || !scene.activeCamera) {
                 return;
             }
 

+ 2 - 2
src/Rendering/babylon.renderingGroup.ts

@@ -16,7 +16,7 @@
         private _renderAlphaTest: (subMeshes: SmartArray<SubMesh>) => void;
         private _renderTransparent: (subMeshes: SmartArray<SubMesh>) => void;
 
-        private _edgesRenderers = new SmartArray<EdgesRenderer>(16);
+        private _edgesRenderers = new SmartArray<IEdgesRenderer>(16);
 
         public onBeforeTransparentRendering: () => void;
 
@@ -345,7 +345,7 @@
                 this._opaqueSubMeshes.push(subMesh); // Opaque
             }
 
-            if (mesh._edgesRenderer !== null && mesh._edgesRenderer !== undefined && mesh._edgesRenderer.isEnabled) {
+            if (mesh._edgesRenderer && mesh._edgesRenderer.isEnabled) {
                 this._edgesRenderers.push(mesh._edgesRenderer);
             }
         }

+ 42 - 6
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -52,7 +52,12 @@ uniform float radiusRange;
 uniform float radius;
 uniform float height;
 uniform float radiusRange;
-uniform float directionRandomizer;
+#ifdef DIRECTEDCYLINDEREMITTER
+  uniform vec3 direction1;
+  uniform vec3 direction2;
+#else
+  uniform float directionRandomizer;
+#endif
 #endif
 
 #ifdef CONEEMITTER
@@ -118,6 +123,15 @@ uniform sampler2D angularSpeedGradientSampler;
 uniform sampler2D velocityGradientSampler;
 #endif
 
+#ifdef LIMITVELOCITYGRADIENTS
+uniform sampler2D limitVelocityGradientSampler;
+uniform float limitVelocityDamping;
+#endif
+
+#ifdef DRAGGRADIENTS
+uniform sampler2D dragGradientSampler;
+#endif
+
 #ifdef NOISE
 uniform vec3 noiseStrength;
 uniform sampler2D noiseSampler;
@@ -238,10 +252,14 @@ void main() {
     float zPos = positionRadius * sin(angle);
     position = vec3(xPos, yPos, zPos);
 
-    // Direction
-    angle = angle + ((randoms3.x-0.5) * PI);
-    direction = vec3(cos(angle), randoms3.y-0.5, sin(angle));
-    direction = normalize(direction);
+    #ifdef DIRECTEDCYLINDEREMITTER
+      direction = direction1 + (direction2 - direction1) * randoms3;
+    #else
+      // Direction
+      angle = angle + ((randoms3.x-0.5) * PI);
+      direction = vec3(cos(angle), randoms3.y-0.5, sin(angle));
+      direction = normalize(direction);
+    #endif
 #elif defined(CONEEMITTER)
     vec3 randoms2 = getRandomVec3(seed.y);
 
@@ -300,6 +318,11 @@ void main() {
 #ifdef VELOCITYGRADIENTS
     directionScale *= texture(velocityGradientSampler, vec2(ageGradient, 0)).r;
 #endif
+
+#ifdef DRAGGRADIENTS
+    directionScale *= texture(dragGradientSampler, vec2(ageGradient, 0)).r;
+#endif
+
     outPosition = position + direction * directionScale;
     
     outLife = life;
@@ -318,7 +341,20 @@ void main() {
 #ifndef BILLBOARD    
     outInitialDirection = initialDirection;
 #endif
-    outDirection = direction + gravity * timeDelta;
+
+    vec3 updatedDirection = direction + gravity * timeDelta;
+
+#ifdef LIMITVELOCITYGRADIENTS
+    float limitVelocity = texture(limitVelocityGradientSampler, vec2(ageGradient, 0)).r;
+
+    float currentVelocity = length(updatedDirection);
+
+    if (currentVelocity > limitVelocity) {
+        updatedDirection = updatedDirection * limitVelocityDamping;
+    }
+#endif
+
+    outDirection = updatedDirection;
 
 #ifdef NOISE
     vec3 localPosition = outPosition - emitterWM[3].xyz;

BIN
tests/validation/ReferenceImages/edges.png


+ 11 - 6
tests/validation/config.json

@@ -2,11 +2,6 @@
   "root": "https://rawgit.com/BabylonJS/Website/master",
   "tests": [
     {
-      "title": "Outline",
-      "playgroundId": "#10WJ5S#6",
-      "referenceImage": "outline.png"
-    },
-    {
       "title": "Clip planes",
       "playgroundId": "#Y6W087#0",
       "referenceImage": "clipplanes.png"
@@ -540,6 +535,16 @@
       "playgroundId": "#3HPMAA#0",
       "renderCount": 50,
       "referenceImage": "depthRenderer.png"
+    },
+    {
+      "title": "Edges",
+      "playgroundId": "#TYAHX#114",
+      "referenceImage": "edges.png"
+    },
+    {
+      "title": "Outline",
+      "playgroundId": "#10WJ5S#6",
+      "referenceImage": "outline.png"
     }
   ]
-}
+}

+ 4 - 0
tests/validation/validation.js

@@ -48,6 +48,9 @@ function compare(renderData, referenceCanvas) {
 
     referenceContext.putImageData(referenceData, 0, 0);
 
+    if (differencesCount) {
+        console.log("Pixel difference: " + differencesCount + " pixels.")
+    }
     return (differencesCount * 100) / (width * height) > errorRatio;
 }
 
@@ -123,6 +126,7 @@ function evaluate(test, resultCanvas, result, renderImage, index, waitRing, done
     var renderB64 = saveRenderImage(renderData, canvas);
     renderImage.src = renderB64;
 
+    engine.applyStates();
     currentScene.dispose();
     currentScene = null;
     engine.setHardwareScalingLevel(1);