Просмотр исходного кода

Merge pull request #8168 from BabylonJS/master

Nightly
mergify[bot] 5 лет назад
Родитель
Сommit
e2183653ba
47 измененных файлов с 1528 добавлено и 615 удалено
  1. 65 18
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 264 91
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 131 37
      dist/preview release/babylon.module.d.ts
  6. 65 18
      dist/preview release/documentation.d.ts
  7. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  8. 110 18
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  10. 5 0
      dist/preview release/inspector/babylon.inspector.d.ts
  11. 10 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  12. 51 51
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  13. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  14. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  15. 51 51
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  17. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  18. 51 51
      dist/preview release/loaders/babylonjs.loaders.js
  19. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  20. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  21. 131 37
      dist/preview release/viewer/babylon.module.d.ts
  22. 69 69
      dist/preview release/viewer/babylon.viewer.js
  23. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  24. 1 0
      dist/preview release/what's new.md
  25. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx
  26. 111 0
      inspector/src/components/actionTabs/tabs/propertyGrids/sprites/spriteManagerPropertyGridComponent.tsx
  27. 57 51
      loaders/src/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.ts
  28. 4 1
      sandbox/index.js
  29. 1 1
      src/Helpers/sceneHelpers.ts
  30. 37 12
      src/Materials/PBR/pbrBaseMaterial.ts
  31. 15 5
      src/Materials/PBR/pbrSubSurfaceConfiguration.ts
  32. 8 2
      src/Materials/Textures/Filtering/hdrFiltering.ts
  33. 0 30
      src/Materials/Textures/baseTexture.ts
  34. 10 0
      src/Meshes/instancedMesh.ts
  35. 0 2
      src/Probes/reflectionProbe.ts
  36. 22 14
      src/Shaders/ShadersInclude/hdrFilteringFunctions.fx
  37. 24 24
      src/Shaders/ShadersInclude/helperFunctions.fx
  38. 15 4
      src/Shaders/ShadersInclude/pbrBlockReflection.fx
  39. 17 2
      src/Shaders/ShadersInclude/pbrBlockSubSurface.fx
  40. 6 0
      src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx
  41. 1 5
      src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx
  42. 2 0
      src/Shaders/ShadersInclude/pbrUboDeclaration.fx
  43. 3 1
      src/Shaders/hdrFiltering.fragment.fx
  44. 69 3
      src/Sprites/sprite.ts
  45. 103 3
      src/Sprites/spriteManager.ts
  46. BIN
      tests/validation/ReferenceImages/gltfExtensionExtMeshGpuInstancingTest.png
  47. 5 0
      tests/validation/config.json

+ 65 - 18
dist/preview release/babylon.d.ts

@@ -10258,13 +10258,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -10898,6 +10910,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11021,6 +11037,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -16125,6 +16163,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -32756,18 +32801,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -37078,9 +37111,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -54031,10 +54065,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -54866,6 +54901,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -58427,7 +58474,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/babylon.js


Разница между файлами не показана из-за своего большого размера
+ 264 - 91
dist/preview release/babylon.max.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 131 - 37
dist/preview release/babylon.module.d.ts

