Explorar el Código

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into csm-optim-blendcascade

Popov72 hace 5 años
padre
commit
49bc330e94
Se han modificado 62 ficheros con 3594 adiciones y 829 borrados
  1. 269 71
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 802 149
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 571 158
      dist/preview release/babylon.module.d.ts
  6. 269 71
      dist/preview release/documentation.d.ts
  7. 1 1
      dist/preview release/glTF2Interface/package.json
  8. 2 2
      dist/preview release/gui/package.json
  9. 7 7
      dist/preview release/inspector/package.json
  10. 3 2
      dist/preview release/loaders/babylon.objFileLoader.js
  11. 1 1
      dist/preview release/loaders/babylon.objFileLoader.js.map
  12. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  13. 3 2
      dist/preview release/loaders/babylonjs.loaders.js
  14. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  15. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  16. 3 3
      dist/preview release/loaders/package.json
  17. 2 2
      dist/preview release/materialsLibrary/package.json
  18. 14 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  19. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  20. 81 30
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  21. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  22. 32 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  23. 2 2
      dist/preview release/nodeEditor/package.json
  24. 1 1
      dist/preview release/package.json
  25. 1 1
      dist/preview release/packagesSizeBaseLine.json
  26. 2 2
      dist/preview release/postProcessesLibrary/package.json
  27. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  28. 3 3
      dist/preview release/serializers/package.json
  29. 571 158
      dist/preview release/viewer/babylon.module.d.ts
  30. 36 24
      dist/preview release/viewer/babylon.viewer.js
  31. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  32. 5 0
      dist/preview release/what's new.md
  33. 3 2
      loaders/src/OBJ/objFileLoader.ts
  34. 2 35
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  35. 7 2
      nodeEditor/src/diagram/graphFrame.ts
  36. 69 0
      nodeEditor/src/diagram/properties/framePropertyComponent.tsx
  37. 2 1
      nodeEditor/src/diagram/properties/trigonometryNodePropertyComponent.tsx
  38. 1 1
      nodeEditor/src/sharedComponents/optionsLineComponent.tsx
  39. 1 1
      package.json
  40. 178 17
      src/Cameras/XR/features/WebXRControllerPointerSelection.ts
  41. 64 10
      src/Cameras/XR/features/WebXRControllerTeleportation.ts
  42. 9 10
      src/Cameras/XR/webXRCamera.ts
  43. 1 3
      src/Cameras/XR/webXRController.ts
  44. 15 18
      src/Cameras/XR/webXRFeaturesManager.ts
  45. 3 3
      src/Engines/thinEngine.ts
  46. 85 0
      src/Lights/Shadows/cascadedShadowGenerator.ts
  47. 2 0
      src/Materials/Textures/MultiviewRenderTarget.ts
  48. 12 14
      src/Materials/Textures/baseTexture.ts
  49. 1 1
      src/Meshes/instancedMesh.ts
  50. 1 2
      src/Meshes/linesMesh.ts
  51. 1 1
      src/Meshes/mesh.ts
  52. 1 1
      src/Meshes/transformNode.ts
  53. 108 0
      src/Misc/depthReducer.ts
  54. 2 0
      src/Misc/index.ts
  55. 244 0
      src/Misc/minMaxReducer.ts
  56. 11 0
      src/Misc/screenshotTools.ts
  57. 3 0
      src/Rendering/depthRenderer.ts
  58. 2 2
      src/Rendering/depthRendererSceneComponent.ts
  59. 1 1
      src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx
  60. 1 1
      src/Shaders/ShadersInclude/pbrVertexDeclaration.fx
  61. 70 0
      src/Shaders/minmaxRedux.fragment.fx
  62. 2 2
      src/sceneComponent.ts

+ 269 - 71
dist/preview release/babylon.d.ts

