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

Merge pull request #7145 from sebavan/WebGPU

Web gpu
sebavan 5 лет назад
Родитель
Сommit
179116d101
100 измененных файлов с 10586 добавлено и 3934 удалено
  1. 160 18
      Playground/babylon.d.txt
  2. 27 0
      Playground/css/img/exitButton.svg
  3. 29 0
      Playground/css/img/nextButton.svg
  4. 29 0
      Playground/css/img/previousButton.svg
  5. 3 2
      Playground/css/index.css
  6. 47 42
      Playground/debug.html
  7. 46 41
      Playground/index-local.html
  8. 45 40
      Playground/index.html
  9. 7359 3200
      Playground/js/babylonWebGpu.max.js
  10. 1 1
      Playground/js/babylonWebGpu.max.js.map
  11. 42 3
      Playground/js/main.js
  12. 38 4
      Playground/js/menuPG.js
  13. 39 13
      Playground/js/monacoCreator.js
  14. 145 9
      dist/preview release/babylon.d.ts
  15. 2 2
      dist/preview release/babylon.js
  16. 532 123
      dist/preview release/babylon.max.js
  17. 1 1
      dist/preview release/babylon.max.js.map
  18. 301 18
      dist/preview release/babylon.module.d.ts
  19. 160 20
      dist/preview release/documentation.d.ts
  20. 1 1
      dist/preview release/glTF2Interface/package.json
  21. 15 11
      dist/preview release/gui/babylon.gui.d.ts
  22. 17 13
      dist/preview release/gui/babylon.gui.js
  23. 1 1
      dist/preview release/gui/babylon.gui.js.map
  24. 1 1
      dist/preview release/gui/babylon.gui.min.js
  25. 41 22
      dist/preview release/gui/babylon.gui.module.d.ts
  26. 2 2
      dist/preview release/gui/package.json
  27. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  28. 58 20
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  29. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  30. 11 10
      dist/preview release/inspector/babylon.inspector.d.ts
  31. 24 21
      dist/preview release/inspector/babylon.inspector.module.d.ts
  32. 7 7
      dist/preview release/inspector/package.json
  33. 3 3
      dist/preview release/loaders/package.json
  34. 2 2
      dist/preview release/materialsLibrary/package.json
  35. 4 1
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  36. 7 7
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  37. 165 26
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  38. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  39. 10 2
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  40. 2 2
      dist/preview release/nodeEditor/package.json
  41. 1 1
      dist/preview release/package.json
  42. 1 1
      dist/preview release/packagesSizeBaseLine.json
  43. 2 2
      dist/preview release/postProcessesLibrary/package.json
  44. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  45. 1 1
      dist/preview release/readme.md
  46. 3 3
      dist/preview release/serializers/package.json
  47. 301 18
      dist/preview release/viewer/babylon.module.d.ts
  48. 39 31
      dist/preview release/viewer/babylon.viewer.js
  49. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  50. 10 0
      dist/preview release/what's new.md
  51. 3 1
      gui/src/2D/controls/checkbox.ts
  52. 2 3
      gui/src/2D/controls/container.ts
  53. 8 3
      gui/src/2D/controls/control.ts
  54. 3 1
      gui/src/2D/controls/displayGrid.ts
  55. 2 1
      gui/src/2D/controls/inputText.ts
  56. 1 1
      gui/src/2D/controls/multiLine.ts
  57. 2 1
      gui/src/2D/controls/sliders/imageBasedSlider.ts
  58. 3 1
      gui/src/2D/controls/sliders/slider.ts
  59. 2 1
      gui/src/2D/controls/textBlock.ts
  60. 5 0
      inspector/src/components/actionTabs/tabs/propertyGrids/cameras/commonCameraPropertyGridComponent.tsx
  61. 5 0
      inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonLightPropertyGridComponent.tsx
  62. 5 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx
  63. 5 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  64. 6 1
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/transformNodePropertyGridComponent.tsx
  65. 5 0
      inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/commonPostProcessPropertyGridComponent.tsx
  66. 11 11
      inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx
  67. 2 0
      inspector/src/components/sceneExplorer/entities/meshTreeItemComponent.tsx
  68. 2 2
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  69. 0 1
      inspector/src/components/sceneExplorer/treeItemSelectableComponent.tsx
  70. 1 1
      inspector/src/components/sceneExplorer/treeItemSpecializedComponent.tsx
  71. 6 0
      nodeEditor/src/blockTools.ts
  72. 1 1
      nodeEditor/src/components/diagram/clamp/clampNodeWidget.tsx
  73. 23 4
      nodeEditor/src/components/diagram/diagram.scss
  74. 38 11
      nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx
  75. 2 2
      nodeEditor/src/components/diagram/input/inputNodeWidget.tsx
  76. 99 5
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  77. 4 0
      nodeEditor/src/graphEditor.tsx
  78. 16 0
      nodeEditor/src/serializationTools.ts
  79. 1 1
      nodeEditor/src/sharedComponents/checkBoxLineComponent.tsx
  80. 2 0
      nodeEditor/src/sharedComponents/draggableLineComponent.tsx
  81. 1 1
      package.json
  82. 61 10
      src/Cameras/VR/vrExperienceHelper.ts
  83. 9 0
      src/Cameras/XR/webXRControllerModelLoader.ts
  84. 29 6
      src/Cameras/XR/webXREnterExitUI.ts
  85. 4 1
      src/Cameras/XR/webXRExperienceHelper.ts
  86. 7 2
      src/Cameras/XR/webXRSessionManager.ts
  87. 11 12
      src/Cameras/camera.ts
  88. 3 3
      src/Engines/WebGPU/webgpuConstants.ts
  89. 13 3
      src/Engines/thinEngine.ts
  90. 7 7
      src/Engines/webgpuEngine.ts
  91. 5 1
      src/Gizmos/axisScaleGizmo.ts
  92. 26 11
      src/Gizmos/lightGizmo.ts
  93. 16 0
      src/Gizmos/scaleGizmo.ts
  94. 184 54
      src/LibDeclarations/webgpu.d.ts
  95. 35 8
      src/Materials/Node/Blocks/Dual/textureBlock.ts
  96. 2 0
      src/Materials/Node/Blocks/index.ts
  97. 80 0
      src/Materials/Node/Blocks/normalBlendBlock.ts
  98. 77 0
      src/Materials/Node/Blocks/rotate2dBlock.ts
  99. 5 5
      src/Materials/Node/Blocks/simplexPerlin3DBlock.ts
  100. 0 0
      src/Materials/Node/Blocks/worleyNoise3DBlock.ts

+ 160 - 18
Playground/babylon.d.txt