@@ -10316,7 +10316,7 @@ declare module "babylonjs/Sprites/sprite" {
     import { Vector3 } from "babylonjs/Maths/math.vector";
     import { Nullable } from "babylonjs/types";
     import { ActionManager } from "babylonjs/Actions/actionManager";
-    import { ISpriteManager } from "babylonjs/Sprites/spriteManager";
+    import { ISpriteManager, SpriteManager } from "babylonjs/Sprites/spriteManager";
     import { Color4 } from "babylonjs/Maths/math.color";
     import { Observable } from "babylonjs/Misc/observable";
     import { IAnimatable } from "babylonjs/Animations/animatable.interface";
@@ -10433,13 +10433,25 @@ declare module "babylonjs/Sprites/sprite" {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module "babylonjs/Collisions/pickingInfo" {
@@ -11123,6 +11135,10 @@ declare module "babylonjs/Sprites/spriteManager" {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11246,6 +11262,28 @@ declare module "babylonjs/Sprites/spriteManager" {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module "babylonjs/Misc/gradients" {
@@ -16544,6 +16582,13 @@ declare module "babylonjs/Meshes/instancedMesh" {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -33879,18 +33924,6 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -38300,9 +38333,10 @@ declare module "babylonjs/Misc/tools" {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -56374,10 +56408,11 @@ declare module "babylonjs/Materials/PBR/pbrSubSurfaceConfiguration" {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -57303,6 +57338,18 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -61115,7 +61162,7 @@ declare module "babylonjs/Materials/Textures/Filtering/hdrFiltering" {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module "babylonjs/Materials/Textures/hdrCubeTexture" {
@@ -87195,13 +87242,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -87835,6 +87894,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -87958,6 +88021,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -93062,6 +93147,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -109693,18 +109785,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -114015,9 +114095,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -130968,10 +131049,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -131803,6 +131885,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -135364,7 +135458,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

+ 65 - 18
dist/preview release/documentation.d.ts

@@ -10258,13 +10258,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -10898,6 +10910,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11021,6 +11037,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -16125,6 +16163,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -32756,18 +32801,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -37078,9 +37111,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -54031,10 +54065,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -54866,6 +54901,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -58427,7 +58474,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


Разница между файлами не показана из-за своего большого размера
+ 110 - 18
dist/preview release/inspector/babylon.inspector.bundle.max.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

@@ -1852,9 +1852,14 @@ declare module INSPECTOR {
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }

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

@@ -2351,9 +2351,14 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/spr
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }
@@ -4934,9 +4939,14 @@ declare module INSPECTOR {
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }

+ 51 - 51
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -290,60 +290,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 51 - 51
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2870,60 +2870,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 51 - 51
dist/preview release/loaders/babylonjs.loaders.js

@@ -4250,60 +4250,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Разница между файлами не показана из-за своего большого размера
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 131 - 37
dist/preview release/viewer/babylon.module.d.ts

@@ -10316,7 +10316,7 @@ declare module "babylonjs/Sprites/sprite" {
     import { Vector3 } from "babylonjs/Maths/math.vector";
     import { Nullable } from "babylonjs/types";
     import { ActionManager } from "babylonjs/Actions/actionManager";
-    import { ISpriteManager } from "babylonjs/Sprites/spriteManager";
+    import { ISpriteManager, SpriteManager } from "babylonjs/Sprites/spriteManager";
     import { Color4 } from "babylonjs/Maths/math.color";
     import { Observable } from "babylonjs/Misc/observable";
     import { IAnimatable } from "babylonjs/Animations/animatable.interface";
@@ -10433,13 +10433,25 @@ declare module "babylonjs/Sprites/sprite" {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module "babylonjs/Collisions/pickingInfo" {
@@ -11123,6 +11135,10 @@ declare module "babylonjs/Sprites/spriteManager" {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11246,6 +11262,28 @@ declare module "babylonjs/Sprites/spriteManager" {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module "babylonjs/Misc/gradients" {
@@ -16544,6 +16582,13 @@ declare module "babylonjs/Meshes/instancedMesh" {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -33879,18 +33924,6 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -38300,9 +38333,10 @@ declare module "babylonjs/Misc/tools" {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -56374,10 +56408,11 @@ declare module "babylonjs/Materials/PBR/pbrSubSurfaceConfiguration" {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -57303,6 +57338,18 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -61115,7 +61162,7 @@ declare module "babylonjs/Materials/Textures/Filtering/hdrFiltering" {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module "babylonjs/Materials/Textures/hdrCubeTexture" {
@@ -87195,13 +87242,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -87835,6 +87894,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -87958,6 +88021,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -93062,6 +93147,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -109693,18 +109785,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -114015,9 +114095,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -130968,10 +131049,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -131803,6 +131885,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -135364,7 +135458,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

Разница между файлами не показана из-за своего большого размера
+ 69 - 69
dist/preview release/viewer/babylon.viewer.js


Разница между файлами не показана из-за своего большого размера
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -31,6 +31,7 @@
 - Allow logging of shader code when a compilation error occurs ([Popov72](https://github.com/Popov72))
 - Add back support for selecting textures based on engine capabilities ([bghgary](https://github.com/bghgary))
 - Fix Draco decoder when running on IE11 ([bghgary](https://github.com/bghgary))
+- Change default camera calculations to only include visible and enabled meshes ([bghgary](https://github.com/bghgary))
 
 ### NME
 

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx

@@ -316,7 +316,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                     }} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="FILE">
-                <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
+                    <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
                     <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="SNIPPET">

+ 111 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/sprites/spriteManagerPropertyGridComponent.tsx

@@ -16,6 +16,8 @@ import { RenderingManager } from 'babylonjs/Rendering/renderingManager';
 import { TextureLinkLineComponent } from '../../../lines/textureLinkLineComponent';
 import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 import { Sprite } from 'babylonjs/Sprites/sprite';
+import { Tools } from 'babylonjs/Misc/tools';
+import { FileButtonLineComponent } from '../../../lines/fileButtonLineComponent';
 
 interface ISpriteManagerPropertyGridComponentProps {
     globalState: GlobalState;
@@ -26,6 +28,9 @@ interface ISpriteManagerPropertyGridComponentProps {
 }
 
 export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+    private _snippetUrl = "https://snippet.babylonjs.com";
+
+
     constructor(props: ISpriteManagerPropertyGridComponentProps) {
         super(props);
     }
@@ -54,6 +59,100 @@ export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteM
         this.props.onSelectionChangedObservable?.notifyObservers(null);
     }
 
+    saveToFile() {        
+        const spriteManager = this.props.spriteManager;
+        let content = JSON.stringify(spriteManager.serialize(true));
+
+        Tools.Download(new Blob([content]), "spriteManager.json");
+    }
+
+    loadFromFile(file: File) {
+        const spriteManager = this.props.spriteManager;
+        const scene = spriteManager.scene;
+
+        Tools.ReadFile(file, (data) => {
+            let decoder = new TextDecoder("utf-8");
+            let jsonObject = JSON.parse(decoder.decode(data));
+            
+            spriteManager.dispose();            
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+
+            let newManager = SpriteManager.Parse(jsonObject, scene, "");
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(newManager);
+        }, undefined, true);
+    }
+
+    loadFromSnippet() {
+        const spriteManager = this.props.spriteManager;
+        const scene = spriteManager.scene;
+
+        let snippedID = window.prompt("Please enter the snippet ID to use");
+
+        if (!snippedID) {
+            return;
+        }
+        
+        spriteManager.dispose();            
+        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+
+        SpriteManager.CreateFromSnippetAsync(snippedID, scene).then((newManager) => {
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(newManager);
+        }).catch(err => {
+            alert("Unable to load your sprite manager: " + err);
+        });
+    }
+
+    saveToSnippet() {
+        const spriteManager = this.props.spriteManager;
+        let content = JSON.stringify(spriteManager.serialize(true));
+
+        var xmlHttp = new XMLHttpRequest();
+        xmlHttp.onreadystatechange = () => {
+            if (xmlHttp.readyState == 4) {
+                if (xmlHttp.status == 200) {
+                    var snippet = JSON.parse(xmlHttp.responseText);
+                    const oldId = spriteManager.snippetId ;
+                    spriteManager.snippetId = snippet.id;
+                    if (snippet.version && snippet.version != "0") {
+                        spriteManager.snippetId += "#" + snippet.version;
+                    }
+                    this.forceUpdate();
+                    if (navigator.clipboard) {
+                        navigator.clipboard.writeText(spriteManager.snippetId);
+                    }
+
+                    let windowAsAny = window as any;
+
+                    if (windowAsAny.Playground && oldId) {
+                        windowAsAny.Playground.onRequestCodeChangeObservable.notifyObservers({
+                            regex: new RegExp(oldId, "g"),
+                            replace: spriteManager.snippetId
+                        });
+                    }
+
+                    alert("Sprite manager saved with ID: " + spriteManager.snippetId + " (please note that the id was also saved to your clipboard)");
+                }
+                else {
+                    alert("Unable to save your sprite manager");
+                }
+            }
+        }
+
+        xmlHttp.open("POST", this._snippetUrl + (spriteManager.snippetId ? "/" + spriteManager.snippetId : ""), true);
+        xmlHttp.setRequestHeader("Content-Type", "application/json");
+
+        var dataToSend = {
+            payload : JSON.stringify({
+                particleSystem: content
+            }),
+            name: "",
+            description: "",
+            tags: ""
+        };
+
+        xmlHttp.send(JSON.stringify(dataToSend));
+    }
+
     render() {
         const spriteManager = this.props.spriteManager;
 
@@ -70,6 +169,18 @@ export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteM
                     }
                     <ButtonLineComponent label="Dispose" onClick={() => this.disposeManager()} />
                 </LineContainerComponent>
+                <LineContainerComponent globalState={this.props.globalState} title="FILE">
+                    <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
+                    <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
+                </LineContainerComponent>                
+                <LineContainerComponent globalState={this.props.globalState} title="SNIPPET">
+                    {
+                        spriteManager.snippetId &&
+                        <TextLineComponent label="Snippet ID" value={spriteManager.snippetId} />
+                    }
+                    <ButtonLineComponent label="Load from snippet server" onClick={() => this.loadFromSnippet()} />
+                    <ButtonLineComponent label="Save to snippet server" onClick={() => this.saveToSnippet()} />
+                </LineContainerComponent>  
                 <LineContainerComponent globalState={this.props.globalState} title="PROPERTIES">
                     <CheckBoxLineComponent label="Pickable" target={spriteManager} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Fog enabled" target={spriteManager} propertyName="fogEnabled" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 57 - 51
loaders/src/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.ts

@@ -7,6 +7,7 @@ import { Nullable } from "babylonjs/types";
 import { GLTFLoader, ArrayItem } from "../glTFLoader";
 import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
 import { INode } from "../glTFLoaderInterfaces";
+import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
 
 const NAME = "EXT_mesh_gpu_instancing";
 
@@ -47,61 +48,66 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
     /** @hidden */
     public loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>> {
         return GLTFLoader.LoadExtensionAsync<IEXTMeshGpuInstancing, TransformNode>(context, node, this.name, (extensionContext, extension) => {
-            return this._loader.loadNodeAsync(`#/nodes/${node.index}`, node, (babylonTransformNode) => {
-                const promises = new Array<Promise<any>>();
-                let instanceCount: Nullable<number> = null;
-                const loadAttribute = (attribute: string, assignBufferFunc: (data: Float32Array) => void) => {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    const accessor = ArrayItem.Get(`${extensionContext}/attributes/${attribute}`, this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    } else if (instanceCount !== accessor.count) {
-                        throw new Error(`${extensionContext}/attributes: Instance buffer accessors do not have the same count.`);
-                    }
-                    promises.push(this._loader._loadFloatAccessorAsync(`/accessors/${accessor.bufferView}`, accessor).then((data) => {
-                        assignBufferFunc(data);
-                    }));
-                };
-                let translationBuffer: Nullable<Float32Array> = null;
-                let rotationBuffer: Nullable<Float32Array> = null;
-                let scaleBuffer: Nullable<Float32Array> = null;
-
-                loadAttribute("TRANSLATION", (data) => { translationBuffer = data; });
-                loadAttribute("ROTATION", (data) => { rotationBuffer = data; });
-                loadAttribute("SCALE", (data) => { scaleBuffer = data; });
-
-                return Promise.all(promises).then(() => {
-                    if (instanceCount) {
-                        let instanceName: string = "";
-                        let instance: Nullable<TransformNode> = null;
-                        const digitLength = instanceCount.toString().length;
+            const promise = this._loader.loadNodeAsync(`#/nodes/${node.index}`, node, assign);
+
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+
+            // Hide the source meshes.
+            for (const babylonMesh of node._primitiveBabylonMeshes) {
+                babylonMesh.isVisible = false;
+            }
+
+            const promises = new Array<Promise<Nullable<Float32Array>>>();
+            let instanceCount = 0;
+
+            const loadAttribute = (attribute: string) => {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
 
+                const accessor = ArrayItem.Get(`${extensionContext}/attributes/${attribute}`, this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(this._loader._loadFloatAccessorAsync(`/accessors/${accessor.bufferView}`, accessor));
+
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                } else if (instanceCount !== accessor.count) {
+                    throw new Error(`${extensionContext}/attributes: Instance buffer accessors do not have the same count.`);
+                }
+            };
+
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+
+            if (instanceCount == 0) {
+                return promise;
+            }
+
+            const digitLength = instanceCount.toString().length;
+            for (let i = 0; i < instanceCount; ++i) {
+                for (const babylonMesh of node._primitiveBabylonMeshes!) {
+                    const instanceName = `${babylonMesh.name || babylonMesh.id}_${StringTools.PadNumber(i, digitLength)}`;
+                    const babylonInstancedMesh = (babylonMesh as (InstancedMesh | Mesh)).createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+
+            return promise.then((babylonTransformNode) => {
+                return Promise.all(promises).then(([translationBuffer, rotationBuffer, scaleBuffer]) => {
+                    for (const babylonMesh of node._primitiveBabylonMeshes!) {
+                        const babylonInstancedMeshes = babylonMesh.getChildMeshes(true, (node) => (node as AbstractMesh).isAnInstance);
                         for (let i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (let j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    const babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + StringTools.PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = (babylonMeshPrimitive as InstancedMesh).sourceMesh.createInstance(instanceName);
-                                    } else if ((babylonMeshPrimitive as Mesh).createInstance) {
-                                        instance = (babylonMeshPrimitive as Mesh).createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? Vector3.FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? Quaternion.FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion!)
-                                            : instance.rotationQuaternion!.set(0, 0, 0, 1);
-                                        scaleBuffer ? Vector3.FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            const babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion!);
+                            scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
+
                     return babylonTransformNode;
                 });
             });

+ 4 - 1
sandbox/index.js

@@ -165,8 +165,11 @@ if (BABYLON.Engine.isSupported()) {
                 framingBehavior.elevationReturnTime = -1;
 
                 if (currentScene.meshes.length) {
-                    var worldExtends = currentScene.getWorldExtends();
                     currentScene.activeCamera.lowerRadiusLimit = null;
+
+                    var worldExtends = currentScene.getWorldExtends(function (mesh) {
+                        return mesh.isVisible && mesh.isEnabled();
+                    });
                     framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
                 }
             }

+ 1 - 1
src/Helpers/sceneHelpers.ts

@@ -115,7 +115,7 @@ Scene.prototype.createDefaultCamera = function(createArcRotateCamera = false, re
 
     // Camera
     if (!this.activeCamera) {
-        var worldExtends = this.getWorldExtends();
+        var worldExtends = this.getWorldExtends((mesh) => mesh.isVisible && mesh.isEnabled());
         var worldSize = worldExtends.max.subtract(worldExtends.min);
         var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
 

+ 37 - 12
src/Materials/PBR/pbrBaseMaterial.ts

@@ -640,6 +640,30 @@ export abstract class PBRBaseMaterial extends PushMaterial {
      */
     protected _forceIrradianceInFragment = false;
 
+    private _realTimeFiltering: boolean = false;
+    /**
+     * Enables realtime filtering on the texture.
+     */
+    public get realTimeFiltering() {
+        return this._realTimeFiltering;
+    }
+    public set realTimeFiltering(b: boolean) {
+        this._realTimeFiltering = b;
+        this.markAsDirty(Constants.MATERIAL_TextureDirtyFlag);
+    }
+
+    private _realTimeFilteringQuality: number = Constants.TEXTURE_FILTERING_QUALITY_LOW;
+    /**
+     * Quality switch for realtime filtering
+     */
+    public get realTimeFilteringQuality() : number {
+        return this._realTimeFilteringQuality;
+    }
+    public set realTimeFilteringQuality(n: number) {
+        this._realTimeFilteringQuality = n;
+        this.markAsDirty(Constants.MATERIAL_TextureDirtyFlag);
+    }
+
     /**
      * Force normal to face away from face.
      */
@@ -1184,7 +1208,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
         var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vMetallicReflectanceFactors", "vEmissiveColor", "visibility", "vReflectionColor",
             "vFogInfos", "vFogColor", "pointSize",
-            "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", "vMetallicReflectanceInfos",
+            "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vReflectionPosition", "vReflectionSize", "vEmissiveInfos", "vReflectivityInfos", "vReflectionFilteringInfo", "vMetallicReflectanceInfos",
             "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos",
             "mBones",
             "vClipPlane", "vClipPlane2", "vClipPlane3", "vClipPlane4", "vClipPlane5", "vClipPlane6", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "normalMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "metallicReflectanceMatrix",
@@ -1198,8 +1222,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
             "vSphericalL2_2", "vSphericalL2_1", "vSphericalL20", "vSphericalL21", "vSphericalL22",
             "vReflectionMicrosurfaceInfos",
             "vTangentSpaceParams", "boneTextureWidth",
-            "vDebugMode",
-            "vFilteringInfo", "linearRoughness"
+            "vDebugMode"
         ];
 
         var samplers = ["albedoSampler", "reflectivitySampler", "ambientSampler", "emissiveSampler",
@@ -1302,8 +1325,12 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                     defines.LODINREFLECTIONALPHA = reflectionTexture.lodLevelInAlpha;
                     defines.LINEARSPECULARREFLECTION = reflectionTexture.linearSpecularLOD;
 
-                    if (reflectionTexture.realTimeFiltering && reflectionTexture.realTimeFilteringQuality > 0) {
-                        defines.NUM_SAMPLES = reflectionTexture.realTimeFilteringQuality + "u";
+                    if (this.realTimeFiltering && this.realTimeFilteringQuality > 0) {
+                        defines.NUM_SAMPLES = "" + this.realTimeFilteringQuality;
+                        if (engine.webGLVersion > 1) {
+                            defines.NUM_SAMPLES = defines.NUM_SAMPLES + "u";
+                        }
+
                         defines.REALTIME_FILTERING = true;
                     } else {
                         defines.REALTIME_FILTERING = false;
@@ -1367,7 +1394,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                         else if (reflectionTexture.isCube) {
                             defines.USESPHERICALFROMREFLECTIONMAP = true;
                             defines.USEIRRADIANCEMAP = false;
-                            if (this._forceIrradianceInFragment || reflectionTexture.realTimeFiltering || scene.getEngine().getCaps().maxVaryingVectors <= 8) {
+                            if (this._forceIrradianceInFragment || this.realTimeFiltering || scene.getEngine().getCaps().maxVaryingVectors <= 8) {
                                 defines.USESPHERICALINVERTEX = false;
                             }
                             else {
@@ -1588,6 +1615,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         ubo.addUniform("vReflectivityInfos", 3);
         ubo.addUniform("vMicroSurfaceSamplerInfos", 2);
         ubo.addUniform("vReflectionInfos", 2);
+        ubo.addUniform("vReflectionFilteringInfo", 2);
         ubo.addUniform("vReflectionPosition", 3);
         ubo.addUniform("vReflectionSize", 3);
         ubo.addUniform("vBumpInfos", 3);
@@ -1723,12 +1751,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                             ubo.updateVector3("vReflectionSize", cubeTexture.boundingBoxSize);
                         }
 
-                        if (reflectionTexture.realTimeFiltering) {
+                        if (this.realTimeFiltering) {
                             const width = reflectionTexture.getSize().width;
-                            const alpha = this._roughness! * this._roughness!;
-
-                            this._activeEffect.setFloat2("vFilteringInfo", width, Scalar.Log2(width));
-                            this._activeEffect.setFloat("linearRoughness", alpha);
+                            ubo.updateFloat2("vReflectionFilteringInfo", width, Scalar.Log2(width));
                         }
 
                         if (!defines.USEIRRADIANCEMAP) {
@@ -1926,7 +1951,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
                 }
             }
 
-            this.subSurface.bindForSubMesh(ubo, scene, engine, this.isFrozen, defines.LODBASEDMICROSFURACE);
+            this.subSurface.bindForSubMesh(ubo, scene, engine, this.isFrozen, defines.LODBASEDMICROSFURACE, this.realTimeFiltering);
             this.clearCoat.bindForSubMesh(ubo, scene, engine, this._disableBumpMap, this.isFrozen, this._invertNormalMapX, this._invertNormalMapY);
             this.anisotropy.bindForSubMesh(ubo, scene, this.isFrozen);
             this.sheen.bindForSubMesh(ubo, scene, this.isFrozen);

+ 15 - 5
src/Materials/PBR/pbrSubSurfaceConfiguration.ts

@@ -10,6 +10,7 @@ import { MaterialFlags } from "../materialFlags";
 import { UniformBuffer } from "../../Materials/uniformBuffer";
 import { MaterialHelper } from "../../Materials/materialHelper";
 import { EffectFallbacks } from '../effectFallbacks';
+import { Scalar } from "../../Maths/math.scalar";
 
 declare type Engine = import("../../Engines/engine").Engine;
 declare type Scene = import("../../scene").Scene;
@@ -290,10 +291,11 @@ export class PBRSubSurfaceConfiguration {
      * @param uniformBuffer defines the Uniform buffer to fill in.
      * @param scene defines the scene the material belongs to.
      * @param engine defines the engine the material belongs to.
-     * @param isFrozen defines wether the material is frozen or not.
-     * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+     * @param isFrozen defines whether the material is frozen or not.
+     * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+     * @param realTimeFiltering defines whether the textures should be filtered on the fly.
      */
-    public bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void {
+    public bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void {
         var refractionTexture = this._getRefractionTexture(scene);
 
         if (!uniformBuffer.useUbo || !isFrozen || !uniformBuffer.isSync) {
@@ -313,11 +315,18 @@ export class PBRSubSurfaceConfiguration {
                         depth = (<any>refractionTexture).depth;
                     }
                 }
+
+                var width = refractionTexture.getSize().width;
+
                 uniformBuffer.updateFloat4("vRefractionInfos", refractionTexture.level, 1 / this._indexOfRefraction, depth, this._invertRefractionY ? -1 : 1);
                 uniformBuffer.updateFloat3("vRefractionMicrosurfaceInfos",
-                    refractionTexture.getSize().width,
+                    width,
                     refractionTexture.lodGenerationScale,
                     refractionTexture.lodGenerationOffset);
+
+                if (realTimeFiltering) {
+                    uniformBuffer.updateFloat2("vRefractionFilteringInfo", width, Scalar.Log2(width));
+                }
             }
 
             uniformBuffer.updateColor3("vDiffusionDistance", this.diffusionDistance);
@@ -503,7 +512,7 @@ export class PBRSubSurfaceConfiguration {
     public static AddUniforms(uniforms: string[]): void {
         uniforms.push(
             "vDiffusionDistance", "vTintColor", "vSubSurfaceIntensity",
-            "vRefractionMicrosurfaceInfos",
+            "vRefractionMicrosurfaceInfos", "vRefractionFilteringInfo",
             "vRefractionInfos", "vThicknessInfos", "vThicknessParam",
             "refractionMatrix", "thicknessMatrix");
     }
@@ -523,6 +532,7 @@ export class PBRSubSurfaceConfiguration {
      */
     public static PrepareUniformBuffer(uniformBuffer: UniformBuffer): void {
         uniformBuffer.addUniform("vRefractionMicrosurfaceInfos", 3);
+        uniformBuffer.addUniform("vRefractionFilteringInfo", 2);
         uniformBuffer.addUniform("vRefractionInfos", 4);
         uniformBuffer.addUniform("refractionMatrix", 16);
         uniformBuffer.addUniform("vThicknessInfos", 2);

+ 8 - 2
src/Materials/Textures/Filtering/hdrFiltering.ts

@@ -10,6 +10,7 @@ import { Nullable } from '../../../types';
 
 import "../../../Shaders/hdrFiltering.vertex";
 import "../../../Shaders/hdrFiltering.fragment";
+import { Logger } from '../../../Misc/logger';
 
 /**
  * Options for texture filtering
@@ -133,7 +134,7 @@ export class HDRFiltering {
                     alpha = 0;
                 }
 
-                effect.setFloat("linearRoughness", alpha);
+                effect.setFloat("alphaG", alpha);
 
                 this._effectRenderer.draw();
             }
@@ -164,7 +165,7 @@ export class HDRFiltering {
             vertexShader: "hdrFiltering",
             fragmentShader: "hdrFiltering",
             samplerNames: ["inputTexture"],
-            uniformNames: ["vSampleDirections", "vWeights", "up", "right", "front", "vFilteringInfo", "hdrScale", "linearRoughness"],
+            uniformNames: ["vSampleDirections", "vWeights", "up", "right", "front", "vFilteringInfo", "hdrScale", "alphaG"],
             useShaderStore: true,
             defines,
             onCompiled: onCompiled
@@ -192,6 +193,11 @@ export class HDRFiltering {
       * @return Promise called when prefiltering is done
       */
     public prefilter(texture: BaseTexture, onFinished: Nullable<() => void> = null) {
+        if (this._engine.webGLVersion === 1) {
+            Logger.Warn("HDR prefiltering is not available in WebGL 1., you can use real time filtering instead.");
+            return;
+        }
+
         return new Promise((resolve) => {
             this._effectRenderer = new EffectRenderer(this._engine);
             this._effectWrapper = this._createEffect(texture);

+ 0 - 30
src/Materials/Textures/baseTexture.ts

@@ -345,36 +345,6 @@ export class BaseTexture implements IAnimatable {
         return "BaseTexture";
     }
 
-    private _realTimeFiltering: boolean = false;
-    /**
-     * Enables realtime filtering on the texture.
-     */
-    public get realTimeFiltering() {
-        return this._realTimeFiltering;
-    }
-    public set realTimeFiltering(b: boolean) {
-        this._realTimeFiltering = b;
-        let scene = this.getScene();
-        if (scene) {
-            scene.markAllMaterialsAsDirty(Constants.MATERIAL_TextureDirtyFlag);
-        }
-    }
-
-    private _realTimeFilteringQuality: number = Constants.TEXTURE_FILTERING_QUALITY_LOW;
-    /**
-     * Quality switch for realtime filtering
-     */
-    public get realTimeFilteringQuality() : number {
-        return this._realTimeFilteringQuality;
-    }
-    public set realTimeFilteringQuality(n: number) {
-        this._realTimeFilteringQuality = n;
-        let scene = this.getScene();
-        if (scene) {
-            scene.markAllMaterialsAsDirty(Constants.MATERIAL_TextureDirtyFlag);
-        }
-    }
-
     /**
      * Define the list of animation attached to the texture.
      */

+ 10 - 0
src/Meshes/instancedMesh.ts

@@ -160,6 +160,16 @@ export class InstancedMesh extends AbstractMesh {
     }
 
     /**
+     * Creates a new InstancedMesh object from the mesh model.
+     * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+     * @param name defines the name of the new instance
+     * @returns a new InstancedMesh
+     */
+    public createInstance(name: string): InstancedMesh {
+        return this._sourceMesh.createInstance(name);
+    }
+
+    /**
      * Is this node ready to be used/rendered
      * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
      * @return {boolean} is it ready

+ 0 - 2
src/Probes/reflectionProbe.ts

@@ -103,8 +103,6 @@ export class ReflectionProbe {
         }
         this._renderTargetTexture = new RenderTargetTexture(name, size, scene, generateMipMaps, true, textureType, true);
 
-        this._renderTargetTexture.realTimeFiltering = true;
-
         this._renderTargetTexture.onBeforeRenderObservable.add((faceIndex: number) => {
             switch (faceIndex) {
                 case 0:

+ 22 - 14
src/Shaders/ShadersInclude/hdrFilteringFunctions.fx

@@ -1,8 +1,5 @@
-#if defined(WEBGL2) && defined(NUM_SAMPLES)
-	#if NUM_SAMPLES > 0u
-		uniform vec2 vFilteringInfo;
-		uniform float linearRoughness;
-
+#ifdef NUM_SAMPLES
+	#if NUM_SAMPLES > 0
 		const float NUM_SAMPLES_FLOAT = float(NUM_SAMPLES);
 		const float NUM_SAMPLES_FLOAT_INVERSED = 1. / NUM_SAMPLES_FLOAT;
 
@@ -124,18 +121,23 @@
 		//
 		//
 
-		vec3 irradiance(samplerCube inputTexture, vec3 n) {
+		vec3 irradiance(samplerCube inputTexture, vec3 N, vec2 filteringInfo) {
+			vec3 n = normalize(N);
 		    vec3 result = vec3(0.0);
 			vec3 tangent = abs(n.z) < 0.999 ? vec3(0., 0., 1.) : vec3(1., 0., 0.);
 			tangent = normalize(cross(tangent, n));
 			vec3 bitangent = cross(n, tangent);
 			mat3 tbn = mat3(tangent, bitangent, n);
 
-		    float maxLevel = vFilteringInfo.y;
-		    float dim0 = vFilteringInfo.x;
+		    float maxLevel = filteringInfo.y;
+		    float dim0 = filteringInfo.x;
 		    float omegaP = (4. * PI) / (6. * dim0 * dim0);
 
+		    #ifdef WEBGL2
 		    for(uint i = 0u; i < NUM_SAMPLES; ++i)
+		    #else
+		    for(int i = 0; i < NUM_SAMPLES; ++i)
+		    #endif
 		    {
 		        vec2 Xi = hammersley(i, NUM_SAMPLES);
 		        vec3 Ls = hemisphereCosSample(Xi);
@@ -166,8 +168,10 @@
 		    return result;
 		}
 
-		vec3 radiance(samplerCube inputTexture, vec3 n) {
-			if (linearRoughness == 0.) {
+		vec3 radiance(float alphaG, samplerCube inputTexture, vec3 N, vec2 filteringInfo) {
+			vec3 n = normalize(N);
+
+			if (alphaG == 0.) {
 				vec3 c = textureCube(inputTexture, n).rgb;
 				#ifdef GAMMA_INPUT
 				    c = toLinearSpace(c);
@@ -181,15 +185,19 @@
 			vec3 bitangent = cross(n, tangent);
 			mat3 tbn = mat3(tangent, bitangent, n);
 
-			float maxLevel = vFilteringInfo.y;
-			float dim0 = vFilteringInfo.x;
+			float maxLevel = filteringInfo.y;
+			float dim0 = filteringInfo.x;
 			float omegaP = (4. * PI) / (6. * dim0 * dim0);
 
 			float weight = 0.;
+			#ifdef WEBGL2
 			for(uint i = 0u; i < NUM_SAMPLES; ++i)
+			#else
+			for(int i = 0; i < NUM_SAMPLES; ++i)
+			#endif
 			{
 			    vec2 Xi = hammersley(i, NUM_SAMPLES);
-			    vec3 H = hemisphereImportanceSampleDggx(Xi, linearRoughness);
+			    vec3 H = hemisphereImportanceSampleDggx(Xi, alphaG);
 
 			    float NoV = 1.;
 			    float NoH = H.z;
@@ -199,7 +207,7 @@
 			    L = normalize(L);
 
 			    if (NoL > 0.) {
-			        float pdf_inversed = 4. / normalDistributionFunction_TrowbridgeReitzGGX(NoH, linearRoughness);
+			        float pdf_inversed = 4. / normalDistributionFunction_TrowbridgeReitzGGX(NoH, alphaG);
 
 			        float omegaS = NUM_SAMPLES_FLOAT_INVERSED * pdf_inversed;
 			        float l = log4(omegaS) - log4(omegaP) + log4(K);

+ 24 - 24
src/Shaders/ShadersInclude/helperFunctions.fx

@@ -91,30 +91,30 @@ float square(float value)
         return vec2(float(i)/float(N), radicalInverse_VdC(i));
     }
 #else
-    // float vanDerCorpus(uint n, uint base)
-    // {
-    //     float invBase = 1.0 / float(base);
-    //     float denom   = 1.0;
-    //     float result  = 0.0;
-
-    //     for(uint i = 0u; i < 32u; ++i)
-    //     {
-    //         if(n > 0u)
-    //         {
-    //             denom   = mod(float(n), 2.0);
-    //             result += denom * invBase;
-    //             invBase = invBase / 2.0;
-    //             n       = uint(float(n) / 2.0);
-    //         }
-    //     }
-
-    //     return result;
-    // }
-
-    // vec2 hammersley(uint i, uint N)
-    // {
-    //     return vec2(float(i)/float(N), vanDerCorpus(i, 2u));
-    // }
+    float vanDerCorpus(int n, int base)
+    {
+        float invBase = 1.0 / float(base);
+        float denom   = 1.0;
+        float result  = 0.0;
+
+        for(int i = 0; i < 32; ++i)
+        {
+            if(n > 0)
+            {
+                denom   = mod(float(n), 2.0);
+                result += denom * invBase;
+                invBase = invBase / 2.0;
+                n       = int(float(n) / 2.0);
+            }
+        }
+
+        return result;
+    }
+
+    vec2 hammersley(int i, int N)
+    {
+        return vec2(float(i)/float(N), vanDerCorpus(i, 2));
+    }
 #endif
 
 float log4(float x) {

+ 15 - 4
src/Shaders/ShadersInclude/pbrBlockReflection.fx

@@ -112,8 +112,15 @@
             #else
                 float requestedReflectionLOD = reflectionLOD;
             #endif
-
-            environmentRadiance = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD);
+            #ifdef REALTIME_FILTERING
+                #ifdef LINEARSPECULARREFLECTION
+                    environmentRadiance = vec4(radiance(roughness, reflectionSampler, reflectionCoords, vReflectionFilteringInfo), 1.0);
+                #else
+                    environmentRadiance = vec4(radiance(alphaG, reflectionSampler, reflectionCoords, vReflectionFilteringInfo), 1.0);
+                #endif
+            #else
+                environmentRadiance = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD);
+            #endif
         #else
             float lodReflectionNormalized = saturate(reflectionLOD / log2(vReflectionMicrosurfaceInfos.x));
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
@@ -256,8 +263,12 @@
                     irradianceVector.z *= -1.0;
                 #endif
 
-                #if defined(WEBGL2) && defined(REALTIME_FILTERING)
-                    environmentIrradiance = irradiance(reflectionSampler, irradianceVector);
+                #ifdef INVERTCUBICMAP
+                    irradianceVector.y *= -1.0;
+                #endif
+
+                #if defined(REALTIME_FILTERING)
+                    environmentIrradiance = irradiance(reflectionSampler, irradianceVector, vReflectionFilteringInfo);
                 #else
                     environmentIrradiance = computeEnvironmentIrradiance(irradianceVector);
                 #endif

+ 17 - 2
src/Shaders/ShadersInclude/pbrBlockSubSurface.fx

@@ -203,7 +203,15 @@ struct subSurfaceOutParams
                 float requestedRefractionLOD = refractionLOD;
             #endif
 
-            environmentRefraction = sampleRefractionLod(refractionSampler, refractionCoords, requestedRefractionLOD);
+            #ifdef REALTIME_FILTERING
+                #ifdef SS_LINEARSPECULARREFRACTION
+                    environmentRefraction = vec4(radiance(roughness, refractionSampler, refractionCoords, vRefractionFilteringInfo), 1.0);
+                #else
+                    environmentRefraction = vec4(radiance(alphaG, refractionSampler, refractionCoords, vRefractionFilteringInfo), 1.0);
+                #endif
+            #else
+                environmentRefraction = sampleRefractionLod(refractionSampler, refractionCoords, requestedRefractionLOD);
+            #endif
         #else
             float lodRefractionNormalized = saturate(refractionLOD / log2(vRefractionMicrosurfaceInfos.x));
             float lodRefractionNormalizedDoubled = lodRefractionNormalized * 2.0;
@@ -301,12 +309,19 @@ struct subSurfaceOutParams
             #ifdef REFLECTIONMAP_OPPOSITEZ
                 irradianceVector.z *= -1.0;
             #endif
+            #ifdef INVERTCUBICMAP
+                irradianceVector.y *= -1.0;
+            #endif
         #else
             vec3 irradianceVector = irradianceVector_;
         #endif
 
         #if defined(USESPHERICALFROMREFLECTIONMAP)
-            vec3 refractionIrradiance = computeEnvironmentIrradiance(-irradianceVector);
+            #if defined(REALTIME_FILTERING)
+                vec3 refractionIrradiance = irradiance(reflectionSampler, -irradianceVector, vReflectionFilteringInfo);
+            #else
+                vec3 refractionIrradiance = computeEnvironmentIrradiance(-irradianceVector);
+            #endif
         #elif defined(USEIRRADIANCEMAP)
             #ifdef REFLECTIONMAP_3D
                 vec3 irradianceCoords = irradianceVector;

+ 6 - 0
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -52,6 +52,9 @@ uniform mat4 view;
 // Reflection
 #ifdef REFLECTION
     uniform vec2 vReflectionInfos;
+    #ifdef REALTIME_FILTERING
+        uniform vec2 vReflectionFilteringInfo;
+    #endif
     uniform mat4 reflectionMatrix;
     uniform vec3 vReflectionMicrosurfaceInfos;
 
@@ -117,6 +120,9 @@ uniform mat4 view;
         uniform vec3 vRefractionMicrosurfaceInfos;
         uniform vec4 vRefractionInfos;
         uniform mat4 refractionMatrix;
+        #ifdef REALTIME_FILTERING
+            uniform vec2 vRefractionFilteringInfo;
+        #endif
     #endif
 
     #ifdef SS_THICKNESSANDMASK_TEXTURE

+ 1 - 5
src/Shaders/ShadersInclude/pbrFragmentSamplersDeclaration.fx

@@ -155,11 +155,7 @@
         uniform samplerCube reflectionSampler;
         
         #ifdef LODBASEDMICROSFURACE
-            #if defined(WEBGL2) && defined(REALTIME_FILTERING)
-                #define sampleReflectionLod(s, c, l) vec4(radiance(s, c), 1.0)
-            #else
-                #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
-            #endif
+            #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
         #else
             uniform samplerCube reflectionSamplerLow;
             uniform samplerCube reflectionSamplerHigh;

+ 2 - 0
src/Shaders/ShadersInclude/pbrUboDeclaration.fx

@@ -10,6 +10,7 @@ uniform Material
     uniform vec3 vReflectivityInfos;
     uniform vec2 vMicroSurfaceSamplerInfos;
     uniform vec2 vReflectionInfos;
+    uniform vec2 vReflectionFilteringInfo;
     uniform vec3 vReflectionPosition;
     uniform vec3 vReflectionSize;
     uniform vec3 vBumpInfos;
@@ -59,6 +60,7 @@ uniform Material
     uniform mat4 sheenMatrix;
 
     uniform vec3 vRefractionMicrosurfaceInfos;
+    uniform vec2 vRefractionFilteringInfo;
     uniform vec4 vRefractionInfos;
     uniform mat4 refractionMatrix;
     uniform vec2 vThicknessInfos;

+ 3 - 1
src/Shaders/hdrFiltering.fragment.fx

@@ -3,13 +3,15 @@
 #include<pbrBRDFFunctions>
 #include<hdrFilteringFunctions>
 
+uniform float alphaG;
 uniform samplerCube inputTexture;
+uniform vec2 vFilteringInfo;
 uniform float hdrScale;
 
 varying vec3 direction;
 
 void main() {
-    vec3 color = radiance(inputTexture, direction);
+    vec3 color = radiance(alphaG, inputTexture, direction, vFilteringInfo);
 
     gl_FragColor = vec4(color * hdrScale, 1.0);
 }

+ 69 - 3
src/Sprites/sprite.ts

@@ -1,7 +1,7 @@
 import { Vector3 } from "../Maths/math.vector";
 import { Nullable } from "../types";
 import { ActionManager } from "../Actions/actionManager";
-import { ISpriteManager } from "./spriteManager";
+import { ISpriteManager, SpriteManager } from "./spriteManager";
 import { Color4 } from '../Maths/math.color';
 import { Observable } from '../Misc/observable';
 import { IAnimatable } from '../Animations/animatable.interface';
@@ -66,7 +66,7 @@ export class Sprite implements IAnimatable {
     private _direction = 1;
     private _manager: ISpriteManager;
     private _time = 0;
-    private _onAnimationEnd: () => void;
+    private _onAnimationEnd: Nullable<() => void> = null;
     /**
      * Gets or sets a boolean indicating if the sprite is visible (renderable). Default is true
      */
@@ -172,7 +172,7 @@ export class Sprite implements IAnimatable {
      * @param delay defines the start delay (in ms)
      * @param onAnimationEnd defines a callback to call when animation ends
      */
-    public playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void {
+    public playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: Nullable<() => void> = null): void {
         this._fromIndex = from;
         this._toIndex = to;
         this._loopAnimation = loop;
@@ -237,4 +237,70 @@ export class Sprite implements IAnimatable {
         this.onDisposeObservable.notifyObservers(this);
         this.onDisposeObservable.clear();
     }
+
+    /**
+     * Serializes the sprite to a JSON object
+     * @returns the JSON object
+     */
+    public serialize(): any {
+        var serializationObject: any = {};
+
+        serializationObject.name = this.name;
+        serializationObject.position = this.position.asArray();
+        serializationObject.color = this.color.asArray();
+        serializationObject.width = this.width;
+        serializationObject.height = this.height;
+        serializationObject.angle = this.angle;
+        serializationObject.cellIndex = this.cellIndex;
+        serializationObject.cellRef = this.cellRef;
+        serializationObject.invertU = this.invertU;
+        serializationObject.invertV = this.invertV;
+        serializationObject.disposeWhenFinishedAnimating = this.disposeWhenFinishedAnimating;
+        serializationObject.isPickable = this.isPickable;
+        serializationObject.isVisible = this.isVisible;
+        serializationObject.useAlphaForPicking = this.useAlphaForPicking;
+
+        serializationObject.animationStarted = this.animationStarted;
+        serializationObject.fromIndex = this.fromIndex;
+        serializationObject.toIndex = this.toIndex;
+        serializationObject.loopAnimation = this.loopAnimation;
+        serializationObject.delay = this.delay;
+
+        return serializationObject;
+    }
+
+    /**
+     * Parses a JSON object to create a new sprite
+     * @param parsedSprite The JSON object to parse
+     * @param manager defines the hosting manager
+     * @returns the new sprite
+     */
+    public static Parse(parsedSprite: any, manager: SpriteManager): Sprite {
+        var sprite = new Sprite(parsedSprite.name, manager);
+
+        sprite.position = Vector3.FromArray(parsedSprite.position);
+        sprite.color = Color4.FromArray(parsedSprite.color);
+        sprite.width = parsedSprite.width;
+        sprite.height = parsedSprite.height;
+        sprite.angle = parsedSprite.angle;
+        sprite.cellIndex = parsedSprite.cellIndex;
+        sprite.cellRef = parsedSprite.cellRef;
+        sprite.invertU = parsedSprite.invertU;
+        sprite.invertV = parsedSprite.invertV;
+        sprite.disposeWhenFinishedAnimating = parsedSprite.disposeWhenFinishedAnimating;
+        sprite.isPickable = parsedSprite.isPickable;
+        sprite.isVisible = parsedSprite.isVisible;
+        sprite.useAlphaForPicking = parsedSprite.useAlphaForPicking;
+
+        sprite.fromIndex = parsedSprite.fromIndex;
+        sprite.toIndex = parsedSprite.toIndex;
+        sprite.loopAnimation = parsedSprite.loopAnimation;
+        sprite.delay = parsedSprite.delay;
+
+        if (parsedSprite.animationStarted) {
+            sprite.playAnimation(sprite.fromIndex, sprite.toIndex, sprite.loopAnimation, sprite.delay);
+        }
+
+        return sprite;
+    }
 }

+ 103 - 3
src/Sprites/spriteManager.ts

@@ -19,6 +19,7 @@ import "../Shaders/sprites.fragment";
 import "../Shaders/sprites.vertex";
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { Engine } from '../Engines/engine';
+import { WebRequest } from '../Misc/webRequest';
 declare type Ray = import("../Culling/ray").Ray;
 
 /**
@@ -98,6 +99,12 @@ export interface ISpriteManager extends IDisposable {
  * @see http://doc.babylonjs.com/babylon101/sprites
  */
 export class SpriteManager implements ISpriteManager {
+    /** Define the Url to load snippets */
+    public static SnippetUrl = "https://snippet.babylonjs.com";
+
+    /** Snippet ID if the manager was created from the snippet server */
+    public snippetId: string;
+
     /** Gets the list of sprites */
     public sprites = new Array<Sprite>();
     /** Gets or sets the rendering group id (0 by default) */
@@ -188,6 +195,8 @@ export class SpriteManager implements ISpriteManager {
 
     public set texture(value: Texture) {
         this._spriteTexture = value;
+        this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+        this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
         this._textureContent = null;
     }
 
@@ -229,9 +238,12 @@ export class SpriteManager implements ISpriteManager {
         }
         this._capacity = capacity;
         this._fromPacked = fromPacked;
-        this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
-        this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
-        this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+
+        if (imgUrl) {
+            this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
+            this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+        }
 
         if (cellSize.width && cellSize.height) {
             this.cellWidth = cellSize.width;
@@ -753,4 +765,92 @@ export class SpriteManager implements ISpriteManager {
         this.onDisposeObservable.notifyObservers(this);
         this.onDisposeObservable.clear();
     }
+
+    /**
+     * Serializes the sprite manager to a JSON object
+     * @param serializeTexture defines if the texture must be serialized as well
+     * @returns the JSON object
+     */
+    public serialize(serializeTexture = false): any {
+        var serializationObject: any = {};
+
+        serializationObject.name = this.name;
+        serializationObject.capacity = this.capacity;
+        serializationObject.cellWidth = this.cellWidth;
+        serializationObject.cellHeight = this.cellHeight;
+
+        if (this.texture) {
+            if (serializeTexture) {
+                serializationObject.texture = this.texture.serialize();
+            } else {
+                serializationObject.textureUrl = this.texture.name;
+                serializationObject.invertY = this.texture._invertY;
+            }
+        }
+
+        serializationObject.sprites = [];
+
+        for (var sprite of this.sprites) {
+            serializationObject.sprites.push(sprite.serialize());
+        }
+
+        return serializationObject;
+    }
+
+    /**
+     * Parses a JSON object to create a new sprite manager.
+     * @param parsedManager The JSON object to parse
+     * @param scene The scene to create the sprite managerin
+     * @param rootUrl The root url to use to load external dependencies like texture
+     * @returns the new sprite manager
+     */
+    public static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager {
+        var manager = new SpriteManager(parsedManager.name, "", parsedManager.capacity, {
+            width: parsedManager.cellWidth,
+            height: parsedManager.cellHeight,
+        }, scene);
+
+        if (parsedManager.texture) {
+            manager.texture = Texture.Parse(parsedManager.texture, scene, rootUrl) as Texture;
+        } else if (parsedManager.textureName) {
+            manager.texture = new Texture(rootUrl + parsedManager.textureUrl, scene, false, parsedManager.invertY !== undefined ? parsedManager.invertY : true);
+        }
+
+        for (var parsedSprite of parsedManager.sprites) {
+            Sprite.Parse(parsedSprite, manager);
+        }
+
+        return manager;
+    }
+
+    /**
+     * Creates a sprite manager from a snippet saved by the sprite editor
+     * @param snippetId defines the snippet to load
+     * @param scene defines the hosting scene
+     * @param rootUrl defines the root URL to use to load textures and relative dependencies
+     * @returns a promise that will resolve to the new sprite manager
+     */
+    public static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl: string = ""): Promise<SpriteManager> {
+        return new Promise((resolve, reject) => {
+            var request = new WebRequest();
+            request.addEventListener("readystatechange", () => {
+                if (request.readyState == 4) {
+                    if (request.status == 200) {
+                        var snippet = JSON.parse(JSON.parse(request.responseText).jsonPayload);
+                        let serializationObject = JSON.parse(snippet.spriteManager);
+                        let output = SpriteManager.Parse(serializationObject, scene, rootUrl);
+
+                        output.snippetId = snippetId;
+
+                        resolve(output);
+                    } else {
+                        reject("Unable to load the snippet " + snippetId);
+                    }
+                }
+            });
+
+            request.open("GET", this.SnippetUrl + "/" + snippetId.replace(/#/g, "/"));
+            request.send();
+        });
+    }
 }

BIN
tests/validation/ReferenceImages/gltfExtensionExtMeshGpuInstancingTest.png


+ 5 - 0
tests/validation/config.json

@@ -827,6 +827,11 @@
             "title": "Visibility",
             "playgroundId": "#PXC9CF#2",
             "referenceImage": "visibility.png"
+        },
+        {
+            "title": "GLTF Extension EXT_mesh_gpu_instancing",
+            "playgroundId": "#QFIGLW#9",
+            "referenceImage": "gltfExtensionExtMeshGpuInstancingTest.png"
         }
     ]
 }