Browse Source

Merge branch 'master' of https://github.com/mrdunk/Babylon.js into ArcRotateCamera_UnitTests

duncan law 6 years ago
parent
commit
1caeeaacb9
73 changed files with 1246 additions and 615 deletions
  1. 0 1
      .vscode/settings.json
  2. 84 15
      Playground/babylon.d.txt
  3. 0 2
      Tools/WebpackPlugins/babylonWebpackConfig.js
  4. 86 15
      dist/preview release/babylon.d.ts
  5. 1 1
      dist/preview release/babylon.js
  6. 195 121
      dist/preview release/babylon.max.js
  7. 1 1
      dist/preview release/babylon.max.js.map
  8. 181 31
      dist/preview release/babylon.module.d.ts
  9. 1 1
      dist/preview release/glTF2Interface/package.json
  10. 4 4
      dist/preview release/gui/babylon.gui.js
  11. 1 1
      dist/preview release/gui/babylon.gui.js.map
  12. 1 1
      dist/preview release/gui/babylon.gui.min.js
  13. 2 2
      dist/preview release/gui/package.json
  14. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  15. 78 18
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  16. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  17. 6 6
      dist/preview release/inspector/package.json
  18. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  19. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  20. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  21. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.js
  22. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  23. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  24. 2 2
      dist/preview release/loaders/babylonjs.loaders.js
  25. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  26. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  27. 3 3
      dist/preview release/loaders/package.json
  28. 28 10
      dist/preview release/materialsLibrary/babylon.mixMaterial.js
  29. 1 1
      dist/preview release/materialsLibrary/babylon.mixMaterial.js.map
  30. 2 2
      dist/preview release/materialsLibrary/babylon.mixMaterial.min.js
  31. 28 10
      dist/preview release/materialsLibrary/babylonjs.materials.js
  32. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js.map
  33. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  34. 2 2
      dist/preview release/materialsLibrary/package.json
  35. 1 1
      dist/preview release/package.json
  36. 1 1
      dist/preview release/packagesSizeBaseLine.json
  37. 2 2
      dist/preview release/postProcessesLibrary/package.json
  38. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  39. 3 3
      dist/preview release/serializers/package.json
  40. 181 31
      dist/preview release/viewer/babylon.module.d.ts
  41. 0 45
      dist/preview release/viewer/babylon.viewer.d.ts
  42. 26 22
      dist/preview release/viewer/babylon.viewer.js
  43. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  44. 1 44
      dist/preview release/viewer/babylon.viewer.module.d.ts
  45. 1 0
      dist/preview release/what's new.md
  46. 4 4
      gui/src/2D/controls/line.ts
  47. 1 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx
  48. 1 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMetallicRoughnessMaterialPropertyGridComponent.tsx
  49. 1 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrSpecularGlossinessMaterialPropertyGridComponent.tsx
  50. 2 2
      loaders/src/glTF/2.0/glTFLoader.ts
  51. 37 10
      materialsLibrary/src/mix/mixMaterial.ts
  52. 5 5
      package.json
  53. 22 7
      src/Actions/abstractActionManager.ts
  54. 13 0
      src/Actions/action.ts
  55. 3 3
      src/Actions/actionManager.ts
  56. 6 1
      src/Cameras/targetCamera.ts
  57. 27 14
      src/Culling/ray.ts
  58. 1 1
      src/Engines/engine.ts
  59. 11 3
      src/Meshes/abstractMesh.ts
  60. 1 9
      src/Meshes/mesh.ts
  61. 11 3
      src/Meshes/subMesh.ts
  62. 5 0
      src/Particles/baseParticleSystem.ts
  63. 2 1
      src/Particles/gpuParticleSystem.ts
  64. 3 3
      src/Particles/particleSystem.ts
  65. 6 5
      src/Shaders/gpuRenderParticles.vertex.fx
  66. 1 0
      src/Shaders/gpuUpdateParticles.vertex.fx
  67. 15 5
      src/scene.ts
  68. BIN
      tests/validation/ReferenceImages/Gizmos.png
  69. BIN
      tests/validation/ReferenceImages/Sliders.png
  70. BIN
      tests/validation/ReferenceImages/TransformStackPanel.png
  71. BIN
      tests/validation/ReferenceImages/assetContainer.png
  72. BIN
      tests/validation/ReferenceImages/xrCameraContainerRotation.png
  73. 127 122
      tests/validation/validation.js

+ 0 - 1
.vscode/settings.json

@@ -11,7 +11,6 @@
         "**/node_modules": true,
         "**/temp": true,
         "**/.temp": true,
-        "src/**/*.d.ts": true,
         "gui/**/*.d.ts": true,
         "inspector/**/*.d.ts": true,
         "loaders/**/*.d.ts": true,

+ 84 - 15
Playground/babylon.d.txt