@@ -11362,9 +11362,9 @@ declare module BABYLON {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -19370,7 +19370,7 @@ declare module BABYLON {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -19820,7 +19820,7 @@ declare module BABYLON {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -24720,7 +24720,7 @@ declare module BABYLON {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -43758,7 +43758,6 @@ declare module BABYLON {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -43888,6 +43887,29 @@ declare module BABYLON {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -43908,11 +43930,11 @@ declare module BABYLON {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -43951,7 +43973,19 @@ declare module BABYLON {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -44176,6 +44210,15 @@ declare module BABYLON {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -44278,6 +44321,7 @@ declare module BABYLON {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -53990,6 +54034,191 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -54348,6 +54577,38 @@ declare module BABYLON {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -65964,13 +66225,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /** @hidden */
     export var volumetricLightScatteringPixelShader: {
         name: string;
         shader: string;
@@ -66195,62 +66449,6 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
-declare module BABYLON {
         interface Scene {
             /** @hidden (Backing field) */
             _depthRenderer: {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 802 - 149
dist/preview release/babylon.max.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 571 - 158
dist/preview release/babylon.module.d.ts

@@ -11563,9 +11563,9 @@ declare module "babylonjs/sceneComponent" {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -19909,7 +19909,7 @@ declare module "babylonjs/Meshes/instancedMesh" {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -20310,7 +20310,6 @@ declare module "babylonjs/Meshes/linesMesh" {
     import { Material } from "babylonjs/Materials/material";
     import "babylonjs/Shaders/color.fragment";
     import "babylonjs/Shaders/color.vertex";
-    import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     /**
      * Line mesh
      * @see https://doc.babylonjs.com/babylon101/parametric_shapes
@@ -20392,7 +20391,7 @@ declare module "babylonjs/Meshes/linesMesh" {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -25455,7 +25454,7 @@ declare module "babylonjs/Meshes/mesh" {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -45280,7 +45279,6 @@ declare module "babylonjs/Cameras/XR/webXRController" {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -45406,6 +45404,8 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
     import { IWebXRFeature } from "babylonjs/Cameras/XR/webXRFeaturesManager";
     import { WebXRSessionManager } from "babylonjs/Cameras/XR/webXRSessionManager";
     import { WebXRInput } from "babylonjs/Cameras/XR/webXRInput";
+    import { WebXRController } from "babylonjs/Cameras/XR/webXRController";
+    import { Nullable } from "babylonjs/types";
     import { Color3 } from "babylonjs/Maths/math.color";
     /**
      * Options interface for the pointer selection module
@@ -45419,6 +45419,29 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -45439,11 +45462,11 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -45482,7 +45505,19 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -45722,6 +45757,15 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerTeleportation" {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -45824,6 +45868,7 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerTeleportation" {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -56396,6 +56441,219 @@ declare module "babylonjs/LensFlares/index" {
     export * from "babylonjs/LensFlares/lensFlareSystem";
     export * from "babylonjs/LensFlares/lensFlareSystemSceneComponent";
 }
+declare module "babylonjs/Shaders/depth.fragment" {
+    import "babylonjs/Shaders/ShadersInclude/packingFunctions";
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Shaders/depth.vertex" {
+    import "babylonjs/Shaders/ShadersInclude/bonesDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/instancesDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertex";
+    import "babylonjs/Shaders/ShadersInclude/instancesVertex";
+    import "babylonjs/Shaders/ShadersInclude/bonesVertex";
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Rendering/depthRenderer" {
+    import { Nullable } from "babylonjs/types";
+    import { SubMesh } from "babylonjs/Meshes/subMesh";
+    import { Scene } from "babylonjs/scene";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import "babylonjs/Shaders/depth.fragment";
+    import "babylonjs/Shaders/depth.vertex";
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module "babylonjs/Shaders/minmaxRedux.fragment" {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Misc/minMaxReducer" {
+    import { Nullable } from "babylonjs/types";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import { Observer } from "babylonjs/Misc/observable";
+    import { PostProcess } from "babylonjs/PostProcesses/postProcess";
+    import { PostProcessManager } from "babylonjs/PostProcesses/postProcessManager";
+    import { Observable } from "babylonjs/Misc/observable";
+    import "babylonjs/Shaders/minmaxRedux.fragment";
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module "babylonjs/Misc/depthReducer" {
+    import { Nullable } from "babylonjs/types";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import { DepthRenderer } from "babylonjs/Rendering/depthRenderer";
+    import { MinMaxReducer } from "babylonjs/Misc/minMaxReducer";
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
 declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
     import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
@@ -56412,6 +56670,7 @@ declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
     import { IShadowGenerator } from "babylonjs/Lights/Shadows/shadowGenerator";
     import { DirectionalLight } from "babylonjs/Lights/directionalLight";
     import { BoundingInfo } from "babylonjs/Culling/boundingInfo";
+    import { DepthRenderer } from "babylonjs/Rendering/depthRenderer";
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -56770,6 +57029,38 @@ declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -69461,20 +69752,6 @@ declare module "babylonjs/PostProcesses/tonemapPostProcess" {
         exposureAdjustment: number, camera: Camera, samplingMode?: number, engine?: Engine, textureFormat?: number);
     }
 }
-declare module "babylonjs/Shaders/depth.vertex" {
-    import "babylonjs/Shaders/ShadersInclude/bonesDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/instancesDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertex";
-    import "babylonjs/Shaders/ShadersInclude/instancesVertex";
-    import "babylonjs/Shaders/ShadersInclude/bonesVertex";
-    /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
 declare module "babylonjs/Shaders/volumetricLightScattering.fragment" {
     /** @hidden */
     export var volumetricLightScatteringPixelShader: {
@@ -69769,70 +70046,6 @@ declare module "babylonjs/Rendering/boundingBoxRenderer" {
         dispose(): void;
     }
 }
-declare module "babylonjs/Shaders/depth.fragment" {
-    import "babylonjs/Shaders/ShadersInclude/packingFunctions";
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module "babylonjs/Rendering/depthRenderer" {
-    import { Nullable } from "babylonjs/types";
-    import { SubMesh } from "babylonjs/Meshes/subMesh";
-    import { Scene } from "babylonjs/scene";
-    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
-    import { Camera } from "babylonjs/Cameras/camera";
-    import "babylonjs/Shaders/depth.fragment";
-    import "babylonjs/Shaders/depth.vertex";
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
 declare module "babylonjs/Rendering/depthRendererSceneComponent" {
     import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
@@ -72077,6 +72290,8 @@ declare module "babylonjs/Misc/index" {
     export * from "babylonjs/Misc/fileTools";
     export * from "babylonjs/Misc/stringTools";
     export * from "babylonjs/Misc/dataReader";
+    export * from "babylonjs/Misc/minMaxReducer";
+    export * from "babylonjs/Misc/depthReducer";
 }
 declare module "babylonjs/index" {
     export * from "babylonjs/abstractScene";
@@ -83593,9 +83808,9 @@ declare module BABYLON {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -91601,7 +91816,7 @@ declare module BABYLON {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -92051,7 +92266,7 @@ declare module BABYLON {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -96951,7 +97166,7 @@ declare module BABYLON {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -115989,7 +116204,6 @@ declare module BABYLON {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -116119,6 +116333,29 @@ declare module BABYLON {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -116139,11 +116376,11 @@ declare module BABYLON {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -116182,7 +116419,19 @@ declare module BABYLON {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -116407,6 +116656,15 @@ declare module BABYLON {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -116509,6 +116767,7 @@ declare module BABYLON {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -126221,6 +126480,191 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -126579,6 +127023,38 @@ declare module BABYLON {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -138195,13 +138671,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /** @hidden */
     export var volumetricLightScatteringPixelShader: {
         name: string;
         shader: string;
@@ -138426,62 +138895,6 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
-declare module BABYLON {
         interface Scene {
             /** @hidden (Backing field) */
             _depthRenderer: {

+ 269 - 71
dist/preview release/documentation.d.ts

@@ -11362,9 +11362,9 @@ declare module BABYLON {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -19370,7 +19370,7 @@ declare module BABYLON {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -19820,7 +19820,7 @@ declare module BABYLON {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -24720,7 +24720,7 @@ declare module BABYLON {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -43758,7 +43758,6 @@ declare module BABYLON {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -43888,6 +43887,29 @@ declare module BABYLON {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -43908,11 +43930,11 @@ declare module BABYLON {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -43951,7 +43973,19 @@ declare module BABYLON {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -44176,6 +44210,15 @@ declare module BABYLON {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -44278,6 +44321,7 @@ declare module BABYLON {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -53990,6 +54034,191 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -54348,6 +54577,38 @@ declare module BABYLON {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -65964,13 +66225,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /** @hidden */
     export var volumetricLightScatteringPixelShader: {
         name: string;
         shader: string;
@@ -66195,62 +66449,6 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
-declare module BABYLON {
         interface Scene {
             /** @hidden (Backing field) */
             _depthRenderer: {

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

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

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

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

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

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

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

@@ -1020,14 +1020,14 @@ var OBJFileLoader = /** @class */ (function () {
                 //Get the name of the material
                 materialNameFromObj = line.substring(7).trim();
                 //If this new material is in the same mesh
-                if (!isFirstMaterial) {
+                if (!isFirstMaterial || !hasMeshes) {
                     //Set the data for the previous mesh
                     addPreviousObjMesh();
                     //Create a new mesh
                     var objMesh = 
                     //Set the name of the current obj mesh
                     {
-                        name: objMeshName + "_mm" + increment.toString(),
+                        name: (objMeshName || "mesh") + "_mm" + increment.toString(),
                         indices: undefined,
                         positions: undefined,
                         normals: undefined,
@@ -1038,6 +1038,7 @@ var OBJFileLoader = /** @class */ (function () {
                     increment++;
                     //If meshes are already defined
                     meshesFromObj.push(objMesh);
+                    hasMeshes = true;
                 }
                 //Set the material name if the previous line define a mesh
                 if (hasMeshes && isFirstMaterial) {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


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

@@ -1249,14 +1249,14 @@ var OBJFileLoader = /** @class */ (function () {
                 //Get the name of the material
                 materialNameFromObj = line.substring(7).trim();
                 //If this new material is in the same mesh
-                if (!isFirstMaterial) {
+                if (!isFirstMaterial || !hasMeshes) {
                     //Set the data for the previous mesh
                     addPreviousObjMesh();
                     //Create a new mesh
                     var objMesh = 
                     //Set the name of the current obj mesh
                     {
-                        name: objMeshName + "_mm" + increment.toString(),
+                        name: (objMeshName || "mesh") + "_mm" + increment.toString(),
                         indices: undefined,
                         positions: undefined,
                         normals: undefined,
@@ -1267,6 +1267,7 @@ var OBJFileLoader = /** @class */ (function () {
                     increment++;
                     //If meshes are already defined
                     meshesFromObj.push(objMesh);
+                    hasMeshes = true;
                 }
                 //Set the material name if the previous line define a mesh
                 if (hasMeshes && isFirstMaterial) {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 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.1.0-beta.18",
+    "version": "4.1.0-beta.20",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.1.0-beta.18",
-        "babylonjs": "4.1.0-beta.18"
+        "babylonjs-gltf2interface": "4.1.0-beta.20",
+        "babylonjs": "4.1.0-beta.20"
     },
     "engines": {
         "node": "*"

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

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

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

@@ -150,6 +150,7 @@ declare module NODEEDITOR {
         private _ports;
         private _controlledPorts;
         private _id;
+        onExpandStateChanged: BABYLON.Observable<GraphFrame>;
         private readonly CloseSVG;
         private readonly ExpandSVG;
         private readonly CollapseSVG;
@@ -1070,6 +1071,19 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IFramePropertyTabComponentProps {
+        globalState: GlobalState;
+        frame: GraphFrame;
+    }
+    export class FramePropertyTabComponent extends React.Component<IFramePropertyTabComponentProps> {
+        private onFrameExpandStateChangedObserver;
+        constructor(props: IFramePropertyTabComponentProps);
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface IPropertyTabComponentProps {
         globalState: GlobalState;
     }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.js


+ 81 - 30
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -52679,10 +52679,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _diagram_graphNode__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../diagram/graphNode */ "./diagram/graphNode.ts");
 /* harmony import */ var _sharedComponents_sliderLineComponent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../sharedComponents/sliderLineComponent */ "./sharedComponents/sliderLineComponent.tsx");
 /* harmony import */ var _diagram_graphFrame__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../diagram/graphFrame */ "./diagram/graphFrame.ts");
-/* harmony import */ var _sharedComponents_textInputLineComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../sharedComponents/textInputLineComponent */ "./sharedComponents/textInputLineComponent.tsx");
-/* harmony import */ var _sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../sharedComponents/color3LineComponent */ "./sharedComponents/color3LineComponent.tsx");
-/* harmony import */ var _sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../sharedComponents/textLineComponent */ "./sharedComponents/textLineComponent.tsx");
-
+/* harmony import */ var _sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../sharedComponents/textLineComponent */ "./sharedComponents/textLineComponent.tsx");
+/* harmony import */ var _diagram_properties_framePropertyComponent__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../diagram/properties/framePropertyComponent */ "./diagram/properties/framePropertyComponent.tsx");
 
 
 
@@ -52751,24 +52749,7 @@ var PropertyTabComponent = /** @class */ (function (_super) {
                 this.state.currentNode.renderProperties()));
         }
         if (this.state.currentFrame) {
-            return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "propertyTab" },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "header" },
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("img", { id: "logo", src: "https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" }),
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "title" }, "NODE MATERIAL EDITOR")),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { title: "GENERAL" },
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textInputLineComponent__WEBPACK_IMPORTED_MODULE_13__["TextInputLineComponent"], { globalState: this.props.globalState, label: "Name", propertyName: "name", target: this.state.currentFrame }),
-                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_14__["Color3LineComponent"], { label: "Color", target: this.state.currentFrame, propertyName: "color" }),
-                        !this.state.currentFrame.isCollapsed &&
-                            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_2__["ButtonLineComponent"], { label: "Collapse", onClick: function () {
-                                    _this.state.currentFrame.isCollapsed = true;
-                                    _this.forceUpdate();
-                                } }),
-                        this.state.currentFrame.isCollapsed &&
-                            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_2__["ButtonLineComponent"], { label: "Expand", onClick: function () {
-                                    _this.state.currentFrame.isCollapsed = false;
-                                    _this.forceUpdate();
-                                } })))));
+            return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_diagram_properties_framePropertyComponent__WEBPACK_IMPORTED_MODULE_14__["FramePropertyTabComponent"], { globalState: this.props.globalState, frame: this.state.currentFrame }));
         }
         var gridSize = _dataStorage__WEBPACK_IMPORTED_MODULE_9__["DataStorage"].ReadNumber("GridSize", 20);
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "propertyTab" },
@@ -52777,8 +52758,8 @@ var PropertyTabComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "title" }, "NODE MATERIAL EDITOR")),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { title: "GENERAL" },
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_15__["TextLineComponent"], { label: "Version", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["Engine"].Version }),
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_15__["TextLineComponent"], { label: "Help", value: "doc.babylonjs.com", underline: true, onLink: function () { return window.open('https://doc.babylonjs.com/how_to/node_material', '_blank'); } }),
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_13__["TextLineComponent"], { label: "Version", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["Engine"].Version }),
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_13__["TextLineComponent"], { label: "Help", value: "doc.babylonjs.com", underline: true, onLink: function () { return window.open('https://doc.babylonjs.com/how_to/node_material', '_blank'); } }),
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_2__["ButtonLineComponent"], { label: "Reset to default", onClick: function () {
                             _this.props.globalState.nodeMaterial.setToDefault();
                             _this.props.globalState.onResetRequiredObservable.notifyObservers();
@@ -54091,8 +54072,8 @@ var GraphCanvasComponent = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GraphFrame", function() { return GraphFrame; });
-/* harmony import */ var babylonjs_Maths_math_color__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.color */ "babylonjs/Misc/observable");
-/* harmony import */ var babylonjs_Maths_math_color__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_color__WEBPACK_IMPORTED_MODULE_0__);
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/observable");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _nodePort__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./nodePort */ "./diagram/nodePort.ts");
 /* harmony import */ var _serializationTools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../serializationTools */ "./serializationTools.ts");
 /* harmony import */ var _stringTools__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../stringTools */ "./stringTools.ts");
@@ -54100,6 +54081,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 var GraphFrame = /** @class */ (function () {
     function GraphFrame(candidate, canvas, doNotCaptureNodes) {
         var _this = this;
@@ -54115,6 +54097,7 @@ var GraphFrame = /** @class */ (function () {
         this._isCollapsed = false;
         this._ports = [];
         this._controlledPorts = [];
+        this.onExpandStateChanged = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
         this.CloseSVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\"><g id=\"Layer_2\" data-name=\"Layer 2\"><path d=\"M16,15l5.85,5.84-1,1L15,15.93,9.15,21.78l-1-1L14,15,8.19,9.12l1-1L15,14l5.84-5.84,1,1Z\"/></g></svg>";
         this.ExpandSVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\"><g id=\"Layer_2\" data-name=\"Layer 2\"><path d=\"M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-6.75,6.75H11.06V14.44h3.38V11.06h1.12v3.38h3.38v1.12H15.56v3.38H14.44Z\"/></g></svg>";
         this.CollapseSVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 30 30\"><g id=\"Layer_2\" data-name=\"Layer 2\"><path d=\"M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-2.25,6.75H11.06V14.44h7.88Z\"/></g></svg>";
@@ -54176,7 +54159,7 @@ var GraphFrame = /** @class */ (function () {
         this._inputPortContainer.classList.add("inputsContainer");
         this._portContainer.appendChild(this._inputPortContainer);
         this.name = "Frame";
-        this.color = babylonjs_Maths_math_color__WEBPACK_IMPORTED_MODULE_0__["Color3"].FromInts(72, 72, 72);
+        this.color = babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Color3"].FromInts(72, 72, 72);
         if (candidate) {
             this.x = parseFloat(candidate.style.left.replace("px", ""));
             this.y = parseFloat(candidate.style.top.replace("px", ""));
@@ -54300,6 +54283,7 @@ var GraphFrame = /** @class */ (function () {
                 this._headerCollapseElement.innerHTML = this.CollapseSVG;
                 this._headerCollapseElement.title = "Collapse";
             }
+            this.onExpandStateChanged.notifyObservers(this);
         },
         enumerable: true,
         configurable: true
@@ -54495,6 +54479,7 @@ var GraphFrame = /** @class */ (function () {
         }
         this.element.parentElement.removeChild(this.element);
         this._ownerCanvas.frames.splice(this._ownerCanvas.frames.indexOf(this), 1);
+        this.onExpandStateChanged.clear();
     };
     GraphFrame.prototype.serialize = function () {
         return {
@@ -54521,7 +54506,7 @@ var GraphFrame = /** @class */ (function () {
         newFrame.width = serializationData.width;
         newFrame.height = serializationData.height;
         newFrame.name = serializationData.name;
-        newFrame.color = babylonjs_Maths_math_color__WEBPACK_IMPORTED_MODULE_0__["Color3"].FromArray(serializationData.color);
+        newFrame.color = babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Color3"].FromArray(serializationData.color);
         if (serializationData.blocks && map) {
             var _loop_1 = function () {
                 var actualId = map[blockId];
@@ -55324,6 +55309,70 @@ var ClampPropertyTabComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./diagram/properties/framePropertyComponent.tsx":
+/*!*******************************************************!*\
+  !*** ./diagram/properties/framePropertyComponent.tsx ***!
+  \*******************************************************/
+/*! exports provided: FramePropertyTabComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FramePropertyTabComponent", function() { return FramePropertyTabComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../sharedComponents/lineContainerComponent */ "./sharedComponents/lineContainerComponent.tsx");
+/* harmony import */ var _sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../sharedComponents/color3LineComponent */ "./sharedComponents/color3LineComponent.tsx");
+/* harmony import */ var _sharedComponents_textInputLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../sharedComponents/textInputLineComponent */ "./sharedComponents/textInputLineComponent.tsx");
+/* harmony import */ var _sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../sharedComponents/buttonLineComponent */ "./sharedComponents/buttonLineComponent.tsx");
+
+
+
+
+
+
+var FramePropertyTabComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(FramePropertyTabComponent, _super);
+    function FramePropertyTabComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    FramePropertyTabComponent.prototype.componentDidMount = function () {
+        var _this = this;
+        this.onFrameExpandStateChangedObserver = this.props.frame.onExpandStateChanged.add(function () { return _this.forceUpdate(); });
+    };
+    FramePropertyTabComponent.prototype.componentWillUnmount = function () {
+        if (this.onFrameExpandStateChangedObserver) {
+            this.props.frame.onExpandStateChanged.remove(this.onFrameExpandStateChangedObserver);
+            this.onFrameExpandStateChangedObserver = null;
+        }
+    };
+    FramePropertyTabComponent.prototype.render = function () {
+        var _this = this;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "propertyTab" },
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "header" },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("img", { id: "logo", src: "https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { id: "title" }, "NODE MATERIAL EDITOR")),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { title: "GENERAL" },
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_textInputLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextInputLineComponent"], { globalState: this.props.globalState, label: "Name", propertyName: "name", target: this.props.frame }),
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_3__["Color3LineComponent"], { label: "Color", target: this.props.frame, propertyName: "color" }),
+                    !this.props.frame.isCollapsed &&
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_5__["ButtonLineComponent"], { label: "Collapse", onClick: function () {
+                                _this.props.frame.isCollapsed = true;
+                            } }),
+                    this.props.frame.isCollapsed &&
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_5__["ButtonLineComponent"], { label: "Expand", onClick: function () {
+                                _this.props.frame.isCollapsed = false;
+                            } })))));
+    };
+    return FramePropertyTabComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./diagram/properties/genericNodePropertyComponent.tsx":
 /*!*************************************************************!*\
   !*** ./diagram/properties/genericNodePropertyComponent.tsx ***!
@@ -56263,8 +56312,9 @@ var TrigonometryPropertyTabComponent = /** @class */ (function (_super) {
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_genericNodePropertyComponent__WEBPACK_IMPORTED_MODULE_5__["GenericPropertyTabComponent"], { globalState: this.props.globalState, block: this.props.block }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { title: "PROPERTIES" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_optionsLineComponent__WEBPACK_IMPORTED_MODULE_3__["OptionsLineComponent"], { label: "Operation", options: operationOptions, target: trigonometryBlock, propertyName: "operation", onSelect: function (value) {
-                        _this.forceUpdate();
+                        _this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         _this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                        _this.forceUpdate();
                     } }))));
     };
     return TrigonometryPropertyTabComponent;
@@ -57949,10 +57999,11 @@ var OptionsLineComponent = /** @class */ (function (_super) {
     };
     OptionsLineComponent.prototype.render = function () {
         var _this = this;
+        var _a;
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "listLine" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "label" }, this.props.label),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "options" + (this.props.className ? " " + this.props.className : "") },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("select", { onChange: function (evt) { return _this.updateValue(evt.target.value); }, value: this.state.value || "" }, this.props.options.map(function (option) {
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("select", { onChange: function (evt) { return _this.updateValue(evt.target.value); }, value: (_a = this.state.value, (_a !== null && _a !== void 0 ? _a : "")) }, this.props.options.map(function (option) {
                     return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("option", { key: option.label, value: option.value }, option.label));
                 })))));
     };

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


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

@@ -198,6 +198,7 @@ declare module "babylonjs-node-editor/diagram/graphFrame" {
     import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
     import { GraphCanvasComponent } from "babylonjs-node-editor/diagram/graphCanvas";
     import { Nullable } from 'babylonjs/types';
+    import { Observable } from 'babylonjs/Misc/observable';
     import { IFrameData } from "babylonjs-node-editor/nodeLocationInfo";
     import { Color3 } from 'babylonjs/Maths/math.color';
     export class GraphFrame {
@@ -229,6 +230,7 @@ declare module "babylonjs-node-editor/diagram/graphFrame" {
         private _ports;
         private _controlledPorts;
         private _id;
+        onExpandStateChanged: Observable<GraphFrame>;
         private readonly CloseSVG;
         private readonly ExpandSVG;
         private readonly CollapseSVG;
@@ -1294,6 +1296,22 @@ declare module "babylonjs-node-editor/components/nodeList/nodeListComponent" {
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-node-editor/diagram/properties/framePropertyComponent" {
+    import * as React from "react";
+    import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    export interface IFramePropertyTabComponentProps {
+        globalState: GlobalState;
+        frame: GraphFrame;
+    }
+    export class FramePropertyTabComponent extends React.Component<IFramePropertyTabComponentProps> {
+        private onFrameExpandStateChangedObserver;
+        constructor(props: IFramePropertyTabComponentProps);
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-node-editor/components/propertyTab/propertyTabComponent" {
     import * as React from "react";
     import { GlobalState } from "babylonjs-node-editor/globalState";
@@ -1641,6 +1659,7 @@ declare module NODEEDITOR {
         private _ports;
         private _controlledPorts;
         private _id;
+        onExpandStateChanged: BABYLON.Observable<GraphFrame>;
         private readonly CloseSVG;
         private readonly ExpandSVG;
         private readonly CollapseSVG;
@@ -2561,6 +2580,19 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IFramePropertyTabComponentProps {
+        globalState: GlobalState;
+        frame: GraphFrame;
+    }
+    export class FramePropertyTabComponent extends React.Component<IFramePropertyTabComponentProps> {
+        private onFrameExpandStateChangedObserver;
+        constructor(props: IFramePropertyTabComponentProps);
+        componentDidMount(): void;
+        componentWillUnmount(): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface IPropertyTabComponentProps {
         globalState: GlobalState;
     }

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

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

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

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

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

@@ -1 +1 @@
-{"thinEngineOnly":112287,"engineOnly":148378,"sceneOnly":502161,"minGridMaterial":632857,"minStandardMaterial":772848}
+{"thinEngineOnly":112302,"engineOnly":148393,"sceneOnly":502176,"minGridMaterial":632872,"minStandardMaterial":772862}

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

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

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

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

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

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

+ 571 - 158
dist/preview release/viewer/babylon.module.d.ts

@@ -11563,9 +11563,9 @@ declare module "babylonjs/sceneComponent" {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -19909,7 +19909,7 @@ declare module "babylonjs/Meshes/instancedMesh" {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -20310,7 +20310,6 @@ declare module "babylonjs/Meshes/linesMesh" {
     import { Material } from "babylonjs/Materials/material";
     import "babylonjs/Shaders/color.fragment";
     import "babylonjs/Shaders/color.vertex";
-    import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     /**
      * Line mesh
      * @see https://doc.babylonjs.com/babylon101/parametric_shapes
@@ -20392,7 +20391,7 @@ declare module "babylonjs/Meshes/linesMesh" {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -25455,7 +25454,7 @@ declare module "babylonjs/Meshes/mesh" {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -45280,7 +45279,6 @@ declare module "babylonjs/Cameras/XR/webXRController" {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -45406,6 +45404,8 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
     import { IWebXRFeature } from "babylonjs/Cameras/XR/webXRFeaturesManager";
     import { WebXRSessionManager } from "babylonjs/Cameras/XR/webXRSessionManager";
     import { WebXRInput } from "babylonjs/Cameras/XR/webXRInput";
+    import { WebXRController } from "babylonjs/Cameras/XR/webXRController";
+    import { Nullable } from "babylonjs/types";
     import { Color3 } from "babylonjs/Maths/math.color";
     /**
      * Options interface for the pointer selection module
@@ -45419,6 +45419,29 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -45439,11 +45462,11 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -45482,7 +45505,19 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerPointerSelection" {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -45722,6 +45757,15 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerTeleportation" {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -45824,6 +45868,7 @@ declare module "babylonjs/Cameras/XR/features/WebXRControllerTeleportation" {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -56396,6 +56441,219 @@ declare module "babylonjs/LensFlares/index" {
     export * from "babylonjs/LensFlares/lensFlareSystem";
     export * from "babylonjs/LensFlares/lensFlareSystemSceneComponent";
 }
+declare module "babylonjs/Shaders/depth.fragment" {
+    import "babylonjs/Shaders/ShadersInclude/packingFunctions";
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Shaders/depth.vertex" {
+    import "babylonjs/Shaders/ShadersInclude/bonesDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/instancesDeclaration";
+    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertex";
+    import "babylonjs/Shaders/ShadersInclude/instancesVertex";
+    import "babylonjs/Shaders/ShadersInclude/bonesVertex";
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Rendering/depthRenderer" {
+    import { Nullable } from "babylonjs/types";
+    import { SubMesh } from "babylonjs/Meshes/subMesh";
+    import { Scene } from "babylonjs/scene";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import "babylonjs/Shaders/depth.fragment";
+    import "babylonjs/Shaders/depth.vertex";
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module "babylonjs/Shaders/minmaxRedux.fragment" {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module "babylonjs/Misc/minMaxReducer" {
+    import { Nullable } from "babylonjs/types";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import { Observer } from "babylonjs/Misc/observable";
+    import { PostProcess } from "babylonjs/PostProcesses/postProcess";
+    import { PostProcessManager } from "babylonjs/PostProcesses/postProcessManager";
+    import { Observable } from "babylonjs/Misc/observable";
+    import "babylonjs/Shaders/minmaxRedux.fragment";
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module "babylonjs/Misc/depthReducer" {
+    import { Nullable } from "babylonjs/types";
+    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
+    import { Camera } from "babylonjs/Cameras/camera";
+    import { DepthRenderer } from "babylonjs/Rendering/depthRenderer";
+    import { MinMaxReducer } from "babylonjs/Misc/minMaxReducer";
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
 declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
     import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
@@ -56412,6 +56670,7 @@ declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
     import { IShadowGenerator } from "babylonjs/Lights/Shadows/shadowGenerator";
     import { DirectionalLight } from "babylonjs/Lights/directionalLight";
     import { BoundingInfo } from "babylonjs/Culling/boundingInfo";
+    import { DepthRenderer } from "babylonjs/Rendering/depthRenderer";
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -56770,6 +57029,38 @@ declare module "babylonjs/Lights/Shadows/cascadedShadowGenerator" {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -69461,20 +69752,6 @@ declare module "babylonjs/PostProcesses/tonemapPostProcess" {
         exposureAdjustment: number, camera: Camera, samplingMode?: number, engine?: Engine, textureFormat?: number);
     }
 }
-declare module "babylonjs/Shaders/depth.vertex" {
-    import "babylonjs/Shaders/ShadersInclude/bonesDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexGlobalDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertexDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/instancesDeclaration";
-    import "babylonjs/Shaders/ShadersInclude/morphTargetsVertex";
-    import "babylonjs/Shaders/ShadersInclude/instancesVertex";
-    import "babylonjs/Shaders/ShadersInclude/bonesVertex";
-    /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
 declare module "babylonjs/Shaders/volumetricLightScattering.fragment" {
     /** @hidden */
     export var volumetricLightScatteringPixelShader: {
@@ -69769,70 +70046,6 @@ declare module "babylonjs/Rendering/boundingBoxRenderer" {
         dispose(): void;
     }
 }
-declare module "babylonjs/Shaders/depth.fragment" {
-    import "babylonjs/Shaders/ShadersInclude/packingFunctions";
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module "babylonjs/Rendering/depthRenderer" {
-    import { Nullable } from "babylonjs/types";
-    import { SubMesh } from "babylonjs/Meshes/subMesh";
-    import { Scene } from "babylonjs/scene";
-    import { RenderTargetTexture } from "babylonjs/Materials/Textures/renderTargetTexture";
-    import { Camera } from "babylonjs/Cameras/camera";
-    import "babylonjs/Shaders/depth.fragment";
-    import "babylonjs/Shaders/depth.vertex";
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
 declare module "babylonjs/Rendering/depthRendererSceneComponent" {
     import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
@@ -72077,6 +72290,8 @@ declare module "babylonjs/Misc/index" {
     export * from "babylonjs/Misc/fileTools";
     export * from "babylonjs/Misc/stringTools";
     export * from "babylonjs/Misc/dataReader";
+    export * from "babylonjs/Misc/minMaxReducer";
+    export * from "babylonjs/Misc/depthReducer";
 }
 declare module "babylonjs/index" {
     export * from "babylonjs/abstractScene";
@@ -83593,9 +83808,9 @@ declare module BABYLON {
         static readonly STEP_AFTERCAMERADRAW_EFFECTLAYER_DRAW: number;
         static readonly STEP_AFTERCAMERADRAW_LAYER: number;
         static readonly STEP_AFTERRENDER_AUDIO: number;
-        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
-        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
         static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER: number;
+        static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR: number;
         static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER: number;
         static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER: number;
         static readonly STEP_POINTERMOVE_SPRITE: number;
@@ -91601,7 +91816,7 @@ declare module BABYLON {
          *
          * Returns the clone.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): InstancedMesh;
         /**
          * Disposes the InstancedMesh.
          * Returns nothing.
@@ -92051,7 +92266,7 @@ declare module BABYLON {
         /**
          * Returns a new LineMesh object cloned from the current one.
          */
-        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<AbstractMesh>;
+        clone(name: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean): LinesMesh;
         /**
          * Creates a new InstancedLinesMesh object from the mesh model.
          * @see http://doc.babylonjs.com/how_to/how_to_use_instances
@@ -96951,7 +97166,7 @@ declare module BABYLON {
          * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
          * @returns a new mesh
          */
-        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Nullable<AbstractMesh>;
+        clone(name?: string, newParent?: Nullable<Node>, doNotCloneChildren?: boolean, clonePhysicsImpostor?: boolean): Mesh;
         /**
          * Releases resources associated with this mesh.
          * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
@@ -115989,7 +116204,6 @@ declare module BABYLON {
          * Pointer which can be used to select objects or attach a visible laser to
          */
         pointer: AbstractMesh;
-        private _gamepadMode;
         /**
          * If available, this is the gamepad object related to this controller.
          * Using this object it is possible to get click events and trackpad changes of the
@@ -116119,6 +116333,29 @@ declare module BABYLON {
          * Different button type to use instead of the main component
          */
         overrideButtonId?: string;
+        /**
+         * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+         * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+         * 3000 means 3 seconds between pointing at something and selecting it
+         */
+        timeToSelect?: number;
+        /**
+         * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+         * If not disabled, the last picked point will be used to execute a pointer up event
+         * If disabled, pointer up event will be triggered right after the pointer down event.
+         * Used in screen and gaze target ray mode only
+         */
+        disablePointerUpOnTouchOut: boolean;
+        /**
+         * For gaze mode (time to select instead of press)
+         */
+        forceGazeMode: boolean;
+        /**
+         * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+         * to start a new countdown to the pointer down event.
+         * Defaults to 1.
+         */
+        gazeModePointerMovedFactor?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -116139,11 +116376,11 @@ declare module BABYLON {
         /**
          * This color will be set to the laser pointer when selection is triggered
          */
-        onPickedLaserPointerColor: Color3;
+        laserPointerPickedColor: Color3;
         /**
          * This color will be applied to the selection ring when selection is triggered
          */
-        onPickedSelectionMeshColor: Color3;
+        selectionMeshPickedColor: Color3;
         /**
          * default color of the selection ring
          */
@@ -116182,7 +116419,19 @@ declare module BABYLON {
          * @returns true if successful.
          */
         detach(): boolean;
+        /**
+         * Get the xr controller that correlates to the pointer id in the pointer event
+         *
+         * @param id the pointer id to search for
+         * @returns the controller that correlates to this id or null if not found
+         */
+        getXRControllerByPointerId(id: number): Nullable<WebXRController>;
         private _attachController;
+        private _attachScreenRayMode;
+        private _attachGazeMode;
+        private _tmpVectorForPickCompare;
+        private _pickingMoved;
+        private _attachTrackedPointerRayMode;
         private _detachController;
         private _generateNewMeshPair;
         private _convertNormalToDirectionOfRay;
@@ -116407,6 +116656,15 @@ declare module BABYLON {
              */
             disableAnimation?: boolean;
         };
+        /**
+         * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+         * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+         */
+        useMainComponentOnly?: boolean;
+        /**
+         * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+         */
+        timeToTeleport?: number;
     }
     /**
      * This is a teleportation feature to be used with webxr-enabled motion controllers.
@@ -116509,6 +116767,7 @@ declare module BABYLON {
         dispose(): void;
         private _currentTeleportationControllerId;
         private _attachController;
+        private _teleportForward;
         private _detachController;
         private createDefaultTargetMesh;
         private setTargetMeshVisibility;
@@ -126221,6 +126480,191 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /** @hidden */
+    export var depthPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /** @hidden */
+    export var depthVertexShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This represents a depth renderer in Babylon.
+     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
+     */
+    export class DepthRenderer {
+        private _scene;
+        private _depthMap;
+        private _effect;
+        private readonly _storeNonLinearDepth;
+        private readonly _clearColor;
+        /** Get if the depth renderer is using packed depth or not */
+        readonly isPacked: boolean;
+        private _cachedDefines;
+        private _camera;
+        /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+        enabled: boolean;
+        /**
+         * Specifiess that the depth renderer will only be used within
+         * the camera it is created for.
+         * This can help forcing its rendering during the camera processing.
+         */
+        useOnlyInActiveCamera: boolean;
+        /** @hidden */
+        static _SceneComponentInitialization: (scene: Scene) => void;
+        /**
+         * Instantiates a depth renderer
+         * @param scene The scene the renderer belongs to
+         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
+         * @param camera The camera to be used to render the depth map (default: scene's active camera)
+         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
+         */
+        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
+        /**
+         * Creates the depth rendering effect and checks if the effect is ready.
+         * @param subMesh The submesh to be used to render the depth map of
+         * @param useInstances If multiple world instances should be used
+         * @returns if the depth renderer is ready to render the depth map
+         */
+        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
+        /**
+         * Gets the texture which the depth map will be written to.
+         * @returns The depth map texture
+         */
+        getDepthMap(): RenderTargetTexture;
+        /**
+         * Disposes of the depth renderer.
+         */
+        dispose(): void;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
+    export var minmaxReduxPixelShader: {
+        name: string;
+        shader: string;
+    };
+}
+declare module BABYLON {
+    /**
+     * This class computes a min/max reduction from a texture: it means it computes the minimum
+     * and maximum values from all values of the texture.
+     * It is performed on the GPU for better performances, thanks to a succession of post processes.
+     * The source values are read from the red channel of the texture.
+     */
+    export class MinMaxReducer {
+        /**
+         * Observable triggered when the computation has been performed
+         */
+        onAfterReductionPerformed: Observable<{
+            min: number;
+            max: number;
+        }>;
+        protected _camera: Camera;
+        protected _sourceTexture: Nullable<RenderTargetTexture>;
+        protected _reductionSteps: Nullable<Array<PostProcess>>;
+        protected _postProcessManager: PostProcessManager;
+        protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+        protected _forceFullscreenViewport: boolean;
+        /**
+         * Creates a min/max reducer
+         * @param camera The camera to use for the post processes
+         */
+        constructor(camera: Camera);
+        /**
+         * Gets the texture used to read the values from.
+         */
+        get sourceTexture(): Nullable<RenderTargetTexture>;
+        /**
+         * Sets the source texture to read the values from.
+         * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+         * because in such textures '1' value must not be taken into account to compute the maximum
+         * as this value is used to clear the texture.
+         * Note that the computation is not activated by calling this function, you must call activate() for that!
+         * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+         * @param depthRedux Indicates if the texture is a depth texture or not
+         * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Defines the refresh rate of the computation.
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         */
+        get refreshRate(): number;
+        set refreshRate(value: number);
+        protected _activated: boolean;
+        /**
+         * Gets the activation status of the reducer
+         */
+        get activated(): boolean;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the min/max reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+     */
+    export class DepthReducer extends MinMaxReducer {
+        private _depthRenderer;
+        private _depthRendererId;
+        /**
+         * Gets the depth renderer used for the computation.
+         * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+         */
+        get depthRenderer(): Nullable<DepthRenderer>;
+        /**
+         * Creates a depth reducer
+         * @param camera The camera used to render the depth texture
+         */
+        constructor(camera: Camera);
+        /**
+         * Sets the depth renderer to use to generate the depth map
+         * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+         * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+         * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+         */
+        setDepthRenderer(depthRenderer?: Nullable<DepthRenderer>, type?: number, forceFullscreenViewport?: boolean): void;
+        /** @hidden */
+        setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type?: number, forceFullscreenViewport?: boolean): void;
+        /**
+         * Activates the reduction computation.
+         * When activated, the observers registered in onAfterReductionPerformed are
+         * called after the compuation is performed
+         */
+        activate(): void;
+        /**
+         * Deactivates the reduction computation.
+         */
+        deactivate(): void;
+        /**
+         * Disposes the depth reducer
+         * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+         */
+        dispose(disposeAll?: boolean): void;
+    }
+}
+declare module BABYLON {
     /**
      * A CSM implementation allowing casting shadows on large scenes.
      * Documentation : https://doc.babylonjs.com/babylon101/cascadedShadows
@@ -126579,6 +127023,38 @@ declare module BABYLON {
          * @returns the cascade view matrix
          */
         getCascadeViewMatrix(cascadeNum: number): Nullable<Matrix>;
+        private _depthRenderer;
+        /**
+         * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+         *
+         * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+         *
+         * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+         * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+         * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+         */
+        setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void;
+        private _depthReducer;
+        private _autoCalcDepthBounds;
+        /**
+         * Gets or sets the autoCalcDepthBounds property.
+         *
+         * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+         * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+         * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+         * It can greatly enhance the shadow quality, at the expense of more GPU works.
+         * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+         */
+        get autoCalcDepthBounds(): boolean;
+        set autoCalcDepthBounds(value: boolean);
+        /**
+         * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+         * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+         * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+         * for setting the refresh rate on the renderer yourself!
+         */
+        get autoCalcDepthBoundsRefreshRate(): number;
+        set autoCalcDepthBoundsRefreshRate(value: number);
         /**
          * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
          * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if
@@ -138195,13 +138671,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
-    export var depthVertexShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /** @hidden */
     export var volumetricLightScatteringPixelShader: {
         name: string;
         shader: string;
@@ -138426,62 +138895,6 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
-    /** @hidden */
-    export var depthPixelShader: {
-        name: string;
-        shader: string;
-    };
-}
-declare module BABYLON {
-    /**
-     * This represents a depth renderer in Babylon.
-     * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
-     */
-    export class DepthRenderer {
-        private _scene;
-        private _depthMap;
-        private _effect;
-        private readonly _storeNonLinearDepth;
-        private readonly _clearColor;
-        /** Get if the depth renderer is using packed depth or not */
-        readonly isPacked: boolean;
-        private _cachedDefines;
-        private _camera;
-        /**
-         * Specifiess that the depth renderer will only be used within
-         * the camera it is created for.
-         * This can help forcing its rendering during the camera processing.
-         */
-        useOnlyInActiveCamera: boolean;
-        /** @hidden */
-        static _SceneComponentInitialization: (scene: Scene) => void;
-        /**
-         * Instantiates a depth renderer
-         * @param scene The scene the renderer belongs to
-         * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
-         * @param camera The camera to be used to render the depth map (default: scene's active camera)
-         * @param storeNonLinearDepth Defines whether the depth is stored linearly like in Babylon Shadows or directly like glFragCoord.z
-         */
-        constructor(scene: Scene, type?: number, camera?: Nullable<Camera>, storeNonLinearDepth?: boolean);
-        /**
-         * Creates the depth rendering effect and checks if the effect is ready.
-         * @param subMesh The submesh to be used to render the depth map of
-         * @param useInstances If multiple world instances should be used
-         * @returns if the depth renderer is ready to render the depth map
-         */
-        isReady(subMesh: SubMesh, useInstances: boolean): boolean;
-        /**
-         * Gets the texture which the depth map will be written to.
-         * @returns The depth map texture
-         */
-        getDepthMap(): RenderTargetTexture;
-        /**
-         * Disposes of the depth renderer.
-         */
-        dispose(): void;
-    }
-}
-declare module BABYLON {
         interface Scene {
             /** @hidden (Backing field) */
             _depthRenderer: {

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 36 - 24
dist/preview release/viewer/babylon.viewer.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -53,6 +53,7 @@
 - PNG support for browsers not supporting SVG ([RaananW](https://github.com/RaananW/))
 - Device orientation event permissions for iOS 13+ ([RaananW](https://github.com/RaananW/))
 - Added `DirectionalLight.autoCalcShadowZBounds` to automatically compute the `shadowMinZ` and `shadowMaxZ` values ([Popov72](https://github.com/Popov72))
+- Added `CascadedShadowGenerator.autoCalcDepthBounds` to improve the shadow quality rendering ([Popov72](https://github.com/Popov72))
 - Improved cascade blending in CSM shadow technic ([Popov72](https://github.com/Popov72))
 
 ### Engine
@@ -188,6 +189,8 @@
 - Teleportation and controller selection are now WebXR features. ([#7290](https://github.com/BabylonJS/Babylon.js/issues/7290)) ([RaananW](https://github.com/RaananW/))
 - Teleportation allows selecting direction before teleporting when using thumbstick/touchpad. ([#7290](https://github.com/BabylonJS/Babylon.js/issues/7290)) ([RaananW](https://github.com/RaananW/))
 - It is now possible to force a certain profile type for the controllers ([#7348](https://github.com/BabylonJS/Babylon.js/issues/7375)) ([RaananW](https://github.com/RaananW/))
+- WebXR camera is initialized on the first frame ([#7389](https://github.com/BabylonJS/Babylon.js/issues/7389)) ([RaananW](https://github.com/RaananW/))
+- Selection has forcable gaze mode and touch-screen support ([#7395](https://github.com/BabylonJS/Babylon.js/issues/7395)) ([RaananW](https://github.com/RaananW/))
 
 ### Ray
 
@@ -281,6 +284,8 @@
 - Fixed issue where textures exported using Safari web browser are Y mirrored. ([#7352](https://github.com/BabylonJS/Babylon.js/issues/7352)) ([Drigax](https://github.com/drigax))
 - Fix a bug when resizing a MRT ([Popov72](https://github.com/Popov72))
 - Fixed an infinite clone recursion bug in `InstancedMesh` due to `DeepCopier.DeepCopy` cloning `parent` ([Poolminer](https://github.com/Poolminer/))
+- Fixed an issue with multiview textures ([RaananW](https://github.com/RaananW/))
+- Screenshot height and width is now forced to be integers to prevent mismatch with openGL context ([jekelija](https://github.com/jekelija))
 
 ## Breaking changes
 

+ 3 - 2
loaders/src/OBJ/objFileLoader.ts

@@ -813,14 +813,14 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
 
                 //If this new material is in the same mesh
 
-                if (!isFirstMaterial) {
+                if (!isFirstMaterial || !hasMeshes) {
                     //Set the data for the previous mesh
                     addPreviousObjMesh();
                     //Create a new mesh
                     var objMesh: MeshObject =
                     //Set the name of the current obj mesh
                     {
-                        name: objMeshName + "_mm" + increment.toString(), //Set the name of the current obj mesh
+                        name: (objMeshName || "mesh") + "_mm" + increment.toString(), //Set the name of the current obj mesh
                         indices: undefined,
                         positions: undefined,
                         normals: undefined,
@@ -831,6 +831,7 @@ export class OBJFileLoader implements ISceneLoaderPluginAsync, ISceneLoaderPlugi
                     increment++;
                     //If meshes are already defined
                     meshesFromObj.push(objMesh);
+                    hasMeshes = true;
                 }
                 //Set the material name if the previous line define a mesh
 

+ 2 - 35
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -13,10 +13,9 @@ import { DataStorage } from '../../dataStorage';
 import { GraphNode } from '../../diagram/graphNode';
 import { SliderLineComponent } from '../../sharedComponents/sliderLineComponent';
 import { GraphFrame } from '../../diagram/graphFrame';
-import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
-import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
+import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
@@ -24,7 +23,6 @@ interface IPropertyTabComponentProps {
 }
 
 export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame> }> {
-
     constructor(props: IPropertyTabComponentProps) {
         super(props)
 
@@ -82,41 +80,10 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
 
         if (this.state.currentFrame) {
             return (
-                <div id="propertyTab">
-                    <div id="header">
-                        <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
-                        <div id="title">
-                            NODE MATERIAL EDITOR
-                        </div>
-                    </div>
-                    <div>
-                        <LineContainerComponent title="GENERAL">
-                            <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.state.currentFrame} />
-                            <Color3LineComponent label="Color" target={this.state.currentFrame} propertyName="color"></Color3LineComponent>
-                            {
-                                !this.state.currentFrame.isCollapsed &&
-                                <ButtonLineComponent label="Collapse" onClick={() => {
-                                        this.state.currentFrame!.isCollapsed = true;
-                                        this.forceUpdate();
-                                    }} />
-                            }
-                            {
-                                this.state.currentFrame.isCollapsed &&
-                                <ButtonLineComponent label="Expand" onClick={() => {
-                                        this.state.currentFrame!.isCollapsed = false;
-                                        this.forceUpdate();
-                                    }} />
-                            }
-                            {/* <ButtonLineComponent label="Export" onClick={() => {
-                                        this.state.currentFrame!.export();
-                                    }} /> */}
-                        </LineContainerComponent>
-                    </div>
-                </div>
+                <FramePropertyTabComponent globalState={this.props.globalState} frame={this.state.currentFrame}/>
             );
         }
 
-
         let gridSize = DataStorage.ReadNumber("GridSize", 20);
 
         return (

+ 7 - 2
nodeEditor/src/diagram/graphFrame.ts

@@ -1,7 +1,7 @@
 import { GraphNode } from './graphNode';
 import { GraphCanvasComponent } from './graphCanvas';
 import { Nullable } from 'babylonjs/types';
-import { Observer } from 'babylonjs/Misc/observable';
+import { Observer, Observable } from 'babylonjs/Misc/observable';
 import { NodeLink } from './nodeLink';
 import { IFrameData } from '../nodeLocationInfo';
 import { Color3 } from 'babylonjs/Maths/math.color';
@@ -39,6 +39,8 @@ export class GraphFrame {
     private _controlledPorts: NodePort[] = [];
     private _id: number;
 
+    public onExpandStateChanged = new Observable<GraphFrame>();
+
     private readonly CloseSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M16,15l5.85,5.84-1,1L15,15.93,9.15,21.78l-1-1L14,15,8.19,9.12l1-1L15,14l5.84-5.84,1,1Z"/></g></svg>`;
     private readonly ExpandSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-6.75,6.75H11.06V14.44h3.38V11.06h1.12v3.38h3.38v1.12H15.56v3.38H14.44Z"/></g></svg>`;
     private readonly CollapseSVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><g id="Layer_2" data-name="Layer 2"><path d="M22.31,7.69V22.31H7.69V7.69ZM21.19,8.81H8.81V21.19H21.19Zm-2.25,6.75H11.06V14.44h7.88Z"/></g></svg>`;
@@ -152,6 +154,8 @@ export class GraphFrame {
             this._headerCollapseElement.innerHTML = this.CollapseSVG;
             this._headerCollapseElement.title = "Collapse";   
         }
+
+        this.onExpandStateChanged.notifyObservers(this);
     }
 
     public get nodes() {
@@ -452,9 +456,10 @@ export class GraphFrame {
         }
 
         this.element.parentElement!.removeChild(this.element);
-
         
         this._ownerCanvas.frames.splice(this._ownerCanvas.frames.indexOf(this), 1);
+
+        this.onExpandStateChanged.clear();
     }
 
     public serialize(): IFrameData {

+ 69 - 0
nodeEditor/src/diagram/properties/framePropertyComponent.tsx

@@ -0,0 +1,69 @@
+
+import * as React from "react";
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { GraphFrame } from '../graphFrame';
+import { GlobalState } from '../../globalState';
+import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
+import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
+import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
+import { Nullable } from 'babylonjs/types';
+import { Observer } from 'babylonjs/Misc/observable';
+
+export interface IFramePropertyTabComponentProps {
+    globalState: GlobalState
+    frame: GraphFrame;
+}
+
+export class FramePropertyTabComponent extends React.Component<IFramePropertyTabComponentProps> {
+    private onFrameExpandStateChangedObserver: Nullable<Observer<GraphFrame>>;
+
+    constructor(props: IFramePropertyTabComponentProps) {
+        super(props)
+    }
+
+
+    componentDidMount() {
+        this.onFrameExpandStateChangedObserver = this.props.frame.onExpandStateChanged.add(() => this.forceUpdate());
+    }
+
+    componentWillUnmount() {
+        if (this.onFrameExpandStateChangedObserver) {
+            this.props.frame.onExpandStateChanged.remove(this.onFrameExpandStateChangedObserver);
+            this.onFrameExpandStateChangedObserver = null;
+        }
+    }    
+
+    render() {      
+        return (
+            <div id="propertyTab">
+            <div id="header">
+                <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                <div id="title">
+                    NODE MATERIAL EDITOR
+                </div>
+            </div>
+            <div>
+                <LineContainerComponent title="GENERAL">
+                    <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.frame} />
+                    <Color3LineComponent label="Color" target={this.props.frame} propertyName="color"></Color3LineComponent>
+                    {
+                        !this.props.frame.isCollapsed &&
+                        <ButtonLineComponent label="Collapse" onClick={() => {
+                                this.props.frame!.isCollapsed = true;
+                            }} />
+                    }
+                    {
+                        this.props.frame.isCollapsed &&
+                        <ButtonLineComponent label="Expand" onClick={() => {
+                                this.props.frame!.isCollapsed = false;
+                            }} />
+                    }
+                    {/* <ButtonLineComponent label="Export" onClick={() => {
+                                this.state.currentFrame!.export();
+                            }} /> */}
+                </LineContainerComponent>
+            </div>
+        </div>
+        );
+    }
+}

+ 2 - 1
nodeEditor/src/diagram/properties/trigonometryNodePropertyComponent.tsx

@@ -44,8 +44,9 @@ export class TrigonometryPropertyTabComponent extends React.Component<IPropertyC
                 <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">  
                     <OptionsLineComponent label="Operation" options={operationOptions} target={trigonometryBlock} propertyName="operation" onSelect={(value: any) => {
-                        this.forceUpdate();
+                        this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                        this.forceUpdate();
                     }} />                  
                 </LineContainerComponent>
             </div>

+ 1 - 1
nodeEditor/src/sharedComponents/optionsLineComponent.tsx

@@ -90,7 +90,7 @@ export class OptionsLineComponent extends React.Component<IOptionsLineComponentP
 
                 </div>
                 <div className={"options" + (this.props.className ? " " + this.props.className : "")}>
-                    <select onChange={evt => this.updateValue(evt.target.value)} value={this.state.value || ""}>
+                    <select onChange={evt => this.updateValue(evt.target.value)} value={this.state.value ?? ""}>
                         {
                             this.props.options.map(option => {
                                 return (

+ 1 - 1
package.json

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

+ 178 - 17
src/Cameras/XR/features/WebXRControllerPointerSelection.ts

@@ -30,6 +30,32 @@ export interface IWebXRControllerPointerSelectionOptions {
      * Different button type to use instead of the main component
      */
     overrideButtonId?: string;
+    /**
+     * The amount of time in miliseconds it takes between pick found something to a pointer down event.
+     * Used in gaze modes. Tracked pointer uses the trigger, screen uses touch events
+     * 3000 means 3 seconds between pointing at something and selecting it
+     */
+    timeToSelect?: number;
+
+    /**
+     * Disable the pointer up event when the xr controller in screen and gaze mode is disposed (meaning - when the user removed the finger from the screen)
+     * If not disabled, the last picked point will be used to execute a pointer up event
+     * If disabled, pointer up event will be triggered right after the pointer down event.
+     * Used in screen and gaze target ray mode only
+     */
+    disablePointerUpOnTouchOut: boolean;
+
+    /**
+     * For gaze mode (time to select instead of press)
+     */
+    forceGazeMode: boolean;
+
+    /**
+     * Factor to be applied to the pointer-moved function in the gaze mode. How sensitive should the gaze mode be when checking if the pointer moved
+     * to start a new countdown to the pointer down event.
+     * Defaults to 1.
+     */
+    gazeModePointerMovedFactor?: number;
 }
 
 /**
@@ -51,11 +77,11 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
     /**
      * This color will be set to the laser pointer when selection is triggered
      */
-    public onPickedLaserPointerColor: Color3 = new Color3(0.7, 0.7, 0.7);
+    public laserPointerPickedColor: Color3 = new Color3(0.7, 0.7, 0.7);
     /**
      * This color will be applied to the selection ring when selection is triggered
      */
-    public onPickedSelectionMeshColor: Color3 = new Color3(0.7, 0.7, 0.7);
+    public selectionMeshPickedColor: Color3 = new Color3(0.7, 0.7, 0.7);
     /**
      * default color of the selection ring
      */
@@ -76,6 +102,7 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
             xrController: WebXRController;
             selectionComponent?: WebXRControllerComponent;
             onButtonChangedObserver?: Nullable<Observer<WebXRControllerComponent>>;
+            onFrameObserver?: Nullable<Observer<XRFrame>>;
             laserPointer: AbstractMesh;
             selectionMesh: AbstractMesh;
             pick: Nullable<PickingInfo>;
@@ -124,14 +151,6 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
                 controllerData.xrController.getWorldPointerRayToRef(this._tmpRay);
                 controllerData.pick = this._scene.pickWithRay(this._tmpRay);
 
-                if (controllerData.selectionComponent && controllerData.selectionComponent.pressed) {
-                    (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.onPickedSelectionMeshColor;
-                    (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.onPickedLaserPointerColor;
-                } else {
-                    (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshDefaultColor;
-                    (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.lasterPointerDefaultColor;
-                }
-
                 const pick = controllerData.pick;
 
                 if (pick && pick.pickedPoint && pick.hit) {
@@ -187,17 +206,29 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
         return true;
     }
 
-    private _attachController = (xrController: WebXRController) => {
-        // only support tracker pointer
-        if (xrController.inputSource.targetRayMode !== "tracked-pointer") {
-            return;
+    /**
+     * Get the xr controller that correlates to the pointer id in the pointer event
+     *
+     * @param id the pointer id to search for
+     * @returns the controller that correlates to this id or null if not found
+     */
+    public getXRControllerByPointerId(id: number): Nullable<WebXRController> {
+        const keys = Object.keys(this._controllers);
+
+        for (let i = 0; i < keys.length; ++i) {
+            if (this._controllers[keys[i]].id === id) {
+                return this._controllers[keys[i]].xrController;
+            }
         }
+        return null;
+    }
 
-        if (this._controllers[xrController.uniqueId] || !xrController.gamepadController) {
+    private _attachController = (xrController: WebXRController) => {
+        if (this._controllers[xrController.uniqueId]) {
             // already attached
             return;
         }
-
+        // only support tracker pointer
         const { laserPointer, selectionMesh } = this._generateNewMeshPair(xrController);
 
         // get two new meshes
@@ -208,6 +239,124 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
             pick: null,
             id: WebXRControllerPointerSelection._idCounter++
         };
+        switch (xrController.inputSource.targetRayMode) {
+            case "tracked-pointer":
+                return this._attachTrackedPointerRayMode(xrController);
+            case "gaze":
+                return this._attachGazeMode(xrController);
+            case "screen":
+                return this._attachScreenRayMode(xrController);
+        }
+    }
+
+    private _attachScreenRayMode(xrController: WebXRController) {
+        const controllerData = this._controllers[xrController.uniqueId];
+        let downTriggered = false;
+        controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
+            if (!controllerData.pick || (this._options.disablePointerUpOnTouchOut && downTriggered)) { return; }
+            if (!downTriggered) {
+                this._scene.simulatePointerDown(controllerData.pick, { pointerId: controllerData.id });
+                downTriggered = true;
+                if (this._options.disablePointerUpOnTouchOut) {
+                    this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+                }
+            } else {
+                this._scene.simulatePointerMove(controllerData.pick, { pointerId: controllerData.id });
+            }
+        });
+        xrController.onDisposeObservable.addOnce(() => {
+            if (controllerData.pick && downTriggered && !this._options.disablePointerUpOnTouchOut) {
+                this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+            }
+        });
+    }
+
+    private _attachGazeMode(xrController: WebXRController) {
+        const controllerData = this._controllers[xrController.uniqueId];
+        // attached when touched, detaches when raised
+        const timeToSelect = this._options.timeToSelect || 3000;
+        let oldPick = new PickingInfo();
+        let discMesh = TorusBuilder.CreateTorus("selection", {
+            diameter: 0.0035 * 15,
+            thickness: 0.0025 * 6,
+            tessellation: 20
+        }, this._scene);
+        discMesh.isVisible = false;
+        discMesh.isPickable = false;
+        discMesh.parent = controllerData.selectionMesh;
+        let timer = 0;
+        let downTriggered = false;
+        controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
+            if (!controllerData.pick) { return; }
+            discMesh.isVisible = false;
+            if (controllerData.pick.hit) {
+                if (!this._pickingMoved(oldPick, controllerData.pick)) {
+                    if (timer > timeToSelect / 10) {
+                        discMesh.isVisible = true;
+                    }
+
+                    timer += this._scene.getEngine().getDeltaTime();
+                    if (timer >= timeToSelect) {
+                        this._scene.simulatePointerDown(controllerData.pick, { pointerId: controllerData.id });
+                        downTriggered = true;
+                        // pointer up right after down, if disable on touch out
+                        if (this._options.disablePointerUpOnTouchOut) {
+                            this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+                        } else {
+                            this._scene.simulatePointerMove(controllerData.pick, { pointerId: controllerData.id });
+                        }
+                        discMesh.isVisible = false;
+                    } else {
+                        const scaleFactor = 1 - (timer / timeToSelect);
+                        discMesh.scaling.set(scaleFactor, scaleFactor, scaleFactor);
+                    }
+                } else {
+                    if (downTriggered) {
+                        if (!this._options.disablePointerUpOnTouchOut) {
+                            this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+                        }
+                    }
+                    downTriggered = false;
+                    timer = 0;
+                }
+            } else {
+                downTriggered = false;
+                timer = 0;
+            }
+
+            oldPick = controllerData.pick;
+        });
+        xrController.onDisposeObservable.addOnce(() => {
+            if (controllerData.pick && !this._options.disablePointerUpOnTouchOut && downTriggered) {
+                this._scene.simulatePointerUp(controllerData.pick, { pointerId: controllerData.id });
+            }
+            discMesh.dispose();
+        });
+    }
+    private _tmpVectorForPickCompare = new Vector3();
+
+    private _pickingMoved(oldPick: PickingInfo, newPick: PickingInfo) {
+        if (!oldPick.hit || !newPick.hit) { return true; }
+        if (!oldPick.pickedMesh || !oldPick.pickedPoint || !newPick.pickedMesh || !newPick.pickedPoint) { return true; }
+        if (oldPick.pickedMesh !== newPick.pickedMesh) { return true; }
+        oldPick.pickedPoint?.subtractToRef(newPick.pickedPoint, this._tmpVectorForPickCompare);
+        this._tmpVectorForPickCompare.set(Math.abs(this._tmpVectorForPickCompare.x), Math.abs(this._tmpVectorForPickCompare.y), Math.abs(this._tmpVectorForPickCompare.z));
+        const delta = (this._options.gazeModePointerMovedFactor || 1) * 0.01 / newPick.distance;
+        const length = this._tmpVectorForPickCompare.length();
+        if (length > delta) { return true; }
+        return false;
+
+    }
+
+    private _attachTrackedPointerRayMode(xrController: WebXRController) {
+        if (!xrController.gamepadController) {
+            return;
+        }
+
+        if (this._options.forceGazeMode) {
+            return this._attachGazeMode(xrController);
+        }
+
         const controllerData = this._controllers[xrController.uniqueId];
 
         if (this._options.overrideButtonId) {
@@ -219,6 +368,16 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
 
         let observer: Nullable<Observer<XRFrame>> = null;
 
+        controllerData.onFrameObserver = this._xrSessionManager.onXRFrameObservable.add(() => {
+            if (controllerData.selectionComponent && controllerData.selectionComponent.pressed) {
+                (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshPickedColor;
+                (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.laserPointerPickedColor;
+            } else {
+                (<StandardMaterial>controllerData.selectionMesh.material).emissiveColor = this.selectionMeshDefaultColor;
+                (<StandardMaterial>controllerData.laserPointer.material).emissiveColor = this.lasterPointerDefaultColor;
+            }
+        });
+
         controllerData.onButtonChangedObserver = controllerData.selectionComponent.onButtonStateChanged.add((component) => {
             if (component.changes.pressed) {
                 const pressed = component.changes.pressed.current;
@@ -237,7 +396,6 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
                 }
             }
         });
-
     }
 
     private _detachController(xrControllerUniqueId: string) {
@@ -248,6 +406,9 @@ export class WebXRControllerPointerSelection implements IWebXRFeature {
                 controllerData.selectionComponent.onButtonStateChanged.remove(controllerData.onButtonChangedObserver);
             }
         }
+        if (controllerData.onFrameObserver) {
+            this._xrSessionManager.onXRFrameObservable.remove(controllerData.onFrameObserver);
+        }
         controllerData.selectionMesh.dispose();
         controllerData.laserPointer.dispose();
         // remove from the map

+ 64 - 10
src/Cameras/XR/features/WebXRControllerTeleportation.ts

@@ -65,6 +65,17 @@ export interface IWebXRTeleportationOptions {
          */
         disableAnimation?: boolean;
     };
+
+    /**
+     * Disable using the thumbstick and use the main component (usuallly trigger) on long press.
+     * This will be automatically true if the controller doesnt have a thumbstick or touchpad.
+     */
+    useMainComponentOnly?: boolean;
+
+    /**
+     * If main component is used (no thumbstick), how long should the "long press" take before teleporting
+     */
+    timeToTeleport?: number;
 }
 
 /**
@@ -325,20 +336,48 @@ export class WebXRMotionControllerTeleportation implements IWebXRFeature {
         // motion controller support
         if (xrController.gamepadController) {
             const movementController = xrController.gamepadController.getComponent(WebXRControllerComponent.THUMBSTICK) || xrController.gamepadController.getComponent(WebXRControllerComponent.TOUCHPAD);
-            if (!movementController) {
+            if (!movementController || this._options.useMainComponentOnly) {
                 // use trigger to move on long press
+                const mainComponent = xrController.gamepadController.getMainComponent();
+                if (!mainComponent) {
+                    return;
+                }
+                controllerData.onButtonChangedObserver = mainComponent.onButtonStateChanged.add(() => {
+                    // did "pressed" changed?
+                    if (mainComponent.changes.pressed) {
+                        if (mainComponent.changes.pressed.current) {
+                            // simulate "forward" thumbstick push
+                            controllerData.teleportationState.forward = true;
+                            this._currentTeleportationControllerId = controllerData.xrController.uniqueId;
+                            controllerData.teleportationState.baseRotation = this._options.xrInput.xrCamera.rotationQuaternion.toEulerAngles().y;
+                            controllerData.teleportationState.currentRotation = 0;
+                            const timeToSelect = this._options.timeToTeleport || 3000;
+                            let timer = 0;
+                            const observer = this._xrSessionManager.onXRFrameObservable.add(() => {
+                                if (!mainComponent.pressed) {
+                                    this._xrSessionManager.onXRFrameObservable.remove(observer);
+                                    return;
+                                }
+                                timer += this._xrSessionManager.scene.getEngine().getDeltaTime();
+                                if (timer >= timeToSelect && this._currentTeleportationControllerId === controllerData.xrController.uniqueId && controllerData.teleportationState.forward) {
+                                    this._teleportForward(xrController.uniqueId);
+                                }
+
+                                // failsafe
+                                if (timer >= timeToSelect) {
+                                    this._xrSessionManager.onXRFrameObservable.remove(observer);
+                                }
+                            });
+                        } else {
+                            controllerData.teleportationState.forward = false;
+                            this._currentTeleportationControllerId = "";
+                        }
+                    }
+                });
             } else {
                 controllerData.onButtonChangedObserver = movementController.onButtonStateChanged.add(() => {
                     if (this._currentTeleportationControllerId === controllerData.xrController.uniqueId && controllerData.teleportationState.forward && !movementController.touched) {
-                        controllerData.teleportationState.forward = false;
-                        this._currentTeleportationControllerId = "";
-                        // do the movement forward here
-                        if (this._options.teleportationTargetMesh && this._options.teleportationTargetMesh.isVisible) {
-                            const height = this._options.xrInput.xrCamera.position.y - this._options.teleportationTargetMesh.position.y;
-                            this._options.xrInput.xrCamera.position.copyFrom(this._options.teleportationTargetMesh.position);
-                            this._options.xrInput.xrCamera.position.y += height;
-                            this._options.xrInput.xrCamera.rotationQuaternion.multiplyInPlace(Quaternion.FromEulerAngles(0, controllerData.teleportationState.currentRotation, 0));
-                        }
+                        this._teleportForward(xrController.uniqueId);
                     }
                 });
                 // use thumbstick (or touchpad if thumbstick not available)
@@ -390,6 +429,8 @@ export class WebXRMotionControllerTeleportation implements IWebXRFeature {
                                     setTimeout(() => {
                                         controllerData.teleportationState.currentRotation = Math.atan2(axesData.x, -axesData.y);
                                     });
+                                } else {
+                                    controllerData.teleportationState.currentRotation = 0;
                                 }
                             }
                         }
@@ -401,6 +442,19 @@ export class WebXRMotionControllerTeleportation implements IWebXRFeature {
         }
     }
 
+    private _teleportForward(controllerId: string) {
+        const controllerData = this._controllers[controllerId];
+        controllerData.teleportationState.forward = false;
+        this._currentTeleportationControllerId = "";
+        // do the movement forward here
+        if (this._options.teleportationTargetMesh && this._options.teleportationTargetMesh.isVisible) {
+            const height = this._options.xrInput.xrCamera.position.y - this._options.teleportationTargetMesh.position.y;
+            this._options.xrInput.xrCamera.position.copyFrom(this._options.teleportationTargetMesh.position);
+            this._options.xrInput.xrCamera.position.y += height;
+            this._options.xrInput.xrCamera.rotationQuaternion.multiplyInPlace(Quaternion.FromEulerAngles(0, controllerData.teleportationState.currentRotation, 0));
+        }
+    }
+
     private _detachController(xrControllerUniqueId: string) {
         const controllerData = this._controllers[xrControllerUniqueId];
         if (!controllerData) { return; }

+ 9 - 10
src/Cameras/XR/webXRCamera.ts

@@ -43,14 +43,16 @@ export class WebXRCamera extends FreeCamera {
             this._referenceQuaternion.copyFromFloats(0, 0, 0, 1);
             // first frame - camera's y position should be 0 for the correct offset
             this._firstFrame = true;
+
         });
 
         // Check transformation changes on each frame. Callback is added to be first so that the transformation will be
         // applied to the rest of the elements using the referenceSpace object
         this._xrSessionManager.onXRFrameObservable.add((frame) => {
-            if (!this._firstFrame) {
-                this._updateReferenceSpace();
+            if (this._firstFrame) {
+                this._updateFromXRSession();
             }
+            this._updateReferenceSpace();
             this._updateFromXRSession();
         }, undefined, true);
     }
@@ -83,16 +85,14 @@ export class WebXRCamera extends FreeCamera {
         this.rigCameras[1].outputRenderTarget = null;
     }
 
-    private _updateReferenceSpace(): boolean {
+    private _updateReferenceSpace() {
         // were position & rotation updated OUTSIDE of the xr update loop
         if (!this.position.equals(this._referencedPosition) || !this.rotationQuaternion.equals(this._referenceQuaternion)) {
             this.position.subtractToRef(this._referencedPosition, this._referencedPosition);
             this._referenceQuaternion.conjugateInPlace();
             this._referenceQuaternion.multiplyToRef(this.rotationQuaternion, this._referenceQuaternion);
             this._updateReferenceSpaceOffset(this._referencedPosition, this._referenceQuaternion.normalize());
-            return true;
         }
-        return false;
     }
 
     private _updateReferenceSpaceOffset(positionOffset: Vector3, rotationOffset?: Quaternion, ignoreHeight: boolean = false) {
@@ -180,12 +180,11 @@ export class WebXRCamera extends FreeCamera {
                 this._referenceQuaternion.copyFromFloats(0, 0, 0, 1);
                 // update the reference space so that the position will be correct
 
-                return this.update();
-
             }
-
-            this.rotationQuaternion.copyFrom(this._referenceQuaternion);
-            this.position.copyFrom(this._referencedPosition);
+            else {
+                this.rotationQuaternion.copyFrom(this._referenceQuaternion);
+                this.position.copyFrom(this._referencedPosition);
+            }
         }
 
         // Update camera rigs

+ 1 - 3
src/Cameras/XR/webXRController.ts

@@ -20,8 +20,6 @@ export class WebXRController {
      * Pointer which can be used to select objects or attach a visible laser to
      */
     public pointer: AbstractMesh;
-
-    private _gamepadMode = false;
     /**
      * If available, this is the gamepad object related to this controller.
      * Using this object it is possible to get click events and trackpad changes of the
@@ -145,7 +143,7 @@ export class WebXRController {
         if (this.grip) {
             this.grip.dispose();
         }
-        if (this.gamepadController && this._gamepadMode) {
+        if (this.gamepadController) {
             this.gamepadController.dispose();
         }
         this.pointer.dispose();

+ 15 - 18
src/Cameras/XR/webXRFeaturesManager.ts

@@ -183,27 +183,24 @@ export class WebXRFeaturesManager implements IDisposable {
         }
         // check if already initialized
         const feature = this._features[name];
-        if (!feature || !feature.featureImplementation || feature.version !== versionToLoad) {
-            const constructFunction = WebXRFeaturesManager.ConstructFeature(name, versionToLoad, this._xrSessionManager, moduleOptions);
-            if (!constructFunction) {
-                // report error?
-                throw new Error(`feature not found - ${name}`);
-            }
-
-            if (feature) {
-                this.disableFeature(name);
-            }
+        const constructFunction = WebXRFeaturesManager.ConstructFeature(name, versionToLoad, this._xrSessionManager, moduleOptions);
+        if (!constructFunction) {
+            // report error?
+            throw new Error(`feature not found - ${name}`);
+        }
 
-            this._features[name] = {
-                featureImplementation: constructFunction(),
-                enabled: true,
-                version: versionToLoad
-            };
-        } else {
-            // make sure it is enabled now:
-            feature.enabled = true;
+        /* If the feature is already enabled, detach and dispose it, and create a new one */
+        if (feature) {
+            this.disableFeature(name);
+            feature.featureImplementation.dispose();
         }
 
+        this._features[name] = {
+            featureImplementation: constructFunction(),
+            enabled: true,
+            version: versionToLoad
+        };
+
         // if session started already, request and enable
         if (this._xrSessionManager.session && !feature.featureImplementation.attached && attachIfPossible) {
             // enable feature

+ 3 - 3
src/Engines/thinEngine.ts

@@ -132,14 +132,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.1.0-beta.18";
+        return "babylonjs@4.1.0-beta.20";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.1.0-beta.18";
+        return "4.1.0-beta.20";
     }
 
     /**
@@ -3094,7 +3094,7 @@ export class ThinEngine {
             return this._gl.TEXTURE_CUBE_MAP;
         } else if (texture.is3D) {
             return this._gl.TEXTURE_3D;
-        } else if (texture.is2DArray) {
+        } else if (texture.is2DArray || texture.isMultiview) {
             return this._gl.TEXTURE_2D_ARRAY;
         }
         return this._gl.TEXTURE_2D;

+ 85 - 0
src/Lights/Shadows/cascadedShadowGenerator.ts

@@ -27,6 +27,8 @@ import { IShadowGenerator } from './shadowGenerator';
 import { DirectionalLight } from '../directionalLight';
 
 import { BoundingInfo } from '../../Culling/boundingInfo';
+import { DepthRenderer } from '../../Rendering/depthRenderer';
+import { DepthReducer } from '../../Misc/depthReducer';
 
 interface ICascade {
     prevBreakDistance: number;
@@ -708,6 +710,89 @@ export class CascadedShadowGenerator implements IShadowGenerator {
         return cascadeNum >= 0 && cascadeNum < this._numCascades ? this._viewMatrices[cascadeNum] : null;
     }
 
+    private _depthRenderer: Nullable<DepthRenderer>;
+    /**
+     * Sets the depth renderer to use when autoCalcDepthBounds is enabled.
+     *
+     * Note that if no depth renderer is set, a new one will be automatically created internally when necessary.
+     *
+     * You should call this function if you already have a depth renderer enabled in your scene, to avoid
+     * doing multiple depth rendering each frame. If you provide your own depth renderer, make sure it stores linear depth!
+     * @param depthRenderer The depth renderer to use when autoCalcDepthBounds is enabled. If you pass null or don't call this function at all, a depth renderer will be automatically created
+     */
+    public setDepthRenderer(depthRenderer: Nullable<DepthRenderer>): void {
+        this._depthRenderer = depthRenderer;
+
+        if (this._depthReducer) {
+            this._depthReducer.setDepthRenderer(this._depthRenderer);
+        }
+    }
+
+    private _depthReducer: Nullable<DepthReducer>;
+    private _autoCalcDepthBounds = false;
+
+    /**
+     * Gets or sets the autoCalcDepthBounds property.
+     *
+     * When enabled, a depth rendering pass is first performed (with an internally created depth renderer or with the one
+     * you provide by calling setDepthRenderer). Then, a min/max reducing is applied on the depth map to compute the
+     * minimal and maximal depth of the map and those values are used as inputs for the setMinMaxDistance() function.
+     * It can greatly enhance the shadow quality, at the expense of more GPU works.
+     * When using this option, you should increase the value of the lambda parameter, and even set it to 1 for best results.
+     */
+    public get autoCalcDepthBounds(): boolean {
+        return this._autoCalcDepthBounds;
+    }
+
+    public set autoCalcDepthBounds(value: boolean) {
+        const camera = this._scene.activeCamera;
+
+        if (!camera) {
+            return;
+        }
+
+        if (!value) {
+            if (this._depthReducer) {
+                this._depthReducer.deactivate();
+            }
+            this.setMinMaxDistance(0, 1);
+            return;
+        }
+
+        if (!this._depthReducer) {
+            this._depthReducer = new DepthReducer(camera);
+            this._depthReducer.onAfterReductionPerformed.add((minmax: { min: number, max: number}) => {
+                let min = minmax.min, max = minmax.max;
+                if (min >= max) {
+                    min = 0;
+                    max = 1;
+                }
+                if (min != this._minDistance || max != this._maxDistance) {
+                    this.setMinMaxDistance(min, max);
+                }
+            });
+            this._depthReducer.setDepthRenderer(this._depthRenderer);
+        }
+
+        this._depthReducer.activate();
+    }
+
+    /**
+     * Defines the refresh rate of the min/max computation used when autoCalcDepthBounds is set to true
+     * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+     * Note that if you provided your own depth renderer through a call to setDepthRenderer, you are responsible
+     * for setting the refresh rate on the renderer yourself!
+     */
+    public get autoCalcDepthBoundsRefreshRate(): number {
+        return this._depthReducer?.depthRenderer?.getDepthMap().refreshRate ?? -1;
+    }
+
+    public set autoCalcDepthBoundsRefreshRate(value: number) {
+        if (this._depthReducer?.depthRenderer) {
+            this._depthReducer.depthRenderer.getDepthMap().refreshRate = value;
+        }
+    }
+
     /**
      * Create the cascade breaks according to the lambda, shadowMaxZ and min/max distance properties, as well as the camera near and far planes.
      * This function is automatically called when updating lambda, shadowMaxZ and min/max distances, however you should call it yourself if

+ 2 - 0
src/Materials/Textures/MultiviewRenderTarget.ts

@@ -1,6 +1,7 @@
 import { RenderTargetTexture } from '../Textures/renderTargetTexture';
 import { Scene } from '../../scene';
 import { InternalTextureSource } from '../Textures/internalTexture';
+import { Constants } from '../../Engines/constants';
 
 /**
  * Renders to multiple views with a single draw call
@@ -16,6 +17,7 @@ export class MultiviewRenderTarget extends RenderTargetTexture {
         super("multiview rtt", size, scene, false, true, InternalTextureSource.Unknown, false, undefined, false, false, true, undefined, true);
         var internalTexture = scene.getEngine().createMultiviewRenderTargetTexture(this.getRenderWidth(), this.getRenderHeight());
         internalTexture.isMultiview = true;
+        internalTexture.format = Constants.TEXTUREFORMAT_RGBA;
         this._texture = internalTexture;
         this.samples = this._engine.getCaps().maxSamples || this.samples;
     }

+ 12 - 14
src/Materials/Textures/baseTexture.ts

@@ -706,23 +706,21 @@ export class BaseTexture implements IAnimatable {
      * Dispose the texture and release its associated resources.
      */
     public dispose(): void {
-        if (!this._scene) {
-            return;
-        }
-
-        // Animations
-        if (this._scene.stopAnimation) {
-            this._scene.stopAnimation(this);
-        }
+        if (this._scene) {
+            // Animations
+            if (this._scene.stopAnimation) {
+                this._scene.stopAnimation(this);
+            }
 
-        // Remove from scene
-        this._scene._removePendingData(this);
-        var index = this._scene.textures.indexOf(this);
+            // Remove from scene
+            this._scene._removePendingData(this);
+            var index = this._scene.textures.indexOf(this);
 
-        if (index >= 0) {
-            this._scene.textures.splice(index, 1);
+            if (index >= 0) {
+                this._scene.textures.splice(index, 1);
+            }
+            this._scene.onTextureRemovedObservable.notifyObservers(this);
         }
-        this._scene.onTextureRemovedObservable.notifyObservers(this);
 
         if (this._texture === undefined) {
             return;

+ 1 - 1
src/Meshes/instancedMesh.ts

@@ -390,7 +390,7 @@ export class InstancedMesh extends AbstractMesh {
      *
      * Returns the clone.
      */
-    public clone(name: string, newParent: Nullable<Node>= null, doNotCloneChildren?: boolean): Nullable<AbstractMesh> {
+    public clone(name: string, newParent: Nullable<Node>= null, doNotCloneChildren?: boolean): InstancedMesh {
         var result = this._sourceMesh.createInstance(name);
 
         // Deep copy

+ 1 - 2
src/Meshes/linesMesh.ts

@@ -13,7 +13,6 @@ import { MaterialHelper } from '../Materials/materialHelper';
 
 import "../Shaders/color.fragment";
 import "../Shaders/color.vertex";
-import { AbstractMesh } from './abstractMesh';
 
 /**
  * Line mesh
@@ -224,7 +223,7 @@ export class LinesMesh extends Mesh {
     /**
      * Returns a new LineMesh object cloned from the current one.
      */
-    public clone(name: string, newParent: Nullable<Node> = null, doNotCloneChildren?: boolean): Nullable<AbstractMesh> {
+    public clone(name: string, newParent: Nullable<Node> = null, doNotCloneChildren?: boolean): LinesMesh {
         return new LinesMesh(name, this.getScene(), newParent, this, doNotCloneChildren);
     }
 

+ 1 - 1
src/Meshes/mesh.ts

@@ -2201,7 +2201,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
      * @param clonePhysicsImpostor allows/denies the cloning in the same time of the original mesh `body` used by the physics engine, if any (default `true`)
      * @returns a new mesh
      */
-    public clone(name: string = "", newParent: Nullable<Node> = null, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true): Nullable<AbstractMesh> {
+    public clone(name: string = "", newParent: Nullable<Node> = null, doNotCloneChildren?: boolean, clonePhysicsImpostor: boolean = true): Mesh {
         return new Mesh(name, this.getScene(), newParent, this, doNotCloneChildren, clonePhysicsImpostor);
     }
 

+ 1 - 1
src/Meshes/transformNode.ts

@@ -1224,7 +1224,7 @@ export class TransformNode extends Node {
      * @param doNotCloneChildren Do not clone children hierarchy
      * @returns the new transform node
      */
-    public clone(name: string, newParent: Nullable<Node>, doNotCloneChildren?: boolean): Nullable<TransformNode> {
+    public clone(name: string, newParent: Nullable<Node>, doNotCloneChildren?: boolean) : Nullable<TransformNode> {
         var result = SerializationHelper.Clone(() => new TransformNode(name, this.getScene()), this);
 
         result.name = name;

+ 108 - 0
src/Misc/depthReducer.ts

@@ -0,0 +1,108 @@
+import { Nullable } from "../types";
+import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
+import { Camera } from "../Cameras/camera";
+import { Constants } from "../Engines/constants";
+import { DepthRenderer } from "../Rendering/depthRenderer";
+
+import { MinMaxReducer } from "./minMaxReducer";
+
+/**
+ * This class is a small wrapper around the MinMaxReducer class to compute the min/max values of a depth texture
+ */
+export class DepthReducer extends MinMaxReducer {
+
+    private _depthRenderer: Nullable<DepthRenderer>;
+    private _depthRendererId: string;
+
+    /**
+     * Gets the depth renderer used for the computation.
+     * Note that the result is null if you provide your own renderer when calling setDepthRenderer.
+     */
+    public get depthRenderer(): Nullable<DepthRenderer> {
+        return this._depthRenderer;
+    }
+
+    /**
+     * Creates a depth reducer
+     * @param camera The camera used to render the depth texture
+     */
+    constructor(camera: Camera) {
+        super(camera);
+    }
+
+    /**
+     * Sets the depth renderer to use to generate the depth map
+     * @param depthRenderer The depth renderer to use. If not provided, a new one will be created automatically
+     * @param type The texture type of the depth map (default: TEXTURETYPE_HALF_FLOAT)
+     * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+     */
+    public setDepthRenderer(depthRenderer: Nullable<DepthRenderer> = null, type: number = Constants.TEXTURETYPE_HALF_FLOAT, forceFullscreenViewport = true): void {
+        const scene = this._camera.getScene();
+
+        if (this._depthRenderer) {
+            delete scene._depthRenderer[this._depthRendererId];
+
+            this._depthRenderer.dispose();
+            this._depthRenderer = null;
+        }
+
+        if (depthRenderer === null) {
+            if (!scene._depthRenderer) {
+                scene._depthRenderer = {};
+            }
+
+            depthRenderer = this._depthRenderer = new DepthRenderer(scene, type, this._camera, false);
+            depthRenderer.enabled = false;
+
+            this._depthRendererId = "minmax" + this._camera.id;
+            scene._depthRenderer[this._depthRendererId] = depthRenderer;
+        }
+
+        super.setSourceTexture(depthRenderer.getDepthMap(), true, type, forceFullscreenViewport);
+    }
+
+    /** @hidden */
+    public setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type: number = Constants.TEXTURETYPE_HALF_FLOAT, forceFullscreenViewport = true): void {
+        super.setSourceTexture(sourceTexture, depthRedux, type, forceFullscreenViewport);
+    }
+
+    /**
+     * Activates the reduction computation.
+     * When activated, the observers registered in onAfterReductionPerformed are
+     * called after the compuation is performed
+     */
+    public activate(): void {
+        if (this._depthRenderer) {
+            this._depthRenderer.enabled = true;
+        }
+
+        super.activate();
+    }
+
+    /**
+     * Deactivates the reduction computation.
+     */
+    public deactivate(): void {
+        super.deactivate();
+
+        if (this._depthRenderer) {
+            this._depthRenderer.enabled = false;
+        }
+    }
+
+    /**
+     * Disposes the depth reducer
+     * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+     */
+    public dispose(disposeAll = true): void {
+        super.dispose(disposeAll);
+
+        if (this._depthRenderer && disposeAll) {
+            delete this._depthRenderer.getDepthMap().getScene()?._depthRenderer[this._depthRendererId];
+
+            this._depthRenderer.dispose();
+            this._depthRenderer = null;
+        }
+    }
+
+}

+ 2 - 0
src/Misc/index.ts

@@ -45,3 +45,5 @@ export * from "./canvasGenerator";
 export * from "./fileTools";
 export * from "./stringTools";
 export * from "./dataReader";
+export * from "./minMaxReducer";
+export * from "./depthReducer";

+ 244 - 0
src/Misc/minMaxReducer.ts

@@ -0,0 +1,244 @@
+import { Nullable } from "../types";
+import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
+import { Camera } from "../Cameras/camera";
+import { Constants } from "../Engines/constants";
+import { Observer } from "./observable";
+import { Effect } from "../Materials/effect";
+import { PostProcess } from "../PostProcesses/postProcess";
+import { PostProcessManager } from "../PostProcesses/postProcessManager";
+import { Observable } from "./observable";
+
+import "../Shaders/minmaxRedux.fragment";
+
+/**
+ * This class computes a min/max reduction from a texture: it means it computes the minimum
+ * and maximum values from all values of the texture.
+ * It is performed on the GPU for better performances, thanks to a succession of post processes.
+ * The source values are read from the red channel of the texture.
+ */
+export class MinMaxReducer {
+
+    /**
+     * Observable triggered when the computation has been performed
+     */
+    public onAfterReductionPerformed = new Observable<{ min: number, max: number }>();
+
+    protected _camera: Camera;
+    protected _sourceTexture: Nullable<RenderTargetTexture>;
+    protected _reductionSteps: Nullable<Array<PostProcess>>;
+    protected _postProcessManager: PostProcessManager;
+    protected _onAfterUnbindObserver: Nullable<Observer<RenderTargetTexture>>;
+    protected _forceFullscreenViewport = true;
+
+    /**
+     * Creates a min/max reducer
+     * @param camera The camera to use for the post processes
+     */
+    constructor(camera: Camera) {
+        this._camera = camera;
+        this._postProcessManager = new PostProcessManager(camera.getScene());
+    }
+
+    /**
+     * Gets the texture used to read the values from.
+     */
+    public get sourceTexture(): Nullable<RenderTargetTexture> {
+        return this._sourceTexture;
+    }
+
+    /**
+     * Sets the source texture to read the values from.
+     * One must indicate if the texture is a depth texture or not through the depthRedux parameter
+     * because in such textures '1' value must not be taken into account to compute the maximum
+     * as this value is used to clear the texture.
+     * Note that the computation is not activated by calling this function, you must call activate() for that!
+     * @param sourceTexture The texture to read the values from. The values should be in the red channel.
+     * @param depthRedux Indicates if the texture is a depth texture or not
+     * @param type The type of the textures created for the reduction (defaults to TEXTURETYPE_HALF_FLOAT)
+     * @param forceFullscreenViewport Forces the post processes used for the reduction to be applied without taking into account viewport (defaults to true)
+     */
+    public setSourceTexture(sourceTexture: RenderTargetTexture, depthRedux: boolean, type: number = Constants.TEXTURETYPE_HALF_FLOAT, forceFullscreenViewport = true): void {
+        if (sourceTexture === this._sourceTexture) {
+            return;
+        }
+
+        this.dispose(false);
+
+        this._sourceTexture = sourceTexture;
+        this._reductionSteps = [];
+        this._forceFullscreenViewport = forceFullscreenViewport;
+
+        const scene = this._camera.getScene();
+
+        // create the first step
+        let reductionInitial = new PostProcess(
+            'Initial reduction phase',
+            'minmaxRedux', // shader
+            ['texSize'],
+            ['sourceTexture'], // textures
+            1.0, // options
+            null, // camera
+            Constants.TEXTURE_NEAREST_NEAREST, // sampling
+            scene.getEngine(), // engine
+            false, // reusable
+            "#define INITIAL" + (depthRedux ? "\n#define DEPTH_REDUX" : ""), // defines
+            type,
+            undefined,
+            undefined,
+            undefined,
+            Constants.TEXTUREFORMAT_RG,
+        );
+
+        reductionInitial.autoClear = false;
+        reductionInitial.forceFullscreenViewport = forceFullscreenViewport;
+
+        let w = this._sourceTexture.getRenderWidth(), h = this._sourceTexture.getRenderHeight();
+
+        reductionInitial.onApply = ((w: number, h: number) => {
+            return (effect: Effect) => {
+                effect.setTexture('sourceTexture', this._sourceTexture);
+                effect.setFloatArray2('texSize', new Float32Array([w, h]));
+            };
+        })(w, h);
+
+        this._reductionSteps.push(reductionInitial);
+
+        let index = 1;
+
+        // create the additional steps
+        while (w > 1 || h > 1) {
+            w = Math.max(Math.round(w / 2), 1);
+            h = Math.max(Math.round(h / 2), 1);
+
+            let reduction = new PostProcess(
+                'Reduction phase ' + index,
+                'minmaxRedux', // shader
+                ['texSize'],
+                null,
+                { width: w, height: h }, // options
+                null, // camera
+                Constants.TEXTURE_NEAREST_NEAREST, // sampling
+                scene.getEngine(), // engine
+                false, // reusable
+                "#define " + ((w == 1 && h == 1) ? 'LAST' : (w == 1 || h == 1) ? 'ONEBEFORELAST' : 'MAIN'), // defines
+                type,
+                undefined,
+                undefined,
+                undefined,
+                Constants.TEXTUREFORMAT_RG,
+            );
+
+            reduction.autoClear = false;
+            reduction.forceFullscreenViewport = forceFullscreenViewport;
+
+            reduction.onApply = ((w: number, h: number) => {
+                return (effect: Effect) => {
+                    if (w == 1 || h == 1) {
+                        effect.setIntArray2('texSize', new Int32Array([w, h]));
+                    } else {
+                        effect.setFloatArray2('texSize', new Float32Array([w, h]));
+                    }
+                };
+            })(w, h);
+
+            this._reductionSteps.push(reduction);
+
+            index++;
+
+            if (w == 1 && h == 1) {
+                let func = (w: number, h: number, reduction: PostProcess) => {
+                    let buffer = new Float32Array(4 * w * h),
+                        minmax = { min: 0, max: 0};
+                    return () => {
+                        scene.getEngine()._readTexturePixels(reduction.inputTexture, w, h, -1, 0, buffer);
+                        minmax.min = buffer[0];
+                        minmax.max = buffer[1];
+                        this.onAfterReductionPerformed.notifyObservers(minmax);
+                    };
+                };
+                reduction.onAfterRenderObservable.add(func(w, h, reduction));
+            }
+        }
+    }
+
+    /**
+     * Defines the refresh rate of the computation.
+     * Use 0 to compute just once, 1 to compute on every frame, 2 to compute every two frames and so on...
+     */
+    public get refreshRate(): number {
+        return this._sourceTexture ? this._sourceTexture.refreshRate : -1;
+    }
+
+    public set refreshRate(value: number) {
+        if (this._sourceTexture) {
+            this._sourceTexture.refreshRate = value;
+        }
+    }
+
+    protected _activated = false;
+
+    /**
+     * Gets the activation status of the reducer
+     */
+    public get activated(): boolean {
+        return this._activated;
+    }
+
+    /**
+     * Activates the reduction computation.
+     * When activated, the observers registered in onAfterReductionPerformed are
+     * called after the compuation is performed
+     */
+    public activate(): void {
+        if (this._onAfterUnbindObserver || !this._sourceTexture) {
+            return;
+        }
+
+        this._onAfterUnbindObserver = this._sourceTexture.onAfterUnbindObservable.add(() => {
+            this._reductionSteps![0].activate(this._camera);
+            this._postProcessManager.directRender(this._reductionSteps!, this._reductionSteps![0].inputTexture, this._forceFullscreenViewport);
+            this._camera.getScene().getEngine().unBindFramebuffer(this._reductionSteps![0].inputTexture, false);
+        });
+
+        this._activated = true;
+    }
+
+    /**
+     * Deactivates the reduction computation.
+     */
+    public deactivate(): void {
+        if (!this._onAfterUnbindObserver || !this._sourceTexture) {
+            return;
+        }
+
+        this._sourceTexture.onAfterUnbindObservable.remove(this._onAfterUnbindObserver);
+        this._onAfterUnbindObserver = null;
+        this._activated = false;
+    }
+
+    /**
+     * Disposes the min/max reducer
+     * @param disposeAll true to dispose all the resources. You should always call this function with true as the parameter (or without any parameter as it is the default one). This flag is meant to be used internally.
+     */
+    public dispose(disposeAll = true): void {
+        if (disposeAll) {
+            this.onAfterReductionPerformed.clear();
+        }
+
+        this.deactivate();
+
+        if (this._reductionSteps) {
+            for (let i = 0; i < this._reductionSteps.length; ++i) {
+                this._reductionSteps[i].dispose();
+            }
+            this._reductionSteps = null;
+        }
+
+        if (this._postProcessManager && disposeAll) {
+            this._postProcessManager.dispose();
+        }
+
+        this._sourceTexture = null;
+    }
+
+}

+ 11 - 0
src/Misc/screenshotTools.ts

@@ -251,6 +251,17 @@ export class ScreenshotTools {
             width = size;
         }
 
+        // When creating the image data from the CanvasRenderingContext2D, the width and height is clamped to the size of the _gl context
+        // On certain GPUs, it seems as if the _gl context truncates to an integer automatically. Therefore, if a user tries to pass the width of their canvas element
+        // and it happens to be a float (1000.5 x 600.5 px), the engine.readPixels will return a different size array than context.createImageData
+        // to resolve this, we truncate the floats here to ensure the same size
+        if (width) {
+            width = Math.floor(width);
+        }
+        if (height) {
+            height = Math.floor(height);
+        }
+
         return { height: height | 0, width: width | 0 };
     }
 }

+ 3 - 0
src/Rendering/depthRenderer.ts

@@ -34,6 +34,9 @@ export class DepthRenderer {
     private _cachedDefines: string;
     private _camera: Nullable<Camera>;
 
+    /** Enable or disable the depth renderer. When disabled, the depth texture is not updated */
+    public enabled = true;
+
     /**
      * Specifiess that the depth renderer will only be used within
      * the camera it is created for.

+ 2 - 2
src/Rendering/depthRendererSceneComponent.ts

@@ -114,7 +114,7 @@ export class DepthRendererSceneComponent implements ISceneComponent {
         if (this.scene._depthRenderer) {
             for (var key in this.scene._depthRenderer) {
                 let depthRenderer = this.scene._depthRenderer[key];
-                if (!depthRenderer.useOnlyInActiveCamera) {
+                if (depthRenderer.enabled && !depthRenderer.useOnlyInActiveCamera) {
                     renderTargets.push(depthRenderer.getDepthMap());
                 }
             }
@@ -125,7 +125,7 @@ export class DepthRendererSceneComponent implements ISceneComponent {
         if (this.scene._depthRenderer) {
             for (var key in this.scene._depthRenderer) {
                 let depthRenderer = this.scene._depthRenderer[key];
-                if (depthRenderer.useOnlyInActiveCamera && this.scene.activeCamera!.id === key) {
+                if (depthRenderer.enabled && depthRenderer.useOnlyInActiveCamera && this.scene.activeCamera!.id === key) {
                     renderTargets.push(depthRenderer.getDepthMap());
                 }
             }

+ 1 - 1
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -117,7 +117,7 @@ uniform mat4 view;
 
     #ifdef SS_THICKNESSANDMASK_TEXTURE
         uniform vec2 vThicknessInfos;
-        uniform mat4 thicknessMatrix;;
+        uniform mat4 thicknessMatrix;
     #endif
 
     uniform vec2 vThicknessParam;

+ 1 - 1
src/Shaders/ShadersInclude/pbrVertexDeclaration.fx

@@ -94,7 +94,7 @@ uniform float pointSize;
 
     #ifdef SS_THICKNESSANDMASK_TEXTURE
         uniform vec2 vThicknessInfos;
-        uniform mat4 thicknessMatrix;;
+        uniform mat4 thicknessMatrix;
     #endif
 #endif
 

+ 70 - 0
src/Shaders/minmaxRedux.fragment.fx

@@ -0,0 +1,70 @@
+attribute vec2 vUV;
+
+uniform sampler2D textureSampler;
+
+#if defined(INITIAL)
+uniform sampler2D sourceTexture;
+uniform vec2 texSize;
+
+void main(void)
+{
+    ivec2 coord = ivec2(vUV * (texSize - 1.0));
+
+    float f1 = texelFetch(sourceTexture, coord, 0).r;
+    float f2 = texelFetch(sourceTexture, coord + ivec2(1, 0), 0).r;
+    float f3 = texelFetch(sourceTexture, coord + ivec2(1, 1), 0).r;
+    float f4 = texelFetch(sourceTexture, coord + ivec2(0, 1), 0).r;
+
+    float minz = min(min(min(f1, f2), f3), f4);
+    #ifdef DEPTH_REDUX
+        float maxz = max(max(max(sign(1.0 - f1) * f1, sign(1.0 - f2) * f2), sign(1.0 - f3) * f3), sign(1.0 - f4) * f4);
+    #else
+        float maxz = max(max(max(f1, f2), f3), f4);
+    #endif
+
+    glFragColor = vec4(minz, maxz, 0., 0.);
+}
+
+#elif defined(MAIN)
+uniform vec2 texSize;
+
+void main(void)
+{
+    ivec2 coord = ivec2(vUV * (texSize - 1.0));
+
+    vec2 f1 = texelFetch(textureSampler, coord, 0).rg;
+    vec2 f2 = texelFetch(textureSampler, coord + ivec2(1, 0), 0).rg;
+    vec2 f3 = texelFetch(textureSampler, coord + ivec2(1, 1), 0).rg;
+    vec2 f4 = texelFetch(textureSampler, coord + ivec2(0, 1), 0).rg;
+
+    float minz = min(min(min(f1.x, f2.x), f3.x), f4.x);
+    float maxz = max(max(max(f1.y, f2.y), f3.y), f4.y);
+
+    glFragColor = vec4(minz, maxz, 0., 0.);
+}
+
+#elif defined(ONEBEFORELAST)
+uniform ivec2 texSize;
+
+void main(void)
+{
+    ivec2 coord = ivec2(vUV * vec2(texSize - 1));
+
+    vec2 f1 = texelFetch(textureSampler, coord % texSize, 0).rg;
+    vec2 f2 = texelFetch(textureSampler, (coord + ivec2(1, 0)) % texSize, 0).rg;
+    vec2 f3 = texelFetch(textureSampler, (coord + ivec2(1, 1)) % texSize, 0).rg;
+    vec2 f4 = texelFetch(textureSampler, (coord + ivec2(0, 1)) % texSize, 0).rg;
+
+    float minz = min(f1.x, f2.x);
+    float maxz = max(f1.y, f2.y);
+
+    glFragColor = vec4(minz, maxz, 0., 0.);
+}
+
+#elif defined(LAST)
+void main(void)
+{
+    discard;
+    glFragColor = vec4(0.);
+}
+#endif

+ 2 - 2
src/sceneComponent.ts

@@ -70,9 +70,9 @@ export class SceneComponentConstants {
 
     public static readonly STEP_AFTERRENDER_AUDIO = 0;
 
-    public static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR = 0;
+    public static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 0;
     public static readonly STEP_GATHERRENDERTARGETS_GEOMETRYBUFFERRENDERER = 1;
-    public static readonly STEP_GATHERRENDERTARGETS_DEPTHRENDERER = 2;
+    public static readonly STEP_GATHERRENDERTARGETS_SHADOWGENERATOR = 2;
     public static readonly STEP_GATHERRENDERTARGETS_POSTPROCESSRENDERPIPELINEMANAGER = 3;
 
     public static readonly STEP_GATHERACTIVECAMERARENDERTARGETS_DEPTHRENDERER = 0;