@@ -4448,6 +4448,16 @@ declare module BABYLON {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -4467,6 +4477,16 @@ declare module BABYLON {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -28911,6 +28931,11 @@ declare module BABYLON {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -40759,6 +40784,18 @@ declare module BABYLON {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -40863,6 +40900,9 @@ declare module BABYLON {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -41075,6 +41115,14 @@ declare module BABYLON {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -41250,7 +41298,7 @@ declare module BABYLON {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -41383,7 +41431,7 @@ declare module BABYLON {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -41444,6 +41492,16 @@ declare module BABYLON {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -42256,6 +42314,11 @@ declare module BABYLON {
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -44948,6 +45011,7 @@ declare module BABYLON {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -44968,6 +45032,10 @@ declare module BABYLON {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -44998,6 +45066,10 @@ declare module BABYLON {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -45604,8 +45676,9 @@ declare module BABYLON {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -45629,7 +45702,7 @@ declare module BABYLON {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -53074,6 +53147,7 @@ declare module BABYLON {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -53130,6 +53204,7 @@ declare module BABYLON {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -55511,9 +55586,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -55552,9 +55627,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -55564,6 +55639,67 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Effect Render Options
      */
     export interface IEffectRendererOptions {
@@ -65304,7 +65440,13 @@ declare module BABYLON.GUI {
          * @param scene defines the hosting scene
          */
         moveToVector3(position: BABYLON.Vector3, scene: BABYLON.Scene): void;
-        /** @hidden */
private _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        /**
+         * Will store all controls that have this control as ascendant in a given array
+         * @param results defines the array where to store the descendants
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         */
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /**
          * Will return all controls that have this control as ascendant
          * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
@@ -65502,7 +65644,7 @@ declare module BABYLON.GUI {
         /** @hidden */
private _layout(parentMeasure: Measure, context: CanvasRenderingContext2D): boolean;
         protected _postMeasure(): void;
         /** @hidden */
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
-        /** @hidden */
private _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /** @hidden */
private _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         /** @hidden */
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -65648,7 +65790,7 @@ declare module BABYLON.GUI {
         protected _getTypeName(): string;
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _drawText;
-        /** @hidden */
private _draw(context: CanvasRenderingContext2D): void;
+        /** @hidden */
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[];
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -65963,7 +66105,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        /** @hidden */
private _draw(context: CanvasRenderingContext2D): void;
+        /** @hidden */
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         /** @hidden */
private _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         /**
          * Utility function to easily create a checkbox with a header
@@ -66202,7 +66344,7 @@ declare module BABYLON.GUI {
         /** @hidden */
         private _onCutText;
         /** @hidden */
-        private _onPasteText;
private _draw(context: CanvasRenderingContext2D): void;
private _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
private _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
private _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
+        private _onPasteText;
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
private _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
private _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
private _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         protected _beforeRenderText(text: string): string;
         dispose(): void;
     }
@@ -66582,7 +66724,7 @@ declare module BABYLON.GUI {
         lineWidth: number;
         horizontalAlignment: number;
         verticalAlignment: number;
-        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D): void;
+        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
private _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         dispose(): void;
@@ -66712,7 +66854,7 @@ declare module BABYLON.GUI {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D): void;
+        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {
@@ -67059,7 +67201,7 @@ declare module BABYLON.GUI {
          * Creates a new GridDisplayRectangle
          * @param name defines the control name
          */
-        constructor(name?: string | undefined);
private _draw(context: CanvasRenderingContext2D): void;
+        constructor(name?: string | undefined);
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _getTypeName(): string;
     }
 }
@@ -67091,7 +67233,7 @@ declare module BABYLON.GUI {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D): void;
+        protected _getTypeName(): string;
private _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {

+ 27 - 0
Playground/css/img/exitButton.svg

@@ -0,0 +1,27 @@
+<svg width="55" height="55" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g>
+  <title>Layer 1</title>
+  <g stroke="null" id="svg_1">
+   <g stroke="null" id="cross">
+    <g stroke="null" id="svg_2">
+     <polygon stroke="null" points="39.666656494140625,16.904794692993164 38.352622985839844,15.602999687194824 28.333335876464844,25.53184700012207 18.31399917602539,15.602999687194824 16.999999046325684,16.904794692993164 27.01933479309082,26.833715438842773 16.999999046325684,36.7618522644043 18.31399917602539,38.06360626220703 28.333335876464844,28.135473251342773 38.352622985839844,38.06360626220703 39.666656494140625,36.7618522644043 29.64663314819336,26.833715438842773 " id="svg_3"/>
+    </g>
+   </g>
+  </g>
+  <g id="svg_4"/>
+  <g id="svg_5"/>
+  <g id="svg_6"/>
+  <g id="svg_7"/>
+  <g id="svg_8"/>
+  <g id="svg_9"/>
+  <g id="svg_10"/>
+  <g id="svg_11"/>
+  <g id="svg_12"/>
+  <g id="svg_13"/>
+  <g id="svg_14"/>
+  <g id="svg_15"/>
+  <g id="svg_16"/>
+  <g id="svg_17"/>
+  <g id="svg_18"/>
+ </g>
+</svg>

+ 29 - 0
Playground/css/img/nextButton.svg

@@ -0,0 +1,29 @@
+<svg width="55" height="55" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g>
+  <title>Layer 1</title>
+  <g stroke="null" id="svg_1">
+   <path stroke="null" id="Chevron_Right_1_" d="m35.3485,26.59648l-11.10481,-10.25958c-0.48727,-0.4492 -1.27673,-0.4492 -1.76523,0c-0.48727,0.4492 -0.48727,1.17881 0,1.62801l10.22399,9.44554l-10.22276,9.44554c-0.48727,0.4492 -0.48727,1.17881 0,1.62914c0.48727,0.4492 1.27796,0.4492 1.76523,0l11.10481,-10.25958c0.47989,-0.44455 0.47989,-1.18563 -0.00123,-1.62905l0,-0.00001z" fill="black"/>
+   <g stroke="null" id="svg_2"/>
+   <g stroke="null" id="svg_3"/>
+   <g stroke="null" id="svg_4"/>
+   <g stroke="null" id="svg_5"/>
+   <g stroke="null" id="svg_6"/>
+   <g stroke="null" id="svg_7"/>
+  </g>
+  <g id="svg_8"/>
+  <g id="svg_9"/>
+  <g id="svg_10"/>
+  <g id="svg_11"/>
+  <g id="svg_12"/>
+  <g id="svg_13"/>
+  <g id="svg_14"/>
+  <g id="svg_15"/>
+  <g id="svg_16"/>
+  <g id="svg_17"/>
+  <g id="svg_18"/>
+  <g id="svg_19"/>
+  <g id="svg_20"/>
+  <g id="svg_21"/>
+  <g id="svg_22"/>
+ </g>
+</svg>

+ 29 - 0
Playground/css/img/previousButton.svg

@@ -0,0 +1,29 @@
+<svg width="55" height="55" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" stroke="null" style="vector-effect: non-scaling-stroke;">
+ <g stroke="null">
+  <title stroke="null">Layer 1</title>
+  <g stroke="null" id="svg_1">
+   <path stroke="null" fill="black" d="m18.11847,26.59648l12.58068,-10.25958c0.55203,-0.4492 1.44641,-0.4492 1.99984,0c0.55203,0.4492 0.55203,1.17881 0,1.62801l-11.58279,9.44554l11.5814,9.44554c0.55203,0.4492 0.55203,1.17881 0,1.62914c-0.55203,0.4492 -1.44781,0.4492 -1.99984,0l-12.58068,-10.25958c-0.54367,-0.44455 -0.54367,-1.18563 0.00139,-1.62905l0,-0.00001l0,-0.00001z" id="Chevron_Right_1_"/>
+   <g stroke="null" id="svg_2"/>
+   <g stroke="null" id="svg_3"/>
+   <g stroke="null" id="svg_4"/>
+   <g stroke="null" id="svg_5"/>
+   <g stroke="null" id="svg_6"/>
+   <g stroke="null" id="svg_7"/>
+  </g>
+  <g stroke="null" id="svg_8"/>
+  <g stroke="null" id="svg_9"/>
+  <g stroke="null" id="svg_10"/>
+  <g stroke="null" id="svg_11"/>
+  <g stroke="null" id="svg_12"/>
+  <g stroke="null" id="svg_13"/>
+  <g stroke="null" id="svg_14"/>
+  <g stroke="null" id="svg_15"/>
+  <g stroke="null" id="svg_16"/>
+  <g stroke="null" id="svg_17"/>
+  <g stroke="null" id="svg_18"/>
+  <g stroke="null" id="svg_19"/>
+  <g stroke="null" id="svg_20"/>
+  <g stroke="null" id="svg_21"/>
+  <g stroke="null" id="svg_22"/>
+ </g>
+</svg>

+ 3 - 2
Playground/css/index.css

@@ -748,8 +748,10 @@ body {
 .save-layer .diff-form {
     height: 200px;
 }
+.displayOnDiff {
+    display: none;
+}
 .diff-view {
-    position: fixed;
     display: none;
     width: 100%;
     height: 100%;
@@ -757,7 +759,6 @@ body {
     left: 0;
     right: 0;
     bottom: 0;
-    z-index: 100;
 }
 
 /* Media queries */

+ 47 - 42
Playground/debug.html

@@ -116,13 +116,16 @@
         <div class="category languageJS" id="JStoTSbar">
             <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1280"><img src="css/img/clearButton.svg"></div>            
-            <div class="buttonPG removeOnPhone" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG select" id="menuButton1280"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
+            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay languageJS">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub languageJS">
@@ -165,11 +168,11 @@
         </div>
 
         <div class="category right">
-            <div class="button select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1280"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none"></div>
             </div>
-            <div class="button select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
@@ -184,14 +187,17 @@
             <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
             <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-
-            <div class="button select" id="menuButton1024"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
+
+            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
 
@@ -235,46 +241,47 @@
         </div>
 
         <div class="category right">
-            <div class="button select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1024"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none">
                 </div>
             </div>
-            <div class="button select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
     <!-- Mobile -->
     <div class="navbar navBarMobile languageJS">
         <div class="category languageJS" id="JStoTSbar">
-            <div class="button select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
+            <div class="buttonPG select" id="menuButtonMobile"><img src="css/img/hamburgerButton.svg">
                 <div class="toDisplay">
                     <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
                     <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download
-                    </div>
-                    <div class="option noSubSelect" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear
-                    </div>
-                    <div class="option noSubSelect" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff
-                    </div>
-                    <div class="option noSubSelect" id="debugButtonMobile"><img
+                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
+                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
+                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
+                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
+                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
+                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
+                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
+                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
+                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
+
+                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
                             src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect">
+                    <div class="option subSelect removeOnDiff">
                         <img src="css/img/optionsButton.svg">
-                        Version<div id="currentVersionMobile"></div>
+                        <div id="currentVersionMobile"></div>
                         <div class="toDisplaySub currentVersionDisplay">
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Theme
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
                         <div class="toDisplaySub">
                             <div class="option selected" id="darkThemeMobile">Dark</div>
                             <div class="option" id="lightThemeMobile">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Font size
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
                         <div class="toDisplaySub displayFontSize">
                             <div class="option">8</div>
                             <div class="option">10</div>
@@ -297,7 +304,7 @@
                     <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
                         style="display: none">Editor
                         Fullscreen</div>
-                    <div class="option nosubselect" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
+                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
                         code</div>
                     <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
                         <i class="fa fa-square" aria-hidden="true"></i>
@@ -307,11 +314,11 @@
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect" id="metadataButtonMobile"><img
+                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
                             src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect"><img class="examplesButton"
+                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
                             src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect"><img src="css/img/examplesButton.svg">Links / Tools
+                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
                         <div class="toDisplaySub displayFooterLinks">
                             <div class="option link">
                                 <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
@@ -338,7 +345,7 @@
             </div>
         </div>
 
-        <div id="switchWrapper" class="languageJS">
+        <div id="switchWrapper" class="languageJS removeOnDiff">
             <img id="switchWrapperCode" src="css/img/codeButton.svg">
             <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
         </div>
@@ -348,6 +355,7 @@
 
     <div class="wrapper">
         <div id="jsEditor"></div>
+        <div id="diffView" class="diff-view"></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
@@ -427,9 +435,6 @@
         </div>
     </div>
 
-    <div id="diffView" class="diff-view">
-    </div>        
-
     <div id="waitDiv">
         <div id="logo-part">
             <img src="css/img/v4.svg" id="waitLogo" />

+ 46 - 41
Playground/index-local.html

@@ -52,13 +52,16 @@
         <div class="category languageJS" id="JStoTSbar">
             <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG select" id="menuButton1280"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
+            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay languageJS">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub languageJS">
@@ -101,11 +104,11 @@
         </div>
 
         <div class="category right">
-            <div class="buttonPG select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1280"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none"></div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
@@ -120,14 +123,17 @@
             <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
             <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-
-            <div class="buttonPG select" id="menuButton1024"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
+
+            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
 
@@ -171,12 +177,12 @@
         </div>
 
         <div class="category right">
-            <div class="buttonPG select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1024"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none">
                 </div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
@@ -187,30 +193,31 @@
                 <div class="toDisplay">
                     <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
                     <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download
-                    </div>
-                    <div class="option noSubSelect" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear
-                    </div>
-                    <div class="option noSubSelect" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff
-                    </div>
-                    <div class="option noSubSelect" id="debugButtonMobile"><img
+                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
+                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
+                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
+                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
+                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
+                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
+                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
+                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
+                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
+
+                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
                             src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect">
+                    <div class="option subSelect removeOnDiff">
                         <img src="css/img/optionsButton.svg">
-                        Version<div id="currentVersionMobile"></div>
+                        <div id="currentVersionMobile"></div>
                         <div class="toDisplaySub currentVersionDisplay">
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Theme
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
                         <div class="toDisplaySub">
                             <div class="option selected" id="darkThemeMobile">Dark</div>
                             <div class="option" id="lightThemeMobile">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Font size
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
                         <div class="toDisplaySub displayFontSize">
                             <div class="option">8</div>
                             <div class="option">10</div>
@@ -233,7 +240,7 @@
                     <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
                         style="display: none">Editor
                         Fullscreen</div>
-                    <div class="option nosubselect" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
+                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
                         code</div>
                     <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
                         <i class="fa fa-square" aria-hidden="true"></i>
@@ -243,11 +250,11 @@
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect" id="metadataButtonMobile"><img
+                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
                             src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect"><img class="examplesButton"
+                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
                             src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect"><img src="css/img/examplesButton.svg">Links / Tools
+                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
                         <div class="toDisplaySub displayFooterLinks">
                             <div class="option link">
                                 <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
@@ -274,7 +281,7 @@
             </div>
         </div>
 
-        <div id="switchWrapper" class="languageJS">
+        <div id="switchWrapper" class="languageJS removeOnDiff">
             <img id="switchWrapperCode" src="css/img/codeButton.svg">
             <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
         </div>
@@ -284,6 +291,7 @@
 
     <div class="wrapper">
         <div id="jsEditor"></div>
+        <div id="diffView" class="diff-view"></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
@@ -363,9 +371,6 @@
         </div>
     </div>
 
-    <div id="diffView" class="diff-view">
-    </div>
-
     <div id="waitDiv">
         <div id="logo-part">
             <img src="css/img/v4.svg" id="waitLogo" />

+ 45 - 40
Playground/index.html

@@ -64,13 +64,16 @@
         <div class="category languageJS" id="JStoTSbar">
             <div class="buttonJStoTS languageTS" id="toTSbutton1280">Typescript</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1280">Javascript</div>
-            <div class="buttonPG run" id="runButton1280"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1280"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
-            <div class="buttonPG select" id="menuButton1280"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1280"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1280"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1280"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1280"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1280"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1280"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1280"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1280"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1280"><img src="css/img/exitButton.svg"></div>
+            <div class="buttonPG select removeOnDiff" id="menuButton1280"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay languageJS">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub languageJS">
@@ -113,11 +116,11 @@
         </div>
 
         <div class="category right">
-            <div class="buttonPG select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1280"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none"></div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
@@ -132,14 +135,17 @@
             <div class="buttonJStoTS languageTS" id="toTSbutton1024">TS</div>
             <div class="buttonJStoTS languageJS" id="toJSbutton1024">JS</div>
             <div class="buttonSpaceKiller"></div>
-            <div class="buttonPG run" id="runButton1024"><img src="css/img/playButton.svg"></div>
-            <div class="buttonPG" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
-            <div class="buttonPG" id="newButton1024"><img src="css/img/newButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
-            <div class="buttonPG removeOnPhone" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
-
-            <div class="buttonPG select" id="menuButton1024"><img src="css/img/optionsButton.svg">
+            <div class="buttonPG run removeOnDiff" id="runButton1024"><img src="css/img/playButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="saveButton1024"><img src="css/img/saveButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="zipButton1024"><img src="css/img/downloadButton.svg"></div>
+            <div class="buttonPG removeOnDiff" id="newButton1024"><img src="css/img/newButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="clearButton1024"><img src="css/img/clearButton.svg"></div>
+            <div class="buttonPG removeOnPhone removeOnDiff" id="diffButton1024"><img src="css/img/diffButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="previousButton1024"><img src="css/img/previousButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="nextButton1024"><img src="css/img/nextButton.svg"></div>
+            <div class="buttonPG removeOnPhone displayOnDiff" id="exitButton1024"><img src="css/img/exitButton.svg"></div>
+
+            <div class="buttonPG select removeOnDiff" id="menuButton1024"><img src="css/img/optionsButton.svg">
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
 
@@ -183,12 +189,12 @@
         </div>
 
         <div class="category right">
-            <div class="buttonPG select">
+            <div class="buttonPG select removeOnDiff">
                 <span id="currentVersion1024"></span>
                 <div class="toDisplay currentVersionDisplay" style="display: none">
                 </div>
             </div>
-            <div class="buttonPG select"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
+            <div class="buttonPG select removeOnDiff"><img class="examplesButton" src="css/img/examplesButton.svg"></div>
         </div>
     </div>
 
@@ -199,30 +205,31 @@
                 <div class="toDisplay">
                     <div class="option noSubSelect languageTS" id="toTSbuttonMobile">TypeScript</div>
                     <div class="option noSubSelect languageJS" id="toJSbuttonMobile">JavaScript</div>
-                    <div class="option noSubSelect run" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
-                    <div class="option noSubSelect" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
-                    <div class="option noSubSelect" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download
-                    </div>
-                    <div class="option noSubSelect" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
-                    <div class="option noSubSelect" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear
-                    </div>
-                    <div class="option noSubSelect" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff
-                    </div>
-                    <div class="option noSubSelect" id="debugButtonMobile"><img
+                    <div class="option noSubSelect run removeOnDiff" id="runButtonMobile"><img src="css/img/playButton.svg">Run</div>
+                    <div class="option noSubSelect removeOnDiff" id="saveButtonMobile"><img src="css/img/saveButton.svg">Save</div>
+                    <div class="option noSubSelect removeOnDiff" id="zipButtonMobile"><img src="css/img/downloadButton.svg">Download</div>
+                    <div class="option noSubSelect removeOnDiff" id="newButtonMobile"><img src="css/img/newButton.svg">New</div>
+                    <div class="option noSubSelect removeOnDiff" id="clearButtonMobile"><img src="css/img/clearButton.svg">Clear</div>
+                    <div class="option noSubSelect removeOnDiff" id="diffButtonMobile"><img src="css/img/DiffButton.svg">Diff</div>
+                    <div class="option noSubSelect displayOnDiff" id="previousButtonMobile"><img src="css/img/previousButton.svg">Previous</div>
+                    <div class="option noSubSelect displayOnDiff" id="nextButtonMobile"><img src="css/img/nextButton.svg">Next</div>
+                    <div class="option noSubSelect displayOnDiff" id="exitButtonMobile"><img src="css/img/exitButton.svg">Exit</div>
+
+                    <div class="option noSubSelect removeOnDiff" id="debugButtonMobile"><img
                             src="css/img/inspectorButton.svg">Inspector</div>
-                    <div class="option subSelect">
+                    <div class="option subSelect removeOnDiff">
                         <img src="css/img/optionsButton.svg">
                         <div id="currentVersionMobile"></div>
                         <div class="toDisplaySub currentVersionDisplay">
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Theme
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Theme
                         <div class="toDisplaySub">
                             <div class="option selected" id="darkThemeMobile">Dark</div>
                             <div class="option" id="lightThemeMobile">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><img src="css/img/optionsButton.svg">Font size
+                    <div class="option subSelect removeOnDiff"><img src="css/img/optionsButton.svg">Font size
                         <div class="toDisplaySub displayFontSize">
                             <div class="option">8</div>
                             <div class="option">10</div>
@@ -245,7 +252,7 @@
                     <div style="display: none;" class="option nosubselect" id="editorFullscreenButtonMobile"
                         style="display: none">Editor
                         Fullscreen</div>
-                    <div class="option nosubselect" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
+                    <div class="option nosubselect removeOnDiff" id="formatButtonMobile"><img src="css/img/optionsButton.svg">Format
                         code</div>
                     <div style="display: none;" class="option nosubselect" id="minimapToggleMobile">Minimap
                         <i class="fa fa-square" aria-hidden="true"></i>
@@ -255,11 +262,11 @@
                             <div class="option" id="qrCodeImageMobile">[QR Code Image]</div>
                         </div>
                     </div> -->
-                    <div class="option nosubselect" id="metadataButtonMobile"><img
+                    <div class="option nosubselect removeOnDiff" id="metadataButtonMobile"><img
                             src="css/img/metadataButton.svg">Metadata</div>
-                    <div class="option nosubselect"><img class="examplesButton"
+                    <div class="option nosubselect removeOnDiff"><img class="examplesButton"
                             src="css/img/examplesButton.svg">Examples</div>
-                    <div class="option subSelect"><img src="css/img/examplesButton.svg">Links / Tools
+                    <div class="option subSelect removeOnDiff"><img src="css/img/examplesButton.svg">Links / Tools
                         <div class="toDisplaySub displayFooterLinks">
                             <div class="option link">
                                 <a target='_new' href="https://www.netlify.com/">Deployed by Netlify</a>
@@ -286,7 +293,7 @@
             </div>
         </div>
 
-        <div id="switchWrapper" class="languageJS">
+        <div id="switchWrapper" class="languageJS removeOnDiff">
             <img id="switchWrapperCode" src="css/img/codeButton.svg">
             <img id="switchWrapperCanvas" src="css/img/canvas3Dbutton.svg">
         </div>
@@ -296,6 +303,7 @@
 
     <div class="wrapper">
         <div id="jsEditor"></div>
+        <div id="diffView" class="diff-view"></div>
         <div id="canvasZone">
             <canvas touch-action="none" id="renderCanvas"></canvas>
         </div>
@@ -375,9 +383,6 @@
         </div>
     </div>
 
-    <div id="diffView" class="diff-view">
-    </div>    
-
     <div id="waitDiv">
         <div id="logo-part">
             <img src="css/img/v4.svg" id="waitLogo" />

Разница между файлами не показана из-за своего большого размера
+ 7359 - 3200
Playground/js/babylonWebGpu.max.js


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


+ 42 - 3
Playground/js/main.js

@@ -280,6 +280,11 @@ class Main {
         this.parent.utils.setToMultipleID("saveButton", "click", this.askForSave.bind(this));
         // Diff
         this.parent.utils.setToMultipleID("diffButton", "click", this.askForDiff.bind(this));
+        this.parent.utils.setToMultipleID("previousButton", "click", this.navigateToPrevious.bind(this));
+        this.parent.utils.setToMultipleID("nextButton", "click", this.navigateToNext.bind(this));
+        this.parent.utils.setToMultipleID("exitButton", "click", function() {
+            this.toggleDiffEditor(this.parent.monacoCreator, this.parent.menuPG)
+        }.bind(this));
         // Zip
         this.parent.utils.setToMultipleID("zipButton", "click", function () {
             this.parent.zipTool.getZip(engine);
@@ -815,16 +820,50 @@ class Main {
         try {
             const leftText = await this.getSnippetCode(document.getElementById("diffFormSource").value);
             const rightText = await this.getSnippetCode(document.getElementById("diffFormCompareTo").value);
-            const diffView = document.getElementById("diffView");
 
-            diffView.style.display = "block";
-            this.parent.monacoCreator.createDiff(leftText, rightText, diffView);
+            this.toggleDiffEditor(this.parent.monacoCreator, this.parent.menuPG, leftText, rightText);
         } catch(e) {
             // only pass the message, we don't want to inspect the stacktrace in this case
             this.parent.utils.showError(e.message, null);
         }
     }
 
+    toggleDiffEditor(monacoCreator, menuPG, leftText, rightText) {
+        const diffView = document.getElementById("diffView");
+
+        if (leftText && rightText) {
+            menuPG.resizeForDiff();
+            diffView.style.display = "block";
+            monacoCreator.createDiff(leftText, rightText, diffView);
+        } else {
+            monacoCreator.disposeDiff();
+            diffView.style.display = "none";
+            if (menuPG.isMobileVersion) {
+                menuPG.resizeBigJsEditor();
+            } else {
+                menuPG.resizeSplitted();
+            }
+        }
+    }
+
+    navigateToPrevious() {
+        var dn = this.parent.monacoCreator.diffNavigator;
+        if (!dn)
+            return;
+
+        if (dn.canNavigate())
+            dn.previous();
+    }
+
+    navigateToNext() {
+        var dn = this.parent.monacoCreator.diffNavigator;
+        if (!dn)
+            return;
+
+        if (dn.canNavigate())
+            dn.next();
+    }
+
     /**
          * Toggle the code editor
          */

+ 38 - 4
Playground/js/menuPG.js

@@ -11,6 +11,8 @@ class MenuPG {
         this.allSubItems = document.querySelectorAll('.toDisplaySub');
         this.allSubSelect = document.querySelectorAll('.subSelect');
         this.allNoSubSelect = document.querySelectorAll('.noSubSelect');
+        this.allDisplayOnDiff = document.querySelectorAll('.displayOnDiff');
+        this.allRemoveOnDiff = document.querySelectorAll('.removeOnDiff');
 
         this.jsEditorElement = document.getElementById('jsEditor');
         this.canvasZoneElement = document.getElementById('canvasZone');
@@ -102,10 +104,12 @@ class MenuPG {
                 return;
             }
 
-            if (document.getElementById("saveLayer").style.display === "block") {
-                return;
+            // we do not want to proceed if a menu is displayed or if we are in diff mode
+            const candidates = ["saveLayer", "diffLayer", "diffView"];
+            if (candidates.every(c => !(document.getElementById(c).style.display === "block"))) {
+                this.removeAllOptions();
             }
-            this.removeAllOptions();
+
         }.bind(this));
 
         // Version selection
@@ -325,6 +329,8 @@ class MenuPG {
             if (document.getElementsByClassName('gutter-horizontal').length > 0) document.getElementsByClassName('gutter-horizontal')[0].style.display = 'none';
             this.switchWrapperCanvas.style.display = 'block';
         }
+        this.setSelectorVisibility(this.allRemoveOnDiff, 'inline-block');
+        this.setSelectorVisibility(this.allDisplayOnDiff, 'none');
     };
     /**
      * Hide the JS editor and display the canvas
@@ -342,6 +348,8 @@ class MenuPG {
             this.switchWrapperCode.style.display = 'block';
             this.fpsLabelElement.style.display = 'block';
         }
+        this.setSelectorVisibility(this.allRemoveOnDiff, 'inline-block');
+        this.setSelectorVisibility(this.allDisplayOnDiff, 'none');
     };
     /**
      * When someone resize from mobile to large screen version
@@ -355,8 +363,25 @@ class MenuPG {
         this.canvasZoneElement.style.width = '50%';
         this.switchWrapperCode.style.display = 'block';
         this.fpsLabelElement.style.display = 'block';
+        this.setSelectorVisibility(this.allRemoveOnDiff, 'inline-block');
+        this.setSelectorVisibility(this.allDisplayOnDiff, 'none');
     };
-
+    /**
+     * Switch to diff mode
+     */
+    resizeForDiff() {
+        this.jsEditorElement.style.width = '0';
+        this.jsEditorElement.style.display = 'none';
+        document.getElementsByClassName('gutter-horizontal')[0].style.display = 'none';
+        this.canvasZoneElement.style.width = '0';
+        this.switchWrapper.style.left = '';
+        this.switchWrapper.style.right = '0';
+        this.switchWrapperCode.style.display = 'none';
+        this.fpsLabelElement.style.display = 'none';
+        // make sure to hide all incompatible buttons with diff mode, and display dedicated buttons
+        this.setSelectorVisibility(this.allRemoveOnDiff, 'none');
+        this.setSelectorVisibility(this.allDisplayOnDiff, 'inline-block');
+    }
     /**
      * Canvas full page
      */
@@ -452,4 +477,13 @@ class MenuPG {
             headings[i].style.visibility = 'visible';
         }
     };
+
+    setSelectorVisibility(selector, displayState) {
+        if (selector) {
+            for (var index = 0; index < selector.length; index++) {
+                var item = selector[index];
+                item.style.display = displayState;
+            }
+        }
+    }
 };

+ 39 - 13
Playground/js/monacoCreator.js

@@ -6,6 +6,8 @@ class MonacoCreator {
         this.parent = parent;
         
         this.jsEditor = null;
+        this.diffEditor = null;
+        this.diffNavigator = null;
         this.monacoMode = "javascript";
         this.blockEditorChange = false;
 
@@ -82,7 +84,7 @@ class MonacoCreator {
         } else {
             typescript.typescriptDefaults.setCompilerOptions({
                 module: typescript.ModuleKind.AMD,
-                target: typescript.ScriptTarget.ES6,
+                target: typescript.ScriptTarget.ES5,
                 noLib: false,
                 noResolve: true,
                 suppressOutputPathCheck: true,
@@ -191,23 +193,47 @@ class MonacoCreator {
             contextmenu: false,
             fontSize: this.parent.settingsPG.fontSize
         }
-       
-        const diffEditor = monaco.editor.createDiffEditor(diffView, diffOptions);
-        diffEditor.setModel({
+
+        this.diffEditor = monaco.editor.createDiffEditor(diffView, diffOptions);
+        this.diffEditor.setModel({
             original: leftModel,
             modified: rightModel
         });
 
-        const cleanup = function() {
-            diffView.style.display = "none";
-            // We need to properly dispose, else the monaco script editor will use those models in the editor compilation pipeline!
-            leftModel.dispose();
-            rightModel.dispose();
-            diffEditor.dispose();
-        }
+        this.diffNavigator = monaco.editor.createDiffNavigator(this.diffEditor, {
+            followsCaret: true,
+            ignoreCharChanges: true
+        });
+        
+        const menuPG = this.parent.menuPG;
+        const main = this.parent.main;
+        const monacoCreator = this;
+
+        this.diffEditor.addCommand(monaco.KeyCode.Escape, function() { main.toggleDiffEditor(monacoCreator, menuPG); });
+        // Adding default VSCode bindinds for previous/next difference
+        this.diffEditor.addCommand(monaco.KeyMod.Alt | monaco.KeyCode.F5, function() { main.navigateToNext(); });
+        this.diffEditor.addCommand(monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.F5, function() { main.navigateToPrevious(); });
+
+        this.diffEditor.focus();
+    }
+
+    disposeDiff() {
+        if (!this.diffEditor)
+            return;
+
+        // We need to properly dispose, else the monaco script editor will use those models in the editor compilation pipeline!
+        let model = this.diffEditor.getModel();
+        let leftModel = model.original;
+        let rightModel = model.modified;
+        
+        leftModel.dispose();
+        rightModel.dispose();
+
+        this.diffNavigator.dispose();
+        this.diffEditor.dispose();
 
-        diffEditor.addCommand(monaco.KeyCode.Escape, cleanup);
-        diffEditor.focus();
+        this.diffNavigator = null;
+        this.diffEditor = null;
     }
 
     /**

+ 145 - 9
dist/preview release/babylon.d.ts

@@ -4458,6 +4458,16 @@ declare module BABYLON {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -4477,6 +4487,16 @@ declare module BABYLON {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -29439,6 +29459,11 @@ declare module BABYLON {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -41499,6 +41524,18 @@ declare module BABYLON {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -41603,6 +41640,9 @@ declare module BABYLON {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -41815,6 +41855,14 @@ declare module BABYLON {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -41990,7 +42038,7 @@ declare module BABYLON {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -42125,7 +42173,7 @@ declare module BABYLON {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -42186,6 +42234,16 @@ declare module BABYLON {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -42999,6 +43057,11 @@ declare module BABYLON {
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -45733,6 +45796,7 @@ declare module BABYLON {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -45753,6 +45817,10 @@ declare module BABYLON {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -45783,6 +45851,10 @@ declare module BABYLON {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -46389,8 +46461,9 @@ declare module BABYLON {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -46414,7 +46487,7 @@ declare module BABYLON {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -53890,6 +53963,7 @@ declare module BABYLON {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -53946,6 +54020,7 @@ declare module BABYLON {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -56374,9 +56449,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -56416,9 +56491,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -56428,6 +56503,67 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Effect Render Options
      */
     export interface IEffectRendererOptions {

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


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


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


+ 301 - 18
dist/preview release/babylon.module.d.ts

@@ -4488,6 +4488,16 @@ declare module "babylonjs/Maths/math.vector" {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -4507,6 +4517,16 @@ declare module "babylonjs/Maths/math.vector" {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -30319,6 +30339,11 @@ declare module "babylonjs/Engines/thinEngine" {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -42966,6 +42991,18 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -43070,6 +43107,9 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -43282,6 +43322,14 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -43477,7 +43525,7 @@ declare module "babylonjs/Cameras/XR/webXRSessionManager" {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -43622,7 +43670,7 @@ declare module "babylonjs/Cameras/XR/webXRExperienceHelper" {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -43688,6 +43736,16 @@ declare module "babylonjs/Cameras/XR/webXREnterExitUI" {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -44545,11 +44603,18 @@ declare module "babylonjs/Gamepads/Controllers/viveController" {
 }
 declare module "babylonjs/Cameras/XR/webXRControllerModelLoader" {
     import { WebXRInput } from "babylonjs/Cameras/XR/webXRInput";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { WebXRController } from "babylonjs/Cameras/XR/webXRController";
     /**
      * Loads a controller model and adds it as a child of the WebXRControllers grip when the controller is created
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -47627,6 +47692,7 @@ declare module "babylonjs/Gizmos/scaleGizmo" {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -47647,6 +47713,10 @@ declare module "babylonjs/Gizmos/scaleGizmo" {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -47687,6 +47757,10 @@ declare module "babylonjs/Gizmos/axisScaleGizmo" {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -48349,8 +48423,9 @@ declare module "babylonjs/Gizmos/lightGizmo" {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -48374,7 +48449,7 @@ declare module "babylonjs/Gizmos/lightGizmo" {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -56446,6 +56521,7 @@ declare module "babylonjs/Materials/Node/Blocks/Dual/textureBlock" {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -56502,6 +56578,7 @@ declare module "babylonjs/Materials/Node/Blocks/Dual/textureBlock" {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -59196,9 +59273,9 @@ declare module "babylonjs/Materials/Node/Blocks/worleyNoise3DBlock" {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -59241,9 +59318,9 @@ declare module "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock" {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -59251,6 +59328,74 @@ declare module "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
     }
 }
+declare module "babylonjs/Materials/Node/Blocks/normalBlendBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module "babylonjs/Materials/Node/Blocks/rotate2dBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/Vertex/index";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/index";
@@ -59294,6 +59439,8 @@ declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/nLerpBlock";
     export * from "babylonjs/Materials/Node/Blocks/worleyNoise3DBlock";
     export * from "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock";
+    export * from "babylonjs/Materials/Node/Blocks/normalBlendBlock";
+    export * from "babylonjs/Materials/Node/Blocks/rotate2dBlock";
 }
 declare module "babylonjs/Materials/Node/Optimizers/index" {
     export * from "babylonjs/Materials/Node/Optimizers/nodeMaterialOptimizer";
@@ -72734,6 +72881,16 @@ declare module BABYLON {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -72753,6 +72910,16 @@ declare module BABYLON {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -97715,6 +97882,11 @@ declare module BABYLON {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -109775,6 +109947,18 @@ declare module BABYLON {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -109879,6 +110063,9 @@ declare module BABYLON {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -110091,6 +110278,14 @@ declare module BABYLON {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -110266,7 +110461,7 @@ declare module BABYLON {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -110401,7 +110596,7 @@ declare module BABYLON {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -110462,6 +110657,16 @@ declare module BABYLON {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -111275,6 +111480,11 @@ declare module BABYLON {
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -114009,6 +114219,7 @@ declare module BABYLON {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -114029,6 +114240,10 @@ declare module BABYLON {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -114059,6 +114274,10 @@ declare module BABYLON {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -114665,8 +114884,9 @@ declare module BABYLON {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -114690,7 +114910,7 @@ declare module BABYLON {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -122166,6 +122386,7 @@ declare module BABYLON {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -122222,6 +122443,7 @@ declare module BABYLON {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -124650,9 +124872,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -124692,9 +124914,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -124704,6 +124926,67 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Effect Render Options
      */
     export interface IEffectRendererOptions {

+ 160 - 20
dist/preview release/documentation.d.ts

@@ -4458,6 +4458,16 @@ declare module BABYLON {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -4477,6 +4487,16 @@ declare module BABYLON {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -29439,6 +29459,11 @@ declare module BABYLON {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -41499,6 +41524,18 @@ declare module BABYLON {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -41603,6 +41640,9 @@ declare module BABYLON {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -41815,6 +41855,14 @@ declare module BABYLON {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -41990,7 +42038,7 @@ declare module BABYLON {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -42125,7 +42173,7 @@ declare module BABYLON {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -42186,6 +42234,16 @@ declare module BABYLON {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -42999,6 +43057,11 @@ declare module BABYLON {
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -45733,6 +45796,7 @@ declare module BABYLON {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -45753,6 +45817,10 @@ declare module BABYLON {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -45783,6 +45851,10 @@ declare module BABYLON {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -46389,8 +46461,9 @@ declare module BABYLON {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -46414,7 +46487,7 @@ declare module BABYLON {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -53890,6 +53963,7 @@ declare module BABYLON {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -53946,6 +54020,7 @@ declare module BABYLON {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -56374,9 +56449,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -56416,9 +56491,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -56428,6 +56503,67 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Effect Render Options
      */
     export interface IEffectRendererOptions {
@@ -66269,8 +66405,13 @@ declare module BABYLON.GUI {
          * @param scene defines the hosting scene
          */
         moveToVector3(position: BABYLON.Vector3, scene: BABYLON.Scene): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        /**
+         * Will store all controls that have this control as ascendant in a given array
+         * @param results defines the array where to store the descendants
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         */
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /**
          * Will return all controls that have this control as ascendant
          * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
@@ -66500,8 +66641,7 @@ declare module BABYLON.GUI {
         protected _postMeasure(): void;
         /** @hidden */
         _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /** @hidden */
         _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         /** @hidden */
@@ -66649,7 +66789,7 @@ declare module BABYLON.GUI {
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _drawText;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[];
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -66971,7 +67111,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         /** @hidden */
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         /**
@@ -67213,7 +67353,7 @@ declare module BABYLON.GUI {
         private _onCutText;
         /** @hidden */
         private _onPasteText;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
@@ -67607,7 +67747,7 @@ declare module BABYLON.GUI {
         horizontalAlignment: number;
         verticalAlignment: number;
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -67744,7 +67884,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {
@@ -68110,7 +68250,7 @@ declare module BABYLON.GUI {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _getTypeName(): string;
     }
 }
@@ -68143,7 +68283,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {

+ 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.1",
+    "version": "4.1.0-beta.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 15 - 11
dist/preview release/gui/babylon.gui.d.ts

@@ -1013,8 +1013,13 @@ declare module BABYLON.GUI {
          * @param scene defines the hosting scene
          */
         moveToVector3(position: BABYLON.Vector3, scene: BABYLON.Scene): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        /**
+         * Will store all controls that have this control as ascendant in a given array
+         * @param results defines the array where to store the descendants
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         */
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /**
          * Will return all controls that have this control as ascendant
          * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
@@ -1244,8 +1249,7 @@ declare module BABYLON.GUI {
         protected _postMeasure(): void;
         /** @hidden */
         _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /** @hidden */
         _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         /** @hidden */
@@ -1393,7 +1397,7 @@ declare module BABYLON.GUI {
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _drawText;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[];
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -1715,7 +1719,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         /** @hidden */
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         /**
@@ -1957,7 +1961,7 @@ declare module BABYLON.GUI {
         private _onCutText;
         /** @hidden */
         private _onPasteText;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
@@ -2351,7 +2355,7 @@ declare module BABYLON.GUI {
         horizontalAlignment: number;
         verticalAlignment: number;
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -2488,7 +2492,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {
@@ -2854,7 +2858,7 @@ declare module BABYLON.GUI {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _getTypeName(): string;
     }
 }
@@ -2887,7 +2891,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {

+ 17 - 13
dist/preview release/gui/babylon.gui.js

@@ -1751,7 +1751,7 @@ var Checkbox = /** @class */ (function (_super) {
         return "Checkbox";
     };
     /** @hidden */
-    Checkbox.prototype._draw = function (context) {
+    Checkbox.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         this._applyStates(context);
         var actualWidth = this._currentMeasure.width - this._thickness;
@@ -3569,8 +3569,7 @@ var Container = /** @class */ (function (_super) {
             child._render(context, invalidatedRectangle);
         }
     };
-    /** @hidden */
-    Container.prototype._getDescendants = function (results, directDescendantsOnly, predicate) {
+    Container.prototype.getDescendantsToRef = function (results, directDescendantsOnly, predicate) {
         if (directDescendantsOnly === void 0) { directDescendantsOnly = false; }
         if (!this.children) {
             return;
@@ -3581,7 +3580,7 @@ var Container = /** @class */ (function (_super) {
                 results.push(item);
             }
             if (!directDescendantsOnly) {
-                item._getDescendants(results, false, predicate);
+                item.getDescendantsToRef(results, false, predicate);
             }
         }
     };
@@ -4727,8 +4726,13 @@ var Control = /** @class */ (function () {
         }
         this.notRenderable = false;
     };
-    /** @hidden */
-    Control.prototype._getDescendants = function (results, directDescendantsOnly, predicate) {
+    /**
+     * Will store all controls that have this control as ascendant in a given array
+     * @param results defines the array where to store the descendants
+     * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+     * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+     */
+    Control.prototype.getDescendantsToRef = function (results, directDescendantsOnly, predicate) {
         if (directDescendantsOnly === void 0) { directDescendantsOnly = false; }
         // Do nothing by default
     };
@@ -4740,7 +4744,7 @@ var Control = /** @class */ (function () {
      */
     Control.prototype.getDescendants = function (directDescendantsOnly, predicate) {
         var results = new Array();
-        this._getDescendants(results, directDescendantsOnly, predicate);
+        this.getDescendantsToRef(results, directDescendantsOnly, predicate);
         return results;
     };
     /**
@@ -5665,7 +5669,7 @@ var DisplayGrid = /** @class */ (function (_super) {
         enumerable: true,
         configurable: true
     });
-    DisplayGrid.prototype._draw = function (context) {
+    DisplayGrid.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         this._applyStates(context);
         if (this._isEnabled) {
@@ -7955,7 +7959,7 @@ var InputText = /** @class */ (function (_super) {
         var insertPosition = this._text.length - this._cursorOffset;
         this.text = this._text.slice(0, insertPosition) + data + this._text.slice(insertPosition);
     };
-    InputText.prototype._draw = function (context) {
+    InputText.prototype._draw = function (context, invalidatedRectangle) {
         var _this = this;
         context.save();
         this._applyStates(context);
@@ -8609,7 +8613,7 @@ var MultiLine = /** @class */ (function (_super) {
     MultiLine.prototype._getTypeName = function () {
         return "MultiLine";
     };
-    MultiLine.prototype._draw = function (context) {
+    MultiLine.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
             context.shadowColor = this.shadowColor;
@@ -10587,7 +10591,7 @@ var ImageBasedSlider = /** @class */ (function (_super) {
     ImageBasedSlider.prototype._getTypeName = function () {
         return "ImageBasedSlider";
     };
-    ImageBasedSlider.prototype._draw = function (context) {
+    ImageBasedSlider.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         this._applyStates(context);
         this._prepareRenderingData("rectangle");
@@ -10896,7 +10900,7 @@ var Slider = /** @class */ (function (_super) {
     Slider.prototype._getTypeName = function () {
         return "Slider";
     };
-    Slider.prototype._draw = function (context) {
+    Slider.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         this._applyStates(context);
         this._prepareRenderingData(this.isThumbCircle ? "circle" : "rectangle");
@@ -11639,7 +11643,7 @@ var TextBlock = /** @class */ (function (_super) {
         context.fillText(text, this._currentMeasure.left + x, y);
     };
     /** @hidden */
-    TextBlock.prototype._draw = function (context) {
+    TextBlock.prototype._draw = function (context, invalidatedRectangle) {
         context.save();
         this._applyStates(context);
         // Render lines

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


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


+ 41 - 22
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1043,8 +1043,13 @@ declare module "babylonjs-gui/2D/controls/control" {
          * @param scene defines the hosting scene
          */
         moveToVector3(position: Vector3, scene: Scene): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        /**
+         * Will store all controls that have this control as ascendant in a given array
+         * @param results defines the array where to store the descendants
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         */
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /**
          * Will return all controls that have this control as ascendant
          * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
@@ -1278,8 +1283,7 @@ declare module "babylonjs-gui/2D/controls/container" {
         protected _postMeasure(): void;
         /** @hidden */
         _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /** @hidden */
         _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         /** @hidden */
@@ -1316,6 +1320,7 @@ declare module "babylonjs-gui/2D/controls/textBlock" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Measure } from "babylonjs-gui/2D/measure";
     import { Control } from "babylonjs-gui/2D/controls/control";
+    import { Nullable } from 'babylonjs/types';
     /**
      * Enum that determines the text-wrapping mode to use.
      */
@@ -1432,7 +1437,7 @@ declare module "babylonjs-gui/2D/controls/textBlock" {
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _drawText;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[];
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -1742,6 +1747,8 @@ declare module "babylonjs-gui/2D/controls/checkbox" {
     import { Vector2 } from "babylonjs/Maths/math";
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { StackPanel } from "babylonjs-gui/2D/controls/stackPanel";
+    import { Nullable } from 'babylonjs/types';
+    import { Measure } from "babylonjs-gui/2D/measure";
     /**
      * Class used to represent a 2D checkbox
      */
@@ -1770,7 +1777,7 @@ declare module "babylonjs-gui/2D/controls/checkbox" {
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
         /** @hidden */
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         /**
@@ -1887,6 +1894,7 @@ declare module "babylonjs-gui/2D/controls/inputText" {
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { IFocusableControl } from "babylonjs-gui/2D/advancedDynamicTexture";
     import { VirtualKeyboard } from "babylonjs-gui/2D/controls/virtualKeyboard";
+    import { Measure } from "babylonjs-gui/2D/measure";
     /**
      * Class used to create input text control
      */
@@ -2022,7 +2030,7 @@ declare module "babylonjs-gui/2D/controls/inputText" {
         private _onCutText;
         /** @hidden */
         private _onPasteText;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
@@ -2375,6 +2383,7 @@ declare module "babylonjs-gui/2D/multiLinePoint" {
     }
 }
 declare module "babylonjs-gui/2D/controls/multiLine" {
+    import { Nullable } from "babylonjs/types";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { MultiLinePoint } from "babylonjs-gui/2D/multiLinePoint";
@@ -2442,7 +2451,7 @@ declare module "babylonjs-gui/2D/controls/multiLine" {
         horizontalAlignment: number;
         verticalAlignment: number;
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -2565,6 +2574,8 @@ declare module "babylonjs-gui/2D/controls/sliders/baseSlider" {
 }
 declare module "babylonjs-gui/2D/controls/sliders/slider" {
     import { BaseSlider } from "babylonjs-gui/2D/controls/sliders/baseSlider";
+    import { Nullable } from 'babylonjs/types';
+    import { Measure } from "babylonjs-gui/2D/measure";
     /**
      * Class used to create slider controls
      */
@@ -2588,7 +2599,7 @@ declare module "babylonjs-gui/2D/controls/sliders/slider" {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
     }
 }
 declare module "babylonjs-gui/2D/controls/selector" {
@@ -2931,6 +2942,8 @@ declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
 }
 declare module "babylonjs-gui/2D/controls/displayGrid" {
     import { Control } from "babylonjs-gui/2D/controls/control";
+    import { Nullable } from 'babylonjs/types';
+    import { Measure } from "babylonjs-gui/2D/measure";
     /** Class used to render a grid  */
     export class DisplayGrid extends Control {
         name?: string | undefined;
@@ -2969,13 +2982,15 @@ declare module "babylonjs-gui/2D/controls/displayGrid" {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
         protected _getTypeName(): string;
     }
 }
 declare module "babylonjs-gui/2D/controls/sliders/imageBasedSlider" {
     import { BaseSlider } from "babylonjs-gui/2D/controls/sliders/baseSlider";
+    import { Measure } from "babylonjs-gui/2D/measure";
     import { Image } from "babylonjs-gui/2D/controls/image";
+    import { Nullable } from 'babylonjs/types';
     /**
      * Class used to create slider controls based on images
      */
@@ -3004,7 +3019,7 @@ declare module "babylonjs-gui/2D/controls/sliders/imageBasedSlider" {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void;
     }
 }
 declare module "babylonjs-gui/2D/controls/statics" {
@@ -4948,8 +4963,13 @@ declare module BABYLON.GUI {
          * @param scene defines the hosting scene
          */
         moveToVector3(position: BABYLON.Vector3, scene: BABYLON.Scene): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        /**
+         * Will store all controls that have this control as ascendant in a given array
+         * @param results defines the array where to store the descendants
+         * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+         * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+         */
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /**
          * Will return all controls that have this control as ascendant
          * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
@@ -5179,8 +5199,7 @@ declare module BABYLON.GUI {
         protected _postMeasure(): void;
         /** @hidden */
         _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Measure): void;
-        /** @hidden */
-        _getDescendants(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
+        getDescendantsToRef(results: Control[], directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): void;
         /** @hidden */
         _processPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): boolean;
         /** @hidden */
@@ -5328,7 +5347,7 @@ declare module BABYLON.GUI {
         protected _processMeasures(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         private _drawText;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _applyStates(context: CanvasRenderingContext2D): void;
         protected _breakLines(refWidth: number, context: CanvasRenderingContext2D): object[];
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;
@@ -5650,7 +5669,7 @@ declare module BABYLON.GUI {
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
         /** @hidden */
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         /** @hidden */
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         /**
@@ -5892,7 +5911,7 @@ declare module BABYLON.GUI {
         private _onCutText;
         /** @hidden */
         private _onPasteText;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: BABYLON.Vector2, pointerId: number): void;
         _onPointerUp(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
@@ -6286,7 +6305,7 @@ declare module BABYLON.GUI {
         horizontalAlignment: number;
         verticalAlignment: number;
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _measure(): void;
         protected _computeAlignment(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
@@ -6423,7 +6442,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {
@@ -6789,7 +6808,7 @@ declare module BABYLON.GUI {
          * @param name defines the control name
          */
         constructor(name?: string | undefined);
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
         protected _getTypeName(): string;
     }
 }
@@ -6822,7 +6841,7 @@ declare module BABYLON.GUI {
          */
         constructor(name?: string | undefined);
         protected _getTypeName(): string;
-        _draw(context: CanvasRenderingContext2D): void;
+        _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: BABYLON.Nullable<Measure>): void;
     }
 }
 declare module BABYLON.GUI {

+ 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.1",
+    "version": "4.1.0-beta.2",
     "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.1"
+        "babylonjs": "4.1.0-beta.2"
     },
     "engines": {
         "node": "*"

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


+ 58 - 20
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -43352,6 +43352,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -43394,7 +43396,11 @@ var CommonCameraPropertyGridComponent = /** @class */ (function (_super) {
                 camera.mode === babylonjs_Cameras_camera__WEBPACK_IMPORTED_MODULE_2__["Camera"].ORTHOGRAPHIC_CAMERA &&
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Right", target: camera, propertyName: "orthoRight", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 camera.mode === babylonjs_Cameras_camera__WEBPACK_IMPORTED_MODULE_2__["Camera"].ORTHOGRAPHIC_CAMERA &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Bottom", target: camera, propertyName: "orthoBottom", onPropertyChangedObservable: this.props.onPropertyChangedObservable }))));
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Bottom", target: camera, propertyName: "orthoBottom", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_9__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        camera.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } }))));
     };
     return CommonCameraPropertyGridComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -44479,6 +44485,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -44491,6 +44499,7 @@ var CommonLightPropertyGridComponent = /** @class */ (function (_super) {
         return _super.call(this, props) || this;
     }
     CommonLightPropertyGridComponent.prototype.render = function () {
+        var _this = this;
         var light = this.props.light;
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_5__["CustomPropertyGridComponent"], { globalState: this.props.globalState, target: light, lockObject: this.props.lockObject, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
@@ -44498,7 +44507,11 @@ var CommonLightPropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "ID", value: light.id }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Unique ID", value: light.uniqueId.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Class", value: light.getClassName() }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Intensity", target: light, propertyName: "intensity", onPropertyChangedObservable: this.props.onPropertyChangedObservable }))));
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Intensity", target: light, propertyName: "intensity", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_6__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        light.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } }))));
     };
     return CommonLightPropertyGridComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -44923,6 +44936,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -44987,7 +45002,11 @@ var CommonMaterialPropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__["CheckBoxLineComponent"], { label: "Wireframe", target: material, propertyName: "wireframe", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__["CheckBoxLineComponent"], { label: "Point cloud", target: material, propertyName: "pointsCloud", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_4__["SliderLineComponent"], { label: "Point size", target: material, propertyName: "pointSize", minimum: 0, maximum: 100, step: 0.1, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_4__["SliderLineComponent"], { label: "Z-offset", target: material, propertyName: "zOffset", minimum: -10, maximum: 10, step: 0.1, onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_4__["SliderLineComponent"], { label: "Z-offset", target: material, propertyName: "zOffset", minimum: -10, maximum: 10, step: 0.1, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_9__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        material.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_5__["LineContainerComponent"], { globalState: this.props.globalState, title: "TRANSPARENCY" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_4__["SliderLineComponent"], { label: "Alpha", target: material, propertyName: "alpha", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 material.transparencyMode !== undefined &&
@@ -45948,6 +45967,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
 /* harmony import */ var _lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../../lines/color3LineComponent */ "./components/actionTabs/lines/color3LineComponent.tsx");
 /* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -46193,7 +46214,11 @@ var MeshPropertyGridComponent = /** @class */ (function (_super) {
                 mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) &&
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Material", value: mesh.material.name, onLink: function () { return _this.onMaterialLink(); } }),
                 mesh.isAnInstance &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Source", value: mesh.sourceMesh.name, onLink: function () { return _this.onSourceMeshLink(); } })),
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__["TextLineComponent"], { label: "Source", value: mesh.sourceMesh.name, onLink: function () { return _this.onSourceMeshLink(); } }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_13__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        mesh.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "TRANSFORMS" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_6__["Vector3LineComponent"], { label: "Position", target: mesh, propertyName: "position", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 !mesh.rotationQuaternion &&
@@ -46412,6 +46437,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _lines_quaternionLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/quaternionLineComponent */ "./components/actionTabs/lines/quaternionLineComponent.tsx");
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -46436,7 +46463,11 @@ var TransformNodePropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Class", value: transformNode.getClassName() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__["CheckBoxLineComponent"], { label: "IsEnabled", isSelected: function () { return transformNode.isEnabled(); }, onSelect: function (value) { return transformNode.setEnabled(value); } }),
                 transformNode.parent &&
-                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Parent", value: transformNode.parent.name, onLink: function () { return _this.props.globalState.onSelectionChangedObservable.notifyObservers(transformNode.parent); } })),
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Parent", value: transformNode.parent.name, onLink: function () { return _this.props.globalState.onSelectionChangedObservable.notifyObservers(transformNode.parent); } }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_8__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        transformNode.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "TRANSFORMATIONS" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_4__["Vector3LineComponent"], { label: "Position", target: transformNode, propertyName: "position", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 !transformNode.rotationQuaternion &&
@@ -46470,6 +46501,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
 /* harmony import */ var _lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/color3LineComponent */ "./components/actionTabs/lines/color3LineComponent.tsx");
 /* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
 
 
 
@@ -46483,6 +46516,7 @@ var CommonPostProcessPropertyGridComponent = /** @class */ (function (_super) {
         return _super.call(this, props) || this;
     }
     CommonPostProcessPropertyGridComponent.prototype.render = function () {
+        var _this = this;
         var postProcess = this.props.postProcess;
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", null,
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { globalState: this.props.globalState, title: "GENERAL" },
@@ -46496,7 +46530,11 @@ var CommonPostProcessPropertyGridComponent = /** @class */ (function (_super) {
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color3LineComponent__WEBPACK_IMPORTED_MODULE_5__["Color3LineComponent"], { label: "Clear color", target: postProcess, propertyName: "clearColor", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_2__["CheckBoxLineComponent"], { label: "Pixel perfect", target: postProcess, propertyName: "enablePixelPerfectMode", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_2__["CheckBoxLineComponent"], { label: "Fullscreen viewport", target: postProcess, propertyName: "forceFullscreenViewport", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Samples", target: postProcess, propertyName: "samples", minimum: 1, maximum: 8, step: 1, decimalCount: 0, onPropertyChangedObservable: this.props.onPropertyChangedObservable }))));
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_6__["SliderLineComponent"], { label: "Samples", target: postProcess, propertyName: "samples", minimum: 1, maximum: 8, step: 1, decimalCount: 0, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_7__["ButtonLineComponent"], { label: "Dispose", onClick: function () {
+                        postProcess.dispose();
+                        _this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    } }))));
     };
     return CommonPostProcessPropertyGridComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -47266,17 +47304,17 @@ var StatisticsTabComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total materials", value: scene.materials.length.toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Total textures", value: scene.textures.length.toString() })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_4__["LineContainerComponent"], { globalState: this.props.globalState, title: "FRAME STEPS DURATION" },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Absolute FPS", value: 1000.0 / this._sceneInstrumentation.frameTimeCounter.current, fractionDigits: 0 }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Meshes selection", value: sceneInstrumentation.activeMeshesEvaluationTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Render targets", value: sceneInstrumentation.renderTargetsRenderTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Particles", value: sceneInstrumentation.particlesRenderTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Sprites", value: sceneInstrumentation.spritesRenderTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Animations", value: sceneInstrumentation.animationsTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Physics", value: sceneInstrumentation.physicsTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Render", value: sceneInstrumentation.renderTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Frame total", value: sceneInstrumentation.frameTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Inter-frame", value: sceneInstrumentation.interFrameTimeCounter.current, units: "ms" }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "GPU Frame time", value: engineInstrumentation.gpuFrameTimeCounter.current * 0.000001, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Absolute FPS", value: 1000.0 / this._sceneInstrumentation.frameTimeCounter.lastSecAverage, fractionDigits: 0 }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Meshes selection", value: sceneInstrumentation.activeMeshesEvaluationTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Render targets", value: sceneInstrumentation.renderTargetsRenderTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Particles", value: sceneInstrumentation.particlesRenderTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Sprites", value: sceneInstrumentation.spritesRenderTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Animations", value: sceneInstrumentation.animationsTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Physics", value: sceneInstrumentation.physicsTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Render", value: sceneInstrumentation.renderTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Frame total", value: sceneInstrumentation.frameTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "Inter-frame", value: sceneInstrumentation.interFrameTimeCounter.lastSecAverage, units: "ms" }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "GPU Frame time", value: engineInstrumentation.gpuFrameTimeCounter.lastSecAverage * 0.000001, units: "ms" }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_6__["ValueLineComponent"], { label: "GPU Frame time (average)", value: engineInstrumentation.gpuFrameTimeCounter.average * 0.000001, units: "ms" })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_4__["LineContainerComponent"], { globalState: this.props.globalState, title: "SYSTEM INFO" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Resolution", value: engine.getRenderWidth() + "x" + engine.getRenderHeight() }),
@@ -49273,10 +49311,11 @@ var SceneExplorerComponent = /** @class */ (function (_super) {
         return _this;
     }
     SceneExplorerComponent.prototype.processMutation = function () {
+        var _this = this;
         if (this.props.globalState.blockMutationUpdates) {
             return;
         }
-        this.forceUpdate();
+        setTimeout(function () { return _this.forceUpdate(); });
     };
     SceneExplorerComponent.prototype.componentDidMount = function () {
         var _this = this;
@@ -49829,7 +49868,6 @@ var TreeItemSelectableComponent = /** @class */ (function (_super) {
                 }
                 if (entity.getDescendants) {
                     if (entity.getDescendants(false, function (n) {
-                        console.log(n.name);
                         return n.name && n.name.toLowerCase().indexOf(lowerCaseFilter_1) !== -1;
                     }).length === 0) {
                         return null;
@@ -49915,7 +49953,7 @@ var TreeItemSpecializedComponent = /** @class */ (function (_super) {
             if (className.indexOf("Mesh") !== -1) {
                 var mesh = entity;
                 if (mesh.isAnInstance || mesh.getTotalVertices() > 0) {
-                    return (react__WEBPACK_IMPORTED_MODULE_9__["createElement"](_entities_meshTreeItemComponent__WEBPACK_IMPORTED_MODULE_1__["MeshTreeItemComponent"], { extensibilityGroups: this.props.extensibilityGroups, mesh: mesh, onClick: function () { return _this.onClick(); } }));
+                    return (react__WEBPACK_IMPORTED_MODULE_9__["createElement"](_entities_meshTreeItemComponent__WEBPACK_IMPORTED_MODULE_1__["MeshTreeItemComponent"], { globalState: this.props.globalState, extensibilityGroups: this.props.extensibilityGroups, mesh: mesh, onClick: function () { return _this.onClick(); } }));
                 }
                 else {
                     return (react__WEBPACK_IMPORTED_MODULE_9__["createElement"](_entities_transformNodeTreeItemComponent__WEBPACK_IMPORTED_MODULE_8__["TransformNodeItemComponent"], { extensibilityGroups: this.props.extensibilityGroups, transformNode: entity, onClick: function () { return _this.onClick(); } }));

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


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

@@ -423,6 +423,16 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface ICommonMaterialPropertyGridComponentProps {
         globalState: GlobalState;
         material: BABYLON.Material;
@@ -500,16 +510,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module INSPECTOR {
     interface ITextureLineComponentProps {
         texture: BABYLON.BaseTexture;
         width: number;
@@ -1465,6 +1465,7 @@ declare module INSPECTOR {
         mesh: BABYLON.AbstractMesh;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class MeshTreeItemComponent extends React.Component<IMeshTreeItemComponentProps, {
         isBoundingBoxEnabled: boolean;

+ 24 - 21
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -482,6 +482,17 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/cus
         render(): JSX.Element | null;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/lines/buttonLineComponent" {
+    import * as React from "react";
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent" {
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
@@ -583,17 +594,6 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mat
         render(): JSX.Element;
     }
 }
-declare module "babylonjs-inspector/components/actionTabs/lines/buttonLineComponent" {
-    import * as React from "react";
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
-        render(): JSX.Element;
-    }
-}
 declare module "babylonjs-inspector/components/actionTabs/lines/textureLineComponent" {
     import * as React from "react";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
@@ -1875,10 +1875,12 @@ declare module "babylonjs-inspector/components/sceneExplorer/entities/meshTreeIt
     import { IExplorerExtensibilityGroup } from "babylonjs/Debug/debugLayer";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import * as React from "react";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
     interface IMeshTreeItemComponentProps {
         mesh: AbstractMesh;
         extensibilityGroups?: IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class MeshTreeItemComponent extends React.Component<IMeshTreeItemComponentProps, {
         isBoundingBoxEnabled: boolean;
@@ -2748,6 +2750,16 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface ICommonMaterialPropertyGridComponentProps {
         globalState: GlobalState;
         material: BABYLON.Material;
@@ -2825,16 +2837,6 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module INSPECTOR {
     interface ITextureLineComponentProps {
         texture: BABYLON.BaseTexture;
         width: number;
@@ -3790,6 +3792,7 @@ declare module INSPECTOR {
         mesh: BABYLON.AbstractMesh;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
         onClick: () => void;
+        globalState: GlobalState;
     }
     export class MeshTreeItemComponent extends React.Component<IMeshTreeItemComponentProps, {
         isBoundingBoxEnabled: boolean;

+ 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.1",
+    "version": "4.1.0-beta.2",
     "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.1",
-        "babylonjs-gui": "4.1.0-beta.1",
-        "babylonjs-loaders": "4.1.0-beta.1",
-        "babylonjs-materials": "4.1.0-beta.1",
-        "babylonjs-serializers": "4.1.0-beta.1",
-        "babylonjs-gltf2interface": "4.1.0-beta.1"
+        "babylonjs": "4.1.0-beta.2",
+        "babylonjs-gui": "4.1.0-beta.2",
+        "babylonjs-loaders": "4.1.0-beta.2",
+        "babylonjs-materials": "4.1.0-beta.2",
+        "babylonjs-serializers": "4.1.0-beta.2",
+        "babylonjs-gltf2interface": "4.1.0-beta.2"
     },
     "devDependencies": {
         "@types/react": "~16.7.3",

+ 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.1",
+    "version": "4.1.0-beta.2",
     "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.1",
-        "babylonjs": "4.1.0-beta.1"
+        "babylonjs-gltf2interface": "4.1.0-beta.2",
+        "babylonjs": "4.1.0-beta.2"
     },
     "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.1",
+    "version": "4.1.0-beta.2",
     "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.1"
+        "babylonjs": "4.1.0-beta.2"
     },
     "engines": {
         "node": "*"

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


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


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


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


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


+ 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.1",
+    "version": "4.1.0-beta.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.1"
+        "babylonjs": "4.1.0-beta.2"
     },
     "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.1",
+    "version": "4.1.0-beta.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1 +1 @@
-{"thinEngineOnly":116089,"engineOnly":152950,"sceneOnly":496943,"minGridMaterial":627573,"minStandardMaterial":751426}
+{"thinEngineOnly":116222,"engineOnly":153083,"sceneOnly":497461,"minGridMaterial":628091,"minStandardMaterial":751944}

+ 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.1",
+    "version": "4.1.0-beta.2",
     "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.1"
+        "babylonjs": "4.1.0-beta.2"
     },
     "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.1",
+    "version": "4.1.0-beta.2",
     "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.1"
+        "babylonjs": "4.1.0-beta.2"
     },
     "engines": {
         "node": "*"

+ 1 - 1
dist/preview release/readme.md

@@ -120,7 +120,7 @@ Please see the [Contributing Guidelines](./contributing.md)
 - Online [sandbox](https://www.babylonjs.com/sandbox) where you can test your .babylon and glTF scenes with a simple drag'n'drop
 - Online [shader creation tool](https://www.babylonjs.com/cyos/) where you can learn how to create GLSL shaders
 - 3DS Max [exporter](https://github.com/BabylonJS/Exporters/tree/master/3ds%20Max) can be used to generate a .babylon file from 3DS Max
-- Maya [exporter](https://github.com/BabylonJS/Exporters/tree/master/Maya) can be used to generate a .babylon file from 3DS Max
+- Maya [exporter](https://github.com/BabylonJS/Exporters/tree/master/Maya) can be used to generate a .babylon file from Maya
 - Blender [exporter](https://github.com/BabylonJS/Exporters/tree/master/Blender) can be used to generate a .babylon file from Blender 3d
 - Unity 5[ (deprecated) exporter](https://github.com/BabylonJS/Exporters/tree/master/Unity) can be used to export your geometries from Unity 5 scene editor(animations are supported)
 - [glTF Tools](https://github.com/KhronosGroup/glTF#gltf-tools) by KhronosGroup

+ 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.1",
+    "version": "4.1.0-beta.2",
     "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.1",
-        "babylonjs-gltf2interface": "4.1.0-beta.1"
+        "babylonjs": "4.1.0-beta.2",
+        "babylonjs-gltf2interface": "4.1.0-beta.2"
     },
     "engines": {
         "node": "*"

+ 301 - 18
dist/preview release/viewer/babylon.module.d.ts

@@ -4488,6 +4488,16 @@ declare module "babylonjs/Maths/math.vector" {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -4507,6 +4517,16 @@ declare module "babylonjs/Maths/math.vector" {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -30319,6 +30339,11 @@ declare module "babylonjs/Engines/thinEngine" {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -42966,6 +42991,18 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -43070,6 +43107,9 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -43282,6 +43322,14 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -43477,7 +43525,7 @@ declare module "babylonjs/Cameras/XR/webXRSessionManager" {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -43622,7 +43670,7 @@ declare module "babylonjs/Cameras/XR/webXRExperienceHelper" {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -43688,6 +43736,16 @@ declare module "babylonjs/Cameras/XR/webXREnterExitUI" {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -44545,11 +44603,18 @@ declare module "babylonjs/Gamepads/Controllers/viveController" {
 }
 declare module "babylonjs/Cameras/XR/webXRControllerModelLoader" {
     import { WebXRInput } from "babylonjs/Cameras/XR/webXRInput";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { WebXRController } from "babylonjs/Cameras/XR/webXRController";
     /**
      * Loads a controller model and adds it as a child of the WebXRControllers grip when the controller is created
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -47627,6 +47692,7 @@ declare module "babylonjs/Gizmos/scaleGizmo" {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -47647,6 +47713,10 @@ declare module "babylonjs/Gizmos/scaleGizmo" {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -47687,6 +47757,10 @@ declare module "babylonjs/Gizmos/axisScaleGizmo" {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -48349,8 +48423,9 @@ declare module "babylonjs/Gizmos/lightGizmo" {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -48374,7 +48449,7 @@ declare module "babylonjs/Gizmos/lightGizmo" {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -56446,6 +56521,7 @@ declare module "babylonjs/Materials/Node/Blocks/Dual/textureBlock" {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -56502,6 +56578,7 @@ declare module "babylonjs/Materials/Node/Blocks/Dual/textureBlock" {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -59196,9 +59273,9 @@ declare module "babylonjs/Materials/Node/Blocks/worleyNoise3DBlock" {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -59241,9 +59318,9 @@ declare module "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock" {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -59251,6 +59328,74 @@ declare module "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
     }
 }
+declare module "babylonjs/Materials/Node/Blocks/normalBlendBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module "babylonjs/Materials/Node/Blocks/rotate2dBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/Vertex/index";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/index";
@@ -59294,6 +59439,8 @@ declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/nLerpBlock";
     export * from "babylonjs/Materials/Node/Blocks/worleyNoise3DBlock";
     export * from "babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock";
+    export * from "babylonjs/Materials/Node/Blocks/normalBlendBlock";
+    export * from "babylonjs/Materials/Node/Blocks/rotate2dBlock";
 }
 declare module "babylonjs/Materials/Node/Optimizers/index" {
     export * from "babylonjs/Materials/Node/Optimizers/nodeMaterialOptimizer";
@@ -72734,6 +72881,16 @@ declare module BABYLON {
          */
         static PerspectiveFovLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a left-handed perspective projection into a given matrix with depth reversed
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseLHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Creates a right-handed perspective projection matrix
          * @param fov defines the horizontal field of view
          * @param aspect defines the aspect ratio
@@ -72753,6 +72910,16 @@ declare module BABYLON {
          */
         static PerspectiveFovRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
         /**
+         * Stores a right-handed perspective projection into a given matrix
+         * @param fov defines the horizontal field of view
+         * @param aspect defines the aspect ratio
+         * @param znear defines the near clip plane
+         * @param zfar not used as infinity is used as far clip
+         * @param result defines the target matrix
+         * @param isVerticalFovFixed defines it the fov is vertically fixed (default) or horizontally
+         */
+        static PerspectiveFovReverseRHToRef(fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed?: boolean): void;
+        /**
          * Stores a perspective projection for WebVR info a given matrix
          * @param fov defines the field of view
          * @param znear defines the near clip plane
@@ -97715,6 +97882,11 @@ declare module BABYLON {
         /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
         validateShaderPrograms: boolean;
         /**
+         * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+         * This can provide greater z depth for distant objects.
+         */
+        useReverseDepthBuffer: boolean;
+        /**
          * Gets or sets a boolean indicating that uniform buffers must be disabled even if they are supported
          */
         disableUniformBuffers: boolean;
@@ -109775,6 +109947,18 @@ declare module BABYLON {
          * A list of meshes to be used as the teleportation floor. (default: empty)
          */
         floorMeshes?: Mesh[];
+        /**
+         * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+         */
+        teleportationMode?: number;
+        /**
+         * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+         */
+        teleportationTime?: number;
+        /**
+         * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+         */
+        teleportationSpeed?: number;
     }
     /**
      * Options to modify the vr experience helper's behavior.
@@ -109879,6 +110063,9 @@ declare module BABYLON {
         private _teleportActive;
         private _floorMeshName;
         private _floorMeshesCollection;
+        private _teleportationMode;
+        private _teleportationTime;
+        private _teleportationSpeed;
         private _rotationAllowed;
         private _teleportBackwardsVector;
         private _teleportationTarget;
@@ -110091,6 +110278,14 @@ declare module BABYLON {
         private _workingQuaternion;
         private _workingMatrix;
         /**
+         * Time Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTTIME: number;
+        /**
+         * Speed Constant Teleportation Mode
+         */
+        static readonly TELEPORTATIONMODE_CONSTANTSPEED: number;
+        /**
          * Teleports the users feet to the desired location
          * @param location The location where the user's feet should be placed
          */
@@ -110266,7 +110461,7 @@ declare module BABYLON {
          * @param optionalFeatures defines optional values to pass to the session builder
          * @returns a promise which will resolve once the session has been initialized
          */
-        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): any;
+        initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures?: any): Promise<XRSession>;
         /**
          * Sets the reference space on the xr session
          * @param referenceSpace space to set
@@ -110401,7 +110596,7 @@ declare module BABYLON {
          * @param renderTarget the output canvas that will be used to enter XR mode
          * @returns promise that resolves after xr mode has entered
          */
-        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): any;
+        enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager>;
         /**
          * Updates the global position of the camera by moving the camera's container
          * This should be used instead of modifying the camera's position as it will be overwritten by an xrSessions's update frame
@@ -110462,6 +110657,16 @@ declare module BABYLON {
          * User provided buttons to enable/disable WebXR. The system will provide default if not set
          */
         customButtons?: Array<WebXREnterExitUIButton>;
+        /**
+         * A session mode to use when creating the default button.
+         * Default is immersive-vr
+         */
+        sessionMode?: XRSessionMode;
+        /**
+         * A reference space type to use when creating the default button.
+         * Default is local-floor
+         */
+        referenceSpaceType?: XRReferenceSpaceType;
     }
     /**
      * UI to allow the user to enter/exit XR mode
@@ -111275,6 +111480,11 @@ declare module BABYLON {
      */
     export class WebXRControllerModelLoader {
         /**
+         * an observable that triggers when a new model (the mesh itself) was initialized.
+         * To know when the mesh was loaded use the controller's own modelLoaded() method
+         */
+        onControllerModelLoaded: Observable<WebXRController>;
+        /**
          * Creates the WebXRControllerModelLoader
          * @param input xr input that creates the controllers
          */
@@ -114009,6 +114219,7 @@ declare module BABYLON {
         private _scaleRatio;
         private _uniformScalingMesh;
         private _octahedron;
+        private _sensitivity;
         /** Fires an event when any of it's sub gizmos are dragged */
         onDragStartObservable: Observable<unknown>;
         /** Fires an event when any of it's sub gizmos are released from dragging */
@@ -114029,6 +114240,10 @@ declare module BABYLON {
          */
         scaleRatio: number;
         /**
+         * Sensitivity factor for dragging (Default: 1)
+         */
+        sensitivity: number;
+        /**
          * Disposes of the gizmo
          */
         dispose(): void;
@@ -114059,6 +114274,10 @@ declare module BABYLON {
          * If the scaling operation should be done on all axis (default: false)
          */
         uniformScaling: boolean;
+        /**
+         * Custom sensitivity value for the drag strength
+         */
+        sensitivity: number;
         private _isEnabled;
         private _parent;
         private _arrow;
@@ -114665,8 +114884,9 @@ declare module BABYLON {
     export class LightGizmo extends Gizmo {
         private _lightMesh;
         private _material;
-        private cachedPosition;
-        private cachedForward;
+        private _cachedPosition;
+        private _cachedForward;
+        private _attachedMeshParent;
         /**
          * Creates a LightGizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -114690,7 +114910,7 @@ declare module BABYLON {
         /**
          * Creates the lines for a light mesh
          */
-        private static _createLightLines;
+        private static _CreateLightLines;
         /**
          * Disposes of the light gizmo
          */
@@ -122166,6 +122386,7 @@ declare module BABYLON {
     export class TextureBlock extends NodeMaterialBlock {
         private _defineName;
         private _linearDefineName;
+        private _tempTextureRead;
         private _samplerName;
         private _transformedUVName;
         private _textureTransformName;
@@ -122222,6 +122443,7 @@ declare module BABYLON {
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
         private readonly _isMixed;
         private _injectVertexCode;
+        private _writeTextureRead;
         private _writeOutput;
         protected _buildBlock(state: NodeMaterialBuildState): this | undefined;
         protected _dumpPropertiesCode(): string;
@@ -124650,9 +124872,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position input component
+         * Gets the seed input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the jitter input component
          */
@@ -124692,9 +124914,9 @@ declare module BABYLON {
          */
         getClassName(): string;
         /**
-         * Gets the position operand input component
+         * Gets the seed operand input component
          */
-        readonly position: NodeMaterialConnectionPoint;
+        readonly seed: NodeMaterialConnectionPoint;
         /**
          * Gets the output component
          */
@@ -124704,6 +124926,67 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to blend normals
+     */
+    export class NormalBlendBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new NormalBlendBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the first input component
+         */
+        readonly input0: NodeMaterialConnectionPoint;
+        /**
+         * Gets the second input component
+         */
+        readonly input1: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to rotate a 2d vector by a given angle
+     */
+    export class Rotate2dBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new Rotate2dBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the input vector
+         */
+        readonly input: NodeMaterialConnectionPoint;
+        /**
+         * Gets the input angle
+         */
+        readonly angle: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Effect Render Options
      */
     export interface IEffectRendererOptions {

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


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


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

@@ -15,6 +15,7 @@
   - WebXR webVR parity helpers (Vive, WMR, Oculus Rift) ([TrevorDev](https://github.com/TrevorDev))
 - Added support for Offscreen canvas [Doc](https://doc.babylonjs.com/how_to/using_offscreen_canvas) ([Deltakosh](https://github.com/deltakosh/)
 - Added support for multiple canvases with one engine [Doc](https://doc.babylonjs.com/how_to/multi_canvases) ([Deltakosh](https://github.com/deltakosh/)
+- Added useReverseDepthBuffer to Engine which can provide greater z depth for distant objects without the cost of a logarithmic depth buffer ([BenAdams](https://github.com/benaadams/))
 
 ## Updates
 
@@ -23,6 +24,7 @@
 - Added support for dual shock gamepads ([Deltakosh](https://github.com/deltakosh/))
 - Support Vive Focus 3Dof controller ([TrevorDev](https://github.com/TrevorDev))
 - Planar positioning support for GizmoManager ([Balupg](https://github.com/balupg))
+- ScaleGizmo and AxisScaleGizmo sensitivity factor ([CedricGuillemet](https://github.com/CedricGuillemet))
 - Individual gizmos can now be enabled/disabled ([Balupg](https://github.com/balupg))
 - Unify preparation of instance attributes. Added `MaterialHelper.PushAttributesForInstances` ([MarkusBillharz](https://github.com/MarkusBillharz))
 - Added support for PBR [irradiance map](https://doc.babylonjs.com/how_to/physically_based_rendering_master#irradiance-map)
@@ -82,6 +84,7 @@
 - Added support for clickable errors in the playground ([sailro](http://www.github.com/sailro))
 - Added a color picker and previewer for BABYLON.ColorX invocations in the playground ([sailro](http://www.github.com/sailro))
 - Added support for diffing snippets in the playground ([sailro](http://www.github.com/sailro))
+- Added diff navigator in the playground ([sailro](http://www.github.com/sailro))
 
 ### Meshes
 
@@ -145,6 +148,11 @@
 - Added option to configure the output canvas ([RaananW](https://github.com/RaananW/))
 - Supporting multisampled multiview rendering using the oculus multiview extension ([RaananW](https://github.com/RaananW/))
 - Preparing to deprecate supportsSession in favor of isSupportedSession ([RaananW](https://github.com/RaananW/))
+- Added onControllerModelLoaded observable for WebXR ([RaananW](https://github.com/RaananW/))
+- UI Button has options to set different session mode and reference type ([RaananW](https://github.com/RaananW/))
+- Added option to change the teleportation duration in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
+- Added support to teleport the camera at constant speed in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
+
 
 ### Ray
 
@@ -218,6 +226,8 @@
 - Fixed missing properties in serialization / parsing of `coneParticleEmitter` ([Popov72](https://github.com/Popov72))
 - Fix a bug with exit VR and Edge ([RaananW](https://github.com/RaananW/))
 - Fixed an issue with size of texture in multiview ([RaananW](https://github.com/RaananW/))
+- Fixed Path3D (bi)normals computation for specific edge cases ([Poolminer](https://github.com/Poolminer/))
+- WebXR UI BUtton will only change to "In XR" after XR Session started ([RaananW](https://github.com/RaananW/))
 
 ## Breaking changes
 

+ 3 - 1
gui/src/2D/controls/checkbox.ts

@@ -5,6 +5,8 @@ import { Control } from "./control";
 import { StackPanel } from "./stackPanel";
 import { TextBlock } from "./textBlock";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Nullable } from 'babylonjs/types';
+import { Measure } from '../measure';
 
 /**
  * Class used to represent a 2D checkbox
@@ -94,7 +96,7 @@ export class Checkbox extends Control {
     }
 
     /** @hidden */
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 2 - 3
gui/src/2D/controls/container.ts

@@ -395,8 +395,7 @@ export class Container extends Control {
         }
     }
 
-    /** @hidden */
-    public _getDescendants(results: Control[], directDescendantsOnly: boolean = false, predicate?: (control: Control) => boolean): void {
+    public getDescendantsToRef(results: Control[], directDescendantsOnly: boolean = false, predicate?: (control: Control) => boolean): void {
         if (!this.children) {
             return;
         }
@@ -409,7 +408,7 @@ export class Container extends Control {
             }
 
             if (!directDescendantsOnly) {
-                item._getDescendants(results, false, predicate);
+                item.getDescendantsToRef(results, false, predicate);
             }
         }
     }

+ 8 - 3
gui/src/2D/controls/control.ts

@@ -1071,8 +1071,13 @@ export class Control {
         this.notRenderable = false;
     }
 
-    /** @hidden */
-    public _getDescendants(results: Control[], directDescendantsOnly: boolean = false, predicate?: (control: Control) => boolean): void {
+    /**
+     * Will store all controls that have this control as ascendant in a given array
+     * @param results defines the array where to store the descendants
+     * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
+     * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
+     */
+    public getDescendantsToRef(results: Control[], directDescendantsOnly: boolean = false, predicate?: (control: Control) => boolean): void {
         // Do nothing by default
     }
 
@@ -1085,7 +1090,7 @@ export class Control {
     public getDescendants(directDescendantsOnly?: boolean, predicate?: (control: Control) => boolean): Control[] {
         var results = new Array<Control>();
 
-        this._getDescendants(results, directDescendantsOnly, predicate);
+        this.getDescendantsToRef(results, directDescendantsOnly, predicate);
 
         return results;
     }

+ 3 - 1
gui/src/2D/controls/displayGrid.ts

@@ -1,5 +1,7 @@
 import { Control } from "./control";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Nullable } from 'babylonjs/types';
+import { Measure } from '../measure';
 
 /** Class used to render a grid  */
 export class DisplayGrid extends Control {
@@ -146,7 +148,7 @@ export class DisplayGrid extends Control {
         super(name);
     }
 
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 2 - 1
gui/src/2D/controls/inputText.ts

@@ -9,6 +9,7 @@ import { IFocusableControl } from "../advancedDynamicTexture";
 import { ValueAndUnit } from "../valueAndUnit";
 import { VirtualKeyboard } from "./virtualKeyboard";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Measure } from '../measure';
 
 /**
  * Class used to create input text control
@@ -797,7 +798,7 @@ export class InputText extends Control implements IFocusableControl {
         this.text = this._text.slice(0, insertPosition) + data + this._text.slice(insertPosition);
     }
 
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 1 - 1
gui/src/2D/controls/multiLine.ts

@@ -173,7 +173,7 @@ export class MultiLine extends Control {
         return "MultiLine";
     }
 
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {

+ 2 - 1
gui/src/2D/controls/sliders/imageBasedSlider.ts

@@ -2,6 +2,7 @@ import { BaseSlider } from "./baseSlider";
 import { Measure } from "../../measure";
 import { Image } from "../image";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Nullable } from 'babylonjs/types';
 
 /**
  * Class used to create slider controls based on images
@@ -101,7 +102,7 @@ export class ImageBasedSlider extends BaseSlider {
         return "ImageBasedSlider";
     }
 
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 3 - 1
gui/src/2D/controls/sliders/slider.ts

@@ -1,5 +1,7 @@
 import { BaseSlider } from "./baseSlider";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Nullable } from 'babylonjs/types';
+import { Measure } from '../../measure';
 
 /**
  * Class used to create slider controls
@@ -78,7 +80,7 @@ export class Slider extends BaseSlider {
         return "Slider";
     }
 
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 2 - 1
gui/src/2D/controls/textBlock.ts

@@ -3,6 +3,7 @@ import { Measure } from "../measure";
 import { ValueAndUnit } from "../valueAndUnit";
 import { Control } from "./control";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { Nullable } from 'babylonjs/types';
 
 /**
  * Enum that determines the text-wrapping mode to use.
@@ -305,7 +306,7 @@ export class TextBlock extends Control {
     }
 
     /** @hidden */
-    public _draw(context: CanvasRenderingContext2D): void {
+    public _draw(context: CanvasRenderingContext2D, invalidatedRectangle?: Nullable<Measure>): void {
         context.save();
 
         this._applyStates(context);

+ 5 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/cameras/commonCameraPropertyGridComponent.tsx

@@ -10,6 +10,7 @@ import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
 import { LockObject } from "../lockObject";
 import { GlobalState } from '../../../../globalState';
 import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface ICommonCameraPropertyGridComponentProps {
     globalState: GlobalState;
@@ -66,6 +67,10 @@ export class CommonCameraPropertyGridComponent extends React.Component<ICommonCa
                         camera.mode === Camera.ORTHOGRAPHIC_CAMERA &&
                         <FloatLineComponent lockObject={this.props.lockObject} label="Bottom" target={camera} propertyName="orthoBottom" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     }
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        camera.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />                       
                 </LineContainerComponent>
             </div>
         );

+ 5 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/lights/commonLightPropertyGridComponent.tsx

@@ -8,6 +8,7 @@ import { TextLineComponent } from "../../../lines/textLineComponent";
 import { LockObject } from "../lockObject";
 import { GlobalState } from '../../../../globalState';
 import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface ICommonLightPropertyGridComponentProps {
     globalState: GlobalState,
@@ -34,6 +35,10 @@ export class CommonLightPropertyGridComponent extends React.Component<ICommonLig
                     <TextLineComponent label="Unique ID" value={light.uniqueId.toString()} />
                     <TextLineComponent label="Class" value={light.getClassName()} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Intensity" target={light} propertyName="intensity" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        light.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />                       
                 </LineContainerComponent>
             </div>
         );

+ 5 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx

@@ -15,6 +15,7 @@ import { OptionsLineComponent } from "../../../lines/optionsLineComponent";
 import { LockObject } from "../lockObject";
 import { GlobalState } from '../../../../globalState';
 import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface ICommonMaterialPropertyGridComponentProps {
     globalState: GlobalState;
@@ -83,6 +84,10 @@ export class CommonMaterialPropertyGridComponent extends React.Component<ICommon
                     <CheckBoxLineComponent label="Point cloud" target={material} propertyName="pointsCloud" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Point size" target={material} propertyName="pointSize" minimum={0} maximum={100} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Z-offset" target={material} propertyName="zOffset" minimum={-10} maximum={10} step={0.1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        material.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />                       
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="TRANSPARENCY">
                     <SliderLineComponent label="Alpha" target={material} propertyName="alpha" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 5 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -25,6 +25,7 @@ import { Color3LineComponent } from '../../../lines/color3LineComponent';
 import { MorphTarget } from 'babylonjs/Morph/morphTarget';
 import { OptionsLineComponent } from '../../../lines/optionsLineComponent';
 import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface IMeshPropertyGridComponentProps {
     globalState: GlobalState;
@@ -315,6 +316,10 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                         mesh.isAnInstance &&
                         <TextLineComponent label="Source" value={(mesh as any).sourceMesh.name} onLink={() => this.onSourceMeshLink()} />
                     }
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        mesh.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="TRANSFORMS">
                     <Vector3LineComponent label="Position" target={mesh} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 6 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/transformNodePropertyGridComponent.tsx

@@ -12,6 +12,7 @@ import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent"
 import { LockObject } from "../lockObject";
 import { GlobalState } from '../../../../globalState';
 import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface ITransformNodePropertyGridComponentProps {
     globalState: GlobalState;
@@ -41,7 +42,11 @@ export class TransformNodePropertyGridComponent extends React.Component<ITransfo
                     {
                         transformNode.parent &&
                         <TextLineComponent label="Parent" value={transformNode.parent.name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(transformNode.parent)}/>
-                    }                      
+                    }        
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        transformNode.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />              
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="TRANSFORMATIONS">
                     <Vector3LineComponent label="Position" target={transformNode} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 5 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/postProcesses/commonPostProcessPropertyGridComponent.tsx

@@ -11,6 +11,7 @@ import { PostProcess } from 'babylonjs/PostProcesses/postProcess';
 import { Color3LineComponent } from '../../../lines/color3LineComponent';
 import { SliderLineComponent } from '../../../lines/sliderLineComponent';
 import { GlobalState } from '../../../../globalState';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface ICommonPostProcessPropertyGridComponentProps {
     globalState: GlobalState;
@@ -47,6 +48,10 @@ export class CommonPostProcessPropertyGridComponent extends React.Component<ICom
                     <CheckBoxLineComponent label="Pixel perfect" target={postProcess} propertyName="enablePixelPerfectMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Fullscreen viewport" target={postProcess} propertyName="forceFullscreenViewport" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Samples" target={postProcess} propertyName="samples" minimum={1} maximum={8} step={1} decimalCount={0} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <ButtonLineComponent label="Dispose" onClick={() => {
+                        postProcess.dispose();
+                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                    }} />                      
                 </LineContainerComponent>
             </div>
         );

+ 11 - 11
inspector/src/components/actionTabs/tabs/statisticsTabComponent.tsx

@@ -86,17 +86,17 @@ export class StatisticsTabComponent extends PaneComponent {
                     <TextLineComponent label="Total textures" value={scene.textures.length.toString()} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="FRAME STEPS DURATION">
-                    <ValueLineComponent label="Absolute FPS" value={1000.0 / this._sceneInstrumentation!.frameTimeCounter.current} fractionDigits={0} />
-                    <ValueLineComponent label="Meshes selection" value={sceneInstrumentation.activeMeshesEvaluationTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Render targets" value={sceneInstrumentation.renderTargetsRenderTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Particles" value={sceneInstrumentation.particlesRenderTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Sprites" value={sceneInstrumentation.spritesRenderTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Animations" value={sceneInstrumentation.animationsTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Physics" value={sceneInstrumentation.physicsTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Render" value={sceneInstrumentation.renderTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Frame total" value={sceneInstrumentation.frameTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="Inter-frame" value={sceneInstrumentation.interFrameTimeCounter.current} units="ms" />
-                    <ValueLineComponent label="GPU Frame time" value={engineInstrumentation.gpuFrameTimeCounter.current * 0.000001} units="ms" />
+                    <ValueLineComponent label="Absolute FPS" value={1000.0 / this._sceneInstrumentation!.frameTimeCounter.lastSecAverage} fractionDigits={0} />
+                    <ValueLineComponent label="Meshes selection" value={sceneInstrumentation.activeMeshesEvaluationTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Render targets" value={sceneInstrumentation.renderTargetsRenderTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Particles" value={sceneInstrumentation.particlesRenderTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Sprites" value={sceneInstrumentation.spritesRenderTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Animations" value={sceneInstrumentation.animationsTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Physics" value={sceneInstrumentation.physicsTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Render" value={sceneInstrumentation.renderTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Frame total" value={sceneInstrumentation.frameTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="Inter-frame" value={sceneInstrumentation.interFrameTimeCounter.lastSecAverage} units="ms" />
+                    <ValueLineComponent label="GPU Frame time" value={engineInstrumentation.gpuFrameTimeCounter.lastSecAverage * 0.000001} units="ms" />
                     <ValueLineComponent label="GPU Frame time (average)" value={engineInstrumentation.gpuFrameTimeCounter.average * 0.000001} units="ms" />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="SYSTEM INFO">

+ 2 - 0
inspector/src/components/sceneExplorer/entities/meshTreeItemComponent.tsx

@@ -7,11 +7,13 @@ import { faEye, faEyeSlash, faSquare } from '@fortawesome/free-regular-svg-icons
 import { TreeItemLabelComponent } from "../treeItemLabelComponent";
 import { ExtensionsComponent } from "../extensionsComponent";
 import * as React from "react";
+import { GlobalState } from '../../globalState';
 
 interface IMeshTreeItemComponentProps {
     mesh: AbstractMesh;
     extensibilityGroups?: IExplorerExtensibilityGroup[];
     onClick: () => void;
+    globalState: GlobalState;
 }
 
 export class MeshTreeItemComponent extends React.Component<IMeshTreeItemComponentProps, { isBoundingBoxEnabled: boolean, isVisible: boolean }> {

+ 2 - 2
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -74,8 +74,8 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
         if (this.props.globalState.blockMutationUpdates) {
             return;
         }
-
-        this.forceUpdate();
+        
+        setTimeout(() => this.forceUpdate());
     }
 
     componentDidMount() {

+ 0 - 1
inspector/src/components/sceneExplorer/treeItemSelectableComponent.tsx

@@ -129,7 +129,6 @@ export class TreeItemSelectableComponent extends React.Component<ITreeItemSelect
 
                 if (entity.getDescendants) {
                     if (entity.getDescendants(false, (n: any) => {
-                        console.log(n.name);
                         return n.name && n.name.toLowerCase().indexOf(lowerCaseFilter) !== -1
                     }).length === 0) {
                         return null;

+ 1 - 1
inspector/src/components/sceneExplorer/treeItemSpecializedComponent.tsx

@@ -62,7 +62,7 @@ export class TreeItemSpecializedComponent extends React.Component<ITreeItemSpeci
             if (className.indexOf("Mesh") !== -1) {
                 const mesh = entity as AbstractMesh;
                 if (mesh.isAnInstance || mesh.getTotalVertices() > 0) {
-                    return (<MeshTreeItemComponent extensibilityGroups={this.props.extensibilityGroups} mesh={mesh} onClick={() => this.onClick()} />);
+                    return (<MeshTreeItemComponent globalState={this.props.globalState} extensibilityGroups={this.props.extensibilityGroups} mesh={mesh} onClick={() => this.onClick()} />);
                 } else {
                     return (<TransformNodeItemComponent extensibilityGroups={this.props.extensibilityGroups} transformNode={entity as TransformNode} onClick={() => this.onClick()} />);
                 }

+ 6 - 0
nodeEditor/src/blockTools.ts

@@ -56,10 +56,16 @@ import { WaveBlock, WaveBlockKind } from 'babylonjs/Materials/Node/Blocks/waveBl
 import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
 import { WorleyNoise3DBlock } from 'babylonjs/Materials/Node/Blocks/worleyNoise3DBlock';
 import { SimplexPerlin3DBlock } from 'babylonjs/Materials/Node/Blocks/simplexPerlin3DBlock';
+import { NormalBlendBlock } from 'babylonjs/Materials/Node/Blocks/normalBlendBlock';
+import { Rotate2dBlock } from 'babylonjs/Materials/Node/Blocks/rotate2dBlock';
 
 export class BlockTools {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
         switch (data) {
+            case "Rotate2dBlock":
+                return new Rotate2dBlock("Rotate2d");            
+            case "NormalBlendBlock":
+                return new NormalBlendBlock("NormalBlend");
             case "WorleyNoise3DBlock":
                 return new WorleyNoise3DBlock("WorleyNoise3D");
             case "SimplexPerlin3DBlock":

+ 1 - 1
nodeEditor/src/components/diagram/clamp/clampNodeWidget.tsx

@@ -43,7 +43,7 @@ export class ClampNodeWidget extends React.Component<ClampNodeWidgetProps> {
         let clampBlock = this.props.node!.block! as ClampBlock;
 
         return (
-            <div className={"diagramBlock remap"}>
+            <div className={"diagramBlock clamp"}>
                 <div className="header">
                     {clampBlock.name}
                 </div>

+ 23 - 4
nodeEditor/src/components/diagram/diagram.scss

@@ -104,6 +104,19 @@
         }        
     }
 
+    &.clamp {
+        color:white;
+        background: #4086BB;
+
+        .value {
+            grid-row: 2;
+        }
+
+        .outputs, .inputs {
+            transform: translateY(5px);
+        }        
+    }    
+
     &.gradient {
         .outputs, .inputs {
             transform: translateY(5px);
@@ -115,10 +128,6 @@
         background: #40866E;
     }
 
-    &.constant {
-        background: #646464 !important;
-    }
-
     &.output {
         background: rgb(106, 44, 131);
         color:white;
@@ -144,6 +153,16 @@
         overflow: hidden;
         background: black;
         color: white;
+
+        &.constant {
+            border-color: #4E5C74;
+            background: #4E5C74 !important;
+        }
+
+        &.inspector {
+            border-color: #396437;
+            background: #396437 !important;
+        }
     }
 
     .value {

+ 38 - 11
nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx

@@ -14,7 +14,6 @@ import { LineContainerComponent } from '../../../sharedComponents/lineContainerC
 import { StringTools } from '../../../stringTools';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { TextInputLineComponent } from '../../../sharedComponents/textInputLineComponent';
-import { CheckBoxLineComponent } from '../../../sharedComponents/checkBoxLineComponent';
 import { Vector4PropertyTabComponent } from '../../propertyTab/properties/vector4PropertyTabComponent';
 import { MatrixPropertyTabComponent } from '../../propertyTab/properties/matrixPropertyTabComponent';
 import { FloatLineComponent } from '../../../sharedComponents/floatLineComponent';
@@ -162,6 +161,12 @@ export class InputPropertyTabComponentProps extends React.Component<IInputProper
             modeOptions.push({ label: "System value", value: 2 });
         }
 
+        var typeOptions = [
+            { label: "None", value: 0 },
+            { label: "Visible in the inspector", value: 1 },
+            { label: "Constant", value: 2 }
+        ];
+
         return (
             <div>
                 <LineContainerComponent title="GENERAL">
@@ -174,17 +179,39 @@ export class InputPropertyTabComponentProps extends React.Component<IInputProper
                 <LineContainerComponent title="PROPERTIES">
                     {
                         inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&
-                        <CheckBoxLineComponent label="Visible in the Inspector" target={inputBlock} propertyName="visibleInInspector"/>
-                    }           
-                    {
-                        inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&
-                        <CheckBoxLineComponent label="IsConstant" target={inputBlock} propertyName="isConstant"
-                            onValueChanged={() => {
-                                this.props.globalState.onRebuildRequiredObservable.notifyObservers();
-                                this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        <OptionsLineComponent label="Type" options={typeOptions} target={inputBlock} 
+                            noDirectUpdate={true}
+                            getSelection={(block) => {
+                                if (block.visibleInInspector) {
+                                    return 1;
+                                }
+
+                                if (block.isConstant) {
+                                    return 2;
+                                }
+
+                                return 0;
                             }}
-                        />
-                    }                             
+                            onSelect={(value: any) => {
+                                switch (value) {
+                                    case 0:
+                                        inputBlock.visibleInInspector = false;
+                                        inputBlock.isConstant = false;
+                                        break;
+                                    case 1:
+                                        inputBlock.visibleInInspector = true;
+                                        inputBlock.isConstant = false;
+                                        break;
+                                    case 2:
+                                        inputBlock.visibleInInspector = false;
+                                        inputBlock.isConstant = true;
+                                        break;
+                                }
+                                this.forceUpdate();
+                                this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                                this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+                            }} />                        
+                    }           
                     <OptionsLineComponent label="Mode" options={modeOptions} target={inputBlock} 
                         noDirectUpdate={true}
                         getSelection={(block) => {

+ 2 - 2
nodeEditor/src/components/diagram/input/inputNodeWidget.tsx

@@ -130,10 +130,10 @@ export class InputNodeWidget extends React.Component<IInputNodeWidgetProps> {
         }
 
         return (
-            <div className={"diagramBlock input" + (inputBlock ? " " + NodeMaterialBlockConnectionPointTypes[inputBlock.type] : "")+ (inputBlock && inputBlock.isConstant ? " constant" : "")} style={{
+            <div className={"diagramBlock input" + (inputBlock ? " " + NodeMaterialBlockConnectionPointTypes[inputBlock.type] : "")} style={{
                 background: color
             }}>
-                <div className="header">
+                <div className={"header" + (inputBlock && inputBlock.isConstant ? " constant" : "") + (inputBlock && inputBlock.visibleInInspector ? " inspector" : "")}>
                     {name}
                 </div>
                 <div className="outputs">

+ 99 - 5
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -12,6 +12,98 @@ interface INodeListComponentProps {
 
 export class NodeListComponent extends React.Component<INodeListComponentProps, {filter: string}> {
 
+    private static _Tooltips:{[key: string]: string} = {
+        "BonesBlock": "Provides a world matrix for each vertex, based on skeletal (bone/joint) animation. mesh.matricesIndices and mesh.matricesWeights are the vertex to bone assignments and weighting, and assume no more than 4 bones influencing any given vertex. If a vertex is influenced by more than 4 bones, then mesh.matricesIndicesExtra and mesh.matricesWeightsExtra can be used for up to 8 bones of influence per vertex",
+        "MorphTargetsBlock": "Provides the final positions, normals, tangents, and uvs based on morph targets in a mesh",
+        "AddBlock": "Adds the left and right inputs together. Left and right inputs have to be of the same type",
+        "DistanceBlock": "Provides a distance vector based on the left and right input vectors",
+        "DivideBlock": "Divides the left input by the right input",
+        "LengthBlock": "Outputs the length of an input vector",
+        "MaxBlock": "Outputs the largest value between the left and right inputs",
+        "MinBlock": "Outputs the smallest value between the left and right inputs",
+        "MultiplyBlock": "Multiplies the left and right inputs together",
+        "NegateBlock": "Multiplies the input by -1",
+        "OneMinusBlock": "Subtracts the input value from 1 (1 - input)",
+        "RandomNumberBlock": "Provides a random number based on an input seed",
+        "ReciprocalBlock": "Outputs the reciprocal value(s) vased on the input value(s)",
+        "ScaleBlock": "Multiplies the input value(s) by the factor",
+        "SubtractBlock": "Subtracts the right input from the left input",
+        "PosterizeBlock": "Reduces the number of colors in an image to the value of input steps",
+        "ReplaceColorBlock": "Replaces a reference color in input value with a different replacement color. Distance is the tolerance variation of the color",
+        "ColorMergerBlock": "Combines individual color channels into color Vectors",
+        "ColorSplitterBlock": "Separates color Vectors into individual color channels",
+        "VectorMergerBlock": "Combines up to 4 input values into Vectors",
+        "VectorSplitterBlock": "Separates Vectors into individual elements",
+        "Color3": "A Vector3 representing combined color values (red, green, and blue)",
+        "Color4": "A Vector4 representing combined color and alpha values (red, green, blue, and alpha)",
+        "DeltaTimeBlock": "A Float representing the time value that's passed since the last frame has rendered",
+        "Float": "A Float for a single floating point value",
+        "TextureBlock": "A container node for a texture (image or url)",
+        "TimeBlock": "A Float of a constantly increasing floating point value, starting when the scene is loaded",
+        "Vector2": "A Vector2 representing two values",
+        "Vector3": "A Vector3 representing three values",
+        "Vector4": "A Vector4 representing four values",
+        "LerpBlock": "Provides linear interpolated value(s) between the left and right inputs, based on the gradient input",
+        "SmoothStepBlock": "Outputs a value based on a the input value's position on a curve between the two edge values",
+        "Matrix": "A container for a vector transformation",
+        "ProjectionMatrixBlock": "A matrix moving from 3D space to screen space",
+        "ViewMatrixBlock": "A matrix moving from 3D space to camera space",
+        "ViewProjectionMatrixBlock": "A matrix moving from 3D space to camera space, and ending in screen space",
+        "WorldMatrixBlock": "A matrix moving from local space to world space",
+        "WorldViewProjectionMatrixBlock": "A matrix moving from local space to world space, then to camera space, and ending in screen space",
+        "ColorBlock": "A Color4 representing the color of each vertex of the attached mesh",
+        "InstancesBlock": "Provides the world matrix for each instance. This is used to apply materials to instances as well as original meshes",
+        "MatrixIndicesBlock": "A Vector4 representing the vertex to bone skinning assignments",
+        "MatricesWeightsBlock": "A Vector4 representing the vertex to bone skinning weights",
+        "NormalBlock": "A Vector3 representing the normal of each vertex of the attached mesh",
+        "PositionBlock": "A Vector3 representing the position of each vertex of the attached mesh",
+        "TangentBlock": "A Vector3 representing the tangent of each vertex of the attached mesh",
+        "UVBlock": "A Vector2 representing the UV coordinates of each vertex of the attached mesh",
+        "DiscardBlock": "A final output node that will not output a pixel below the cutoff value",
+        "FragmentOutputBlock": "The final node for outputing the color of each pixel. This node must be included in every node material",
+        "VertexOutputBlock": "The final node for outputing the position of each vertex. This node must be included in every node material",
+        "ClampBlock": "Ignores all values of the input outside of the Minimum and Maximum property values",
+        "NormalizeBlock": "Remaps the length of a vector or color to 1",
+        "RemapBlock": "Remaps all input values between sourceMin and sourceMax, to be between targetMin and targetMax. source and target inputs can be static or variable inputs",
+        "CeilingBlock": "Outputs the highest value of the input",
+        "FloorBlock": "Outputs the lowest value of the input",
+        "RoundBlock": "Outputs the nearest whole number based on the input value",
+        "StepBlock": "Outputs 1 for any input value above the edge input, outputs 0 for any input value below the edge input",
+        "CameraPositionBlock": "A Vector3 position of the active scene camera",
+        "FogBlock": "Applies fog to a scene. Outputs fog with increasing value based on distance from the camera",
+        "FogColorBlock": "A Color3 for the fog color",
+        "ImageProcessingBlock": "Provides access to all of the Babylon image processing properties",        
+        "LightBlock": "Returns the individual color values (red, green, and blue) of the diffuse or specular colors of the combined OR individual lighting within the scene",
+        "LightInformationBlock": "Provides the direction, color and intensity of a selected light based on its world position",
+        "PerturbNormalBlock": "Creates a new normal direction based on a normal map, the world position, and world normal",
+        "ReflectionTextureBlock": "Creates a reflection of the input texture",
+        "ViewDirectionBlock": "Outputs the direction vector of where the camera is aimed",
+        "AbsBlock": "Outputs the absolute value of the input value",
+        "ArcCosBlock": "Outputs the inverse of the cosine value based on the input value",
+        "ArcSinBlock": "Outputs the inverse of the sine value based on the input value",
+        "ArcTan2Block": "Outputs the inverse of the tangent value based on the input value",
+        "ArcTanBlock": "Outputs the inverse of the tangent value based on the input value",
+        "CosBlock": "Outputs the cosine value based on the input value",
+        "DegreesToRadiansBlock": "Converts the input value (degrees) to radians",
+        "Exp2Block": "Outputs the input value multiplied by itself 1 time. (Exponent of 2)",
+        "ExpBlock": "Outputs the input value multiplied by itself 9 time. (Exponent of 10)",
+        "FractBlock": "Everything after the period",
+        "LogBlock": "The logarithm value based on the input value",
+        "PowBlock": "Outputs the input value multiplied by itself the number of times equal to the power input (Exponent of power)",
+        "RadiansToDegreesBlock": "Converts the input value (radians) to degrees",
+        "SawToothWaveBlock": "Outputs a sawtooth pattern value between -1 and 1 based on the input value",
+        "SignBlock": "returns 1 if 10 or -1 if -10",
+        "SinBlock": "Outputs the the sine value based on the input value",
+        "SqrtBlock": "Outputs the the square root of the input value",
+        "SquareWaveBlock": "Outputs a stepped pattern value between -1 and 1 based on the input value",
+        "TanBlock": "Outputs the the tangent value based on the input value",
+        "TriangleWaveBlock": "Outputs a sawtooth pattern value between 0 and 1 based on the input value",
+        "CrossBlock": "Outputs a vector that is perpendicular to two input vectors",
+        "DotBlock": "Outputs the cos of the angle between two vectors",
+        "FresnelBlock": "Outputs the grazing angle of the surface of the mesh, relative to a camera. Angle can be influenced by the bias and power inputs",
+        "TransformBlock": "Transforms a input vector based on an input matrix"
+    }
+
     constructor(props: INodeListComponentProps) {
         super(props);
 
@@ -30,16 +122,16 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Color_Management: ["ReplaceColorBlock", "PosterizeBlock", "GradientBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock"],
-            Interpolation: ["LerpBlock", "SmoothStepBlock", "NLerpBlock"],
+            Interpolation: ["LerpBlock", "StepBlock", "SmoothStepBlock", "NLerpBlock"],
             Matrices: ["Matrix", "WorldMatrixBlock", "WorldViewMatrixBlock", "WorldViewProjectionMatrixBlock", "ViewMatrixBlock", "ViewProjectionMatrixBlock", "ProjectionMatrixBlock"],
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "FrontFacingBlock"], 
             Noises: ["SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Blocks: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
-            Round: ["StepBlock", "RoundBlock", "CeilingBlock", "FloorBlock"],
-            Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock", "PerturbNormalBlock"],
+            Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
+            Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock", "PerturbNormalBlock", "NormalBlendBlock"],
             Trigonometry: ["CosBlock", "SinBlock", "AbsBlock", "ExpBlock", "Exp2Block", "SqrtBlock", "PowBlock", "LogBlock", "ArcCosBlock", "ArcSinBlock", "TanBlock", "ArcTanBlock", "FractBlock", "SignBlock", "ArcTan2Block", "DegreesToRadiansBlock", "RadiansToDegreesBlock", "SawToothWaveBlock", "TriangleWaveBlock", "SquareWaveBlock"],
-            Vector_Math: ["CrossBlock", "DotBlock", "TransformBlock", "FresnelBlock"],
+            Vector_Math: ["CrossBlock", "DotBlock", "TransformBlock", "FresnelBlock", "Rotate2dBlock"],
         }
 
         // Create node menu
@@ -48,7 +140,9 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             var blockList = (allBlocks as any)[key].filter((b: string) => !this.state.filter || b.toLowerCase().indexOf(this.state.filter.toLowerCase()) !== -1)
             .sort((a: string, b: string) => a.localeCompare(b))
             .map((block: any, i: number) => {
-                return <DraggableLineComponent key={block} data={block} />
+                let tooltip = NodeListComponent._Tooltips[block] || "";
+
+                return <DraggableLineComponent key={block} data={block} tooltip={tooltip}/>
             });
 
             if (blockList.length) {

+ 4 - 0
nodeEditor/src/graphEditor.tsx

@@ -57,6 +57,7 @@ import { GradientNodeFactory } from './components/diagram/gradient/gradientNodeF
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionTextureNodeFactory } from './components/diagram/reflectionTexture/reflectionTextureNodeFactory';
 import { ReflectionTextureNodeModel } from './components/diagram/reflectionTexture/reflectionTextureNodeModel';
+import { SerializationTools } from './serializationTools';
 
 require("storm-react-diagrams/dist/style.min.css");
 require("./main.scss");
@@ -180,6 +181,7 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
             widget.setState({ document: this.props.globalState.hostDocument })
             this._onWidgetKeyUpPointer = this.onWidgetKeyUp.bind(this)
             this.props.globalState.hostDocument!.addEventListener("keyup", this._onWidgetKeyUpPointer, false);
+            this.props.globalState.hostDocument!.defaultView!.addEventListener("blur", () => this._altKeyIsPressed = false, false);
 
             let previousMouseMove = widget.onMouseMove;
             widget.onMouseMove = (evt: any) => {
@@ -368,6 +370,8 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
         catch (err) {
             this.props.globalState.onLogRequiredObservable.notifyObservers(new LogEntry(err, true));
         }
+
+        SerializationTools.UpdateLocations(this.props.globalState.nodeMaterial, this.props.globalState);
     }
 
     applyFragmentOutputConstraints(rootInput: DefaultPortModel) {

+ 16 - 0
nodeEditor/src/serializationTools.ts

@@ -4,6 +4,22 @@ import { Texture } from 'babylonjs/Materials/Textures/texture';
 import { DataStorage } from './dataStorage';
 
 export class SerializationTools {
+
+    public static UpdateLocations(material: NodeMaterial, globalState: GlobalState) {
+        material.editorData = [];
+
+        // Store node locations
+        for (var block of material.attachedBlocks) {
+            let node = globalState.onGetNodeFromBlock(block);
+
+            material.editorData.push({
+                blockId: block.uniqueId,
+                x: node ? node.x : 0,
+                y: node ? node.y : 0
+            });
+        }
+    }
+
     public static Serialize(material: NodeMaterial, globalState: GlobalState) {
         let bufferSerializationState = Texture.SerializeBuffers;
         Texture.SerializeBuffers = DataStorage.ReadBoolean("EmbedTextures", true);

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

@@ -42,7 +42,7 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
             this._localChange = false;
             return true;
         }
-        return false;
+        return nextProps.label !== this.props.label;
     }
 
     onChange() {

+ 2 - 0
nodeEditor/src/sharedComponents/draggableLineComponent.tsx

@@ -2,6 +2,7 @@ import * as React from "react";
 
 export interface IButtonLineComponentProps {
     data: string;
+    tooltip: string;
 }
 
 export class DraggableLineComponent extends React.Component<IButtonLineComponentProps> {
@@ -12,6 +13,7 @@ export class DraggableLineComponent extends React.Component<IButtonLineComponent
     render() {
         return (
             <div className="draggableLine"
+                title={this.props.tooltip}
                 draggable={true}
                 onDragStart={event => {
                     event.dataTransfer.setData("babylonjs-material-node", this.props.data);

+ 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.1",
+    "version": "4.1.0-beta.2",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 61 - 10
src/Cameras/VR/vrExperienceHelper.ts

@@ -49,6 +49,18 @@ export interface VRTeleportationOptions {
      * A list of meshes to be used as the teleportation floor. (default: empty)
      */
     floorMeshes?: Mesh[];
+    /**
+     * The teleportation mode. (default: TELEPORTATIONMODE_CONSTANTTIME)
+     */
+    teleportationMode?: number;
+    /**
+     * The duration of the animation in ms, apply when animationMode is TELEPORTATIONMODE_CONSTANTTIME. (default 122ms)
+     */
+    teleportationTime?: number;
+    /**
+     * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
+     */
+    teleportationSpeed?: number;
 }
 
 /**
@@ -385,6 +397,9 @@ export class VRExperienceHelper {
     private _teleportActive = false;
     private _floorMeshName: string;
     private _floorMeshesCollection: Mesh[] = [];
+    private _teleportationMode: number = VRExperienceHelper.TELEPORTATIONMODE_CONSTANTTIME;
+    private _teleportationTime: number = 122;
+    private _teleportationSpeed: number = 20;
     private _rotationAllowed: boolean = true;
     private _teleportBackwardsVector = new Vector3(0, -1, -1);
     private _teleportationTarget: Mesh;
@@ -1310,6 +1325,16 @@ export class VRExperienceHelper {
                 this._floorMeshesCollection = vrTeleportationOptions.floorMeshes;
             }
 
+            if (vrTeleportationOptions.teleportationMode) {
+                this._teleportationMode = vrTeleportationOptions.teleportationMode;
+            }
+            if (vrTeleportationOptions.teleportationTime && vrTeleportationOptions.teleportationTime > 0) {
+                this._teleportationTime = vrTeleportationOptions.teleportationTime;
+            }
+            if (vrTeleportationOptions.teleportationSpeed && vrTeleportationOptions.teleportationSpeed > 0) {
+                this._teleportationSpeed = vrTeleportationOptions.teleportationSpeed;
+            }
+
             if (this._leftController != null) {
                 this._enableTeleportationOnController(this._leftController);
             }
@@ -1771,6 +1796,16 @@ export class VRExperienceHelper {
     private _workingVector = Vector3.Zero();
     private _workingQuaternion = Quaternion.Identity();
     private _workingMatrix = Matrix.Identity();
+
+    /**
+     * Time Constant Teleportation Mode
+     */
+    public static readonly TELEPORTATIONMODE_CONSTANTTIME = 0;
+    /**
+     * Speed Constant Teleportation Mode
+     */
+    public static readonly TELEPORTATIONMODE_CONSTANTSPEED = 1;
+
     /**
      * Teleports the users feet to the desired location
      * @param location The location where the user's feet should be placed
@@ -1797,15 +1832,28 @@ export class VRExperienceHelper {
 
         this.onBeforeCameraTeleport.notifyObservers(this._workingVector);
 
+        // Animations FPS
+        const FPS = 90;
+        var speedRatio, lastFrame;
+        if (this._teleportationMode == VRExperienceHelper.TELEPORTATIONMODE_CONSTANTSPEED) {
+            lastFrame = FPS;
+            var dist = Vector3.Distance(this.currentVRCamera.position, this._workingVector);
+            speedRatio = this._teleportationSpeed / dist;
+        } else {
+            // teleportationMode is TELEPORTATIONMODE_CONSTANTTIME
+            lastFrame = Math.round(this._teleportationTime * FPS / 1000);
+            speedRatio = 1;
+        }
+
         // Create animation from the camera's position to the new location
         this.currentVRCamera.animations = [];
-        var animationCameraTeleportation = new Animation("animationCameraTeleportation", "position", 90, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CONSTANT);
+        var animationCameraTeleportation = new Animation("animationCameraTeleportation", "position", FPS, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CONSTANT);
         var animationCameraTeleportationKeys = [{
             frame: 0,
             value: this.currentVRCamera.position
         },
         {
-            frame: 11,
+            frame: lastFrame,
             value: this._workingVector
         }
         ];
@@ -1816,7 +1864,10 @@ export class VRExperienceHelper {
 
         this._postProcessMove.animations = [];
 
-        var animationPP = new Animation("animationPP", "vignetteWeight", 90, Animation.ANIMATIONTYPE_FLOAT,
+        // Calculate the mid frame for vignette animations
+        var midFrame = Math.round(lastFrame / 2);
+
+        var animationPP = new Animation("animationPP", "vignetteWeight", FPS, Animation.ANIMATIONTYPE_FLOAT,
             Animation.ANIMATIONLOOPMODE_CONSTANT);
 
         var vignetteWeightKeys = [];
@@ -1825,18 +1876,18 @@ export class VRExperienceHelper {
             value: 0
         });
         vignetteWeightKeys.push({
-            frame: 5,
+            frame: midFrame,
             value: 8
         });
         vignetteWeightKeys.push({
-            frame: 11,
+            frame: lastFrame,
             value: 0
         });
 
         animationPP.setKeys(vignetteWeightKeys);
         this._postProcessMove.animations.push(animationPP);
 
-        var animationPP2 = new Animation("animationPP2", "vignetteStretch", 90, Animation.ANIMATIONTYPE_FLOAT,
+        var animationPP2 = new Animation("animationPP2", "vignetteStretch", FPS, Animation.ANIMATIONTYPE_FLOAT,
             Animation.ANIMATIONLOOPMODE_CONSTANT);
 
         var vignetteStretchKeys = [];
@@ -1845,11 +1896,11 @@ export class VRExperienceHelper {
             value: 0
         });
         vignetteStretchKeys.push({
-            frame: 5,
+            frame: midFrame,
             value: 10
         });
         vignetteStretchKeys.push({
-            frame: 11,
+            frame: lastFrame,
             value: 0
         });
 
@@ -1860,10 +1911,10 @@ export class VRExperienceHelper {
         this._postProcessMove.imageProcessingConfiguration.vignetteStretch = 0;
 
         this._webVRCamera.attachPostProcess(this._postProcessMove);
-        this._scene.beginAnimation(this._postProcessMove, 0, 11, false, 1, () => {
+        this._scene.beginAnimation(this._postProcessMove, 0, lastFrame, false, speedRatio, () => {
             this._webVRCamera.detachPostProcess(this._postProcessMove);
         });
-        this._scene.beginAnimation(this.currentVRCamera, 0, 11, false, 1, () => {
+        this._scene.beginAnimation(this.currentVRCamera, 0, lastFrame, false, speedRatio, () => {
             this.onAfterCameraTeleport.notifyObservers(this._workingVector);
         });
 

+ 9 - 0
src/Cameras/XR/webXRControllerModelLoader.ts

@@ -4,11 +4,19 @@ import { OculusTouchController } from '../../Gamepads/Controllers/oculusTouchCon
 import { WebXRInput } from './webXRInput';
 import { ViveController } from '../../Gamepads/Controllers/viveController';
 import { WebVRController } from '../../Gamepads/Controllers/webVRController';
+import { Observable } from '../../Misc/observable';
+import { WebXRController } from './webXRController';
 
 /**
  * Loads a controller model and adds it as a child of the WebXRControllers grip when the controller is created
  */
 export class WebXRControllerModelLoader {
+
+    /**
+     * an observable that triggers when a new model (the mesh itself) was initialized.
+     * To know when the mesh was loaded use the controller's own modelLoaded() method
+     */
+    public onControllerModelLoaded = new Observable<WebXRController>();
     /**
      * Creates the WebXRControllerModelLoader
      * @param input xr input that creates the controllers
@@ -60,6 +68,7 @@ export class WebXRControllerModelLoader {
                 m.getChildMeshes(false).forEach((m) => {
                     m.isPickable = false;
                 });
+                this.onControllerModelLoaded.notifyObservers(c);
             });
 
             c.gamepadController = controllerModel;

Разница между файлами не показана из-за своего большого размера
+ 29 - 6
src/Cameras/XR/webXREnterExitUI.ts


+ 4 - 1
src/Cameras/XR/webXRExperienceHelper.ts

@@ -93,7 +93,7 @@ export class WebXRExperienceHelper implements IDisposable {
      * @param renderTarget the output canvas that will be used to enter XR mode
      * @returns promise that resolves after xr mode has entered
      */
-    public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget) {
+    public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget): Promise<WebXRSessionManager> {
         if (!this._supported) {
             throw "XR session not supported by this browser";
         }
@@ -139,9 +139,12 @@ export class WebXRExperienceHelper implements IDisposable {
             this.sessionManager.onXRFrameObservable.addOnce(() => {
                 this._setState(WebXRState.IN_XR);
             });
+
+            return this.sessionManager;
         }).catch((e: any) => {
             console.log(e);
             console.log(e.message);
+            throw(e);
         });
     }
 

+ 7 - 2
src/Cameras/XR/webXRSessionManager.ts

@@ -87,7 +87,7 @@ export class WebXRSessionManager implements IDisposable {
      * @param optionalFeatures defines optional values to pass to the session builder
      * @returns a promise which will resolve once the session has been initialized
      */
-    public initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures: any = {}) {
+    public initializeSessionAsync(xrSessionMode: XRSessionMode, optionalFeatures: any = {}): Promise<XRSession> {
         return this._xrNavigator.xr.requestSession(xrSessionMode, optionalFeatures).then((session: XRSession) => {
             this.session = session;
             this._sessionEnded = false;
@@ -106,6 +106,7 @@ export class WebXRSessionManager implements IDisposable {
                 this.onXRSessionEnded.notifyObservers(null);
                 this.scene.getEngine()._renderLoop();
             }, { once: true });
+            return this.session;
         });
     }
 
@@ -192,7 +193,11 @@ export class WebXRSessionManager implements IDisposable {
      */
     public exitXRAsync() {
         if (this.session) {
-            return this.session.end();
+            try {
+                return this.session.end();
+            } catch (e) {
+                Logger.Warn("could not end XR session. It has ended already.");
+            }
         }
         return Promise.resolve();
     }

+ 11 - 12
src/Cameras/camera.ts

@@ -719,21 +719,20 @@ export class Camera extends Node {
                 this.minZ = 0.1;
             }
 
+            const reverseDepth = engine.useReverseDepthBuffer;
+            let getProjectionMatrix: (fov: number, aspect: number, znear: number, zfar: number, result: Matrix, isVerticalFovFixed: boolean) => void;
             if (scene.useRightHandedSystem) {
-                Matrix.PerspectiveFovRHToRef(this.fov,
-                    engine.getAspectRatio(this),
-                    this.minZ,
-                    this.maxZ,
-                    this._projectionMatrix,
-                    this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
+                getProjectionMatrix = reverseDepth ? Matrix.PerspectiveFovReverseRHToRef : Matrix.PerspectiveFovRHToRef;
             } else {
-                Matrix.PerspectiveFovLHToRef(this.fov,
-                    engine.getAspectRatio(this),
-                    this.minZ,
-                    this.maxZ,
-                    this._projectionMatrix,
-                    this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
+                getProjectionMatrix = reverseDepth ? Matrix.PerspectiveFovReverseLHToRef : Matrix.PerspectiveFovLHToRef;
             }
+
+            getProjectionMatrix(this.fov,
+                engine.getAspectRatio(this),
+                this.minZ,
+                this.maxZ,
+                this._projectionMatrix,
+                this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
         } else {
             var halfWidth = engine.getRenderWidth() / 2.0;
             var halfHeight = engine.getRenderHeight() / 2.0;

+ 3 - 3
src/Engines/WebGPU/webgpuConstants.ts

@@ -149,10 +149,10 @@ export class WebGPUConstants {
     public static readonly GPUCompareFunction_never: GPUCompareFunction = "never";
     public static readonly GPUCompareFunction_less: GPUCompareFunction = "less";
     public static readonly GPUCompareFunction_equal: GPUCompareFunction = "equal";
-    public static readonly GPUCompareFunction_lessEqual: GPUCompareFunction = "lessEqual";
+    public static readonly GPUCompareFunction_lessEqual: GPUCompareFunction = "less-equal";
     public static readonly GPUCompareFunction_greater: GPUCompareFunction = "greater";
-    public static readonly GPUCompareFunction_notEqual: GPUCompareFunction = "notEqual";
-    public static readonly GPUCompareFunction_greaterEqual: GPUCompareFunction = "greaterEqual";
+    public static readonly GPUCompareFunction_notEqual: GPUCompareFunction = "not-equal";
+    public static readonly GPUCompareFunction_greaterEqual: GPUCompareFunction = "greater-equal";
     public static readonly GPUCompareFunction_always: GPUCompareFunction = "always";
 
     public static readonly GPUBindingType_uniformBuffer: GPUBindingType = "uniform-buffer";

+ 13 - 3
src/Engines/thinEngine.ts

@@ -129,14 +129,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.1.0-beta.1";
+        return "babylonjs@4.1.0-beta.2";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.1.0-beta.1";
+        return "4.1.0-beta.2";
     }
 
     /**
@@ -202,6 +202,11 @@ export class ThinEngine {
     /** Gets or sets a boolean indicating if the engine should validate programs after compilation */
     public validateShaderPrograms = false;
 
+    /**
+     * Gets or sets a boolean indicating if depth buffer should be reverse, going from far to near.
+     * This can provide greater z depth for distant objects.
+     */
+    public useReverseDepthBuffer = false;
     // Uniform buffers list
 
     /**
@@ -1190,7 +1195,12 @@ export class ThinEngine {
             mode |= this._gl.COLOR_BUFFER_BIT;
         }
         if (depth) {
-            this._gl.clearDepth(1.0);
+            if (this.useReverseDepthBuffer) {
+                this._depthCullingState.depthFunc = this._gl.GREATER;
+                this._gl.clearDepth(0.0);
+            } else {
+                this._gl.clearDepth(1.0);
+            }
             mode |= this._gl.DEPTH_BUFFER_BIT;
         }
         if (stencil) {

+ 7 - 7
src/Engines/webgpuEngine.ts

@@ -1903,8 +1903,8 @@ export class WebGPUEngine extends Engine {
         throw new Error("Invalid Format '" + kind + "'");
     }
 
-    private _getVertexInputDescriptor(): GPUVertexInputDescriptor {
-        const descriptors: GPUVertexBufferDescriptor[] = [];
+    private _getVertexInputDescriptor(): GPUVertexStateDescriptor {
+        const descriptors: GPUVertexBufferLayoutDescriptor[] = [];
         const effect = this._currentEffect!;
         const attributes = effect.getAttributesNames();
         for (var index = 0; index < attributes.length; index++) {
@@ -1923,10 +1923,10 @@ export class WebGPUEngine extends Engine {
                 };
 
                 // TODO WEBGPU. Factorize the one with the same underlying buffer.
-                const vertexBufferDescriptor: GPUVertexBufferDescriptor = {
-                    stride: vertexBuffer.byteStride,
+                const vertexBufferDescriptor: GPUVertexBufferLayoutDescriptor = {
+                    arrayStride: vertexBuffer.byteStride,
                     stepMode: vertexBuffer.getIsInstanced() ? WebGPUConstants.GPUInputStepMode_instance : WebGPUConstants.GPUInputStepMode_vertex,
-                    attributeSet: [positionAttributeDescriptor]
+                    attributes: [positionAttributeDescriptor]
                 };
 
                descriptors.push(vertexBufferDescriptor);
@@ -1940,7 +1940,7 @@ export class WebGPUEngine extends Engine {
             };
         }
 
-        const inputStateDescriptor: GPUVertexInputDescriptor = {
+        const inputStateDescriptor: GPUVertexStateDescriptor = {
             indexFormat: this._currentIndexBuffer!.is32Bits ? WebGPUConstants.GPUIndexFormat_uint32 : WebGPUConstants.GPUIndexFormat_uint16,
             vertexBuffers: descriptors
         };
@@ -2030,7 +2030,7 @@ export class WebGPUEngine extends Engine {
             colorStates: colorStateDescriptors,
 
             ...stages,
-            vertexInput: inputStateDescriptor,
+            vertexState: inputStateDescriptor,
             layout: pipelineLayout,
         });
         return gpuPipeline.renderPipeline;

+ 5 - 1
src/Gizmos/axisScaleGizmo.ts

@@ -37,6 +37,10 @@ export class AxisScaleGizmo extends Gizmo {
      * If the scaling operation should be done on all axis (default: false)
      */
     public uniformScaling = false;
+    /**
+     * Custom sensitivity value for the drag strength
+     */
+    public sensitivity = 1;
 
     private _isEnabled: boolean = true;
     private _parent: Nullable<ScaleGizmo> = null;
@@ -92,7 +96,7 @@ export class AxisScaleGizmo extends Gizmo {
         this.dragBehavior.onDragObservable.add((event) => {
             if (this.attachedMesh) {
                 // Drag strength is modified by the scale of the gizmo (eg. for small objects like boombox the strength will be increased to match the behavior of larger objects)
-                var dragStrength = event.dragDistance * ((this.scaleRatio * 3) / this._rootMesh.scaling.length());
+                var dragStrength = this.sensitivity * event.dragDistance * ((this.scaleRatio * 3) / this._rootMesh.scaling.length());
 
                 // Snapping logic
                 var snapped = false;

+ 26 - 11
src/Gizmos/lightGizmo.ts

@@ -14,6 +14,7 @@ import { DirectionalLight } from '../Lights/directionalLight';
 import { SphereBuilder } from '../Meshes/Builders/sphereBuilder';
 import { HemisphereBuilder } from '../Meshes/Builders/hemisphereBuilder';
 import { SpotLight } from '../Lights/spotLight';
+import { TransformNode } from '../Meshes/transformNode';
 
 /**
  * Gizmo that enables viewing a light
@@ -21,8 +22,9 @@ import { SpotLight } from '../Lights/spotLight';
 export class LightGizmo extends Gizmo {
     private _lightMesh: Mesh;
     private _material: StandardMaterial;
-    private cachedPosition = new Vector3();
-    private cachedForward = new Vector3(0, 0, 1);
+    private _cachedPosition = new Vector3();
+    private _cachedForward = new Vector3(0, 0, 1);
+    private _attachedMeshParent: TransformNode;
 
     /**
      * Creates a LightGizmo
@@ -31,6 +33,9 @@ export class LightGizmo extends Gizmo {
     constructor(gizmoLayer?: UtilityLayerRenderer) {
         super(gizmoLayer);
         this.attachedMesh = new AbstractMesh("", this.gizmoLayer.utilityLayerScene);
+        this._attachedMeshParent = new TransformNode("parent", this.gizmoLayer.originalScene);
+
+        this.attachedMesh.parent = this._attachedMeshParent;
         this._material = new StandardMaterial("light", this.gizmoLayer.originalScene);
         this._material.diffuseColor = new Color3(0.5, 0.5, 0.5);
         this._material.specularColor = new Color3(0.1, 0.1, 0.1);
@@ -73,6 +78,10 @@ export class LightGizmo extends Gizmo {
             }
             this.attachedMesh!.reservedDataStore.lightGizmo = this;
 
+            if (light.parent) {
+                this._attachedMeshParent.freezeWorldMatrix(light.parent.getWorldMatrix());
+            }
+
             // Get update position and direction if the light has it
             if ((light as any).position) {
                 this.attachedMesh!.position.copyFrom((light as any).position);
@@ -104,12 +113,17 @@ export class LightGizmo extends Gizmo {
         if (!this._light) {
             return;
         }
+
+        if (this._light.parent) {
+            this._attachedMeshParent.freezeWorldMatrix(this._light.parent.getWorldMatrix());
+        }
+
         if ((this._light as any).position) {
             // If the gizmo is moved update the light otherwise update the gizmo to match the light
-            if (!this.attachedMesh!.position.equals(this.cachedPosition)) {
+            if (!this.attachedMesh!.position.equals(this._cachedPosition)) {
                 // update light to match gizmo
                 (this._light as any).position.copyFrom(this.attachedMesh!.position);
-                this.cachedPosition.copyFrom(this.attachedMesh!.position);
+                this._cachedPosition.copyFrom(this.attachedMesh!.position);
             } else {
                 // update gizmo to match light
                 this.attachedMesh!.position.copyFrom((this._light as any).position);
@@ -118,14 +132,14 @@ export class LightGizmo extends Gizmo {
         }
         if ((this._light as any).direction) {
             // If the gizmo is moved update the light otherwise update the gizmo to match the light
-            if (Vector3.DistanceSquared(this.attachedMesh!.forward, this.cachedForward) > 0.0001) {
+            if (Vector3.DistanceSquared(this.attachedMesh!.forward, this._cachedForward) > 0.0001) {
                 // update light to match gizmo
                 (this._light as any).direction.copyFrom(this.attachedMesh!.forward);
-                this.cachedForward.copyFrom(this.attachedMesh!.forward);
+                this._cachedForward.copyFrom(this.attachedMesh!.forward);
             } else if (Vector3.DistanceSquared(this.attachedMesh!.forward, (this._light as any).direction) > 0.0001) {
                 // update gizmo to match light
                 this.attachedMesh!.setDirection((this._light as any).direction);
-                this.cachedForward.copyFrom(this._lightMesh.forward);
+                this._cachedForward.copyFrom(this._lightMesh.forward);
             }
         }
         if (!this._light.isEnabled()) {
@@ -141,7 +155,7 @@ export class LightGizmo extends Gizmo {
     /**
      * Creates the lines for a light mesh
      */
-    private static _createLightLines = (levels: number, scene: Scene) => {
+    private static _CreateLightLines = (levels: number, scene: Scene) => {
         var distFromSphere = 1.2;
 
         var root = new Mesh("root", scene);
@@ -204,6 +218,7 @@ export class LightGizmo extends Gizmo {
     public dispose() {
         this._material.dispose();
         super.dispose();
+        this._attachedMeshParent.dispose();
     }
 
     private static _CreateHemisphericLightMesh(scene: Scene) {
@@ -213,7 +228,7 @@ export class LightGizmo extends Gizmo {
         hemisphere.rotation.x = Math.PI / 2;
         hemisphere.parent = root;
 
-        var lines = this._createLightLines(3, scene);
+        var lines = this._CreateLightLines(3, scene);
         lines.parent = root;
         lines.position.z - 0.15;
 
@@ -229,7 +244,7 @@ export class LightGizmo extends Gizmo {
         sphere.rotation.x = Math.PI / 2;
         sphere.parent = root;
 
-        var lines = this._createLightLines(5, scene);
+        var lines = this._CreateLightLines(5, scene);
         lines.parent = root;
         root.scaling.scaleInPlace(LightGizmo._Scale);
         root.rotation.x = Math.PI / 2;
@@ -246,7 +261,7 @@ export class LightGizmo extends Gizmo {
         hemisphere.parent = root;
         hemisphere.rotation.x = -Math.PI / 2;
 
-        var lines = this._createLightLines(2, scene);
+        var lines = this._CreateLightLines(2, scene);
         lines.parent = root;
         root.scaling.scaleInPlace(LightGizmo._Scale);
         root.rotation.x = Math.PI / 2;

+ 16 - 0
src/Gizmos/scaleGizmo.ts

@@ -37,6 +37,7 @@ export class ScaleGizmo extends Gizmo {
     private _scaleRatio: number;
     private _uniformScalingMesh: Mesh;
     private _octahedron: Mesh;
+    private _sensitivity: number = 1;
 
     /** Fires an event when any of it's sub gizmos are dragged */
     public onDragStartObservable = new Observable();
@@ -142,6 +143,21 @@ export class ScaleGizmo extends Gizmo {
     }
 
     /**
+     * Sensitivity factor for dragging (Default: 1)
+     */
+    public set sensitivity(value: number) {
+        this._sensitivity = value;
+        [this.xGizmo, this.yGizmo, this.zGizmo, this.uniformScaleGizmo].forEach((gizmo) => {
+            if (gizmo) {
+                gizmo.sensitivity = value;
+            }
+        });
+    }
+    public get sensitivity() {
+        return this._sensitivity;
+    }
+
+    /**
      * Disposes of the gizmo
      */
     public dispose() {

+ 184 - 54
src/LibDeclarations/webgpu.d.ts

@@ -1,5 +1,7 @@
-// https://github.com/gpuweb/gpuweb/blob/0a2bb28a584aa1c6adabaec1f841ed29de400626/spec/index.bs
+https://github.com/gpuweb/gpuweb/blob/37812f5f39ae8c6dc85f6a12c0f65e9c9d6e2155
 // except #280 setSubData (TODO)
+// plus #489 GPUAdapter.limits
+// v 0.0.17
 
 interface GPUColorDict {
   a: number;
@@ -66,10 +68,10 @@ type GPUCompareFunction =
   | "never"
   | "less"
   | "equal"
-  | "lessEqual"
+  | "less-equal"
   | "greater"
-  | "notEqual"
-  | "greaterEqual"
+  | "not-equal"
+  | "greater-equal"
   | "always";
 type GPUCullMode = "none" | "front" | "back";
 type GPUFilterMode = "nearest" | "linear";
@@ -323,20 +325,20 @@ interface GPUFenceDescriptor extends GPUObjectDescriptorBase {
 }
 
 interface GPUVertexAttributeDescriptor {
-  offset?: number;
+  offset: number;
   format: GPUVertexFormat;
   shaderLocation: number;
 }
 
-interface GPUVertexBufferDescriptor {
-  stride: number;
+interface GPUVertexBufferLayoutDescriptor {
+  arrayStride: number;
   stepMode?: GPUInputStepMode;
-  attributeSet: GPUVertexAttributeDescriptor[];
+  attributes: GPUVertexAttributeDescriptor[];
 }
 
-interface GPUVertexInputDescriptor {
+interface GPUVertexStateDescriptor {
   indexFormat?: GPUIndexFormat;
-  vertexBuffers: GPUVertexBufferDescriptor[];
+  vertexBuffers: GPUVertexBufferLayoutDescriptor[];
 }
 
 interface GPULimits {
@@ -345,11 +347,22 @@ interface GPULimits {
   maxDynamicStorageBuffersPerPipelineLayout?: number;
   maxSampledTexturesPerShaderStage?: number;
   maxSamplersPerShaderStage?: number;
-  maxStorageBuffersPerPipelineLayout?: number;
+  maxStorageBuffersPerShaderStage?: number;
   maxStorageTexturesPerShaderStage?: number;
   maxUniformBuffersPerShaderStage?: number;
 }
 
+interface GPULimitsOut {
+  maxBindGroups: number;
+  maxDynamicUniformBuffersPerPipelineLayout: number;
+  maxDynamicStorageBuffersPerPipelineLayout: number;
+  maxSampledTexturesPerShaderStage: number;
+  maxSamplersPerShaderStage: number;
+  maxStorageBuffersPerShaderStage: number;
+  maxStorageTexturesPerShaderStage: number;
+  maxUniformBuffersPerShaderStage: number;
+}
+
 interface GPUPipelineDescriptorBase {
   label?: string;
   layout: GPUPipelineLayout;
@@ -406,7 +419,7 @@ interface GPURenderPipelineDescriptor
   rasterizationState?: GPURasterizationStateDescriptor;
   colorStates: GPUColorStateDescriptor[];
   depthStencilState?: GPUDepthStencilStateDescriptor;
-  vertexInput: GPUVertexInputDescriptor;
+  vertexState?: GPUVertexStateDescriptor;
 
   sampleCount?: number;
   sampleMask?: number;
@@ -464,17 +477,24 @@ interface GPUTextureViewDescriptor extends GPUObjectDescriptorBase {
   mipLevelCount?: number;
 }
 
-interface GPUAdapter extends GPUObjectBase {
-  readonly extensions: GPUExtensions;
+class GPUAdapter {
   readonly name: string;
+  readonly extensions: GPUExtensions;
+  readonly limits: GPULimitsOut;
+
   requestDevice(descriptor?: GPUDeviceDescriptor): Promise<GPUDevice>;
 }
 
-interface GPUBindGroup extends GPUObjectBase {}
+class GPUBindGroup implements GPUObjectBase {
+  label: string | undefined;
+}
 
-interface GPUBindGroupLayout extends GPUObjectBase {}
+class GPUBindGroupLayout implements GPUObjectBase {
+  label: string | undefined;
+}
 
-interface GPUBuffer extends GPUObjectBase {
+class GPUBuffer implements GPUObjectBase {
+  label: string | undefined;
   //readonly mapping: ArrayBuffer | null;
   destroy(): void;
   unmap(): void;
@@ -490,11 +510,14 @@ interface GPUBuffer extends GPUObjectBase {
   ): void;
 }
 
-interface GPUCommandBuffer extends GPUObjectBase {}
+class GPUCommandBuffer implements GPUObjectBase {
+  label: string | undefined;
+}
 
 interface GPUCommandBufferDescriptor extends GPUObjectDescriptorBase {}
 
-interface GPUCommandEncoder extends GPUObjectBase {
+class GPUCommandEncoder implements GPUObjectBase {
+  label: string | undefined;
   beginComputePass(
     descriptor?: GPUComputePassDescriptor
   ): GPUComputePassEncoder;
@@ -535,7 +558,19 @@ interface GPUCommandEncoder extends GPUObjectBase {
 
 interface GPUComputePassDescriptor extends GPUObjectDescriptorBase {}
 
-interface GPUComputePassEncoder extends GPUProgrammablePassEncoder {
+class GPUComputePassEncoder implements GPUProgrammablePassEncoder {
+  label: string | undefined;
+
+  setBindGroup(
+    index: number,
+    bindGroup: GPUBindGroup,
+    dynamicOffsets?: number[]
+  ): void;
+
+  popDebugGroup(): void;
+  pushDebugGroup(groupLabel: string): void;
+  insertDebugMarker(markerLabel: string): void;
+
   setPipeline(pipeline: GPUComputePipeline): void;
   dispatch(x: number, y?: number, z?: number): void;
   dispatchIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): void;
@@ -543,7 +578,9 @@ interface GPUComputePassEncoder extends GPUProgrammablePassEncoder {
   endPass(): void;
 }
 
-interface GPUComputePipeline extends GPUObjectBase {}
+class GPUComputePipeline implements GPUObjectBase {
+  label: string | undefined;
+}
 
 interface GPUObjectBase {
   label: string | undefined;
@@ -554,16 +591,17 @@ interface GPUObjectDescriptorBase {
 }
 
 // SwapChain / CanvasContext
-interface GPUCanvasContext {
+class GPUCanvasContext {
   configureSwapChain(descriptor: GPUSwapChainDescriptor): GPUSwapChain;
 
   getSwapChainPreferredFormat(device: GPUDevice): Promise<GPUTextureFormat>;
 }
 
-interface GPUDevice extends GPUObjectBase {
+class GPUDevice extends EventTarget implements GPUObjectBase {
+  label: string | undefined;
   readonly adapter: GPUAdapter;
   readonly extensions: GPUExtensions;
-  readonly limits: GPULimits;
+  readonly limits: GPULimitsOut;
 
   createBindGroup(descriptor: GPUBindGroupDescriptor): GPUBindGroup;
   createBindGroupLayout(
@@ -598,27 +636,39 @@ interface GPUDevice extends GPUObjectBase {
 
   getQueue(): GPUQueue;
 
+  pushErrorScope(filter: GPUErrorFilter): void;
+  popErrorScope(): Promise<GPUError | null>;
+  onuncapturederror: Event | undefined;
   readonly lost: Promise<GPUDeviceLostInfo>;
 }
 
-interface GPUFence extends GPUObjectBase {
+class GPUFence implements GPUObjectBase {
+  label: string | undefined;
+
   getCompletedValue(): number;
   onCompletion(completionValue: number): Promise<void>;
 }
 
-interface GPUPipelineLayout extends GPUObjectBase {}
+class GPUPipelineLayout implements GPUObjectBase {
+  label: string | undefined;
+}
 
 interface GPUProgrammablePassEncoder extends GPUObjectBase {
-  setBindGroup(index: number, bindGroup: GPUBindGroup): void;
+  setBindGroup(
+    index: number,
+    bindGroup: GPUBindGroup,
+    dynamicOffsets?: number[]
+  ): void;
 
   popDebugGroup(): void;
   pushDebugGroup(groupLabel: string): void;
   insertDebugMarker(markerLabel: string): void;
 }
 
-interface GPUQueue extends GPUObjectBase {
+class GPUQueue implements GPUObjectBase {
+  label: string | undefined;
   signal(fence: GPUFence, signalValue: number): void;
-  submit(buffers: GPUCommandBuffer[]): void;
+  submit(commandBuffers: GPUCommandBuffer[]): void;
   createFence(descriptor?: GPUFenceDescriptor): GPUFence;
 }
 
@@ -650,7 +700,44 @@ interface GPURenderEncoderBase extends GPUProgrammablePassEncoder {
   ): void;
 }
 
-interface GPURenderPassEncoder extends GPURenderEncoderBase {
+class GPURenderPassEncoder implements GPURenderEncoderBase {
+  label: string | undefined;
+
+  setBindGroup(
+    index: number,
+    bindGroup: GPUBindGroup,
+    dynamicOffsets?: number[]
+  ): void;
+
+  popDebugGroup(): void;
+  pushDebugGroup(groupLabel: string): void;
+  insertDebugMarker(markerLabel: string): void;
+
+  setPipeline(pipeline: GPURenderPipeline): void;
+
+  setIndexBuffer(buffer: GPUBuffer, offset?: number): void;
+  setVertexBuffer(slot: number, buffer: GPUBuffer, offset?: number): void;
+
+  draw(
+    vertexCount: number,
+    instanceCount: number,
+    firstVertex: number,
+    firstInstance: number
+  ): void;
+  drawIndexed(
+    indexCount: number,
+    instanceCount: number,
+    firstIndex: number,
+    baseVertex: number,
+    firstInstance: number
+  ): void;
+
+  drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): void;
+  drawIndexedIndirect(
+    indirectBuffer: GPUBuffer,
+    indirectOffset: number
+  ): void;
+
   setViewport(
     x: number,
     y: number,
@@ -670,9 +757,47 @@ interface GPURenderPassEncoder extends GPURenderEncoderBase {
 
 interface GPURenderBundleDescriptor extends GPUObjectDescriptorBase {}
 
-interface GPURenderBundle extends GPUObjectBase {}
+class GPURenderBundle implements GPUObjectBase {
+  label: string | undefined;
+}
+
+class GPURenderBundleEncoder implements GPURenderEncoderBase {
+  label: string | undefined;
+
+  setBindGroup(
+    index: number,
+    bindGroup: GPUBindGroup,
+    dynamicOffsets?: number[]
+  ): void;
+
+  popDebugGroup(): void;
+  pushDebugGroup(groupLabel: string): void;
+  insertDebugMarker(markerLabel: string): void;
+
+  setPipeline(pipeline: GPURenderPipeline): void;
+
+  setIndexBuffer(buffer: GPUBuffer, offset?: number): void;
+  setVertexBuffer(slot: number, buffer: GPUBuffer, offset?: number): void;
+
+  draw(
+    vertexCount: number,
+    instanceCount: number,
+    firstVertex: number,
+    firstInstance: number
+  ): void;
+  drawIndexed(
+    indexCount: number,
+    instanceCount: number,
+    firstIndex: number,
+    baseVertex: number,
+    firstInstance: number
+  ): void;
 
-interface GPURenderBundleEncoder extends GPURenderEncoderBase {
+  drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): void;
+  drawIndexedIndirect(
+    indirectBuffer: GPUBuffer,
+    indirectOffset: number
+  ): void;
   finish(descriptor?: GPURenderBundleDescriptor): GPURenderBundle;
 }
 
@@ -683,29 +808,39 @@ interface GPURenderBundleEncoderDescriptor
   sampleCount?: number;
 }
 
-interface GPURenderPipeline extends GPUObjectBase {}
+class GPURenderPipeline implements GPUObjectBase {
+  label: string | undefined;
+}
 
-interface GPUSampler extends GPUObjectBase {}
+class GPUSampler implements GPUObjectBase {
+  label: string | undefined;
+}
 
-interface GPUShaderModule extends GPUObjectBase {}
+class GPUShaderModule implements GPUObjectBase {
+  label: string | undefined;
+}
 
-interface GPUSwapChain extends GPUObjectBase {
+class GPUSwapChain implements GPUObjectBase {
+  label: string | undefined;
   getCurrentTexture(): GPUTexture;
 }
 
-interface GPUTexture extends GPUObjectBase {
+class GPUTexture implements GPUObjectBase {
+  label: string | undefined;
   createView(descriptor?: GPUTextureViewDescriptor): GPUTextureView;
   destroy(): void;
 }
 
-interface GPUTextureView extends GPUObjectBase {}
+class GPUTextureView implements GPUObjectBase {
+  label: string | undefined;
+}
 
 type GPUPowerPreference = "low-power" | "high-performance";
 interface GPURequestAdapterOptions {
   powerPreference?: GPUPowerPreference;
 }
 
-interface GPU {
+class GPU {
   requestAdapter(options?: GPURequestAdapterOptions): Promise<GPUAdapter>;
 }
 
@@ -726,27 +861,22 @@ declare class GPUValidationError {
 
 type GPUError = GPUOutOfMemoryError | GPUValidationError;
 
-interface GPUDevice {
-  pushErrorScope(filter: GPUErrorFilter): void;
-  popErrorScope(): Promise<GPUError | null>;
-}
-
-// ****************************************************************************
-// TELEMETRY
-// ****************************************************************************
-
-interface GPUUncapturedErrorEvent extends Event {
-  readonly error: GPUError;
-}
-
 interface GPUUncapturedErrorEventInit extends EventInit {
   error: GPUError;
 }
 
-interface GPUDevice extends EventTarget {
-  onuncapturederror: Event | undefined;
+class GPUUncapturedErrorEvent extends Event {
+  constructor(
+    type: string,
+    gpuUncapturedErrorEventInitDict: GPUUncapturedErrorEventInit
+  );
+  readonly error: GPUError;
 }
 
+// ****************************************************************************
+// TELEMETRY
+// ****************************************************************************
+
 interface GPUDeviceLostInfo {
   readonly message: string;
 }

+ 35 - 8
src/Materials/Node/Blocks/Dual/textureBlock.ts

@@ -21,6 +21,7 @@ import "../../../../Shaders/ShadersInclude/helperFunctions";
 export class TextureBlock extends NodeMaterialBlock {
     private _defineName: string;
     private _linearDefineName: string;
+    private _tempTextureRead: string;
     private _samplerName: string;
     private _transformedUVName: string;
     private _textureTransformName: string;
@@ -253,6 +254,8 @@ export class TextureBlock extends NodeMaterialBlock {
             return;
         }
 
+        this._writeTextureRead(state, true);
+
         for (var output of this._outputs) {
             if (output.hasEndpoints) {
                 this._writeOutput(state, output, output.name, true);
@@ -260,7 +263,7 @@ export class TextureBlock extends NodeMaterialBlock {
         }
     }
 
-    private _writeOutput(state: NodeMaterialBuildState, output: NodeMaterialConnectionPoint, swizzle: string, vertexMode = false) {
+    private _writeTextureRead(state: NodeMaterialBuildState, vertexMode = false) {
         let uvInput = this.uv;
 
         if (vertexMode) {
@@ -268,24 +271,42 @@ export class TextureBlock extends NodeMaterialBlock {
                 return;
             }
 
-            state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${uvInput.associatedVariableName}).${swizzle};\r\n`;
-
+            state.compilationString += `vec4 ${this._tempTextureRead} = texture2D(${this._samplerName}, ${uvInput.associatedVariableName});\r\n`;
             return;
         }
 
         if (this.uv.ownerBlock.target === NodeMaterialBlockTargets.Fragment) {
-            state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${uvInput.associatedVariableName}).${swizzle};\r\n`;
+            state.compilationString += `vec4 ${this._tempTextureRead} = texture2D(${this._samplerName}, ${uvInput.associatedVariableName});\r\n`;
             return;
         }
 
-        const complement = ` * ${this._textureInfoName}`;
-
         state.compilationString += `#ifdef ${this._defineName}\r\n`;
-        state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${this._transformedUVName}).${swizzle}${complement};\r\n`;
+        state.compilationString += `vec4 ${this._tempTextureRead} = texture2D(${this._samplerName}, ${this._transformedUVName});\r\n`;
         state.compilationString += `#endif\r\n`;
         state.compilationString += `#ifdef ${this._mainUVDefineName}\r\n`;
-        state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${this._mainUVName}).${swizzle}${complement};\r\n`;
+        state.compilationString += `vec4 ${this._tempTextureRead} = texture2D(${this._samplerName}, ${this._mainUVName});\r\n`;
         state.compilationString += `#endif\r\n`;
+    }
+
+    private _writeOutput(state: NodeMaterialBuildState, output: NodeMaterialConnectionPoint, swizzle: string, vertexMode = false) {
+        if (vertexMode) {
+            if (state.target === NodeMaterialBlockTargets.Fragment) {
+                return;
+            }
+
+            state.compilationString += `${this._declareOutput(output, state)} = ${this._tempTextureRead}.${swizzle};\r\n`;
+
+            return;
+        }
+
+        if (this.uv.ownerBlock.target === NodeMaterialBlockTargets.Fragment) {
+            state.compilationString += `${this._declareOutput(output, state)} = ${this._tempTextureRead}.${swizzle};\r\n`;
+            return;
+        }
+
+        const complement = ` * ${this._textureInfoName}`;
+
+        state.compilationString += `${this._declareOutput(output, state)} = ${this._tempTextureRead}.${swizzle}${complement};\r\n`;
 
         state.compilationString += `#ifdef ${this._linearDefineName}\r\n`;
         state.compilationString += `${output.associatedVariableName} = toGammaSpace(${output.associatedVariableName});\r\n`;
@@ -295,6 +316,10 @@ export class TextureBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
+        if (state.target === NodeMaterialBlockTargets.Vertex) {
+            this._tempTextureRead = state._getFreeVariableName("tempTextureRead");
+        }
+
         if (!this._isMixed && state.target === NodeMaterialBlockTargets.Fragment || this._isMixed && state.target === NodeMaterialBlockTargets.Vertex) {
             this._samplerName = state._getFreeVariableName(this.name + "Sampler");
 
@@ -332,6 +357,8 @@ export class TextureBlock extends NodeMaterialBlock {
             state._emitUniformFromString(this._textureInfoName, "float");
         }
 
+        this._writeTextureRead(state);
+
         for (var output of this._outputs) {
             if (output.hasEndpoints) {
                 this._writeOutput(state, output, output.name);

+ 2 - 0
src/Materials/Node/Blocks/index.ts

@@ -40,3 +40,5 @@ export * from "./gradientBlock";
 export * from "./nLerpBlock";
 export * from "./worleyNoise3DBlock";
 export * from "./simplexPerlin3DBlock";
+export * from "./normalBlendBlock";
+export * from "./rotate2dBlock";

+ 80 - 0
src/Materials/Node/Blocks/normalBlendBlock.ts

@@ -0,0 +1,80 @@
+import { NodeMaterialBlock } from '../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../Enums/nodeMaterialBlockTargets';
+import { _TypeStore } from '../../../Misc/typeStore';
+/**
+ * Block used to blend normals
+ */
+export class NormalBlendBlock extends NodeMaterialBlock {
+    /**
+     * Creates a new NormalBlendBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Neutral);
+
+        this.registerInput("input0", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerInput("input1", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector3);
+
+        this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Color3);
+        this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Color4);
+        this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector4);
+
+        this._inputs[1].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Color3);
+        this._inputs[1].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Color4);
+        this._inputs[1].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector4);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "NormalBlendBlock";
+    }
+
+    /**
+     * Gets the first input component
+     */
+    public get input0(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the second input component
+     */
+    public get input1(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the output component
+     */
+    public get output(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        let output = this._outputs[0];
+        let input0 = this._inputs[0];
+        let input1 = this._inputs[1];
+        let stepR = state._getFreeVariableName("stepR");
+        let stepG = state._getFreeVariableName("stepG");
+
+        state.compilationString += `float ${stepR} = step(0.5, ${input0.associatedVariableName}.r);\r\n`;
+        state.compilationString += `float ${stepG} = step(0.5, ${input0.associatedVariableName}.g);\r\n`;
+        state.compilationString += this._declareOutput(output, state) + `;\r\n`;
+        state.compilationString += `${output.associatedVariableName}.r = (1.0 - ${stepR}) * ${input0.associatedVariableName}.r * ${input1.associatedVariableName}.r * 2.0 + ${stepR} * (1.0 - ${input0.associatedVariableName}.r) * (1.0 - ${input1.associatedVariableName}.r) * 2.0;\r\n`;
+        state.compilationString += `${output.associatedVariableName}.g = (1.0 - ${stepG}) * ${input0.associatedVariableName}.g * ${input1.associatedVariableName}.g * 2.0 + ${stepG} * (1.0 - ${input0.associatedVariableName}.g) * (1.0 - ${input1.associatedVariableName}.g) * 2.0;\r\n`;
+        state.compilationString += `${output.associatedVariableName}.b = ${input0.associatedVariableName}.b * ${input1.associatedVariableName}.b;\r\n`;
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.NormalBlendBlock"] = NormalBlendBlock;

+ 77 - 0
src/Materials/Node/Blocks/rotate2dBlock.ts

@@ -0,0 +1,77 @@
+import { NodeMaterialBlock } from '../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../nodeMaterialBuildState';
+import { NodeMaterialBlockTargets } from '../Enums/nodeMaterialBlockTargets';
+import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
+import { _TypeStore } from '../../../Misc/typeStore';
+import { NodeMaterial } from '../nodeMaterial';
+import { InputBlock } from './Input/inputBlock';
+
+/**
+ * Block used to rotate a 2d vector by a given angle
+ */
+export class Rotate2dBlock extends NodeMaterialBlock {
+
+    /**
+     * Creates a new Rotate2dBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Neutral);
+
+        this.registerInput("input", NodeMaterialBlockConnectionPointTypes.Vector2);
+        this.registerInput("angle", NodeMaterialBlockConnectionPointTypes.Float);
+        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector2);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "Rotate2dBlock";
+    }
+
+    /**
+     * Gets the input vector
+     */
+    public get input(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the input angle
+     */
+    public get angle(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the output component
+     */
+    public get output(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    public autoConfigure(material: NodeMaterial) {
+        if (!this.angle.isConnected) {
+            let angleInput = new InputBlock("angle");
+            angleInput.value = 0;
+            angleInput.output.connectTo(this.angle);
+        }
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        let output = this._outputs[0];
+        let angle = this.angle;
+        let input = this.input;
+
+        state.compilationString += this._declareOutput(output, state) + ` = vec2(cos(${angle.associatedVariableName}) * ${input.associatedVariableName}.x - sin(${angle.associatedVariableName}) * ${input.associatedVariableName}.y, sin(${angle.associatedVariableName}) * ${input.associatedVariableName}.x + cos(${angle.associatedVariableName}) * ${input.associatedVariableName}.y);\r\n`;
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.Rotate2dBlock"] = Rotate2dBlock;

+ 5 - 5
src/Materials/Node/Blocks/simplexPerlin3DBlock.ts

@@ -43,7 +43,7 @@ export class SimplexPerlin3DBlock extends NodeMaterialBlock {
      */
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.Neutral);
-        this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerInput("seed", NodeMaterialBlockConnectionPointTypes.Vector3);
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Float);
     }
 
@@ -56,9 +56,9 @@ export class SimplexPerlin3DBlock extends NodeMaterialBlock {
     }
 
     /**
-     * Gets the position operand input component
+     * Gets the seed operand input component
      */
-    public get position(): NodeMaterialConnectionPoint {
+    public get seed(): NodeMaterialConnectionPoint {
         return this._inputs[0];
     }
 
@@ -72,7 +72,7 @@ export class SimplexPerlin3DBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
-        if (!this.position.isConnected) {
+        if (!this.seed.isConnected) {
             return;
         }
 
@@ -122,7 +122,7 @@ export class SimplexPerlin3DBlock extends NodeMaterialBlock {
         functionString += `}\r\n`;
 
         state._emitFunction('SimplexPerlin3D', functionString, 'SimplexPerlin3D');
-        state.compilationString += this._declareOutput(this._outputs[0], state) + ` = SimplexPerlin3D(${this.position.associatedVariableName});\r\n`;
+        state.compilationString += this._declareOutput(this._outputs[0], state) + ` = SimplexPerlin3D(${this.seed.associatedVariableName});\r\n`;
 
         return this;
     }

+ 0 - 0
src/Materials/Node/Blocks/worleyNoise3DBlock.ts


Некоторые файлы не были показаны из-за большого количества измененных файлов