@@ -8308,7 +8308,11 @@ declare module BABYLON {
         /** @hidden */
updateCache(ignoreParentClass?: boolean): void;
         /** @hidden */
isSynchronizedViewMatrix(): boolean;
         /** @hidden */
computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -10107,6 +10111,14 @@ declare module BABYLON {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -10848,13 +10860,13 @@ declare module BABYLON {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -11036,12 +11048,16 @@ declare module BABYLON {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
         interface Scene {
             /** @hidden */
tempPickingRay: Nullable<Ray>;
             /** @hidden */
cachedRayForTransform: Ray;
             /** @hidden */
pickWithRayInverseMatrix: Matrix;
-            /** @hidden */
internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
-            /** @hidden */
internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            /** @hidden */
internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
+            /** @hidden */
internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
 }
 declare module BABYLON {
@@ -13792,6 +13808,10 @@ declare module BABYLON {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -21330,9 +21350,10 @@ declare module BABYLON {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -23389,10 +23410,11 @@ declare module BABYLON {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -23703,12 +23725,24 @@ declare module BABYLON {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -32068,32 +32102,36 @@ declare module BABYLON {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -42314,6 +42352,13 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
     export var pbrPixelShader: {
         name: string;
         shader: string;
@@ -42677,6 +42722,30 @@ declare module BABYLON {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */

+ 0 - 2
Tools/WebpackPlugins/babylonWebpackConfig.js

@@ -1,6 +1,5 @@
 const webpack = require('webpack');
 const babylonExternals = require('./babylonExternals');
-const hardSourceWebpackPlugin = require('hard-source-webpack-plugin');
 
 const config = require("../Config/config.js");
 
@@ -54,7 +53,6 @@ module.exports = function defaultConfig(options) {
             hints: false
         },
         plugins: [
-            //new hardSourceWebpackPlugin(),
             new webpack.WatchIgnorePlugin([
                 /\.js$/,
                 /\.d\.ts$/,

+ 86 - 15
dist/preview release/babylon.d.ts

@@ -8415,7 +8415,11 @@ declare module BABYLON {
         _isSynchronizedViewMatrix(): boolean;
         /** @hidden */
         _computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -10231,6 +10235,16 @@ declare module BABYLON {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
+        _prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
+        _actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -10994,13 +11008,13 @@ declare module BABYLON {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -11184,6 +11198,10 @@ declare module BABYLON {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
         interface Scene {
             /** @hidden */
             _tempPickingRay: Nullable<Ray>;
@@ -11192,9 +11210,9 @@ declare module BABYLON {
             /** @hidden */
             _pickWithRayInverseMatrix: Matrix;
             /** @hidden */
-            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
             /** @hidden */
-            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
 }
 declare module BABYLON {
@@ -13986,6 +14004,10 @@ declare module BABYLON {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -21658,9 +21680,10 @@ declare module BABYLON {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -23782,10 +23805,11 @@ declare module BABYLON {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -24097,12 +24121,24 @@ declare module BABYLON {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -32634,32 +32670,36 @@ declare module BABYLON {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -42962,6 +43002,13 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
     export var pbrPixelShader: {
         name: string;
         shader: string;
@@ -43325,6 +43372,30 @@ declare module BABYLON {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 195 - 121
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 181 - 31
dist/preview release/babylon.module.d.ts

@@ -8486,7 +8486,11 @@ declare module "babylonjs/Cameras/targetCamera" {
         _isSynchronizedViewMatrix(): boolean;
         /** @hidden */
         _computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -10338,6 +10342,7 @@ declare module "babylonjs/Lights/light" {
 declare module "babylonjs/Actions/action" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Condition } from "babylonjs/Actions/condition";
+    import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { ActionManager } from "babylonjs/Actions/actionManager";
     import { ActionEvent } from "babylonjs/Actions/actionEvent";
     /**
@@ -10366,6 +10371,16 @@ declare module "babylonjs/Actions/action" {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
+        _prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
+        _actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -10995,7 +11010,7 @@ declare module "babylonjs/Actions/actionManager" {
     import { Nullable } from "babylonjs/types";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { Scene } from "babylonjs/scene";
-    import { Action } from "babylonjs/Actions/action";
+    import { IAction } from "babylonjs/Actions/action";
     import { IActionEvent } from "babylonjs/Actions/actionEvent";
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     /**
@@ -11139,13 +11154,13 @@ declare module "babylonjs/Actions/actionManager" {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -11336,6 +11351,10 @@ declare module "babylonjs/Culling/ray" {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
     module "babylonjs/scene" {
         interface Scene {
             /** @hidden */
@@ -11345,9 +11364,9 @@ declare module "babylonjs/Culling/ray" {
             /** @hidden */
             _pickWithRayInverseMatrix: Matrix;
             /** @hidden */
-            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
             /** @hidden */
-            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
     }
 }
@@ -14280,6 +14299,10 @@ declare module "babylonjs/Particles/baseParticleSystem" {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -22045,6 +22068,7 @@ declare module "babylonjs/Meshes/subMesh" {
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Ray } from "babylonjs/Culling/ray";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     /**
      * Base class for submeshes
      */
@@ -22212,9 +22236,10 @@ declare module "babylonjs/Meshes/subMesh" {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -23800,6 +23825,7 @@ declare module "babylonjs/Meshes/abstractMesh" {
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { Ray } from "babylonjs/Culling/ray";
     import { Collider } from "babylonjs/Collisions/collider";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     /**
      * Class used to store all common mesh properties
      */
@@ -24382,10 +24408,11 @@ declare module "babylonjs/Meshes/abstractMesh" {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -24647,6 +24674,7 @@ declare module "babylonjs/Actions/abstractActionManager" {
     import { IDisposable } from "babylonjs/scene";
     import { IActionEvent } from "babylonjs/Actions/actionEvent";
     import { IAction } from "babylonjs/Actions/action";
+    import { Nullable } from "babylonjs/types";
     /**
      * Abstract class used to decouple action Manager from scene and meshes.
      * Do not instantiate.
@@ -24705,12 +24733,24 @@ declare module "babylonjs/Actions/abstractActionManager" {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -31712,6 +31752,7 @@ declare module "babylonjs/scene" {
     import { MorphTarget } from "babylonjs/Morph/morphTarget";
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { Ray } from "babylonjs/Culling/ray";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     import { Animation } from "babylonjs/Animations/animation";
     import { Animatable } from "babylonjs/Animations/animatable";
     import { AnimationGroup } from "babylonjs/Animations/animationGroup";
@@ -33411,32 +33452,36 @@ declare module "babylonjs/scene" {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -44613,6 +44658,13 @@ declare module "babylonjs/Shaders/ShadersInclude/pbrLightingFunctions" {
         shader: string;
     };
 }
+declare module "babylonjs/Shaders/ShadersInclude/pbrDebug" {
+    /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
 declare module "babylonjs/Shaders/pbr.fragment" {
     import "babylonjs/Shaders/ShadersInclude/pbrFragmentDeclaration";
     import "babylonjs/Shaders/ShadersInclude/pbrUboDeclaration";
@@ -44638,6 +44690,7 @@ declare module "babylonjs/Shaders/pbr.fragment" {
     import "babylonjs/Shaders/ShadersInclude/lightFragment";
     import "babylonjs/Shaders/ShadersInclude/logDepthFragment";
     import "babylonjs/Shaders/ShadersInclude/fogFragment";
+    import "babylonjs/Shaders/ShadersInclude/pbrDebug";
     /** @hidden */
     export var pbrPixelShader: {
         name: string;
@@ -45040,6 +45093,30 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */
@@ -56810,7 +56887,9 @@ declare module "babylonjs/Animations/pathCursor" {
     }
 }
 declare module "babylonjs/Legacy/legacy" {
+    import * as Babylon from "babylonjs/index";
     export * from "babylonjs/index";
+    
 }
 declare module "babylonjs/Shaders/blur.fragment" {
     /** @hidden */
@@ -65824,7 +65903,11 @@ declare module BABYLON {
         _isSynchronizedViewMatrix(): boolean;
         /** @hidden */
         _computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -67640,6 +67723,16 @@ declare module BABYLON {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
+        _prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
+        _actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -68403,13 +68496,13 @@ declare module BABYLON {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -68593,6 +68686,10 @@ declare module BABYLON {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
         interface Scene {
             /** @hidden */
             _tempPickingRay: Nullable<Ray>;
@@ -68601,9 +68698,9 @@ declare module BABYLON {
             /** @hidden */
             _pickWithRayInverseMatrix: Matrix;
             /** @hidden */
-            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
             /** @hidden */
-            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
 }
 declare module BABYLON {
@@ -71395,6 +71492,10 @@ declare module BABYLON {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -79067,9 +79168,10 @@ declare module BABYLON {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -81191,10 +81293,11 @@ declare module BABYLON {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -81506,12 +81609,24 @@ declare module BABYLON {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -90043,32 +90158,36 @@ declare module BABYLON {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -100371,6 +100490,13 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
     export var pbrPixelShader: {
         name: string;
         shader: string;
@@ -100734,6 +100860,30 @@ declare module BABYLON {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */

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

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

+ 4 - 4
dist/preview release/gui/babylon.gui.js

@@ -8183,8 +8183,8 @@ var Line = /** @class */ (function (_super) {
         context.lineWidth = this._lineWidth;
         context.setLineDash(this._dash);
         context.beginPath();
-        context.moveTo(this._x1.getValue(this._host), this._y1.getValue(this._host));
-        context.lineTo(this._effectiveX2, this._effectiveY2);
+        context.moveTo(this._currentMeasure.left, this._currentMeasure.top);
+        context.lineTo(this._currentMeasure.left + this._currentMeasure.width, this._currentMeasure.top + this._currentMeasure.height);
         context.stroke();
         context.restore();
     };
@@ -8194,8 +8194,8 @@ var Line = /** @class */ (function (_super) {
         this._currentMeasure.height = Math.abs(this._y1.getValue(this._host) - this._effectiveY2) + this._lineWidth;
     };
     Line.prototype._computeAlignment = function (parentMeasure, context) {
-        this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
-        this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
+        this._currentMeasure.left = parentMeasure.left + Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
+        this._currentMeasure.top = parentMeasure.top + Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
     };
     /**
      * Move one end of the line given 3D cartesian coordinates.

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


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

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

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


+ 78 - 18
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -37982,8 +37982,10 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/color3LineComponent */ "./components/actionTabs/lines/color3LineComponent.tsx");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
 /* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
-/* harmony import */ var _commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./commonMaterialPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx");
-/* harmony import */ var _lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../../lines/textureLinkLineComponent */ "./components/actionTabs/lines/textureLinkLineComponent.tsx");
+/* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
+/* harmony import */ var _commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./commonMaterialPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx");
+/* harmony import */ var _lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../../lines/textureLinkLineComponent */ "./components/actionTabs/lines/textureLinkLineComponent.tsx");
+
 
 
 
@@ -38006,29 +38008,81 @@ var PBRMaterialPropertyGridComponent = /** @class */ (function (_super) {
             return null;
         }
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "TEXTURES" },
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Albedo", texture: material.albedoTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Metallic", texture: material.metallicTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Reflection", texture: material.reflectionTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Refraction", texture: material.refractionTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Micro-surface", texture: material.microSurfaceTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Bump", texture: material.bumpTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Emissive", texture: material.emissiveTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Opacity", texture: material.opacityTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Ambient", texture: material.ambientTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Lightmap", texture: material.lightmapTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable })));
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Albedo", texture: material.albedoTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Metallic", texture: material.metallicTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Reflection", texture: material.reflectionTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Refraction", texture: material.refractionTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Micro-surface", texture: material.microSurfaceTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Bump", texture: material.bumpTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Emissive", texture: material.emissiveTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Opacity", texture: material.opacityTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Ambient", texture: material.ambientTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Lightmap", texture: material.lightmapTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable })));
     };
     PBRMaterialPropertyGridComponent.prototype.render = function () {
         var _this = this;
         var material = this.props.material;
+        var debugMode = [
+            { label: "None", value: 0 },
+            // Geometry
+            { label: "Normalized position", value: 1 },
+            { label: "Normals", value: 2 },
+            { label: "Tangents", value: 3 },
+            { label: "Bitangents", value: 4 },
+            { label: "Bump Normals", value: 5 },
+            { label: "UV1", value: 6 },
+            { label: "UV2", value: 7 },
+            { label: "ClearCoat Normals", value: 8 },
+            { label: "ClearCoat Tangents", value: 9 },
+            { label: "ClearCoat Bitangents", value: 10 },
+            { label: "Anisotropic Normals", value: 11 },
+            // Maps
+            { label: "Albdeo Map", value: 20 },
+            { label: "Ambient Map", value: 21 },
+            { label: "Opacity Map", value: 22 },
+            { label: "Emissive Map", value: 23 },
+            { label: "Light Map", value: 24 },
+            { label: "Metallic Map", value: 25 },
+            { label: "Reflectivity Map", value: 26 },
+            { label: "ClearCoat Map", value: 27 },
+            { label: "ClearCoat Tint Map", value: 28 },
+            // Env
+            { label: "Env Refraction", value: 40 },
+            { label: "Env Reflection", value: 41 },
+            { label: "Env Clear Coat", value: 42 },
+            // Lighting
+            { label: "Direct Diffuse", value: 50 },
+            { label: "Direct Specular", value: 51 },
+            { label: "Direct Clear Coat", value: 52 },
+            { label: "Env Irradiance", value: 53 },
+            // Lighting Params
+            { label: "Surface Albedo", value: 60 },
+            { label: "Reflectance 0", value: 61 },
+            { label: "Roughness", value: 62 },
+            { label: "AlphaG", value: 63 },
+            { label: "NdotV", value: 64 },
+            { label: "ClearCoat Color", value: 65 },
+            { label: "ClearCoat Roughness", value: 66 },
+            { label: "ClearCoat NdotV", value: 67 },
+            // Misc
+            { label: "SEO", value: 70 },
+            { label: "EHO", value: 71 },
+            { label: "Energy Factor", value: 72 },
+            { label: "Specular Reflectance", value: 73 },
+            { label: "Clear Coat Reflectance", value: 74 },
+            { label: "Luminance Over Alpha", value: 75 },
+            { label: "Alpha", value: 76 },
+        ];
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "pane" },
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_7__["CommonMaterialPropertyGridComponent"], { globalState: this.props.globalState, lockObject: this.props.lockObject, material: material, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_8__["CommonMaterialPropertyGridComponent"], { globalState: this.props.globalState, lockObject: this.props.lockObject, material: material, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
             this.renderTextures(this._onDebugSelectionChangeObservable),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "LIGHTING & COLORS" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Albedo", target: material, propertyName: "albedoColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Reflectivity", target: material, propertyName: "reflectivityColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Micro-surface", target: material, propertyName: "microSurface", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Emissive", target: material, propertyName: "emissiveColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Ambient", target: material, propertyName: "ambientColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Color3LineComponent"], { label: "Ambient", target: material, propertyName: "ambientColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Use physical light falloff", target: material, propertyName: "usePhysicalLightFalloff ", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "METALLIC WORKFLOW" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Metallic", target: material, propertyName: "metallic", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Roughness", target: material, propertyName: "roughness", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
@@ -38039,8 +38093,8 @@ var PBRMaterialPropertyGridComponent = /** @class */ (function (_super) {
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Intensity", target: material.clearCoat, propertyName: "intensity", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Roughness", target: material.clearCoat, propertyName: "roughness", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "IOR", target: material.clearCoat, propertyName: "indiceOfRefraction", minimum: 1.0, maximum: 3, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Texture", texture: material.clearCoat.texture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }),
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Bump", texture: material.clearCoat.bumpTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }),
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Texture", texture: material.clearCoat.texture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }),
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Bump", texture: material.clearCoat.bumpTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }),
                         material.clearCoat.bumpTexture &&
                             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Bump strength", target: material.clearCoat.bumpTexture, propertyName: "level", minimum: 0, maximum: 2, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                         react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Tint", target: material.clearCoat, propertyName: "isTintEnabled", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
@@ -38051,7 +38105,7 @@ var PBRMaterialPropertyGridComponent = /** @class */ (function (_super) {
                         material.clearCoat.isEnabled && material.clearCoat.isTintEnabled &&
                             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Tint Thickness", target: material.clearCoat, propertyName: "tintThickness", minimum: 0, maximum: 20, step: 0.1, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                         material.clearCoat.isEnabled && material.clearCoat.isTintEnabled &&
-                            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_8__["TextureLinkLineComponent"], { label: "Tint Texture", texture: material.clearCoat.tintTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }))),
+                            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_9__["TextureLinkLineComponent"], { label: "Tint Texture", texture: material.clearCoat.tintTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: this._onDebugSelectionChangeObservable }))),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "ANISOTROPIC" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Enabled", target: material.anisotropy, propertyName: "isEnabled", onValueChanged: function () { return _this.forceUpdate(); }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 material.anisotropy.isEnabled &&
@@ -38081,7 +38135,11 @@ var PBRMaterialPropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Energy Conservation", target: material.brdf, propertyName: "useEnergyConservation", onValueChanged: function () { return _this.forceUpdate(); }, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Radiance occlusion", target: material, propertyName: "useRadianceOcclusion", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Horizon occlusion ", target: material, propertyName: "useHorizonOcclusion", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Unlit", target: material, propertyName: "unlit", onPropertyChangedObservable: this.props.onPropertyChangedObservable }))));
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_5__["CheckBoxLineComponent"], { label: "Unlit", target: material, propertyName: "unlit", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "DEBUG", closed: true },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_7__["OptionsLineComponent"], { label: "Debug mode", options: debugMode, target: material, propertyName: "debugMode" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Split position", target: material, propertyName: "debugLimit", minimum: -1, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Output factor", target: material, propertyName: "debugFactor", minimum: 0, maximum: 5, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }))));
     };
     return PBRMaterialPropertyGridComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -38134,6 +38192,7 @@ var PBRMetallicRoughnessMaterialPropertyGridComponent = /** @class */ (function
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "TEXTURES" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Base", texture: material.baseTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Metallic roughness", texture: material.metallicRoughnessTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Normal", texture: material.normalTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Environment", texture: material.environmentTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Emissive", texture: material.emissiveTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Lightmap", texture: material.lightmapTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable })));
@@ -38201,6 +38260,7 @@ var PBRSpecularGlossinessMaterialPropertyGridComponent = /** @class */ (function
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "TEXTURES" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Diffuse", texture: material.diffuseTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Specular glossiness", texture: material.specularGlossinessTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Normal", texture: material.normalTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Environment", texture: material.environmentTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Emissive", texture: material.emissiveTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Lightmap", texture: material.lightmapTexture, material: material, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onDebugSelectionChangeObservable: onDebugSelectionChangeObservable })));

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.0.0-alpha.25",
+    "version": "4.0.0-alpha.26",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -31,11 +31,11 @@
     "dependencies": {
         "@types/react": "~16.7.3",
         "@types/react-dom": "~16.0.9",
-        "babylonjs": "4.0.0-alpha.25",
-        "babylonjs-gui": "4.0.0-alpha.25",
-        "babylonjs-loaders": "4.0.0-alpha.25",
-        "babylonjs-serializers": "4.0.0-alpha.25",
-        "babylonjs-gltf2interface": "4.0.0-alpha.25"
+        "babylonjs": "4.0.0-alpha.26",
+        "babylonjs-gui": "4.0.0-alpha.26",
+        "babylonjs-loaders": "4.0.0-alpha.26",
+        "babylonjs-serializers": "4.0.0-alpha.26",
+        "babylonjs-gltf2interface": "4.0.0-alpha.26"
     },
     "engines": {
         "node": "*"

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

@@ -1543,8 +1543,8 @@ var GLTFLoader = /** @class */ (function () {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
-            else {
-                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene || 0);
+            else if (_this.gltf.scene != undefined) {
+                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             if (_this._parent.compileMaterials) {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


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

@@ -4092,8 +4092,8 @@ var GLTFLoader = /** @class */ (function () {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
-            else {
-                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene || 0);
+            else if (_this.gltf.scene != undefined) {
+                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             if (_this._parent.compileMaterials) {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -5408,8 +5408,8 @@ var GLTFLoader = /** @class */ (function () {
             if (nodes) {
                 promises.push(_this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
-            else {
-                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene || 0);
+            else if (_this.gltf.scene != undefined) {
+                var scene = ArrayItem.Get("/scene", _this.gltf.scenes, _this.gltf.scene);
                 promises.push(_this.loadSceneAsync("/scenes/" + scene.index, scene));
             }
             if (_this._parent.compileMaterials) {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

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

+ 28 - 10
dist/preview release/materialsLibrary/babylon.mixMaterial.js

@@ -556,22 +556,40 @@ var MixMaterial = /** @class */ (function (_super) {
         var engine = scene.getEngine();
         // Textures
         if (scene.texturesEnabled) {
+            if (!this._mixTexture1 || !this._mixTexture1.isReady()) {
+                return false;
+            }
+            defines._needUVs = true;
             if (babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__["MaterialFlags"].DiffuseTextureEnabled) {
-                if (this._mixTexture1) {
-                    if (!this._mixTexture1.isReady()) {
-                        return false;
-                    }
-                    else {
-                        defines._needUVs = true;
-                        defines.DIFFUSE = true;
-                    }
+                if (!this._diffuseTexture1 || !this._diffuseTexture1.isReady()) {
+                    return false;
+                }
+                defines.DIFFUSE = true;
+                if (!this._diffuseTexture2 || !this._diffuseTexture2.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture3 || !this._diffuseTexture3.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture4 || !this._diffuseTexture4.isReady()) {
+                    return false;
                 }
                 if (this._mixTexture2) {
                     if (!this._mixTexture2.isReady()) {
                         return false;
                     }
-                    else {
-                        defines.MIXMAP2 = true;
+                    defines.MIXMAP2 = true;
+                    if (!this._diffuseTexture5 || !this._diffuseTexture5.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture6 || !this._diffuseTexture6.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture7 || !this._diffuseTexture7.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture8 || !this._diffuseTexture8.isReady()) {
+                        return false;
                     }
                 }
             }

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.mixMaterial.js.map


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/materialsLibrary/babylon.mixMaterial.min.js


+ 28 - 10
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -3427,22 +3427,40 @@ var MixMaterial = /** @class */ (function (_super) {
         var engine = scene.getEngine();
         // Textures
         if (scene.texturesEnabled) {
+            if (!this._mixTexture1 || !this._mixTexture1.isReady()) {
+                return false;
+            }
+            defines._needUVs = true;
             if (babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__["MaterialFlags"].DiffuseTextureEnabled) {
-                if (this._mixTexture1) {
-                    if (!this._mixTexture1.isReady()) {
-                        return false;
-                    }
-                    else {
-                        defines._needUVs = true;
-                        defines.DIFFUSE = true;
-                    }
+                if (!this._diffuseTexture1 || !this._diffuseTexture1.isReady()) {
+                    return false;
+                }
+                defines.DIFFUSE = true;
+                if (!this._diffuseTexture2 || !this._diffuseTexture2.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture3 || !this._diffuseTexture3.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture4 || !this._diffuseTexture4.isReady()) {
+                    return false;
                 }
                 if (this._mixTexture2) {
                     if (!this._mixTexture2.isReady()) {
                         return false;
                     }
-                    else {
-                        defines.MIXMAP2 = true;
+                    defines.MIXMAP2 = true;
+                    if (!this._diffuseTexture5 || !this._diffuseTexture5.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture6 || !this._diffuseTexture6.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture7 || !this._diffuseTexture7.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture8 || !this._diffuseTexture8.isReady()) {
+                        return false;
                     }
                 }
             }

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


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

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

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

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

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

@@ -1 +1 @@
-{"engineOnly":304312,"sceneOnly":505423,"minGridMaterial":624915,"minStandardMaterial":747376}
+{"engineOnly":304342,"sceneOnly":505532,"minGridMaterial":624988,"minStandardMaterial":747449}

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

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

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

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

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

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

+ 181 - 31
dist/preview release/viewer/babylon.module.d.ts

@@ -8486,7 +8486,11 @@ declare module "babylonjs/Cameras/targetCamera" {
         _isSynchronizedViewMatrix(): boolean;
         /** @hidden */
         _computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -10338,6 +10342,7 @@ declare module "babylonjs/Lights/light" {
 declare module "babylonjs/Actions/action" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Condition } from "babylonjs/Actions/condition";
+    import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { ActionManager } from "babylonjs/Actions/actionManager";
     import { ActionEvent } from "babylonjs/Actions/actionEvent";
     /**
@@ -10366,6 +10371,16 @@ declare module "babylonjs/Actions/action" {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
+        _prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
+        _actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -10995,7 +11010,7 @@ declare module "babylonjs/Actions/actionManager" {
     import { Nullable } from "babylonjs/types";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { Scene } from "babylonjs/scene";
-    import { Action } from "babylonjs/Actions/action";
+    import { IAction } from "babylonjs/Actions/action";
     import { IActionEvent } from "babylonjs/Actions/actionEvent";
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     /**
@@ -11139,13 +11154,13 @@ declare module "babylonjs/Actions/actionManager" {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -11336,6 +11351,10 @@ declare module "babylonjs/Culling/ray" {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
     module "babylonjs/scene" {
         interface Scene {
             /** @hidden */
@@ -11345,9 +11364,9 @@ declare module "babylonjs/Culling/ray" {
             /** @hidden */
             _pickWithRayInverseMatrix: Matrix;
             /** @hidden */
-            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
             /** @hidden */
-            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
     }
 }
@@ -14280,6 +14299,10 @@ declare module "babylonjs/Particles/baseParticleSystem" {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -22045,6 +22068,7 @@ declare module "babylonjs/Meshes/subMesh" {
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Ray } from "babylonjs/Culling/ray";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     /**
      * Base class for submeshes
      */
@@ -22212,9 +22236,10 @@ declare module "babylonjs/Meshes/subMesh" {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -23800,6 +23825,7 @@ declare module "babylonjs/Meshes/abstractMesh" {
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { Ray } from "babylonjs/Culling/ray";
     import { Collider } from "babylonjs/Collisions/collider";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     /**
      * Class used to store all common mesh properties
      */
@@ -24382,10 +24408,11 @@ declare module "babylonjs/Meshes/abstractMesh" {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -24647,6 +24674,7 @@ declare module "babylonjs/Actions/abstractActionManager" {
     import { IDisposable } from "babylonjs/scene";
     import { IActionEvent } from "babylonjs/Actions/actionEvent";
     import { IAction } from "babylonjs/Actions/action";
+    import { Nullable } from "babylonjs/types";
     /**
      * Abstract class used to decouple action Manager from scene and meshes.
      * Do not instantiate.
@@ -24705,12 +24733,24 @@ declare module "babylonjs/Actions/abstractActionManager" {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -31712,6 +31752,7 @@ declare module "babylonjs/scene" {
     import { MorphTarget } from "babylonjs/Morph/morphTarget";
     import { AbstractActionManager } from "babylonjs/Actions/abstractActionManager";
     import { Ray } from "babylonjs/Culling/ray";
+    import { TrianglePickingPredicate } from "babylonjs/Culling/ray";
     import { Animation } from "babylonjs/Animations/animation";
     import { Animatable } from "babylonjs/Animations/animatable";
     import { AnimationGroup } from "babylonjs/Animations/animationGroup";
@@ -33411,32 +33452,36 @@ declare module "babylonjs/scene" {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -44613,6 +44658,13 @@ declare module "babylonjs/Shaders/ShadersInclude/pbrLightingFunctions" {
         shader: string;
     };
 }
+declare module "babylonjs/Shaders/ShadersInclude/pbrDebug" {
+    /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
 declare module "babylonjs/Shaders/pbr.fragment" {
     import "babylonjs/Shaders/ShadersInclude/pbrFragmentDeclaration";
     import "babylonjs/Shaders/ShadersInclude/pbrUboDeclaration";
@@ -44638,6 +44690,7 @@ declare module "babylonjs/Shaders/pbr.fragment" {
     import "babylonjs/Shaders/ShadersInclude/lightFragment";
     import "babylonjs/Shaders/ShadersInclude/logDepthFragment";
     import "babylonjs/Shaders/ShadersInclude/fogFragment";
+    import "babylonjs/Shaders/ShadersInclude/pbrDebug";
     /** @hidden */
     export var pbrPixelShader: {
         name: string;
@@ -45040,6 +45093,30 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */
@@ -56810,7 +56887,9 @@ declare module "babylonjs/Animations/pathCursor" {
     }
 }
 declare module "babylonjs/Legacy/legacy" {
+    import * as Babylon from "babylonjs/index";
     export * from "babylonjs/index";
+    
 }
 declare module "babylonjs/Shaders/blur.fragment" {
     /** @hidden */
@@ -65824,7 +65903,11 @@ declare module BABYLON {
         _isSynchronizedViewMatrix(): boolean;
         /** @hidden */
         _computeLocalCameraSpeed(): number;
-        /** @hidden */
+        /**
+         * Defines the target the camera should look at.
+         * This will automatically adapt alpha beta and radius to fit within the new target.
+         * @param target Defines the new target as a Vector or a mesh
+         */
         setTarget(target: Vector3): void;
         /**
          * Return the current target position of the camera. This value is expressed in local space.
@@ -67640,6 +67723,16 @@ declare module BABYLON {
          * @returns the serialized object
          */
         serialize(parent: any): any;
+        /**
+        * Internal only
+        * @hidden
+        */
+        _prepare(): void;
+        /**
+         * Internal only - manager for action
+         * @hidden
+         */
+        _actionManager: AbstractActionManager;
     }
     /**
      * The action to be carried out following a trigger
@@ -68403,13 +68496,13 @@ declare module BABYLON {
          * @param action defines the action to be registered
          * @return the action amended (prepared) after registration
          */
-        registerAction(action: Action): Nullable<Action>;
+        registerAction(action: IAction): Nullable<IAction>;
         /**
          * Unregisters an action to this action manager
          * @param action defines the action to be unregistered
          * @return a boolean indicating whether the action has been unregistered
          */
-        unregisterAction(action: Action): Boolean;
+        unregisterAction(action: IAction): Boolean;
         /**
          * Process a specific trigger
          * @param trigger defines the trigger to process
@@ -68593,6 +68686,10 @@ declare module BABYLON {
           */
         unprojectRayToRef(sourceX: float, sourceY: float, viewportWidth: number, viewportHeight: number, world: DeepImmutable<Matrix>, view: DeepImmutable<Matrix>, projection: DeepImmutable<Matrix>): void;
     }
+    /**
+     * Type used to define predicate used to select faces when a mesh intersection is detected
+     */
+    export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
         interface Scene {
             /** @hidden */
             _tempPickingRay: Nullable<Ray>;
@@ -68601,9 +68698,9 @@ declare module BABYLON {
             /** @hidden */
             _pickWithRayInverseMatrix: Matrix;
             /** @hidden */
-            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+            _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
             /** @hidden */
-            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+            _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         }
 }
 declare module BABYLON {
@@ -71395,6 +71492,10 @@ declare module BABYLON {
          */
         beginAnimationLoop: boolean;
         /**
+         * Gets or sets a world offset applied to all particles
+         */
+        worldOffset: Vector3;
+        /**
          * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
          */
         isAnimationSheetEnabled: boolean;
@@ -79067,9 +79168,10 @@ declare module BABYLON {
          * @param positions defines mesh's positions array
          * @param indices defines mesh's indices array
          * @param fastCheck defines if only bounding info should be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns intersection info or null if no intersection
          */
-        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo>;
+        intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo>;
         /** @hidden */
         private _intersectLines;
         /** @hidden */
@@ -81191,10 +81293,11 @@ declare module BABYLON {
          * Checks if the passed Ray intersects with the mesh
          * @param ray defines the ray to use
          * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns the picking info
          * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
          */
-        intersects(ray: Ray, fastCheck?: boolean): PickingInfo;
+        intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo;
         /**
          * Clones the current mesh
          * @param name defines the mesh name
@@ -81506,12 +81609,24 @@ declare module BABYLON {
          */
         abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
         /**
-             * Serialize this manager to a JSON object
-             * @param name defines the property name to store this manager
-             * @returns a JSON representation of this manager
-             */
+         * Serialize this manager to a JSON object
+         * @param name defines the property name to store this manager
+         * @returns a JSON representation of this manager
+         */
         abstract serialize(name: string): any;
         /**
+         * Registers an action to this action manager
+         * @param action defines the action to be registered
+         * @return the action amended (prepared) after registration
+         */
+        abstract registerAction(action: IAction): Nullable<IAction>;
+        /**
+         * Unregisters an action to this action manager
+         * @param action defines the action to be unregistered
+         * @return a boolean indicating whether the action has been unregistered
+         */
+        abstract unregisterAction(action: IAction): Boolean;
+        /**
          * Does exist one action manager with at least one trigger
          **/
         static readonly HasTriggers: boolean;
@@ -90043,32 +90158,36 @@ declare module BABYLON {
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
          * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo>;
+        pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean): Nullable<PickingInfo>;
         /** Use the given ray to pick a mesh in the scene
          * @param ray The ray to use to pick meshes
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
          * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns a PickingInfo
          */
-        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param x X position on screen
          * @param y Y position on screen
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
          * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+        multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Launch a ray to try to pick a mesh in the scene
          * @param ray Ray to use
          * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+         * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
          * @returns an array of PickingInfo
          */
-        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
         /**
          * Force the value of meshUnderPointer
          * @param mesh defines the mesh to use
@@ -100371,6 +100490,13 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export var pbrDebug: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
     export var pbrPixelShader: {
         name: string;
         shader: string;
@@ -100734,6 +100860,30 @@ declare module BABYLON {
          * If set to true, no lighting calculations will be applied.
          */
         private _unlit;
+        private _debugMode;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Defines the material debug mode.
+         * It helps seeing only some components of the material while troubleshooting.
+         */
+        debugMode: number;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * Specify from where on screen the debug mode should start.
+         * The value goes from -1 (full screen) to 1 (not visible)
+         * It helps with side by side comparison against the final render
+         * This defaults to -1
+         */
+        private debugLimit;
+        /**
+         * @hidden
+         * This is reserved for the inspector.
+         * As the default viewing range might not be enough (if the ambient is really small for instance)
+         * You can use the factor to better multiply the final value.
+         */
+        private debugFactor;
         /**
          * Defines the clear coat layer parameters for the material.
          */

+ 0 - 45
dist/preview release/viewer/babylon.viewer.d.ts

@@ -439,51 +439,6 @@ declare module BabylonViewer {
 }
 declare module BabylonViewer {
     /**
-        * The data structure of a telemetry event.
-        */
-    export interface TelemetryData {
-            event: string;
-            session: string;
-            date: Date;
-            now: number;
-            viewerId?: string;
-            detail: any;
-    }
-    /**
-        * Receives Telemetry events and raises events to the API
-        */
-    export class TelemetryManager {
-            onEventBroadcastedObservable: BABYLON.Observable<TelemetryData>;
-            /**
-                * Receives a telemetry event
-                * @param event The name of the Telemetry event
-                * @param details An additional value, or an object containing a list of property/value pairs
-                */
-            readonly broadcast: (event: string, viewerId?: string | undefined, details?: any) => void;
-            /**
-                * Log a Telemetry event for errors raised on the WebGL context.
-                * @param engine The Babylon engine with the WebGL context.
-                */
-            flushWebGLErrors(engine: BABYLON.Engine, viewerId?: string): void;
-            /**
-                * Enable or disable telemetry events
-                * @param enabled Boolan, true if events are enabled
-                */
-            enable: boolean;
-            /**
-                * Returns the current session ID or creates one if it doesn't exixt
-                * @return The current session ID
-                */
-            readonly session: string;
-            /**
-                * Disposes the telemetry manager
-                */
-            dispose(): void;
-    }
-    export const telemetryManager: TelemetryManager;
-}
-declare module BabylonViewer {
-    /**
         * An instance of the class is in charge of loading the model correctly.
         * This class will continously be expended with tasks required from the specific loaders Babylon has.
         *

File diff suppressed because it is too large
+ 26 - 22
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 1 - 44
dist/preview release/viewer/babylon.viewer.module.d.ts

@@ -481,50 +481,7 @@ declare module 'babylonjs-viewer/viewer/viewer' {
 }
 
 declare module 'babylonjs-viewer/managers/telemetryManager' {
-    import { Engine, Observable } from "babylonjs";
-    /**
-        * The data structure of a telemetry event.
-        */
-    export interface TelemetryData {
-            event: string;
-            session: string;
-            date: Date;
-            now: number;
-            viewerId?: string;
-            detail: any;
-    }
-    /**
-        * Receives Telemetry events and raises events to the API
-        */
-    export class TelemetryManager {
-            onEventBroadcastedObservable: Observable<TelemetryData>;
-            /**
-                * Receives a telemetry event
-                * @param event The name of the Telemetry event
-                * @param details An additional value, or an object containing a list of property/value pairs
-                */
-            readonly broadcast: (event: string, viewerId?: string | undefined, details?: any) => void;
-            /**
-                * Log a Telemetry event for errors raised on the WebGL context.
-                * @param engine The Babylon engine with the WebGL context.
-                */
-            flushWebGLErrors(engine: Engine, viewerId?: string): void;
-            /**
-                * Enable or disable telemetry events
-                * @param enabled Boolan, true if events are enabled
-                */
-            enable: boolean;
-            /**
-                * Returns the current session ID or creates one if it doesn't exixt
-                * @return The current session ID
-                */
-            readonly session: string;
-            /**
-                * Disposes the telemetry manager
-                */
-            dispose(): void;
-    }
-    export const telemetryManager: TelemetryManager;
+    
 }
 
 declare module 'babylonjs-viewer/loader/modelLoader' {

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

@@ -145,6 +145,7 @@
 - Fixed `GradientMaterial` to consider disableLighting working as emissive ([julien-moreau](https://github.com/julien-moreau))
 - Fixed fresnel term computation in `WaterMaterial` ([julien-moreau](https://github.com/julien-moreau))
 - Fixed `TerrainMaterial.isReadyForSubMesh` to remove WebGL warnings ([julien-moreau](https://github.com/julien-moreau))
+- Fixed `MixMaterial.isReadyForSubMesh` to remove WebGL warnings ([dad72](https://github.com/dad72))
 
 ## Bug fixes
 - Fixed ArcRotateCamera.setTarget (position was sometimes wrong) ([Deltakosh](https://github.com/deltakosh))

+ 4 - 4
gui/src/2D/controls/line.ts

@@ -180,9 +180,9 @@ export class Line extends Control {
         context.setLineDash(this._dash);
 
         context.beginPath();
-        context.moveTo(this._x1.getValue(this._host), this._y1.getValue(this._host));
+        context.moveTo(this._currentMeasure.left, this._currentMeasure.top);
 
-        context.lineTo(this._effectiveX2, this._effectiveY2);
+        context.lineTo(this._currentMeasure.left + this._currentMeasure.width, this._currentMeasure.top + this._currentMeasure.height);
 
         context.stroke();
 
@@ -196,8 +196,8 @@ export class Line extends Control {
     }
 
     protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
-        this._currentMeasure.left = Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
-        this._currentMeasure.top = Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
+        this._currentMeasure.left = parentMeasure.left + Math.min(this._x1.getValue(this._host), this._effectiveX2) - this._lineWidth / 2;
+        this._currentMeasure.top = parentMeasure.top + Math.min(this._y1.getValue(this._host), this._effectiveY2) - this._lineWidth / 2;
     }
 
     /**

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -117,6 +117,7 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                     <SliderLineComponent label="Micro-surface" target={material} propertyName="microSurface" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Emissive" target={material} propertyName="emissiveColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Ambient" target={material} propertyName="ambientColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <CheckBoxLineComponent label="Use physical light falloff" target={material} propertyName="usePhysicalLightFalloff " onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                           
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="METALLIC WORKFLOW">
                     <SliderLineComponent label="Metallic" target={material} propertyName="metallic" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMetallicRoughnessMaterialPropertyGridComponent.tsx

@@ -41,6 +41,7 @@ export class PBRMetallicRoughnessMaterialPropertyGridComponent extends React.Com
             <LineContainerComponent globalState={this.props.globalState} title="TEXTURES">
                 <TextureLinkLineComponent label="Base" texture={material.baseTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Metallic roughness" texture={material.metallicRoughnessTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
+                <TextureLinkLineComponent label="Normal" texture={material.normalTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Environment" texture={material.environmentTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Emissive" texture={material.emissiveTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Lightmap" texture={material.lightmapTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrSpecularGlossinessMaterialPropertyGridComponent.tsx

@@ -41,6 +41,7 @@ export class PBRSpecularGlossinessMaterialPropertyGridComponent extends React.Co
             <LineContainerComponent globalState={this.props.globalState} title="TEXTURES">
                 <TextureLinkLineComponent label="Diffuse" texture={material.diffuseTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Specular glossiness" texture={material.specularGlossinessTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
+                <TextureLinkLineComponent label="Normal" texture={material.normalTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Environment" texture={material.environmentTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Emissive" texture={material.emissiveTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />
                 <TextureLinkLineComponent label="Lightmap" texture={material.lightmapTexture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={onDebugSelectionChangeObservable} />

+ 2 - 2
loaders/src/glTF/2.0/glTFLoader.ts

@@ -257,8 +257,8 @@ export class GLTFLoader implements IGLTFLoader {
             if (nodes) {
                 promises.push(this.loadSceneAsync("/nodes", { nodes: nodes, index: -1 }));
             }
-            else {
-                const scene = ArrayItem.Get(`/scene`, this.gltf.scenes, this.gltf.scene || 0);
+            else if (this.gltf.scene != undefined) {
+                const scene = ArrayItem.Get(`/scene`, this.gltf.scenes, this.gltf.scene);
                 promises.push(this.loadSceneAsync(`/scenes/${scene.index}`, scene));
             }
 

+ 37 - 10
materialsLibrary/src/mix/mixMaterial.ts

@@ -171,20 +171,47 @@ export class MixMaterial extends PushMaterial {
 
         // Textures
         if (scene.texturesEnabled) {
+            if (!this._mixTexture1 || !this._mixTexture1.isReady()) {
+                return false;
+            }
+
+            defines._needUVs = true;
+
             if (MaterialFlags.DiffuseTextureEnabled) {
-                if (this._mixTexture1) {
-                    if (!this._mixTexture1.isReady()) {
-                        return false;
-                    } else {
-                        defines._needUVs = true;
-                        defines.DIFFUSE = true;
-                    }
+                if (!this._diffuseTexture1 || !this._diffuseTexture1.isReady()) {
+                    return false;
                 }
+
+                defines.DIFFUSE = true;
+
+                if (!this._diffuseTexture2 || !this._diffuseTexture2.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture3 || !this._diffuseTexture3.isReady()) {
+                    return false;
+                }
+                if (!this._diffuseTexture4 || !this._diffuseTexture4.isReady()) {
+                    return false;
+                }
+
                 if (this._mixTexture2) {
                     if (!this._mixTexture2.isReady()) {
                         return false;
-                    } else {
-                        defines.MIXMAP2 = true;
+                    }
+
+                    defines.MIXMAP2 = true;
+
+                    if (!this._diffuseTexture5 || !this._diffuseTexture5.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture6 || !this._diffuseTexture6.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture7 || !this._diffuseTexture7.isReady()) {
+                        return false;
+                    }
+                    if (!this._diffuseTexture8 || !this._diffuseTexture8.isReady()) {
+                        return false;
                     }
                 }
             }
@@ -535,4 +562,4 @@ export class MixMaterial extends PushMaterial {
     }
 }
 
-_TypeStore.RegisteredTypes["BABYLON.MixMaterial"] = MixMaterial;
+_TypeStore.RegisteredTypes["BABYLON.MixMaterial"] = MixMaterial;

+ 5 - 5
package.json

@@ -9,7 +9,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.0.0-alpha.25",
+    "version": "4.0.0-alpha.26",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -69,7 +69,6 @@
         "gulp-tslint": "^8.1.3",
         "gulp-typedoc": "^2.2.1",
         "gulp-typescript": "4.0.2",
-        "hard-source-webpack-plugin": "^0.13.1",
         "karma": "^3.1.1",
         "karma-browserstack-launcher": "^1.4.0",
         "karma-chai": "^0.1.0",
@@ -100,10 +99,11 @@
         "tslint": "^5.11.0",
         "typedoc": "^0.12.0",
         "typescript": "^3.2.2",
-        "webpack": "^4.25.1",
+        "webpack": "^4.29.3",
         "webpack-cli": "^3.1.2",
         "webpack-dev-server": "^3.1.14",
         "webpack-stream": "5.0.0",
-        "react-contextmenu": "~2.10.0"
+        "react-contextmenu": "~2.10.0",
+        "ajv": "^6.9.1"
     }
-}
+}

+ 22 - 7
src/Actions/abstractActionManager.ts

@@ -1,7 +1,8 @@
-import { IDisposable } from '../scene';
-import { IActionEvent } from './actionEvent';
-import { IAction } from './action';
+import { IDisposable } from "../scene";
+import { IActionEvent } from "./actionEvent";
+import { IAction } from "./action";
 import { Constants } from "../Engines/constants";
+import { Nullable } from "../types";
 
 /**
  * Abstract class used to decouple action Manager from scene and meshes.
@@ -71,13 +72,27 @@ export abstract class AbstractActionManager implements IDisposable {
     public abstract hasSpecificTrigger(trigger: number, parameterPredicate?: (parameter: any) => boolean): boolean;
 
     /**
-         * Serialize this manager to a JSON object
-         * @param name defines the property name to store this manager
-         * @returns a JSON representation of this manager
-         */
+     * Serialize this manager to a JSON object
+     * @param name defines the property name to store this manager
+     * @returns a JSON representation of this manager
+     */
     public abstract serialize(name: string): any;
 
     /**
+     * Registers an action to this action manager
+     * @param action defines the action to be registered
+     * @return the action amended (prepared) after registration
+     */
+    public abstract registerAction(action: IAction): Nullable<IAction>;
+
+    /**
+     * Unregisters an action to this action manager
+     * @param action defines the action to be unregistered
+     * @return a boolean indicating whether the action has been unregistered
+     */
+    public abstract unregisterAction(action: IAction): Boolean;
+
+    /**
      * Does exist one action manager with at least one trigger
      **/
     public static get HasTriggers(): boolean {

+ 13 - 0
src/Actions/action.ts

@@ -2,6 +2,7 @@ import { Observable } from "../Misc/observable";
 import { Vector2, Vector3, Color3, Color4 } from "../Maths/math";
 import { Condition } from "./condition";
 import { _TypeStore } from '../Misc/typeStore';
+import { AbstractActionManager } from './abstractActionManager';
 
 declare type Scene = import("../scene").Scene;
 declare type ActionManager = import("./actionManager").ActionManager;
@@ -41,6 +42,18 @@ export interface IAction {
      * @returns the serialized object
      */
     serialize(parent: any): any;
+
+     /**
+     * Internal only
+     * @hidden
+     */
+    _prepare(): void;
+
+    /**
+     * Internal only - manager for action
+     * @hidden
+     */
+    _actionManager: AbstractActionManager;
 }
 
 /**

+ 3 - 3
src/Actions/actionManager.ts

@@ -4,7 +4,7 @@ import { Scene } from "../scene";
 import { Vector3, Vector4, Color3, Color4 } from "../Maths/math";
 
 import { Condition, ValueCondition } from "./condition";
-import { Action } from "./action";
+import { Action, IAction } from "./action";
 import { DoNothingAction } from "./directActions";
 
 import { EngineStore } from "../Engines/engineStore";
@@ -260,7 +260,7 @@ export class ActionManager extends AbstractActionManager {
      * @param action defines the action to be registered
      * @return the action amended (prepared) after registration
      */
-    public registerAction(action: Action): Nullable<Action> {
+    public registerAction(action: IAction): Nullable<IAction> {
         if (action.trigger === ActionManager.OnEveryFrameTrigger) {
             if (this.getScene().actionManager !== this) {
                 Logger.Warn("OnEveryFrameTrigger can only be used with scene.actionManager");
@@ -288,7 +288,7 @@ export class ActionManager extends AbstractActionManager {
      * @param action defines the action to be unregistered
      * @return a boolean indicating whether the action has been unregistered
      */
-    public unregisterAction(action: Action): Boolean {
+    public unregisterAction(action: IAction): Boolean {
         var index = this.actions.indexOf(action);
         if (index !== -1) {
             this.actions.splice(index, 1);

+ 6 - 1
src/Cameras/targetCamera.ts

@@ -216,7 +216,12 @@ export class TargetCamera extends Camera {
     }
 
     // Target
-    /** @hidden */
+
+    /**
+     * Defines the target the camera should look at.
+     * This will automatically adapt alpha beta and radius to fit within the new target.
+     * @param target Defines the new target as a Vector or a mesh
+     */
     public setTarget(target: Vector3): void {
         this.upVector.normalize();
 

+ 27 - 14
src/Culling/ray.ts

@@ -534,6 +534,10 @@ export class Ray {
 }
 
 // Picking
+/**
+ * Type used to define predicate used to select faces when a mesh intersection is detected
+ */
+export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
 
 declare module "../scene" {
     export interface Scene {
@@ -547,10 +551,10 @@ declare module "../scene" {
         _pickWithRayInverseMatrix: Matrix;
 
         /** @hidden */
-        _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
 
         /** @hidden */
-        _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
 
     }
 }
@@ -619,7 +623,9 @@ Scene.prototype.createPickingRayInCameraSpaceToRef = function(x: number, y: numb
     return this;
 };
 
-Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean,
+    fastCheck?: boolean,
+    trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     if (!PickingInfo) {
         return null;
     }
@@ -640,7 +646,7 @@ Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, pr
         var world = mesh.getWorldMatrix();
         var ray = rayFunction(world);
 
-        var result = mesh.intersects(ray, fastCheck);
+        var result = mesh.intersects(ray, fastCheck, trianglePredicate);
         if (!result || !result.hit) {
             continue;
         }
@@ -659,7 +665,9 @@ Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, pr
     return pickingInfo || new PickingInfo();
 };
 
-Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ray,
+        predicate?: (mesh: AbstractMesh) => boolean,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
     if (!PickingInfo) {
         return null;
     }
@@ -679,7 +687,7 @@ Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ra
         var world = mesh.getWorldMatrix();
         var ray = rayFunction(world);
 
-        var result = mesh.intersects(ray, false);
+        var result = mesh.intersects(ray, false, trianglePredicate);
         if (!result || !result.hit) {
             continue;
         }
@@ -690,7 +698,9 @@ Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ra
     return pickingInfos;
 };
 
-Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo> {
+Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean,
+    fastCheck?: boolean, camera?: Nullable<Camera>,
+    trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     if (!PickingInfo) {
         return null;
     }
@@ -701,14 +711,15 @@ Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: Abstrac
 
         this.createPickingRayToRef(x, y, world, this._tempPickingRay, camera || null);
         return this._tempPickingRay;
-    }, predicate, fastCheck);
+    }, predicate, fastCheck, trianglePredicate);
     if (result) {
         result.ray = this.createPickingRay(x, y, Matrix.Identity(), camera || null);
     }
     return result;
 };
 
-Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean,
+    fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     var result = this._internalPick((world) => {
         if (!this._pickWithRayInverseMatrix) {
             this._pickWithRayInverseMatrix = Matrix.Identity();
@@ -721,18 +732,20 @@ Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh
 
         Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
         return this._cachedRayForTransform;
-    }, predicate, fastCheck);
+    }, predicate, fastCheck, trianglePredicate);
     if (result) {
         result.ray = ray;
     }
     return result;
 };
 
-Scene.prototype.multiPick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
-    return this._internalMultiPick((world) => this.createPickingRay(x, y, world, camera || null), predicate);
+Scene.prototype.multiPick = function(x: number, y: number,
+    predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
+    return this._internalMultiPick((world) => this.createPickingRay(x, y, world, camera || null), predicate, trianglePredicate);
 };
 
-Scene.prototype.multiPickWithRay = function(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+Scene.prototype.multiPickWithRay = function(ray: Ray,
+    predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
     return this._internalMultiPick((world) => {
         if (!this._pickWithRayInverseMatrix) {
             this._pickWithRayInverseMatrix = Matrix.Identity();
@@ -745,7 +758,7 @@ Scene.prototype.multiPickWithRay = function(ray: Ray, predicate: (mesh: Abstract
 
         Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
         return this._cachedRayForTransform;
-    }, predicate);
+    }, predicate, trianglePredicate);
 };
 
 Camera.prototype.getForwardRay = function(length = 100, transform?: Matrix, origin?: Vector3): Ray {

+ 1 - 1
src/Engines/engine.ts

@@ -491,7 +491,7 @@ export class Engine {
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.0.0-alpha.25";
+        return "4.0.0-alpha.26";
     }
 
     /**

+ 11 - 3
src/Meshes/abstractMesh.ts

@@ -24,6 +24,7 @@ import { AbstractActionManager } from '../Actions/abstractActionManager';
 
 declare type Ray = import("../Culling/ray").Ray;
 declare type Collider = import("../Collisions/collider").Collider;
+declare type TrianglePickingPredicate = import("../Culling/ray").TrianglePickingPredicate;
 
 /** @hidden */
 class _FacetDataStorage {
@@ -1443,10 +1444,11 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
      * Checks if the passed Ray intersects with the mesh
      * @param ray defines the ray to use
      * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns the picking info
      * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
      */
-    public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
+    public intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): PickingInfo {
         var pickingInfo = new PickingInfo();
         const intersectionThreshold = this.getClassName() === "InstancedLinesMesh" || this.getClassName() === "LinesMesh" ? (this as any).intersectionThreshold : 0;
         const boundingInfo = this._boundingInfo;
@@ -1470,7 +1472,9 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
                 continue;
             }
 
-            var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions), (<IndicesArray>this.getIndices()), fastCheck);
+            var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions),
+                (<IndicesArray>this.getIndices()), fastCheck,
+                trianglePredicate);
 
             if (currentIntersectInfo) {
                 if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
@@ -1618,7 +1622,11 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
 
         if (disposeMaterialAndTextures) {
             if (this.material) {
-                this.material.dispose(false, true);
+                if (this.material.getClassName() === "MultiMaterial") {
+                    this.material.dispose(false, true, true);
+                } else {
+                    this.material.dispose(false, true);
+                }
             }
         }
 

+ 1 - 9
src/Meshes/mesh.ts

@@ -140,15 +140,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
      * @hidden
      */
     public static _GetDefaultSideOrientation(orientation?: number): number {
-        if (orientation == Mesh.DOUBLESIDE) {
-            return Mesh.DOUBLESIDE;
-        }
-
-        if (orientation === undefined || orientation === null) {
-            return Mesh.FRONTSIDE;
-        }
-
-        return orientation;
+        return orientation || Mesh.FRONTSIDE; // works as Mesh.FRONTSIDE is 0
     }
 
     // Events

+ 11 - 3
src/Meshes/subMesh.ts

@@ -15,6 +15,7 @@ declare type MultiMaterial = import("../Materials/multiMaterial").MultiMaterial;
 declare type AbstractMesh = import("./abstractMesh").AbstractMesh;
 declare type Mesh = import("./mesh").Mesh;
 declare type Ray = import("../Culling/ray").Ray;
+declare type TrianglePickingPredicate = import("../Culling/ray").TrianglePickingPredicate;
 
 /**
  * Base class for submeshes
@@ -341,9 +342,11 @@ export class SubMesh extends BaseSubMesh implements ICullable {
      * @param positions defines mesh's positions array
      * @param indices defines mesh's indices array
      * @param fastCheck defines if only bounding info should be used
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns intersection info or null if no intersection
      */
-    public intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo> {
+    public intersects(ray: Ray, positions: Vector3[], indices: IndicesArray,
+        fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo> {
         const material = this.getMaterial();
         if (!material) {
             return null;
@@ -364,7 +367,7 @@ export class SubMesh extends BaseSubMesh implements ICullable {
             return this._intersectLines(ray, positions, indices, (this._mesh as any).intersectionThreshold, fastCheck);
         }
 
-        return this._intersectTriangles(ray, positions, indices, fastCheck);
+        return this._intersectTriangles(ray, positions, indices, fastCheck, trianglePredicate);
     }
 
     /** @hidden */
@@ -393,7 +396,8 @@ export class SubMesh extends BaseSubMesh implements ICullable {
     }
 
     /** @hidden */
-    private _intersectTriangles(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo> {
+    private _intersectTriangles(ray: Ray, positions: Vector3[], indices: IndicesArray,
+        fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<IntersectionInfo> {
         var intersectInfo: Nullable<IntersectionInfo> = null;
         // Triangles test
         for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
@@ -401,6 +405,10 @@ export class SubMesh extends BaseSubMesh implements ICullable {
             var p1 = positions[indices[index + 1]];
             var p2 = positions[indices[index + 2]];
 
+            if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
+                continue;
+            }
+
             var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
 
             if (currentIntersectInfo) {

+ 5 - 0
src/Particles/baseParticleSystem.ts

@@ -271,6 +271,11 @@ export class BaseParticleSystem {
     public beginAnimationLoop = false;
 
     /**
+     * Gets or sets a world offset applied to all particles
+     */
+    public worldOffset = new Vector3(0, 0, 0);
+
+    /**
      * Gets or sets whether an animation sprite sheet is enabled or not on the particle system
      */
     public get isAnimationSheetEnabled(): boolean {

+ 2 - 1
src/Particles/gpuParticleSystem.ts

@@ -1064,7 +1064,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
             return;
         }
 
-        var uniforms = ["view", "projection", "colorDead", "invView", "vClipPlane", "vClipPlane2", "vClipPlane3", "vClipPlane4", "sheetInfos", "translationPivot", "eyePosition"];
+        var uniforms = ["worldOffset", "view", "projection", "colorDead", "invView", "vClipPlane", "vClipPlane2", "vClipPlane3", "vClipPlane4", "sheetInfos", "translationPivot", "eyePosition"];
         var samplers = ["textureSampler", "colorGradientSampler"];
 
         if (ImageProcessingConfiguration) {
@@ -1296,6 +1296,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
             this._renderEffect.setMatrix("projection", this._scene.getProjectionMatrix());
             this._renderEffect.setTexture("textureSampler", this.particleTexture);
             this._renderEffect.setVector2("translationPivot", this.translationPivot);
+            this._renderEffect.setVector3("worldOffset", this.worldOffset);
             if (this._colorGradientsTexture) {
                 this._renderEffect.setTexture("colorGradientSampler", this._colorGradientsTexture);
             } else {

+ 3 - 3
src/Particles/particleSystem.ts

@@ -1121,9 +1121,9 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
     public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
         var offset = index * this._vertexBufferSize;
 
-        this._vertexData[offset++] = particle.position.x;
-        this._vertexData[offset++] = particle.position.y;
-        this._vertexData[offset++] = particle.position.z;
+        this._vertexData[offset++] = particle.position.x + this.worldOffset.x;
+        this._vertexData[offset++] = particle.position.y + this.worldOffset.y;
+        this._vertexData[offset++] = particle.position.z + this.worldOffset.z;
         this._vertexData[offset++] = particle.color.r;
         this._vertexData[offset++] = particle.color.g;
         this._vertexData[offset++] = particle.color.b;

+ 6 - 5
src/Shaders/gpuRenderParticles.vertex.fx

@@ -4,6 +4,7 @@
 uniform mat4 view;
 uniform mat4 projection;
 uniform vec2 translationPivot;
+uniform vec3 worldOffset;
 
 // Particles state
 in vec3 position;
@@ -59,7 +60,7 @@ vec3 rotate(vec3 yaxis, vec3 rotatedCorner) {
 
 	vec3 alignedCorner = rotMatrix * rotatedCorner;
 
-	return position + alignedCorner;
+	return (position + worldOffset) + alignedCorner;
 }
 
 #ifdef BILLBOARDSTRETCHED
@@ -75,7 +76,7 @@ vec3 rotateAlign(vec3 toCamera, vec3 rotatedCorner) {
 	mat3 rotMatrix =  mat3(row0, row1, row2);
 
 	vec3 alignedCorner = rotMatrix * rotatedCorner;
-	return position + alignedCorner; 
+	return (position + worldOffset) + alignedCorner; 
 }
 #endif
 
@@ -109,7 +110,7 @@ void main() {
 		rotatedCorner.z = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 		rotatedCorner.y = 0.;
 
-		vec3 yaxis = position - eyePosition;
+		vec3 yaxis = (position + worldOffset) - eyePosition;
 		yaxis.y = 0.;
 		vec3 worldPos = rotate(normalize(yaxis), rotatedCorner.xyz);
 
@@ -119,7 +120,7 @@ void main() {
 		rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 		rotatedCorner.z = 0.;
 
-		vec3 toCamera = position - eyePosition;	
+		vec3 toCamera = (position + worldOffset) - eyePosition;	
 		vec3 worldPos = rotateAlign(toCamera, rotatedCorner.xyz);
 		
 		vec4 viewPosition = (view * vec4(worldPos, 1.0)); 	
@@ -130,7 +131,7 @@ void main() {
 		rotatedCorner.z = 0.;
 
 		// Expand position
-		vec4 viewPosition = view * vec4(position, 1.0) + rotatedCorner;
+		vec4 viewPosition = view * vec4((position + worldOffset), 1.0) + rotatedCorner;
 	#endif
 
 #else

+ 1 - 0
src/Shaders/gpuUpdateParticles.vertex.fx

@@ -10,6 +10,7 @@ uniform vec2 lifeTime;
 uniform vec2 emitPower;
 uniform vec2 sizeRange;
 uniform vec4 scaleRange;
+
 #ifndef COLORGRADIENTS
 uniform vec4 color1;
 uniform vec4 color2;

+ 15 - 5
src/scene.ts

@@ -47,6 +47,7 @@ import { AbstractActionManager } from './Actions/abstractActionManager';
 import { _DevTools } from './Misc/devTools';
 
 declare type Ray = import("./Culling/ray").Ray;
+declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
 declare type Animation = import("./Animations/animation").Animation;
 declare type Animatable = import("./Animations/animatable").Animatable;
 declare type AnimationGroup = import("./Animations/animationGroup").AnimationGroup;
@@ -4562,7 +4563,7 @@ export class Scene extends AbstractScene implements IAnimatable {
             this.meshes[0].dispose(true);
         }
         while (this.transformNodes.length) {
-            this.removeTransformNode(this.transformNodes[0]);
+            this.transformNodes[0].dispose(true);
         }
 
         // Release cameras
@@ -4750,9 +4751,13 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
      * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
      * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns a PickingInfo
      */
-    public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo> {
+    public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean,
+        fastCheck?: boolean, camera?: Nullable<Camera>,
+        trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean
+        ): Nullable<PickingInfo> {
         // Dummy info if picking as not been imported
         const pi = new PickingInfo();
         pi._pickingUnavailable = true;
@@ -4763,9 +4768,11 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param ray The ray to use to pick meshes
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
      * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns a PickingInfo
      */
-    public pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+    public pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
         throw _DevTools.WarnImport("Ray");
     }
 
@@ -4775,9 +4782,11 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param y Y position on screen
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
      * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns an array of PickingInfo
      */
-    public multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
+    public multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
         throw _DevTools.WarnImport("Ray");
     }
 
@@ -4785,9 +4794,10 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Launch a ray to try to pick a mesh in the scene
      * @param ray Ray to use
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns an array of PickingInfo
      */
-    public multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+    public multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
         throw _DevTools.WarnImport("Ray");
     }
 

BIN
tests/validation/ReferenceImages/Gizmos.png


BIN
tests/validation/ReferenceImages/Sliders.png


BIN
tests/validation/ReferenceImages/TransformStackPanel.png


BIN
tests/validation/ReferenceImages/assetContainer.png


BIN
tests/validation/ReferenceImages/xrCameraContainerRotation.png


+ 127 - 122
tests/validation/validation.js

@@ -40,6 +40,10 @@ function compare(renderData, referenceCanvas) {
             continue;
         }
 
+        if (differencesCount === 0) {
+            console.log(`First pixel off at ${index}: Value: (${renderData[index]}, ${renderData[index + 1]}, ${renderData[index] + 2}) - Expected: (${referenceData.data[index]}, ${referenceData.data[index + 1]}, ${referenceData.data[index + 2]}) `);
+        }
+
         referenceData.data[index] = 255;
         referenceData.data[index + 1] *= 0.5;
         referenceData.data[index + 2] *= 0.5;
@@ -49,7 +53,7 @@ function compare(renderData, referenceCanvas) {
     referenceContext.putImageData(referenceData, 0, 0);
 
     if (differencesCount) {
-        console.log("Pixel difference: " + differencesCount + " pixels.");
+        console.log("%c Pixel difference: " + differencesCount + " pixels.", 'color: orange');
     }
 
     return (differencesCount * 100) / (width * height) > errorRatio;
@@ -144,7 +148,7 @@ function processCurrentScene(test, resultCanvas, result, renderImage, index, wai
             currentScene.activeCamera.useAutoRotationBehavior = false;
         }
         engine.runRenderLoop(function() {
-            try {
+            try {                
                 currentScene.render();
                 renderCount--;
 
@@ -204,152 +208,153 @@ function runTest(index, done) {
         resultCanvas.width = img.width;
         resultCanvas.height = img.height;
         resultContext.drawImage(img, 0, 0);
-    }
 
-    img.src = "/tests/validation/ReferenceImages/" + test.referenceImage;
-
-    var renderImage = new Image();
-    renderImage.className = "renderImage";
-    container.appendChild(renderImage);
+        var renderImage = new Image();
+        renderImage.className = "renderImage";
+        container.appendChild(renderImage);
 
-    location.href = "#" + container.id;
+        location.href = "#" + container.id;
 
-    if (test.sceneFolder) {
-        BABYLON.SceneLoader.Load(config.root + test.sceneFolder, test.sceneFilename, engine, function(newScene) {
-            currentScene = newScene;
-            processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
-        },
-            null,
-            function(loadedScene, msg) {
-                console.error(msg);
-                done(false);
-            });
-    }
-    else if (test.playgroundId) {
-        if (test.playgroundId[0] !== "#" || test.playgroundId.indexOf("#", 1) === -1) {
-            console.error("Invalid playground id");
-            done(false);
-            return;
+        if (test.sceneFolder) {
+            BABYLON.SceneLoader.Load(config.root + test.sceneFolder, test.sceneFilename, engine, function(newScene) {
+                currentScene = newScene;
+                processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+            },
+                null,
+                function(loadedScene, msg) {
+                    console.error(msg);
+                    done(false);
+                });
         }
+        else if (test.playgroundId) {
+            if (test.playgroundId[0] !== "#" || test.playgroundId.indexOf("#", 1) === -1) {
+                console.error("Invalid playground id");
+                done(false);
+                return;
+            }
 
-        var snippetUrl = "https://snippet.babylonjs.com";
-        var pgRoot = "/Playground"
+            var snippetUrl = "https://snippet.babylonjs.com";
+            var pgRoot = "/Playground"
 
-        var retryTime = 500;
-        var maxRetry = 5;
-        var retry = 0;
+            var retryTime = 500;
+            var maxRetry = 5;
+            var retry = 0;
 
-        var onError = function() {
-            retry++;
-            if (retry < maxRetry) {
-                setTimeout(function() {
-                    loadPG();
-                }, retryTime);
-            }
-            else {
-                // Skip the test as we can not fetch the source.
-                done(true);
+            var onError = function() {
+                retry++;
+                if (retry < maxRetry) {
+                    setTimeout(function() {
+                        loadPG();
+                    }, retryTime);
+                }
+                else {
+                    // Skip the test as we can not fetch the source.
+                    done(true);
+                }
             }
-        }
 
-        var loadPG = function() {
-            var xmlHttp = new XMLHttpRequest();
-            xmlHttp.onreadystatechange = function() {
-                if (xmlHttp.readyState === 4) {
-                    try {
-                        xmlHttp.onreadystatechange = null;
-                        var snippet = JSON.parse(xmlHttp.responseText);
-                        var code = JSON.parse(snippet.jsonPayload).code.toString();
-                        code = code.replace(/\/textures\//g, pgRoot + "/textures/");
-                        code = code.replace(/"textures\//g, "\"" + pgRoot + "/textures/");
-                        code = code.replace(/\/scenes\//g, pgRoot + "/scenes/");
-                        code = code.replace(/"scenes\//g, "\"" + pgRoot + "/scenes/");
-                        currentScene = eval(code + "\r\ncreateScene(engine)");
-
-                        if (currentScene.then) {
-                            // Handle if createScene returns a promise
-                            currentScene.then(function(scene) {
-                                currentScene = scene;
+            var loadPG = function() {
+                var xmlHttp = new XMLHttpRequest();
+                xmlHttp.onreadystatechange = function() {
+                    if (xmlHttp.readyState === 4) {
+                        try {
+                            xmlHttp.onreadystatechange = null;
+                            var snippet = JSON.parse(xmlHttp.responseText);
+                            var code = JSON.parse(snippet.jsonPayload).code.toString();
+                            code = code.replace(/\/textures\//g, pgRoot + "/textures/");
+                            code = code.replace(/"textures\//g, "\"" + pgRoot + "/textures/");
+                            code = code.replace(/\/scenes\//g, pgRoot + "/scenes/");
+                            code = code.replace(/"scenes\//g, "\"" + pgRoot + "/scenes/");
+                            currentScene = eval(code + "\r\ncreateScene(engine)");
+
+                            if (currentScene.then) {
+                                // Handle if createScene returns a promise
+                                currentScene.then(function(scene) {
+                                    currentScene = scene;
+                                    processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+                                }).catch(function(e) {
+                                    console.error(e);
+                                    onError();
+                                })
+                            } else {
+                                // Handle if createScene returns a scene
                                 processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
-                            }).catch(function(e) {
-                                console.error(e);
-                                onError();
-                            })
-                        } else {
-                            // Handle if createScene returns a scene
-                            processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+                            }
+                        }
+                        catch (e) {
+                            console.error(e);
+                            onError();
                         }
-                    }
-                    catch (e) {
-                        console.error(e);
-                        onError();
                     }
                 }
-            }
-            xmlHttp.onerror = function() {
-                console.error("Network error during test load.");
-                onError();
+                xmlHttp.onerror = function() {
+                    console.error("Network error during test load.");
+                    onError();
+                }
+
+                xmlHttp.open("GET", snippetUrl + test.playgroundId.replace(/#/g, "/"));
+                xmlHttp.send();
             }
 
-            xmlHttp.open("GET", snippetUrl + test.playgroundId.replace(/#/g, "/"));
-            xmlHttp.send();
-        }
+            loadPG();
+        } else {
+            // Fix references
+            if (test.specificRoot) {
+                BABYLON.Tools.BaseUrl = config.root + test.specificRoot;
+            }
 
-        loadPG();
-    } else {
-        // Fix references
-        if (test.specificRoot) {
-            BABYLON.Tools.BaseUrl = config.root + test.specificRoot;
-        }
+            var request = new XMLHttpRequest();
+            request.open('GET', config.root + test.scriptToRun, true);
 
-        var request = new XMLHttpRequest();
-        request.open('GET', config.root + test.scriptToRun, true);
-
-        request.onreadystatechange = function() {
-            if (request.readyState === 4) {
-                try {
-                    request.onreadystatechange = null;
-
-                    var scriptToRun = request.responseText.replace(/..\/..\/assets\//g, config.root + "/Assets/");
-                    scriptToRun = scriptToRun.replace(/..\/..\/Assets\//g, config.root + "/Assets/");
-                    scriptToRun = scriptToRun.replace(/\/assets\//g, config.root + "/Assets/");
-                    scriptToRun = scriptToRun.replace(/\/Assets\//g, config.root + "/Assets/");
-
-                    if (test.replace) {
-                        var split = test.replace.split(",");
-                        for (var i = 0; i < split.length; i += 2) {
-                            var source = split[i].trim();
-                            var destination = split[i + 1].trim();
-                            scriptToRun = scriptToRun.replace(source, destination);
+            request.onreadystatechange = function() {
+                if (request.readyState === 4) {
+                    try {
+                        request.onreadystatechange = null;
+
+                        var scriptToRun = request.responseText.replace(/..\/..\/assets\//g, config.root + "/Assets/");
+                        scriptToRun = scriptToRun.replace(/..\/..\/Assets\//g, config.root + "/Assets/");
+                        scriptToRun = scriptToRun.replace(/\/assets\//g, config.root + "/Assets/");
+                        scriptToRun = scriptToRun.replace(/\/Assets\//g, config.root + "/Assets/");
+
+                        if (test.replace) {
+                            var split = test.replace.split(",");
+                            for (var i = 0; i < split.length; i += 2) {
+                                var source = split[i].trim();
+                                var destination = split[i + 1].trim();
+                                scriptToRun = scriptToRun.replace(source, destination);
+                            }
                         }
-                    }
 
-                    if (test.replaceUrl) {
-                        var split = test.replaceUrl.split(",");
-                        for (var i = 0; i < split.length; i++) {
-                            var source = split[i].trim();
-                            var regex = new RegExp(source, "g");
-                            scriptToRun = scriptToRun.replace(regex, config.root + test.rootPath + source);
+                        if (test.replaceUrl) {
+                            var split = test.replaceUrl.split(",");
+                            for (var i = 0; i < split.length; i++) {
+                                var source = split[i].trim();
+                                var regex = new RegExp(source, "g");
+                                scriptToRun = scriptToRun.replace(regex, config.root + test.rootPath + source);
+                            }
                         }
-                    }
 
-                    currentScene = eval(scriptToRun + test.functionToCall + "(engine)");
-                    processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
-                }
-                catch (e) {
-                    console.error(e);
-                    done(false);
+                        currentScene = eval(scriptToRun + test.functionToCall + "(engine)");
+                        processCurrentScene(test, resultCanvas, result, renderImage, index, waitRing, done);
+                    }
+                    catch (e) {
+                        console.error(e);
+                        done(false);
+                    }
                 }
+            };
+            request.onerror = function() {
+                console.error("Network error during test load.");
+                done(false);
             }
-        };
-        request.onerror = function() {
-            console.error("Network error during test load.");
-            done(false);
-        }
 
-        request.send(null);
+            request.send(null);
 
+        }
     }
+
+    img.src = "/tests/validation/ReferenceImages/" + test.referenceImage;
+
 }
 
 function init() {