Переглянути джерело

Merge pull request #1 from BabylonJS/master

pull latest changes
Devin Wright 6 роки тому
батько
коміт
d49d8347a6
100 змінених файлів з 157742 додано та 149225 видалено
  1. 1 1
      .vscode/launch.json
  2. 114 12
      Playground/babylon.d.txt
  3. 1862 765
      Playground/babylonWebGPU.d.txt
  4. 1 1
      Playground/css/index.css
  5. 1 7
      Playground/indexStable.html
  6. 152204 147754
      Playground/js/babylonWebGpu.max.js
  7. 1 1
      Playground/js/babylonWebGpu.max.js.map
  8. 31 3
      Playground/js/config_versions.js
  9. 12 7
      Playground/js/main.js
  10. 60 16
      Playground/js/mainWebGPU.js
  11. 2 2
      Playground/js/menuPG.js
  12. 36 14
      Playground/js/settingsPG.js
  13. 3 0
      Playground/package.json
  14. 2 1
      Tools/Config/config.json
  15. 1 2
      dist/gui/readme.md
  16. 116 12
      dist/preview release/babylon.d.ts
  17. 1 1
      dist/preview release/babylon.js
  18. 585 184
      dist/preview release/babylon.max.js
  19. 1 1
      dist/preview release/babylon.max.js.map
  20. 248 29
      dist/preview release/babylon.module.d.ts
  21. 116 12
      dist/preview release/documentation.d.ts
  22. 1 1
      dist/preview release/glTF2Interface/package.json
  23. 2 2
      dist/preview release/gui/package.json
  24. 7 7
      dist/preview release/inspector/package.json
  25. 1 0
      dist/preview release/loaders/babylon.stlFileLoader.js
  26. 1 1
      dist/preview release/loaders/babylon.stlFileLoader.js.map
  27. 1 0
      dist/preview release/loaders/babylonjs.loaders.js
  28. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  29. 1 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  30. 3 3
      dist/preview release/loaders/package.json
  31. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  32. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.js.map
  33. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  34. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js
  35. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js.map
  36. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  37. 2 2
      dist/preview release/materialsLibrary/package.json
  38. 111 8
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  39. 7 7
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  40. 570 78
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  41. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  42. 242 17
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  43. 2 2
      dist/preview release/nodeEditor/package.json
  44. 1 1
      dist/preview release/package.json
  45. 1 1
      dist/preview release/packagesSizeBaseLine.json
  46. 2 2
      dist/preview release/postProcessesLibrary/package.json
  47. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  48. 3 3
      dist/preview release/serializers/package.json
  49. 248 29
      dist/preview release/viewer/babylon.module.d.ts
  50. 44 36
      dist/preview release/viewer/babylon.viewer.js
  51. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  52. 1 0
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  53. 2 1
      dist/preview release/what's new.md
  54. 2 0
      loaders/src/STL/stlFileLoader.ts
  55. 1 1
      materialsLibrary/src/water/water.fragment.fx
  56. 8 0
      nodeEditor/public/index.html
  57. 38 33
      nodeEditor/public/index.js
  58. 8 5
      nodeEditor/src/blockTools.ts
  59. 3 2
      nodeEditor/src/components/diagram/diagram.scss
  60. 8 1
      nodeEditor/src/components/diagram/generic/genericNodeModel.tsx
  61. 10 0
      nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx
  62. 24 3
      nodeEditor/src/components/diagram/remap/remapNodeWidget.tsx
  63. 59 4
      nodeEditor/src/components/diagram/texture/texturePropertyTabComponent.tsx
  64. 0 1
      nodeEditor/src/components/log/log.scss
  65. 1 1
      nodeEditor/src/components/nodeList/nodeList.scss
  66. 3 3
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  67. 54 0
      nodeEditor/src/components/preview/previewAreaComponent.tsx
  68. 115 28
      nodeEditor/src/components/preview/previewManager.ts
  69. 21 2
      nodeEditor/src/components/preview/previewMeshControlComponent.tsx
  70. 2 1
      nodeEditor/src/components/preview/previewMeshType.ts
  71. 21 0
      nodeEditor/src/components/propertyTab/properties/matrixPropertyTabComponent.tsx
  72. 21 0
      nodeEditor/src/components/propertyTab/properties/vector4PropertyTabComponent.tsx
  73. 15 6
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  74. 13 2
      nodeEditor/src/globalState.ts
  75. 4 3
      nodeEditor/src/graphEditor.tsx
  76. 59 20
      nodeEditor/src/main.scss
  77. 2 2
      nodeEditor/src/nodeEditor.ts
  78. 87 0
      nodeEditor/src/sharedComponents/matrixLineComponent.tsx
  79. 3 3
      nodeEditor/src/sharedComponents/textInputLineComponent.tsx
  80. 137 0
      nodeEditor/src/sharedComponents/vector4LineComponent.tsx
  81. 2 26
      nodeEditor/src/stringTools.ts
  82. 5 3
      package.json
  83. 8 0
      src/Cameras/VR/vrExperienceHelper.ts
  84. 12 1
      src/Cameras/camera.ts
  85. 2 2
      src/Engines/engine.ts
  86. 76 9
      src/Engines/nativeEngine.ts
  87. 6 0
      src/Helpers/photoDome.ts
  88. 1 2
      src/Materials/Node/Blocks/Dual/fogBlock.ts
  89. 2 9
      src/Materials/Node/Blocks/Dual/lightBlock.ts
  90. 5 1
      src/Materials/Node/Blocks/Dual/textureBlock.ts
  91. 2 1
      src/Materials/Node/Blocks/Fragment/index.ts
  92. 182 0
      src/Materials/Node/Blocks/Fragment/perturbNormalBlock.ts
  93. 4 0
      src/Materials/Node/Blocks/Input/inputBlock.ts
  94. 1 1
      src/Materials/Node/Blocks/fresnelBlock.ts
  95. 1 1
      src/Materials/Node/Blocks/index.ts
  96. 6 5
      src/Materials/Node/Blocks/oppositeBlock.ts
  97. 40 1
      src/Materials/Node/Blocks/remapBlock.ts
  98. 4 3
      src/Materials/Node/nodeMaterial.ts
  99. 1 1
      src/Materials/Node/nodeMaterialBlock.ts
  100. 0 0
      src/Materials/Node/nodeMaterialBuildState.ts

+ 1 - 1
.vscode/launch.json

@@ -2,7 +2,7 @@
     "version": "2.0.0",
     "version": "2.0.0",
     "configurations": [
     "configurations": [
         {
         {
-            "name": "Node Material Editor (Chrome)",
+            "name": "Launch Node Material Editor (Chrome)",
             "type": "chrome",
             "type": "chrome",
             "request": "launch",
             "request": "launch",
             "url": "http://localhost:1338/nodeEditor/public/index-local.html",
             "url": "http://localhost:1338/nodeEditor/public/index-local.html",

+ 114 - 12
Playground/babylon.d.txt

@@ -21727,7 +21727,7 @@ declare module BABYLON {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -21737,7 +21737,7 @@ declare module BABYLON {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -24542,6 +24542,10 @@ declare module BABYLON {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -27199,9 +27203,9 @@ declare module BABYLON {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -40306,6 +40310,10 @@ declare module BABYLON {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -43457,7 +43465,11 @@ declare module BABYLON {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -45077,6 +45089,10 @@ declare module BABYLON {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -45114,14 +45130,21 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Class used to host texture specific utilities
+     * Class used to host RGBD texture specific utilities
      */
      */
-    export class BRDFTextureTools {
+    export class RGBDTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
          * @param texture the texture to expand.
          * @param texture the texture to expand.
          */
          */
-        private static _ExpandDefaultBRDFTexture;
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * Class used to host texture specific utilities
+     */
+    export class BRDFTextureTools {
         /**
         /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
@@ -46083,6 +46106,7 @@ declare module BABYLON {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -51437,6 +51461,8 @@ declare module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -51897,6 +51923,12 @@ declare module BABYLON {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -51931,6 +51963,7 @@ declare module BABYLON {
         /** @hidden */
private _getFreeDefineName(prefix: string): string;
         /** @hidden */
private _getFreeDefineName(prefix: string): string;
         /** @hidden */
private _excludeVariableName(name: string): void;
         /** @hidden */
private _excludeVariableName(name: string): void;
         /** @hidden */
private _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
private _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
+        /** @hidden */
private _emitExtension(name: string, extension: string): void;
         /** @hidden */
private _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
private _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
private _emitCodeFromInclude(includeName: string, comments: string, options?: {
         /** @hidden */
private _emitCodeFromInclude(includeName: string, comments: string, options?: {
             replaceStrings?: {
             replaceStrings?: {
@@ -52288,6 +52321,7 @@ declare module BABYLON {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -52659,6 +52693,58 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
private _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      * Block used to add support for scene fog
      */
      */
     export class FogBlock extends NodeMaterialBlock {
     export class FogBlock extends NodeMaterialBlock {
@@ -52959,6 +53045,22 @@ declare module BABYLON {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -53363,11 +53465,11 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);

Різницю між файлами не показано, бо вона завелика
+ 1862 - 765
Playground/babylonWebGPU.d.txt


+ 1 - 1
Playground/css/index.css

@@ -682,7 +682,7 @@ body {
 .navbarBottom .links .link a {
 .navbarBottom .links .link a {
     text-decoration: none;
     text-decoration: none;
     line-height: 35px;
     line-height: 35px;
-    padding: 6px 15px;
+    padding: 5px 15px;
     font-size: 16px;
     font-size: 16px;
     color: white;
     color: white;
 }
 }

+ 1 - 7
Playground/indexStable.html

@@ -1,11 +1,6 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html>
 <html>
 
 
-<!--
-    The purpose of the indexStable.html file is to ???
-    // TO DO - Complete that
- -->
-
 <head>
 <head>
     <title>Babylon.js Playground</title>
     <title>Babylon.js Playground</title>
     <meta charset='utf-8' />
     <meta charset='utf-8' />
@@ -14,8 +9,7 @@
 
 
     <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
     <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css" />
     <link rel="stylesheet" href="css/index.css" />
     <link rel="stylesheet" href="css/index.css" />
-    <link rel="stylesheet" href="css/index710.css" />
-    <link rel="stylesheet" href="css/indexMobile.css" />
+    <link rel="stylesheet" href="css/index_mobile.css" />
 
 
     <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
     <link rel="manifest" href="https://www.babylonjs.com/img/favicon/manifest.json">
     <meta name="msapplication-TileColor" content="#ffffff">
     <meta name="msapplication-TileColor" content="#ffffff">

Різницю між файлами не показано, бо вона завелика
+ 152204 - 147754
Playground/js/babylonWebGpu.max.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
Playground/js/babylonWebGpu.max.js.map


+ 31 - 3
Playground/js/config_versions.js

@@ -1,5 +1,33 @@
 CONFIG_last_versions = [
 CONFIG_last_versions = [
-    ["Latest","https://preview.babylonjs.com/babylon.js"],
-    ["4.0.3","https://unpkg.com/babylonjs@4.0.3/babylon.js"],
-    ["3.3","https://unpkg.com/babylonjs@3.3.0/babylon.js"]
+    ["Latest",[
+        "https://preview.babylonjs.com/babylon.js",
+        "https://preview.babylonjs.com/gui/babylon.gui.min.js",
+        "https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js",
+        "https://preview.babylonjs.com/nodeEditor/babylon.nodeEditor.js",
+        "https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js",
+        "https://preview.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
+        "https://preview.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js",
+        "https://preview.babylonjs.com/loaders/babylonjs.loaders.min.js",
+        "https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"
+    ]],
+    ["4.0.3", [
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/babylon.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/gui/babylon.gui.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/inspector/babylon.inspector.bundle.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/materialsLibrary/babylonjs.materials.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/postProcessesLibrary/babylonjs.postProcess.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/loaders/babylonjs.loaders.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@4.0.3/dist/serializers/babylonjs.serializers.min.js"
+    ]],
+    ["3.3", [
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/babylon.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/gui/babylon.gui.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/inspector/babylon.inspector.bundle.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/materialsLibrary/babylonjs.materials.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/postProcessesLibrary/babylonjs.postProcess.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/loaders/babylonjs.loaders.min.js",
+        "https://cdn.jsdelivr.net/gh/BabylonJS/Babylon.js@3.3.0/dist/serializers/babylonjs.serializers.min.js"
+    ]]
 ];
 ];

+ 12 - 7
Playground/js/main.js

@@ -5,7 +5,7 @@ var engine = null;
  */
  */
 compileAndRun = function(parent, fpsLabel) {
 compileAndRun = function(parent, fpsLabel) {
     // If we need to change the version, don't do this
     // If we need to change the version, don't do this
-    if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null) return;
+    if (parent.settingsPG.mustModifyBJSversion()) return;
 
 
     try {
     try {
         parent.menuPG.hideWaitDiv();
         parent.menuPG.hideWaitDiv();
@@ -228,17 +228,19 @@ class Main {
         );
         );
 
 
         // Restore BJS version if needed
         // Restore BJS version if needed
+        var restoreVersionResult = true;
         if (this.parent.settingsPG.restoreVersion() == false) {
         if (this.parent.settingsPG.restoreVersion() == false) {
             // Check if there a hash in the URL
             // Check if there a hash in the URL
             this.checkHash();
             this.checkHash();
+            restoreVersionResult = false;
         }
         }
 
 
         // Load scripts list
         // Load scripts list
-        this.loadScriptsList();
+        this.loadScriptsList(restoreVersionResult);
 
 
         // -------------------- UI --------------------
         // -------------------- UI --------------------
 
 
-        // Display BJS version - Need a check in case of version selection
+        // Display BJS version
         if (BABYLON) this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
         if (BABYLON) this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
         // Run
         // Run
         this.parent.utils.setToMultipleID("runButton", "click", () => compileAndRun(this.parent, this.fpsLabel));
         this.parent.utils.setToMultipleID("runButton", "click", () => compileAndRun(this.parent, this.fpsLabel));
@@ -442,11 +444,11 @@ class Main {
     /**
     /**
      * Load the examples scripts list in the database
      * Load the examples scripts list in the database
      */
      */
-    loadScriptsList() {
+    loadScriptsList(restoreVersionResult) {
         var exampleList = document.getElementById("exampleList");
         var exampleList = document.getElementById("exampleList");
 
 
         var xhr = new XMLHttpRequest();
         var xhr = new XMLHttpRequest();
-        //Open Typescript or Javascript examples
+        // Open Typescript or Javascript examples
         if (exampleList.className != 'typescript') {
         if (exampleList.className != 'typescript') {
             xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
             xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
         }
         }
@@ -510,6 +512,10 @@ class Main {
                                 examplePGLink.classList.add("itemLinePGLink");
                                 examplePGLink.classList.add("itemLinePGLink");
                                 examplePGLink.innerText = "Display";
                                 examplePGLink.innerText = "Display";
                                 examplePGLink.href = this.scripts[i].samples[ii].PGID;
                                 examplePGLink.href = this.scripts[i].samples[ii].PGID;
+                                examplePGLink.addEventListener("click", function() {
+                                    location.href = this.href;
+                                    location.reload();
+                                });
 
 
                                 exampleContentLink.appendChild(exampleTitle);
                                 exampleContentLink.appendChild(exampleTitle);
                                 exampleContentLink.appendChild(exampleDescr);
                                 exampleContentLink.appendChild(exampleDescr);
@@ -534,7 +540,7 @@ class Main {
                         exampleList.appendChild(noResultContainer);
                         exampleList.appendChild(noResultContainer);
                     }
                     }
 
 
-                    if (!location.hash) {
+                    if (!location.hash && restoreVersionResult == false) {
                         // Query string
                         // Query string
                         var queryString = window.location.search;
                         var queryString = window.location.search;
 
 
@@ -686,7 +692,6 @@ class Main {
         document.getElementById("saveFormDescription").readOnly = true;
         document.getElementById("saveFormDescription").readOnly = true;
         document.getElementById("saveFormTags").readOnly = true;
         document.getElementById("saveFormTags").readOnly = true;
         document.getElementById("saveFormButtonOk").style.display = "none";
         document.getElementById("saveFormButtonOk").style.display = "none";
-        this.parent.utils.setToMultipleID("metadataButton", "display", "inline-block");
     };
     };
 
 
     /*
     /*

+ 60 - 16
Playground/js/mainWebGPU.js

@@ -5,7 +5,7 @@ var engine = null;
  */
  */
 compileAndRun = function(parent, fpsLabel) {
 compileAndRun = function(parent, fpsLabel) {
     // If we need to change the version, don't do this
     // If we need to change the version, don't do this
-    if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null) return;
+    if (parent.settingsPG.mustModifyBJSversion()) return;
 
 
     try {
     try {
         parent.menuPG.hideWaitDiv();
         parent.menuPG.hideWaitDiv();
@@ -251,17 +251,19 @@ class Main {
         );
         );
 
 
         // Restore BJS version if needed
         // Restore BJS version if needed
+        var restoreVersionResult = true;
         if (this.parent.settingsPG.restoreVersion() == false) {
         if (this.parent.settingsPG.restoreVersion() == false) {
             // Check if there a hash in the URL
             // Check if there a hash in the URL
             this.checkHash();
             this.checkHash();
+            restoreVersionResult = false;
         }
         }
 
 
         // Load scripts list
         // Load scripts list
-        this.loadScriptsList();
+        this.loadScriptsList(restoreVersionResult);
 
 
         // -------------------- UI --------------------
         // -------------------- UI --------------------
 
 
-        // Display BJS version - Need a check in case of version selection
+        // Display BJS version
         if (BABYLON) this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
         if (BABYLON) this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
         // Run
         // Run
         this.parent.utils.setToMultipleID("runButton", "click", () => compileAndRun(this.parent, this.fpsLabel));
         this.parent.utils.setToMultipleID("runButton", "click", () => compileAndRun(this.parent, this.fpsLabel));
@@ -311,15 +313,52 @@ class Main {
         }
         }
         // Language (JS / TS)
         // Language (JS / TS)
         this.parent.utils.setToMultipleID("toTSbutton", "click", function () {
         this.parent.utils.setToMultipleID("toTSbutton", "click", function () {
-            if (this.parent.settingsPG.ScriptLanguage == "JS") {
+            if(location.hash != null && location.hash != ""){
                 this.parent.settingsPG.ScriptLanguage = "TS";
                 this.parent.settingsPG.ScriptLanguage = "TS";
-                location.reload();
+                window.location = "./";
+            }else{
+                if (this.parent.settingsPG.ScriptLanguage == "JS") {
+                    //revert in case the reload is cancel due to safe mode
+                    if(document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')){
+                        // Message before unload
+                        var languageTSswapper =  function () {
+                            this.parent.settingsPG.ScriptLanguage = "TS";
+                            window.removeEventListener('unload', languageTSswapper.bind(this));
+                        };
+                        window.addEventListener('unload',languageTSswapper.bind(this));
+                        
+                        location.reload();
+                    }
+                    else {
+                        this.parent.settingsPG.ScriptLanguage = "TS";
+                        location.reload();
+                    }
+                }
             }
             }
+           
         }.bind(this));
         }.bind(this));
         this.parent.utils.setToMultipleID("toJSbutton", "click", function () {
         this.parent.utils.setToMultipleID("toJSbutton", "click", function () {
-            if (this.parent.settingsPG.ScriptLanguage == "TS") {
+            if(location.hash != null && location.hash != ""){
                 this.parent.settingsPG.ScriptLanguage = "JS";
                 this.parent.settingsPG.ScriptLanguage = "JS";
-                location.reload();
+                window.location = "./";
+            }else{
+                if (this.parent.settingsPG.ScriptLanguage == "TS") {
+                    //revert in case the reload is cancel due to safe mode
+                    if(document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')){
+                        // Message before unload
+                        var LanguageJSswapper =  function () {
+                            this.parent.settingsPG.ScriptLanguage = "JS";
+                            window.removeEventListener('unload', LanguageJSswapper.bind(this));
+                        };
+                        window.addEventListener('unload',LanguageJSswapper.bind(this));
+                        
+                        location.reload();
+                    }
+                    else {
+                        this.parent.settingsPG.ScriptLanguage = "JS";
+                        location.reload();
+                    }
+                }
             }
             }
         }.bind(this));
         }.bind(this));
         // Safe mode
         // Safe mode
@@ -428,11 +467,11 @@ class Main {
     /**
     /**
      * Load the examples scripts list in the database
      * Load the examples scripts list in the database
      */
      */
-    loadScriptsList() {
+    loadScriptsList(restoreVersionResult) {
         var exampleList = document.getElementById("exampleList");
         var exampleList = document.getElementById("exampleList");
 
 
         var xhr = new XMLHttpRequest();
         var xhr = new XMLHttpRequest();
-        //Open Typescript or Javascript examples
+        // Open Typescript or Javascript examples
         if (exampleList.className != 'typescript') {
         if (exampleList.className != 'typescript') {
             xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
             xhr.open('GET', 'https://raw.githubusercontent.com/BabylonJS/Documentation/master/examples/list.json', true);
         }
         }
@@ -496,6 +535,10 @@ class Main {
                                 examplePGLink.classList.add("itemLinePGLink");
                                 examplePGLink.classList.add("itemLinePGLink");
                                 examplePGLink.innerText = "Display";
                                 examplePGLink.innerText = "Display";
                                 examplePGLink.href = this.scripts[i].samples[ii].PGID;
                                 examplePGLink.href = this.scripts[i].samples[ii].PGID;
+                                examplePGLink.addEventListener("click", function() {
+                                    location.href = this.href;
+                                    location.reload();
+                                });
 
 
                                 exampleContentLink.appendChild(exampleTitle);
                                 exampleContentLink.appendChild(exampleTitle);
                                 exampleContentLink.appendChild(exampleDescr);
                                 exampleContentLink.appendChild(exampleDescr);
@@ -520,7 +563,7 @@ class Main {
                         exampleList.appendChild(noResultContainer);
                         exampleList.appendChild(noResultContainer);
                     }
                     }
 
 
-                    if (!location.hash) {
+                    if (!location.hash && restoreVersionResult == false) {
                         // Query string
                         // Query string
                         var queryString = window.location.search;
                         var queryString = window.location.search;
 
 
@@ -577,8 +620,6 @@ class Main {
                         }
                         }
                     }
                     }
 
 
-                    // Restore theme
-                    this.parent.settingsPG.restoreTheme(this.parent.monacoCreator);
                     // Restore language
                     // Restore language
                     this.parent.settingsPG.setScriptLanguage();
                     this.parent.settingsPG.setScriptLanguage();
                 }
                 }
@@ -617,9 +658,13 @@ class Main {
         this.parent.monacoCreator.JsEditor.focus();
         this.parent.monacoCreator.JsEditor.focus();
     };
     };
 
 
+    compileAndRunFromOutside() {
+        compileAndRun(this.parent, this.fpsLabel);
+    };
+
     checkSafeMode(message) {
     checkSafeMode(message) {
-        if (document.getElementById("safemodeToggle" + this.parent.getCurrentSize) &&
-            document.getElementById("safemodeToggle" + this.parent.getCurrentSize).classList.contains('checked')) {
+        if (document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()) &&
+            document.getElementById("safemodeToggle" + this.parent.utils.getCurrentSize()).classList.contains('checked')) {
             let confirm = window.confirm(message);
             let confirm = window.confirm(message);
             if (!confirm) {
             if (!confirm) {
                 return false;
                 return false;
@@ -670,7 +715,6 @@ class Main {
         document.getElementById("saveFormDescription").readOnly = true;
         document.getElementById("saveFormDescription").readOnly = true;
         document.getElementById("saveFormTags").readOnly = true;
         document.getElementById("saveFormTags").readOnly = true;
         document.getElementById("saveFormButtonOk").style.display = "none";
         document.getElementById("saveFormButtonOk").style.display = "none";
-        this.parent.utils.setToMultipleID("metadataButton", "display", "inline-block");
     };
     };
 
 
     /*
     /*
@@ -857,4 +901,4 @@ class Main {
         }
         }
         setTimeout(this.checkHash.bind(this), 200);
         setTimeout(this.checkHash.bind(this), 200);
     };
     };
-}
+}

+ 2 - 2
Playground/js/menuPG.js

@@ -86,7 +86,7 @@ class MenuPG {
 
 
         // Message before unload
         // Message before unload
         window.addEventListener('beforeunload', function () {
         window.addEventListener('beforeunload', function () {
-            if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null) return;
+            if (this.parent.settingsPG.mustModifyBJSversion()) return;
             this.exitPrompt();
             this.exitPrompt();
         }.bind(this));
         }.bind(this));
 
 
@@ -130,7 +130,7 @@ class MenuPG {
                 newButton.classList.add("option");
                 newButton.classList.add("option");
                 if(CONFIG_last_versions[j][0] == "Latest") newButton.innerText = "Latest";
                 if(CONFIG_last_versions[j][0] == "Latest") newButton.innerText = "Latest";
                 else newButton.innerText = "v" + CONFIG_last_versions[j][0];
                 else newButton.innerText = "v" + CONFIG_last_versions[j][0];
-                newButton.value = CONFIG_last_versions[j][1];
+                newButton.value = CONFIG_last_versions[j][0];
 
 
                 newButton.addEventListener("click", function (evt) {
                 newButton.addEventListener("click", function (evt) {
                     this.parent.settingsPG.setBJSversion(evt, this.parent.monacoCreator.getCode());
                     this.parent.settingsPG.setBJSversion(evt, this.parent.monacoCreator.getCode());

+ 36 - 14
Playground/js/settingsPG.js

@@ -148,26 +148,48 @@ class SettingsPG {
      * Check if we need to restore a BJS version
      * Check if we need to restore a BJS version
      */
      */
     restoreVersion() {
     restoreVersion() {
-        if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null) {
+        if (this.mustModifyBJSversion()) {
+            this.parent.menuPG.displayWaitDiv();
+
+            var apiVersion = localStorage.getItem("bjs-playground-apiversion");
             BABYLON = null;
             BABYLON = null;
 
 
-            this.parent.menuPG.displayWaitDiv();
+            var position = 0;
+            for (var i = 0; i < CONFIG_last_versions.length; i++) {
+                if (CONFIG_last_versions[i][0] == apiVersion) {
+                    position = i;
+                    break;
+                }
+            }
+
+            var count = CONFIG_last_versions[position][1].length;
+            for (var i = 0; i < CONFIG_last_versions[position][1].length; i++) {
+                var newBJSscript = document.createElement('script');
+                newBJSscript.src = CONFIG_last_versions[position][1][i];
+                newBJSscript.onload = function () {
+                    count--;
+                    if (count == 0) {
+                        if (BABYLON.Engine.Version.search('-') != -1) this.parent.menuPG.displayVersionNumber("Latest");
+                        else this.parent.menuPG.displayVersionNumber(BABYLON.Engine.Version);
+                        this.parent.utils.setToMultipleID("mainTitle", "innerHTML", "v" + BABYLON.Engine.Version);
 
 
-            var newBJSscript = document.createElement('script');
-            newBJSscript.src = localStorage.getItem("bjs-playground-apiversion");
-            newBJSscript.onload = function () {
-                if(BABYLON.Engine.Version.search('-') != -1) this.parent.menuPG.displayVersionNumber("Latest");
-                else this.parent.menuPG.displayVersionNumber(BABYLON.Engine.Version);
-                this.parent.monacoCreator.setCode(localStorage.getItem("bjs-playground-apiversion-tempcode"));
+                        this.parent.monacoCreator.setCode(localStorage.getItem("bjs-playground-apiversion-tempcode"));
 
 
-                localStorage.removeItem("bjs-playground-apiversion");
-                localStorage.removeItem("bjs-playground-apiversion-tempcode");
+                        localStorage.removeItem("bjs-playground-apiversion");
+                        localStorage.removeItem("bjs-playground-apiversion-tempcode");
 
 
-                this.parent.main.compileAndRunFromOutside();
-            }.bind(this);
+                        this.parent.main.compileAndRunFromOutside();
+                    }
+                }.bind(this);
 
 
-            document.head.appendChild(newBJSscript);
+                document.head.appendChild(newBJSscript);
+            }
         }
         }
         else return false;
         else return false;
     };
     };
-};
+
+    mustModifyBJSversion() {
+        if (localStorage.getItem("bjs-playground-apiversion") && localStorage.getItem("bjs-playground-apiversion") != null && localStorage.getItem("bjs-playground-apiversion") != "Latest") return true;
+        else return false;
+    };
+};

+ 3 - 0
Playground/package.json

@@ -13,5 +13,8 @@
   },
   },
   "scripts": {
   "scripts": {
     "test": "browser-sync start --server --files **/* --no-inject-changes --startPath index.html"
     "test": "browser-sync start --server --files **/* --no-inject-changes --startPath index.html"
+  },
+  "dependencies": {
+    "npm": "^6.11.2"
   }
   }
 }
 }

+ 2 - 1
Tools/Config/config.json

@@ -600,7 +600,8 @@
                 "react-dom",
                 "react-dom",
                 "dagre",
                 "dagre",
                 "re-resizable",
                 "re-resizable",
-                "glTF"
+                "glTF",
+                "file-saver"
             ],
             ],
             "umd": {
             "umd": {
                 "packageName": "babylonjs-node-editor",
                 "packageName": "babylonjs-node-editor",

+ 1 - 2
dist/gui/readme.md

@@ -26,8 +26,7 @@ If using TypeScript, the typing needs to be added to tsconfig.json:
     ....
     ....
     "types": [
     "types": [
         "babylonjs",
         "babylonjs",
-        "babylonjs-gui",
-        "angularFTW"
+        "babylonjs-gui"
     ],
     ],
     ....
     ....
 ```
 ```

+ 116 - 12
dist/preview release/babylon.d.ts

@@ -22033,7 +22033,7 @@ declare module BABYLON {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -22043,7 +22043,7 @@ declare module BABYLON {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -24923,6 +24923,10 @@ declare module BABYLON {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -27689,9 +27693,9 @@ declare module BABYLON {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -41024,6 +41028,10 @@ declare module BABYLON {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -44215,7 +44223,11 @@ declare module BABYLON {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -45841,6 +45853,10 @@ declare module BABYLON {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -45878,14 +45894,21 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Class used to host texture specific utilities
+     * Class used to host RGBD texture specific utilities
      */
      */
-    export class BRDFTextureTools {
+    export class RGBDTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
          * @param texture the texture to expand.
          * @param texture the texture to expand.
          */
          */
-        private static _ExpandDefaultBRDFTexture;
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * Class used to host texture specific utilities
+     */
+    export class BRDFTextureTools {
         /**
         /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
@@ -46858,6 +46881,7 @@ declare module BABYLON {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -52229,6 +52253,8 @@ declare module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -52692,6 +52718,12 @@ declare module BABYLON {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -52738,6 +52770,8 @@ declare module BABYLON {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -53107,6 +53141,7 @@ declare module BABYLON {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -53488,6 +53523,59 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      * Block used to add support for scene fog
      */
      */
     export class FogBlock extends NodeMaterialBlock {
     export class FogBlock extends NodeMaterialBlock {
@@ -53790,6 +53878,22 @@ declare module BABYLON {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -54196,11 +54300,11 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/babylon.js


Різницю між файлами не показано, бо вона завелика
+ 585 - 184
dist/preview release/babylon.max.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/babylon.max.js.map


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

@@ -22669,7 +22669,7 @@ declare module "babylonjs/Meshes/meshLODLevel" {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -22679,7 +22679,7 @@ declare module "babylonjs/Meshes/meshLODLevel" {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -25137,7 +25137,7 @@ declare module "babylonjs/Cameras/camera" {
     import { Nullable } from "babylonjs/types";
     import { Nullable } from "babylonjs/types";
     import { CameraInputsManager } from "babylonjs/Cameras/cameraInputsManager";
     import { CameraInputsManager } from "babylonjs/Cameras/cameraInputsManager";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
-    import { Matrix, Vector3 } from "babylonjs/Maths/math.vector";
+    import { Matrix, Vector3, Quaternion } from "babylonjs/Maths/math.vector";
     import { Node } from "babylonjs/node";
     import { Node } from "babylonjs/node";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
@@ -25624,6 +25624,10 @@ declare module "babylonjs/Cameras/camera" {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -28489,9 +28493,9 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -42441,6 +42445,10 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -45961,7 +45969,11 @@ declare module "babylonjs/Engines/nativeEngine" {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -47784,6 +47796,10 @@ declare module "babylonjs/Helpers/photoDome" {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -47819,20 +47835,28 @@ declare module "babylonjs/Helpers/photoDome" {
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
     }
     }
 }
 }
+declare module "babylonjs/Misc/rgbdTextureTools" {
+    import "babylonjs/Shaders/rgbdDecode.fragment";
+    import { Texture } from "babylonjs/Materials/Textures/texture";
+    /**
+     * Class used to host RGBD texture specific utilities
+     */
+    export class RGBDTextureTools {
+        /**
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
+         * @param texture the texture to expand.
+         */
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
 declare module "babylonjs/Misc/brdfTextureTools" {
 declare module "babylonjs/Misc/brdfTextureTools" {
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
-    import "babylonjs/Shaders/rgbdDecode.fragment";
     /**
     /**
      * Class used to host texture specific utilities
      * Class used to host texture specific utilities
      */
      */
     export class BRDFTextureTools {
     export class BRDFTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
-         * @param texture the texture to expand.
-         */
-        private static _ExpandDefaultBRDFTexture;
-        /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
          * @returns the environment BRDF texture
          * @returns the environment BRDF texture
@@ -48909,6 +48933,7 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -54670,6 +54695,8 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -55152,6 +55179,12 @@ declare module "babylonjs/Materials/Node/nodeMaterialBuildState" {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -55198,6 +55231,8 @@ declare module "babylonjs/Materials/Node/nodeMaterialBuildState" {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -55588,6 +55623,7 @@ declare module "babylonjs/Materials/Node/Blocks/Input/inputBlock" {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -56018,10 +56054,72 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
+declare module "babylonjs/Materials/Node/Blocks/Fragment/perturbNormalBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { NodeMaterial, NodeMaterialDefines } from "babylonjs/Materials/Node/nodeMaterial";
+    import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+    import { Effect } from "babylonjs/Materials/effect";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    import { Scene } from "babylonjs/scene";
+    /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/perturbNormalBlock";
 }
 }
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
@@ -56378,6 +56476,22 @@ declare module "babylonjs/Materials/Node/Blocks/remapBlock" {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -56813,16 +56927,16 @@ declare module "babylonjs/Materials/Node/Blocks/stepBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
-declare module "babylonjs/Materials/Node/Blocks/oppositeBlock" {
+declare module "babylonjs/Materials/Node/Blocks/oneMinusBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
     import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);
@@ -57009,7 +57123,7 @@ declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/divideBlock";
     export * from "babylonjs/Materials/Node/Blocks/divideBlock";
     export * from "babylonjs/Materials/Node/Blocks/subtractBlock";
     export * from "babylonjs/Materials/Node/Blocks/subtractBlock";
     export * from "babylonjs/Materials/Node/Blocks/stepBlock";
     export * from "babylonjs/Materials/Node/Blocks/stepBlock";
-    export * from "babylonjs/Materials/Node/Blocks/oppositeBlock";
+    export * from "babylonjs/Materials/Node/Blocks/oneMinusBlock";
     export * from "babylonjs/Materials/Node/Blocks/viewDirectionBlock";
     export * from "babylonjs/Materials/Node/Blocks/viewDirectionBlock";
     export * from "babylonjs/Materials/Node/Blocks/fresnelBlock";
     export * from "babylonjs/Materials/Node/Blocks/fresnelBlock";
     export * from "babylonjs/Materials/Node/Blocks/maxBlock";
     export * from "babylonjs/Materials/Node/Blocks/maxBlock";
@@ -65331,6 +65445,7 @@ declare module "babylonjs/Misc/index" {
     export * from "babylonjs/Misc/webRequest";
     export * from "babylonjs/Misc/webRequest";
     export * from "babylonjs/Misc/iInspectable";
     export * from "babylonjs/Misc/iInspectable";
     export * from "babylonjs/Misc/brdfTextureTools";
     export * from "babylonjs/Misc/brdfTextureTools";
+    export * from "babylonjs/Misc/rgbdTextureTools";
     export * from "babylonjs/Misc/gradients";
     export * from "babylonjs/Misc/gradients";
     export * from "babylonjs/Misc/perfCounter";
     export * from "babylonjs/Misc/perfCounter";
     export * from "babylonjs/Misc/fileRequest";
     export * from "babylonjs/Misc/fileRequest";
@@ -87524,7 +87639,7 @@ declare module BABYLON {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -87534,7 +87649,7 @@ declare module BABYLON {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -90414,6 +90529,10 @@ declare module BABYLON {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -93180,9 +93299,9 @@ declare module BABYLON {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -106515,6 +106634,10 @@ declare module BABYLON {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -109706,7 +109829,11 @@ declare module BABYLON {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -111332,6 +111459,10 @@ declare module BABYLON {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -111369,14 +111500,21 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Class used to host texture specific utilities
+     * Class used to host RGBD texture specific utilities
      */
      */
-    export class BRDFTextureTools {
+    export class RGBDTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
          * @param texture the texture to expand.
          * @param texture the texture to expand.
          */
          */
-        private static _ExpandDefaultBRDFTexture;
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * Class used to host texture specific utilities
+     */
+    export class BRDFTextureTools {
         /**
         /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
@@ -112349,6 +112487,7 @@ declare module BABYLON {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -117720,6 +117859,8 @@ declare module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -118183,6 +118324,12 @@ declare module BABYLON {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -118229,6 +118376,8 @@ declare module BABYLON {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -118598,6 +118747,7 @@ declare module BABYLON {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -118979,6 +119129,59 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      * Block used to add support for scene fog
      */
      */
     export class FogBlock extends NodeMaterialBlock {
     export class FogBlock extends NodeMaterialBlock {
@@ -119281,6 +119484,22 @@ declare module BABYLON {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -119687,11 +119906,11 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);

+ 116 - 12
dist/preview release/documentation.d.ts

@@ -22033,7 +22033,7 @@ declare module BABYLON {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -22043,7 +22043,7 @@ declare module BABYLON {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -24923,6 +24923,10 @@ declare module BABYLON {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -27689,9 +27693,9 @@ declare module BABYLON {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -41024,6 +41028,10 @@ declare module BABYLON {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -44215,7 +44223,11 @@ declare module BABYLON {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -45841,6 +45853,10 @@ declare module BABYLON {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -45878,14 +45894,21 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Class used to host texture specific utilities
+     * Class used to host RGBD texture specific utilities
      */
      */
-    export class BRDFTextureTools {
+    export class RGBDTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
          * @param texture the texture to expand.
          * @param texture the texture to expand.
          */
          */
-        private static _ExpandDefaultBRDFTexture;
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * Class used to host texture specific utilities
+     */
+    export class BRDFTextureTools {
         /**
         /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
@@ -46858,6 +46881,7 @@ declare module BABYLON {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -52229,6 +52253,8 @@ declare module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -52692,6 +52718,12 @@ declare module BABYLON {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -52738,6 +52770,8 @@ declare module BABYLON {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -53107,6 +53141,7 @@ declare module BABYLON {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -53488,6 +53523,59 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      * Block used to add support for scene fog
      */
      */
     export class FogBlock extends NodeMaterialBlock {
     export class FogBlock extends NodeMaterialBlock {
@@ -53790,6 +53878,22 @@ declare module BABYLON {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -54196,11 +54300,11 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);

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

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

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "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.",
     "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-alpha.17",
+    "version": "4.1.0-alpha.18",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.1.0-alpha.17"
+        "babylonjs": "4.1.0-alpha.18"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

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

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

+ 1 - 0
dist/preview release/loaders/babylon.stlFileLoader.js

@@ -161,6 +161,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
 
 
 
+
 /**
 /**
  * STL file type loader.
  * STL file type loader.
  * This is a babylon scene loader plugin.
  * This is a babylon scene loader plugin.

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylon.stlFileLoader.js.map


+ 1 - 0
dist/preview release/loaders/babylonjs.loaders.js

@@ -1484,6 +1484,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
 
 
 
+
 /**
 /**
  * STL file type loader.
  * STL file type loader.
  * This is a babylon scene loader plugin.
  * This is a babylon scene loader plugin.

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


+ 1 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -2224,6 +2224,7 @@ declare module "babylonjs-loaders/STL/stlFileLoader" {
     import { ISceneLoaderPlugin, ISceneLoaderPluginExtensions } from "babylonjs/Loading/sceneLoader";
     import { ISceneLoaderPlugin, ISceneLoaderPluginExtensions } from "babylonjs/Loading/sceneLoader";
     import { AssetContainer } from "babylonjs/assetContainer";
     import { AssetContainer } from "babylonjs/assetContainer";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
+    import "babylonjs/Helpers/sceneHelpers";
     /**
     /**
      * STL file type loader.
      * STL file type loader.
      * This is a babylon scene loader plugin.
      * This is a babylon scene loader plugin.

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

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "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.",
     "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-alpha.17",
+    "version": "4.1.0-alpha.18",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs-gltf2interface": "4.1.0-alpha.17",
-        "babylonjs": "4.1.0-alpha.17"
+        "babylonjs-gltf2interface": "4.1.0-alpha.18",
+        "babylonjs": "4.1.0-alpha.18"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.js.map


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js.map


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


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

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

Різницю між файлами не показано, бо вона завелика
+ 111 - 8
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts


Різницю між файлами не показано, бо вона завелика
+ 7 - 7
dist/preview release/nodeEditor/babylon.nodeEditor.js


Різницю між файлами не показано, бо вона завелика
+ 570 - 78
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Різницю між файлами не показано, бо вона завелика
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


Різницю між файлами не показано, бо вона завелика
+ 242 - 17
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",
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
     "description": "The Babylon.js node material editor.",
-    "version": "4.1.0-alpha.17",
+    "version": "4.1.0-alpha.18",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     },
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.1.0-alpha.17"
+        "babylonjs": "4.1.0-alpha.18"
     },
     },
     "files": [
     "files": [
         "babylon.nodeEditor.max.js.map",
         "babylon.nodeEditor.max.js.map",

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

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

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

@@ -1 +1 @@
-{"engineOnly":167802,"sceneOnly":508293,"minGridMaterial":638479,"minStandardMaterial":767423}
+{"engineOnly":167802,"sceneOnly":508463,"minGridMaterial":638613,"minStandardMaterial":767743}

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

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

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

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

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

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

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

@@ -22669,7 +22669,7 @@ declare module "babylonjs/Meshes/meshLODLevel" {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -22679,7 +22679,7 @@ declare module "babylonjs/Meshes/meshLODLevel" {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -25137,7 +25137,7 @@ declare module "babylonjs/Cameras/camera" {
     import { Nullable } from "babylonjs/types";
     import { Nullable } from "babylonjs/types";
     import { CameraInputsManager } from "babylonjs/Cameras/cameraInputsManager";
     import { CameraInputsManager } from "babylonjs/Cameras/cameraInputsManager";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
-    import { Matrix, Vector3 } from "babylonjs/Maths/math.vector";
+    import { Matrix, Vector3, Quaternion } from "babylonjs/Maths/math.vector";
     import { Node } from "babylonjs/node";
     import { Node } from "babylonjs/node";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { Mesh } from "babylonjs/Meshes/mesh";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
@@ -25624,6 +25624,10 @@ declare module "babylonjs/Cameras/camera" {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -28489,9 +28493,9 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -42441,6 +42445,10 @@ declare module "babylonjs/Cameras/VR/vrExperienceHelper" {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -45961,7 +45969,11 @@ declare module "babylonjs/Engines/nativeEngine" {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -47784,6 +47796,10 @@ declare module "babylonjs/Helpers/photoDome" {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -47819,20 +47835,28 @@ declare module "babylonjs/Helpers/photoDome" {
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
     }
     }
 }
 }
+declare module "babylonjs/Misc/rgbdTextureTools" {
+    import "babylonjs/Shaders/rgbdDecode.fragment";
+    import { Texture } from "babylonjs/Materials/Textures/texture";
+    /**
+     * Class used to host RGBD texture specific utilities
+     */
+    export class RGBDTextureTools {
+        /**
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
+         * @param texture the texture to expand.
+         */
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
 declare module "babylonjs/Misc/brdfTextureTools" {
 declare module "babylonjs/Misc/brdfTextureTools" {
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
-    import "babylonjs/Shaders/rgbdDecode.fragment";
     /**
     /**
      * Class used to host texture specific utilities
      * Class used to host texture specific utilities
      */
      */
     export class BRDFTextureTools {
     export class BRDFTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
-         * @param texture the texture to expand.
-         */
-        private static _ExpandDefaultBRDFTexture;
-        /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
          * @returns the environment BRDF texture
          * @returns the environment BRDF texture
@@ -48909,6 +48933,7 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -54670,6 +54695,8 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -55152,6 +55179,12 @@ declare module "babylonjs/Materials/Node/nodeMaterialBuildState" {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -55198,6 +55231,8 @@ declare module "babylonjs/Materials/Node/nodeMaterialBuildState" {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -55588,6 +55623,7 @@ declare module "babylonjs/Materials/Node/Blocks/Input/inputBlock" {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -56018,10 +56054,72 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
+declare module "babylonjs/Materials/Node/Blocks/Fragment/perturbNormalBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { NodeMaterial, NodeMaterialDefines } from "babylonjs/Materials/Node/nodeMaterial";
+    import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+    import { Effect } from "babylonjs/Materials/effect";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    import { Scene } from "babylonjs/scene";
+    /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/perturbNormalBlock";
 }
 }
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
@@ -56378,6 +56476,22 @@ declare module "babylonjs/Materials/Node/Blocks/remapBlock" {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -56813,16 +56927,16 @@ declare module "babylonjs/Materials/Node/Blocks/stepBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
-declare module "babylonjs/Materials/Node/Blocks/oppositeBlock" {
+declare module "babylonjs/Materials/Node/Blocks/oneMinusBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
     import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
     import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);
@@ -57009,7 +57123,7 @@ declare module "babylonjs/Materials/Node/Blocks/index" {
     export * from "babylonjs/Materials/Node/Blocks/divideBlock";
     export * from "babylonjs/Materials/Node/Blocks/divideBlock";
     export * from "babylonjs/Materials/Node/Blocks/subtractBlock";
     export * from "babylonjs/Materials/Node/Blocks/subtractBlock";
     export * from "babylonjs/Materials/Node/Blocks/stepBlock";
     export * from "babylonjs/Materials/Node/Blocks/stepBlock";
-    export * from "babylonjs/Materials/Node/Blocks/oppositeBlock";
+    export * from "babylonjs/Materials/Node/Blocks/oneMinusBlock";
     export * from "babylonjs/Materials/Node/Blocks/viewDirectionBlock";
     export * from "babylonjs/Materials/Node/Blocks/viewDirectionBlock";
     export * from "babylonjs/Materials/Node/Blocks/fresnelBlock";
     export * from "babylonjs/Materials/Node/Blocks/fresnelBlock";
     export * from "babylonjs/Materials/Node/Blocks/maxBlock";
     export * from "babylonjs/Materials/Node/Blocks/maxBlock";
@@ -65331,6 +65445,7 @@ declare module "babylonjs/Misc/index" {
     export * from "babylonjs/Misc/webRequest";
     export * from "babylonjs/Misc/webRequest";
     export * from "babylonjs/Misc/iInspectable";
     export * from "babylonjs/Misc/iInspectable";
     export * from "babylonjs/Misc/brdfTextureTools";
     export * from "babylonjs/Misc/brdfTextureTools";
+    export * from "babylonjs/Misc/rgbdTextureTools";
     export * from "babylonjs/Misc/gradients";
     export * from "babylonjs/Misc/gradients";
     export * from "babylonjs/Misc/perfCounter";
     export * from "babylonjs/Misc/perfCounter";
     export * from "babylonjs/Misc/fileRequest";
     export * from "babylonjs/Misc/fileRequest";
@@ -87524,7 +87639,7 @@ declare module BABYLON {
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      * @see http://doc.babylonjs.com/how_to/how_to_use_lod
      */
      */
     export class MeshLODLevel {
     export class MeshLODLevel {
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number;
         distance: number;
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>;
         mesh: Nullable<Mesh>;
@@ -87534,7 +87649,7 @@ declare module BABYLON {
          * @param mesh defines the mesh to use to render this level
          * @param mesh defines the mesh to use to render this level
          */
          */
         constructor(
         constructor(
-        /** Defines the distance where this level should star being displayed */
+        /** Defines the distance where this level should start being displayed */
         distance: number, 
         distance: number, 
         /** Defines the mesh to use to render this level */
         /** Defines the mesh to use to render this level */
         mesh: Nullable<Mesh>);
         mesh: Nullable<Mesh>);
@@ -90414,6 +90529,10 @@ declare module BABYLON {
          */
          */
         getDirection(localAxis: Vector3): Vector3;
         getDirection(localAxis: Vector3): Vector3;
         /**
         /**
+         * Returns the current camera absolute rotation
+         */
+        readonly absoluteRotation: Quaternion;
+        /**
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * Gets the direction of the camera relative to a given local axis into a passed vector.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param localAxis Defines the reference axis to provide a relative direction.
          * @param result Defines the vector to store the result in
          * @param result Defines the vector to store the result in
@@ -93180,9 +93299,9 @@ declare module BABYLON {
          */
          */
         gammaSpace: boolean;
         gammaSpace: boolean;
         /**
         /**
-         * Gets whether or not the texture contains RGBD data.
+         * Gets or sets whether or not the texture contains RGBD data.
          */
          */
-        readonly isRGBD: boolean;
+        isRGBD: boolean;
         /**
         /**
          * Is Z inverted in the texture (useful in a cube texture).
          * Is Z inverted in the texture (useful in a cube texture).
          */
          */
@@ -106515,6 +106634,10 @@ declare module BABYLON {
          */
          */
         updateGazeTrackerColor: boolean;
         updateGazeTrackerColor: boolean;
         /**
         /**
+         * If the controller laser color should be updated when selecting meshes
+         */
+        updateControllerLaserColor: boolean;
+        /**
          * The gaze tracking mesh corresponding to the left controller
          * The gaze tracking mesh corresponding to the left controller
          */
          */
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
         readonly leftControllerGazeTrackerMesh: Nullable<Mesh>;
@@ -109706,7 +109829,11 @@ declare module BABYLON {
          */
          */
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad?: Nullable<(data?: any) => void>, onError?: Nullable<(message?: string, exception?: any) => void>, format?: number, forcedExtension?: any, createPolynomials?: boolean, lodScale?: number, lodOffset?: number, fallback?: Nullable<InternalTexture>): InternalTexture;
         private _getSamplingFilter;
         private _getSamplingFilter;
-        createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture;
+        private static _GetNativeTextureFormat;
+        createRenderTargetTexture(size: number | {
+            width: number;
+            height: number;
+        }, options: boolean | RenderTargetCreationOptions): InternalTexture;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         updateTextureSamplingMode(samplingMode: number, texture: InternalTexture): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
         unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps?: boolean, onBeforeUnbind?: () => void): void;
@@ -111332,6 +111459,10 @@ declare module BABYLON {
          */
          */
         protected _mesh: Mesh;
         protected _mesh: Mesh;
         /**
         /**
+         * Gets the mesh used for the skybox.
+         */
+        readonly mesh: Mesh;
+        /**
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
          * Also see the options.resolution property.
          * Also see the options.resolution property.
          */
          */
@@ -111369,14 +111500,21 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Class used to host texture specific utilities
+     * Class used to host RGBD texture specific utilities
      */
      */
-    export class BRDFTextureTools {
+    export class RGBDTextureTools {
         /**
         /**
-         * Expand the BRDF Texture from RGBD to Half Float if necessary.
+         * Expand the RGBD Texture from RGBD to Half Float if possible.
          * @param texture the texture to expand.
          * @param texture the texture to expand.
          */
          */
-        private static _ExpandDefaultBRDFTexture;
+        static ExpandRGBDTexture(texture: Texture): void;
+    }
+}
+declare module BABYLON {
+    /**
+     * Class used to host texture specific utilities
+     */
+    export class BRDFTextureTools {
         /**
         /**
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * Gets a default environment BRDF for MS-BRDF Height Correlated BRDF
          * @param scene defines the hosting scene
          * @param scene defines the hosting scene
@@ -112349,6 +112487,7 @@ declare module BABYLON {
         LIGHTMAPDIRECTUV: number;
         LIGHTMAPDIRECTUV: number;
         USELIGHTMAPASSHADOWMAP: boolean;
         USELIGHTMAPASSHADOWMAP: boolean;
         GAMMALIGHTMAP: boolean;
         GAMMALIGHTMAP: boolean;
+        RGBDLIGHTMAP: boolean;
         REFLECTION: boolean;
         REFLECTION: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_3D: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
         REFLECTIONMAP_SPHERICAL: boolean;
@@ -117720,6 +117859,8 @@ declare module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
+        /** MISC. */
+        BUMPDIRECTUV: number;
         constructor();
         constructor();
         setValue(name: string, value: boolean): void;
         setValue(name: string, value: boolean): void;
     }
     }
@@ -118183,6 +118324,12 @@ declare module BABYLON {
             [key: string]: string;
             [key: string]: string;
         };
         };
         /**
         /**
+         * Gets the list of emitted extensions
+         */
+        extensions: {
+            [key: string]: string;
+        };
+        /**
          * Gets the target of the compilation state
          * Gets the target of the compilation state
          */
          */
         target: NodeMaterialBlockTargets;
         target: NodeMaterialBlockTargets;
@@ -118229,6 +118376,8 @@ declare module BABYLON {
         /** @hidden */
         /** @hidden */
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         _getGLType(type: NodeMaterialBlockConnectionPointTypes): string;
         /** @hidden */
         /** @hidden */
+        _emitExtension(name: string, extension: string): void;
+        /** @hidden */
         _emitFunction(name: string, code: string, comments: string): void;
         _emitFunction(name: string, code: string, comments: string): void;
         /** @hidden */
         /** @hidden */
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
         _emitCodeFromInclude(includeName: string, comments: string, options?: {
@@ -118598,6 +118747,7 @@ declare module BABYLON {
          */
          */
         animate(scene: Scene): void;
         animate(scene: Scene): void;
         private _emitDefine;
         private _emitDefine;
+        initialize(state: NodeMaterialBuildState): void;
         /**
         /**
          * Set the input block to its default value (based on its type)
          * Set the input block to its default value (based on its type)
          */
          */
@@ -118979,6 +119129,59 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Block used to pertub normals based on a normal map
+     */
+    export class PerturbNormalBlock extends NodeMaterialBlock {
+        private _tangentSpaceParameterName;
+        /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+        invertX: boolean;
+        /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+        invertY: boolean;
+        /**
+         * Create a new PerturbNormalBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the world position input component
+         */
+        readonly worldPosition: NodeMaterialConnectionPoint;
+        /**
+         * Gets the world normal input component
+         */
+        readonly worldNormal: NodeMaterialConnectionPoint;
+        /**
+         * Gets the uv input component
+         */
+        readonly uv: NodeMaterialConnectionPoint;
+        /**
+        * Gets the normal map color input component
+        */
+        readonly normalMapColor: NodeMaterialConnectionPoint;
+        /**
+        * Gets the strength input component
+        */
+        readonly strength: NodeMaterialConnectionPoint;
+        /**
+         * Gets the output component
+         */
+        readonly output: NodeMaterialConnectionPoint;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        autoConfigure(material: NodeMaterial): void;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      * Block used to add support for scene fog
      */
      */
     export class FogBlock extends NodeMaterialBlock {
     export class FogBlock extends NodeMaterialBlock {
@@ -119281,6 +119484,22 @@ declare module BABYLON {
          */
          */
         readonly input: NodeMaterialConnectionPoint;
         readonly input: NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the source min input component
+         */
+        readonly sourceMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the source max input component
+         */
+        readonly sourceMax: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target min input component
+         */
+        readonly targetMin: NodeMaterialConnectionPoint;
+        /**
+         * Gets the target max input component
+         */
+        readonly targetMax: NodeMaterialConnectionPoint;
+        /**
          * Gets the output component
          * Gets the output component
          */
          */
         readonly output: NodeMaterialConnectionPoint;
         readonly output: NodeMaterialConnectionPoint;
@@ -119687,11 +119906,11 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Block used to get the opposite of a value
+     * Block used to get the opposite (1 - x) of a value
      */
      */
-    export class OppositeBlock extends NodeMaterialBlock {
+    export class OneMinusBlock extends NodeMaterialBlock {
         /**
         /**
-         * Creates a new OppositeBlock
+         * Creates a new OneMinusBlock
          * @param name defines the block name
          * @param name defines the block name
          */
          */
         constructor(name: string);
         constructor(name: string);

Різницю між файлами не показано, бо вона завелика
+ 44 - 36
dist/preview release/viewer/babylon.viewer.js


Різницю між файлами не показано, бо вона завелика
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 1 - 0
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -2224,6 +2224,7 @@ declare module "babylonjs-loaders/STL/stlFileLoader" {
     import { ISceneLoaderPlugin, ISceneLoaderPluginExtensions } from "babylonjs/Loading/sceneLoader";
     import { ISceneLoaderPlugin, ISceneLoaderPluginExtensions } from "babylonjs/Loading/sceneLoader";
     import { AssetContainer } from "babylonjs/assetContainer";
     import { AssetContainer } from "babylonjs/assetContainer";
     import { Scene } from "babylonjs/scene";
     import { Scene } from "babylonjs/scene";
+    import "babylonjs/Helpers/sceneHelpers";
     /**
     /**
      * STL file type loader.
      * STL file type loader.
      * This is a babylon scene loader plugin.
      * This is a babylon scene loader plugin.

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

@@ -63,6 +63,7 @@
 - Added `ShadowGenerator.onAfterShadowMapRenderObservable` and `ShadowGenerator.onAfterShadowMapMeshRenderObservable` ([Deltakosh](https://github.com/deltakosh/))
 - Added `ShadowGenerator.onAfterShadowMapRenderObservable` and `ShadowGenerator.onAfterShadowMapMeshRenderObservable` ([Deltakosh](https://github.com/deltakosh/))
 - Added support for side by side and top bottom images in the `PhotoDome` ([Deltakosh](https://github.com/deltakosh/))
 - Added support for side by side and top bottom images in the `PhotoDome` ([Deltakosh](https://github.com/deltakosh/))
 - Added playground ts-local (TypeScript support for local playground) ([pjoe](https://github.com/pjoe/))
 - Added playground ts-local (TypeScript support for local playground) ([pjoe](https://github.com/pjoe/))
+- Added RGBD Texture tools [Sebavan](https://github.com/sebavan/)
 
 
 ### Meshes
 ### Meshes
 - Added `TransformNode.instantiateHierarchy()` which try to instantiate (or clone) a node and its entire hiearchy ([Deltakosh](https://github.com/deltakosh/))
 - Added `TransformNode.instantiateHierarchy()` which try to instantiate (or clone) a node and its entire hiearchy ([Deltakosh](https://github.com/deltakosh/))
@@ -117,7 +118,7 @@
 - Removing assetContainer from scene will also remove gui layers ([TrevorDev](https://github.com/TrevorDev))
 - Removing assetContainer from scene will also remove gui layers ([TrevorDev](https://github.com/TrevorDev))
 - A scene's input manager not adding key listeners when the canvas is already focused ([Poolminer](https://github.com/Poolminer))
 - A scene's input manager not adding key listeners when the canvas is already focused ([Poolminer](https://github.com/Poolminer))
 - Runtime animation `goToFrame` when going back in time now correctly triggers future events when reached ([zakhenry](https://github.com/zakhenry))
 - Runtime animation `goToFrame` when going back in time now correctly triggers future events when reached ([zakhenry](https://github.com/zakhenry))
-- Fixed bug in Ray.intersectsTriangle where the barycentric coordinates `bu` and `bv` being returned is actually `bv` and `bw`. ([bghgary](https://github.com/bghgary))
+- Fixed bug in `Ray.intersectsTriangle` where the barycentric coordinates `bu` and `bv` being returned is actually `bv` and `bw`. ([bghgary](https://github.com/bghgary))
 - Do not call onError when creating a texture when falling back to another loader ([TrevorDev](https://github.com/TrevorDev))
 - Do not call onError when creating a texture when falling back to another loader ([TrevorDev](https://github.com/TrevorDev))
 - Context loss should not cause PBR materials to render black or instances to stop rendering ([TrevorDev](https://github.com/TrevorDev))
 - Context loss should not cause PBR materials to render black or instances to stop rendering ([TrevorDev](https://github.com/TrevorDev))
 - Only cast pointer ray input when pointer is locked in webVR ([TrevorDev](https://github.com/TrevorDev))
 - Only cast pointer ray input when pointer is locked in webVR ([TrevorDev](https://github.com/TrevorDev))

+ 2 - 0
loaders/src/STL/stlFileLoader.ts

@@ -9,6 +9,8 @@ import { SceneLoader, ISceneLoaderPlugin, ISceneLoaderPluginExtensions } from "b
 import { AssetContainer } from "babylonjs/assetContainer";
 import { AssetContainer } from "babylonjs/assetContainer";
 import { Scene } from "babylonjs/scene";
 import { Scene } from "babylonjs/scene";
 
 
+import "babylonjs/Helpers/sceneHelpers";
+
 /**
 /**
  * STL file type loader.
  * STL file type loader.
  * This is a babylon scene loader plugin.
  * This is a babylon scene loader plugin.

+ 1 - 1
materialsLibrary/src/water/water.fragment.fx

@@ -246,7 +246,7 @@ vec4 color = vec4(finalDiffuse + finalSpecular, alpha);
 // We first move from gamma to linear.
 // We first move from gamma to linear.
 #ifdef IMAGEPROCESSINGPOSTPROCESS
 #ifdef IMAGEPROCESSINGPOSTPROCESS
 	color.rgb = toLinearSpace(color.rgb);
 	color.rgb = toLinearSpace(color.rgb);
-#elif IMAGEPROCESSING
+#elif defined(IMAGEPROCESSING)
     color.rgb = toLinearSpace(color.rgb);
     color.rgb = toLinearSpace(color.rgb);
     color = applyImageProcessing(color);
     color = applyImageProcessing(color);
 #endif
 #endif

+ 8 - 0
nodeEditor/public/index.html

@@ -21,6 +21,14 @@
             margin: 0;
             margin: 0;
             overflow: hidden;
             overflow: hidden;
         }
         }
+
+        #host-element {
+            width: 100%;
+            height: 100%;               
+            padding: 0;
+            margin: 0;
+            overflow: hidden;         
+        }
     </style>
     </style>
 </head>
 </head>
 
 

+ 38 - 33
nodeEditor/public/index.js

@@ -29,11 +29,12 @@ var checkHash = function () {
                     if (xmlHttp.readyState == 4) {
                     if (xmlHttp.readyState == 4) {
                         if (xmlHttp.status == 200) {
                         if (xmlHttp.status == 200) {
                             var snippet = JSON.parse(JSON.parse(xmlHttp.responseText).jsonPayload);
                             var snippet = JSON.parse(JSON.parse(xmlHttp.responseText).jsonPayload);
+                            let serializationObject = JSON.parse(snippet.nodeMaterial);
 
 
                             if (editorDisplayed) {
                             if (editorDisplayed) {
-                                customLoadObservable.notifyObservers(snippet.nodeMaterial);
+                                customLoadObservable.notifyObservers(serializationObject);
                             } else {
                             } else {
-                                nodeMaterial.loadFromSerialization(snippet.nodeMaterial);
+                                nodeMaterial.loadFromSerialization(serializationObject);
                                 nodeMaterial.build(true);
                                 nodeMaterial.build(true);
                                 showEditor();
                                 showEditor();
                             }
                             }
@@ -65,38 +66,41 @@ var showEditor = function() {
         customSave: {
         customSave: {
             label: "Save as unique URL",
             label: "Save as unique URL",
             action: (data) => {
             action: (data) => {
-                var xmlHttp = new XMLHttpRequest();
-                xmlHttp.onreadystatechange = function () {
-                    if (xmlHttp.readyState == 4) {
-                        if (xmlHttp.status == 200) {
-                            var baseUrl = location.href.replace(location.hash, "").replace(location.search, "");
-                            var snippet = JSON.parse(xmlHttp.responseText);
-                            var newUrl = baseUrl + "#" + snippet.id;
-                            currentSnippetToken = snippet.id;
-                            if (snippet.version && snippet.version != "0") {
-                                newUrl += "#" + snippet.version;
+                return new Promise((resolve, reject) => {
+                    var xmlHttp = new XMLHttpRequest();
+                    xmlHttp.onreadystatechange = function () {
+                        if (xmlHttp.readyState == 4) {
+                            if (xmlHttp.status == 200) {
+                                var baseUrl = location.href.replace(location.hash, "").replace(location.search, "");
+                                var snippet = JSON.parse(xmlHttp.responseText);
+                                var newUrl = baseUrl + "#" + snippet.id;
+                                currentSnippetToken = snippet.id;
+                                if (snippet.version && snippet.version != "0") {
+                                    newUrl += "#" + snippet.version;
+                                }
+                                location.href = newUrl;
+                                resolve();
+                            }
+                            else {
+                                reject(`Unable to save your node material. It may be too large (${(dataToSend.payload.length / 1024).toFixed(2)} KB) because of embedded textures. Please reduce texture sizes or point to a specific url instead of embedding them and try again.`);
                             }
                             }
-                            location.href = newUrl;
-                        }
-                        else {
-                            console.log("Unable to save your code. Please retry.", null);
                         }
                         }
                     }
                     }
-                }
-    
-                xmlHttp.open("POST", snippetUrl + (currentSnippetToken ? "/" + currentSnippetToken : ""), true);
-                xmlHttp.setRequestHeader("Content-Type", "application/json");
-    
-                var dataToSend = {
-                    payload : JSON.stringify({
-                        nodeMaterial: data
-                    }),
-                    name: "",
-                    description: "",
-                    tags: ""
-                };
-    
-                xmlHttp.send(JSON.stringify(dataToSend));
+        
+                    xmlHttp.open("POST", snippetUrl + (currentSnippetToken ? "/" + currentSnippetToken : ""), true);
+                    xmlHttp.setRequestHeader("Content-Type", "application/json");
+        
+                    var dataToSend = {
+                        payload : JSON.stringify({
+                            nodeMaterial: data
+                        }),
+                        name: "",
+                        description: "",
+                        tags: ""
+                    };
+        
+                    xmlHttp.send(JSON.stringify(dataToSend));
+                });
             }
             }
         }
         }
     });
     });
@@ -105,8 +109,9 @@ var showEditor = function() {
 // Let's start
 // Let's start
 if (BABYLON.Engine.isSupported()) {
 if (BABYLON.Engine.isSupported()) {
     var canvas = document.createElement("canvas");
     var canvas = document.createElement("canvas");
-    var engine = new BABYLON.Engine(canvas, false);
-    var scene = new BABYLON.Scene(engine);
+    var engine = new BABYLON.Engine(canvas, false, {disableWebGL2Support: true});
+    var scene = new BABYLON.Scene(engine);    
+    var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
 
 
     nodeMaterial = new BABYLON.NodeMaterial("node");
     nodeMaterial = new BABYLON.NodeMaterial("node");
 
 

+ 8 - 5
nodeEditor/src/blockTools.ts

@@ -32,11 +32,12 @@ import { StepBlock } from 'babylonjs/Materials/Node/Blocks/stepBlock';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { NodeMaterialSystemValues } from 'babylonjs/Materials/Node/nodeMaterialSystemValues';
 import { NodeMaterialSystemValues } from 'babylonjs/Materials/Node/nodeMaterialSystemValues';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
-import { OppositeBlock } from 'babylonjs/Materials/Node/Blocks/oppositeBlock';
+import { OneMinusBlock } from 'babylonjs/Materials/Node/Blocks/oneMinusBlock';
 import { ViewDirectionBlock } from 'babylonjs/Materials/Node/Blocks/viewDirectionBlock';
 import { ViewDirectionBlock } from 'babylonjs/Materials/Node/Blocks/viewDirectionBlock';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
 import { MaxBlock } from 'babylonjs/Materials/Node/Blocks/maxBlock';
 import { MaxBlock } from 'babylonjs/Materials/Node/Blocks/maxBlock';
 import { MinBlock } from 'babylonjs/Materials/Node/Blocks/minBlock';
 import { MinBlock } from 'babylonjs/Materials/Node/Blocks/minBlock';
+import { PerturbNormalBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/perturbNormalBlock';
 
 
 export class BlockTools {
 export class BlockTools {
     public static GetBlockFromString(data: string) {
     public static GetBlockFromString(data: string) {
@@ -78,7 +79,7 @@ export class BlockTools {
             case "ScaleBlock":
             case "ScaleBlock":
                 return new ScaleBlock("Scale");
                 return new ScaleBlock("Scale");
             case "CrossBlock":
             case "CrossBlock":
-                return new CrossBlock("Dot");
+                return new CrossBlock("Cross");
             case "DotBlock":
             case "DotBlock":
                 return new DotBlock("Dot");
                 return new DotBlock("Dot");
             case "MultiplyBlock":
             case "MultiplyBlock":
@@ -101,8 +102,8 @@ export class BlockTools {
                 return new SubtractBlock("Subtract"); 
                 return new SubtractBlock("Subtract"); 
             case "StepBlock":
             case "StepBlock":
                 return new StepBlock("Step");        
                 return new StepBlock("Step");        
-            case "OppositeBlock":
-                return new OppositeBlock("Opposite");      
+            case "OneMinusBlock":
+                return new OneMinusBlock("One minus");      
             case "ViewDirectionBlock":
             case "ViewDirectionBlock":
                 return new ViewDirectionBlock("View direction");    
                 return new ViewDirectionBlock("View direction");    
             case "LightInformationBlock":
             case "LightInformationBlock":
@@ -110,7 +111,9 @@ export class BlockTools {
             case "MaxBlock":
             case "MaxBlock":
                 return new MaxBlock("Max");       
                 return new MaxBlock("Max");       
             case "MinBlock":
             case "MinBlock":
-                return new MinBlock("Min");                                                  
+                return new MinBlock("Min");        
+            case "PerturbNormalBlock":                                          
+                return new PerturbNormalBlock("Perturb normal");        
             case "CosBlock": {
             case "CosBlock": {
                 let cosBlock = new TrigonometryBlock("Cos");
                 let cosBlock = new TrigonometryBlock("Cos");
                 cosBlock.operation = TrigonometryBlockOperations.Cos;
                 cosBlock.operation = TrigonometryBlockOperations.Cos;

+ 3 - 2
nodeEditor/src/components/diagram/diagram.scss

@@ -68,7 +68,7 @@
         background: #4086BB;
         background: #4086BB;
 
 
         .value {
         .value {
-            grid-row: 2;
+            grid-row: 3;
         }
         }
 
 
         .outputs, .inputs {
         .outputs, .inputs {
@@ -97,7 +97,8 @@
         border-top-left-radius: 16px;
         border-top-left-radius: 16px;
         font-size: 16px;
         font-size: 16px;
         text-align: center;
         text-align: center;
-        margin-top: -1px;
+        margin-top: -1px;    
+        transform: scaleX(1.001);
         
         
         white-space: nowrap;
         white-space: nowrap;
         text-overflow: ellipsis;
         text-overflow: ellipsis;

+ 8 - 1
nodeEditor/src/components/diagram/generic/genericNodeModel.tsx

@@ -64,7 +64,14 @@ export class GenericNodeModel extends DefaultNodeModel {
                         globalState.onRebuildRequiredObservable.notifyObservers();
                         globalState.onRebuildRequiredObservable.notifyObservers();
                     }} isSelected={() => (this.block as TransformBlock).complementW === 0} />
                     }} isSelected={() => (this.block as TransformBlock).complementW === 0} />
                 </LineContainerComponent>
                 </LineContainerComponent>
-            }        
+            }                    
+            {
+                this.block!.getClassName() === "PerturbNormalBlock" &&
+                <LineContainerComponent title="PROPERTIES">
+                    <CheckBoxLineComponent label="Invert X axis" target={this.block} propertyName="invertX" onValueChanged={() => globalState.onRebuildRequiredObservable.notifyObservers()} />
+                    <CheckBoxLineComponent label="Invert Y axis" target={this.block} propertyName="invertY" onValueChanged={() => globalState.onRebuildRequiredObservable.notifyObservers()}/>                    
+                </LineContainerComponent>
+            }   
             </div>
             </div>
         );
         );
     }
     }

+ 10 - 0
nodeEditor/src/components/diagram/input/inputNodePropertyComponent.tsx

@@ -15,6 +15,8 @@ import { StringTools } from '../../../stringTools';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { TextInputLineComponent } from '../../../sharedComponents/textInputLineComponent';
 import { TextInputLineComponent } from '../../../sharedComponents/textInputLineComponent';
 import { CheckBoxLineComponent } from '../../../sharedComponents/checkBoxLineComponent';
 import { CheckBoxLineComponent } from '../../../sharedComponents/checkBoxLineComponent';
+import { Vector4PropertyTabComponent } from '../../propertyTab/properties/vector4PropertyTabComponent';
+import { MatrixPropertyTabComponent } from '../../propertyTab/properties/matrixPropertyTabComponent';
 
 
 interface IInputPropertyTabComponentProps {
 interface IInputPropertyTabComponentProps {
     globalState: GlobalState;
     globalState: GlobalState;
@@ -46,7 +48,15 @@ export class InputPropertyTabComponentProps extends React.Component<IInputProper
             case NodeMaterialBlockConnectionPointTypes.Vector3:
             case NodeMaterialBlockConnectionPointTypes.Vector3:
                 return (
                 return (
                     <Vector3PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
                     <Vector3PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
+                );            
+            case NodeMaterialBlockConnectionPointTypes.Vector4:
+                return (
+                    <Vector4PropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
                 );
                 );
+            case NodeMaterialBlockConnectionPointTypes.Matrix:
+                return (
+                    <MatrixPropertyTabComponent globalState={globalState} inputBlock={inputBlock} />
+                );                
         }
         }
 
 
         return null;
         return null;

+ 24 - 3
nodeEditor/src/components/diagram/remap/remapNodeWidget.tsx

@@ -4,6 +4,8 @@ import { Nullable } from 'babylonjs/types';
 import { GlobalState } from '../../../globalState';
 import { GlobalState } from '../../../globalState';
 import { PortHelper } from '../portHelper';
 import { PortHelper } from '../portHelper';
 import { RemapBlock } from 'babylonjs/Materials/Node/Blocks/remapBlock';
 import { RemapBlock } from 'babylonjs/Materials/Node/Blocks/remapBlock';
+import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 
 
 /**
 /**
  * RemapNodeWidgetProps
  * RemapNodeWidgetProps
@@ -47,11 +49,30 @@ export class RemapNodeWidget extends React.Component<RemapNodeWidgetProps> {
         return null;
         return null;
     }
     }
 
 
+    extractInputValue(connectionPoint: NodeMaterialConnectionPoint) {
+        let connectedBlock = connectionPoint.connectedPoint!.ownerBlock;
+
+        if (connectedBlock.isInput) {
+            let inputBlock = connectedBlock as InputBlock;
+
+            if (inputBlock.isUniform && !inputBlock.isSystemValue) {
+                return inputBlock.value;
+            }
+        }
+
+        return "?";
+    }
+
     render() {
     render() {
-        var inputPorts = PortHelper.GenerateInputPorts(this.props.node, undefined, true);
-        var outputPorts = PortHelper.GenerateOutputPorts(this.props.node, true);
+        var inputPorts = PortHelper.GenerateInputPorts(this.props.node, undefined, false);
+        var outputPorts = PortHelper.GenerateOutputPorts(this.props.node, false);
         let remapBlock = this.props.node!.block! as RemapBlock;
         let remapBlock = this.props.node!.block! as RemapBlock;
 
 
+        let sourceRangeX = remapBlock.sourceMin.isConnected ? this.extractInputValue(remapBlock.sourceMin) : remapBlock.sourceRange.x;
+        let sourceRangeY = remapBlock.sourceMax.isConnected ? this.extractInputValue(remapBlock.sourceMax) : remapBlock.sourceRange.y;
+        let targetRangeX = remapBlock.targetMin.isConnected ? this.extractInputValue(remapBlock.targetMin) : remapBlock.targetRange.x;
+        let targetRangeY = remapBlock.targetMax.isConnected ? this.extractInputValue(remapBlock.targetMax) : remapBlock.targetRange.y;
+
         return (
         return (
             <div className={"diagramBlock remap"}>
             <div className={"diagramBlock remap"}>
                 <div className="header">
                 <div className="header">
@@ -65,7 +86,7 @@ export class RemapNodeWidget extends React.Component<RemapNodeWidgetProps> {
                 </div>
                 </div>
                 <div className="value">  
                 <div className="value">  
                 {
                 {
-                    `[${remapBlock.sourceRange.x}, ${remapBlock.sourceRange.y}] -> [${remapBlock.targetRange.x}, ${remapBlock.targetRange.y}]`
+                    `[${sourceRangeX}, ${sourceRangeY}] -> [${targetRangeX}, ${targetRangeY}]`
                 }                 
                 }                 
                 </div>
                 </div>
             </div>
             </div>

+ 59 - 4
nodeEditor/src/components/diagram/texture/texturePropertyTabComponent.tsx

@@ -16,7 +16,16 @@ interface ITexturePropertyTabComponentProps {
     node: TextureNodeModel;
     node: TextureNodeModel;
 }
 }
 
 
-export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps, {isEmbedded: boolean}> {
+
+    constructor(props: ITexturePropertyTabComponentProps) {
+        super(props);
+
+        let texture = this.props.node.texture as BaseTexture;
+
+        this.state = {isEmbedded: !texture || texture.name.substring(0, 4) !== "http"};
+    }
+
 
 
     updateAftertextureLoad() {
     updateAftertextureLoad() {
         this.props.globalState.onUpdateRequiredObservable.notifyObservers();
         this.props.globalState.onUpdateRequiredObservable.notifyObservers();
@@ -34,7 +43,7 @@ export class TexturePropertyTabComponent extends React.Component<ITexturePropert
 
 
         let texture = this.props.node.texture as BaseTexture;
         let texture = this.props.node.texture as BaseTexture;
         if (!texture) {
         if (!texture) {
-            this.props.node.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, false)
+            this.props.node.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, false);
             texture = this.props.node.texture;
             texture = this.props.node.texture;
         }
         }
 
 
@@ -62,17 +71,63 @@ export class TexturePropertyTabComponent extends React.Component<ITexturePropert
         }, undefined, true);
         }, undefined, true);
     }
     }
 
 
+    replaceTextureWithUrl(url: string) {
+        let texture = this.props.node.texture as BaseTexture;
+        if (!texture) {
+            this.props.node.texture = new Texture(url, this.props.globalState.nodeMaterial.getScene(), false, false, undefined, () => {
+                this.updateAftertextureLoad();
+            });
+            return;
+        }
+
+        (texture as Texture).updateURL(url, null, () => this.updateAftertextureLoad());
+    }
+
     render() {
     render() {
+        let url = "";
+
+        let texture = this.props.node.texture as BaseTexture;
+        if (texture && texture.name && texture.name.substring(0, 4) === "http") {
+            url = texture.name;
+        }
+
         return (
         return (
             <div>
             <div>
                 <LineContainerComponent title="GENERAL">
                 <LineContainerComponent title="GENERAL">
                     <TextLineComponent label="Type" value="Texture" />
                     <TextLineComponent label="Type" value="Texture" />
                     <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.node.block!} onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
                     <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.node.block!} onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
                 </LineContainerComponent>
                 </LineContainerComponent>
-
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     <CheckBoxLineComponent label="Auto select UV" propertyName="autoSelectUV" target={this.props.node.block!} />
                     <CheckBoxLineComponent label="Auto select UV" propertyName="autoSelectUV" target={this.props.node.block!} />
-                    <FileButtonLineComponent label="Replace texture" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
+                    {
+                        texture &&
+                        <CheckBoxLineComponent label="Clamp U" isSelected={() => texture.wrapU === Texture.CLAMP_ADDRESSMODE} onSelect={(value) => {
+                            texture.wrapU = value ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE;
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }} />
+                    }
+                    {
+                        texture &&
+                        <CheckBoxLineComponent label="Clamp V" isSelected={() => texture.wrapV === Texture.CLAMP_ADDRESSMODE} onSelect={(value) => {
+                            texture.wrapV = value ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }} />
+                    }
+                </LineContainerComponent>
+                <LineContainerComponent title="SOURCE">
+                    <CheckBoxLineComponent label="Embed texture" isSelected={() => this.state.isEmbedded} onSelect={value => {
+                        this.setState({isEmbedded: value});
+                        this.props.node.texture = null;
+                        this.updateAftertextureLoad();
+                    }}/>
+                    {
+                        this.state.isEmbedded &&
+                        <FileButtonLineComponent label="Upload" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
+                    }
+                    {
+                        !this.state.isEmbedded &&
+                        <TextInputLineComponent label="Link" globalState={this.props.globalState} value={url} onChange={newUrl => this.replaceTextureWithUrl(newUrl)}/>
+                    }
                 </LineContainerComponent>
                 </LineContainerComponent>
             </div>
             </div>
         );
         );

+ 0 - 1
nodeEditor/src/components/log/log.scss

@@ -1,6 +1,5 @@
 #log-console {
 #log-console {
     background: #333333;
     background: #333333;
-    border: #555555 solid 1px;
     height: 120px;
     height: 120px;
     box-sizing: border-box;
     box-sizing: border-box;
     margin: 0;
     margin: 0;

+ 1 - 1
nodeEditor/src/components/nodeList/nodeList.scss

@@ -49,7 +49,7 @@
             .list-container {
             .list-container {
                 overflow-x: hidden;
                 overflow-x: hidden;
                 overflow-y: auto;
                 overflow-y: auto;
-                height: 100%;
+                height: calc(100% - 32px);
 
 
                 .underline {
                 .underline {
                     border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
                     border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);

+ 3 - 3
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -26,7 +26,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         // Block types used to create the menu from
         // Block types used to create the menu from
         const allBlocks = {
         const allBlocks = {
             Animation: ["BonesBlock", "MorphTargetsBlock"],
             Animation: ["BonesBlock", "MorphTargetsBlock"],
-            Basic_Math: ["AddBlock",  "DivideBlock", "MultiplyBlock", "ScaleBlock", "SubtractBlock", "OppositeBlock", "MaxBlock", "MinBlock"],
+            Basic_Math: ["AddBlock",  "DivideBlock", "MultiplyBlock", "ScaleBlock", "SubtractBlock", "OneMinusBlock", "MaxBlock", "MinBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "TimeBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "TimeBlock"],
             Interpolation: ["LerpBlock"],
             Interpolation: ["LerpBlock"],
@@ -35,7 +35,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Output_Blocks: ["VertexOutputBlock", "FragmentOutputBlock", "AlphaTestBlock"],
             Output_Blocks: ["VertexOutputBlock", "FragmentOutputBlock", "AlphaTestBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Round: ["StepBlock", "RoundBlock", "CeilingBlock", "FloorBlock"],
             Round: ["StepBlock", "RoundBlock", "CeilingBlock", "FloorBlock"],
-            Scene_Attributes: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ReflectionTextureBlock", "ViewDirectionBlock"],
+            Scene_Attributes: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ReflectionTextureBlock", "ViewDirectionBlock", "PerturbNormalBlock"],
             Trigonometry: ["CosBlock", "SinBlock", "AbsBlock", "ExpBlock", "Exp2Block"],
             Trigonometry: ["CosBlock", "SinBlock", "AbsBlock", "ExpBlock", "Exp2Block"],
             Vector_Math: ["CrossBlock", "DotBlock", "TransformBlock", "FresnelBlock"],
             Vector_Math: ["CrossBlock", "DotBlock", "TransformBlock", "FresnelBlock"],
         }
         }
@@ -59,7 +59,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         }
         }
 
 
         return (
         return (
-            <div id="nodeList" style={{ borderRightStyle: "solid", borderColor: "grey", borderWidth: "1px" }} >
+            <div id="nodeList">
                 <div className="panes">
                 <div className="panes">
                     <div className="pane">
                     <div className="pane">
                         <div className="filter">
                         <div className="filter">

+ 54 - 0
nodeEditor/src/components/preview/previewAreaComponent.tsx

@@ -0,0 +1,54 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faPlay, faStop, faPalette } from '@fortawesome/free-solid-svg-icons';
+import { Color3, Color4 } from 'babylonjs/Maths/math.color';
+import { DataStorage } from '../../dataStorage';
+
+interface IPreviewAreaComponent {
+    globalState: GlobalState;
+    width: number;
+}
+
+export class PreviewAreaComponent extends React.Component<IPreviewAreaComponent> {
+
+    changeAnimation() {
+        this.props.globalState.rotatePreview = !this.props.globalState.rotatePreview;
+        this.props.globalState.onAnimationCommandActivated.notifyObservers();
+        this.forceUpdate();
+    }
+
+    changeBackground(value: string) {
+        const newColor = Color3.FromHexString(value);
+
+        DataStorage.StoreNumber("BackgroundColorR", newColor.r);
+        DataStorage.StoreNumber("BackgroundColorG", newColor.g);
+        DataStorage.StoreNumber("BackgroundColorB", newColor.b);
+
+        this.props.globalState.backgroundColor = Color4.FromColor3(newColor, 1.0);
+        this.props.globalState.onPreviewBackgroundChanged.notifyObservers();
+    }
+
+    render() {
+        return (
+            <>
+                <div id="preview" style={{height: this.props.width + "px"}}>
+                    <canvas id="preview-canvas"/>
+                </div>                
+                <div id="preview-config-bar">
+                    <div onClick={() => this.changeAnimation()} className={"button"}>
+                        <FontAwesomeIcon icon={this.props.globalState.rotatePreview ? faStop : faPlay} />
+                    </div>
+                    <div className={"button align"}>
+                        <label htmlFor="color-picker" id="color-picker-label">
+                            <FontAwesomeIcon icon={faPalette} />
+                        </label>
+                        <input ref="color-picker" id="color-picker" type="color" onChange={evt => this.changeBackground(evt.target.value)} />
+                    </div>
+                </div>
+            </>
+        );
+
+    }
+}

+ 115 - 28
nodeEditor/src/components/preview/previewManager.ts

@@ -9,19 +9,27 @@ import { Vector3 } from 'babylonjs/Maths/math.vector';
 import { HemisphericLight } from 'babylonjs/Lights/hemisphericLight';
 import { HemisphericLight } from 'babylonjs/Lights/hemisphericLight';
 import { ArcRotateCamera } from 'babylonjs/Cameras/arcRotateCamera';
 import { ArcRotateCamera } from 'babylonjs/Cameras/arcRotateCamera';
 import { PreviewMeshType } from './previewMeshType';
 import { PreviewMeshType } from './previewMeshType';
+import { Animation } from 'babylonjs/Animations/animation';
+import { SceneLoader } from 'babylonjs/Loading/sceneLoader';
+import { TransformNode } from 'babylonjs/Meshes/transformNode';
+import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { FramingBehavior } from 'babylonjs/Behaviors/Cameras/framingBehavior';
 
 
 export class PreviewManager {
 export class PreviewManager {
     private _nodeMaterial: NodeMaterial;
     private _nodeMaterial: NodeMaterial;
     private _onBuildObserver: Nullable<Observer<NodeMaterial>>;    
     private _onBuildObserver: Nullable<Observer<NodeMaterial>>;    
-    private _onPreviewMeshTypeChangedObserver: Nullable<Observer<void>>;
+    private _onPreviewCommandActivatedObserver: Nullable<Observer<void>>;
+    private _onAnimationCommandActivatedObserver: Nullable<Observer<void>>;
     private _onUpdateRequiredObserver: Nullable<Observer<void>>;
     private _onUpdateRequiredObserver: Nullable<Observer<void>>;
+    private _onPreviewBackgroundChangedObserver: Nullable<Observer<void>>;
     private _engine: Engine;
     private _engine: Engine;
     private _scene: Scene;
     private _scene: Scene;
     private _light: HemisphericLight;
     private _light: HemisphericLight;
-    private _dummy: Mesh;
+    private _meshes: AbstractMesh[];
     private _camera: ArcRotateCamera;
     private _camera: ArcRotateCamera;
     private _material: NodeMaterial;
     private _material: NodeMaterial;
-    private _globalState: GlobalState;    
+    private _globalState: GlobalState;   
+    private _currentType: number; 
 
 
     public constructor(targetCanvas: HTMLCanvasElement, globalState: GlobalState) {
     public constructor(targetCanvas: HTMLCanvasElement, globalState: GlobalState) {
         this._nodeMaterial = globalState.nodeMaterial;
         this._nodeMaterial = globalState.nodeMaterial;
@@ -32,7 +40,7 @@ export class PreviewManager {
             this._updatePreview(serializationObject);
             this._updatePreview(serializationObject);
         });
         });
 
 
-        this._onPreviewMeshTypeChangedObserver = globalState.onPreviewMeshTypeChanged.add(() => {
+        this._onPreviewCommandActivatedObserver = globalState.onPreviewCommandActivated.add(() => {
             this._refreshPreviewMesh();
             this._refreshPreviewMesh();
         });
         });
 
 
@@ -41,12 +49,19 @@ export class PreviewManager {
             this._updatePreview(serializationObject);
             this._updatePreview(serializationObject);
         });
         });
 
 
+        this._onPreviewBackgroundChangedObserver = globalState.onPreviewBackgroundChanged.add(() => {
+            this._scene.clearColor = this._globalState.backgroundColor;    
+        });
+
+        this._onAnimationCommandActivatedObserver = globalState.onAnimationCommandActivated.add(() => {
+            this._handleAnimations();
+        });
+
         this._engine = new Engine(targetCanvas, true);
         this._engine = new Engine(targetCanvas, true);
         this._scene = new Scene(this._engine);
         this._scene = new Scene(this._engine);
         this._camera = new ArcRotateCamera("Camera", 0, 0.8, 4, Vector3.Zero(), this._scene);
         this._camera = new ArcRotateCamera("Camera", 0, 0.8, 4, Vector3.Zero(), this._scene);
         this._light = new HemisphericLight("light", new Vector3(0, 1, 0), this._scene);
         this._light = new HemisphericLight("light", new Vector3(0, 1, 0), this._scene);
 
 
-
         this._camera.lowerRadiusLimit = 3;
         this._camera.lowerRadiusLimit = 3;
         this._camera.upperRadiusLimit = 10;
         this._camera.upperRadiusLimit = 10;
         this._camera.wheelPrecision = 20;
         this._camera.wheelPrecision = 20;
@@ -63,29 +78,94 @@ export class PreviewManager {
         this._updatePreview(serializationObject);
         this._updatePreview(serializationObject);
     }
     }
 
 
-    private _refreshPreviewMesh() {    
-        if (this._dummy) {
-            this._dummy.dispose();
+    private _handleAnimations() {
+        this._scene.stopAllAnimations();
+                        
+        if (this._globalState.rotatePreview) {
+            for (var root of this._scene.rootNodes) {
+                let transformNode = root as TransformNode;
+
+                if (transformNode.getClassName() === "TransformNode" || transformNode.getClassName() === "Mesh") {
+                    if (transformNode.rotationQuaternion) {
+                        transformNode.rotation = transformNode.rotationQuaternion.toEulerAngles();
+                        transformNode.rotationQuaternion = null;
+                    }
+                    Animation.CreateAndStartAnimation("turnTable", root, "rotation.y", 60, 1200, transformNode.rotation.y, transformNode.rotation.y + 2 * Math.PI, 1);
+                }
+            }
         }
         }
+    }
+
+    private _prepareMeshes() {
+        // Material
+        for (var mesh of this._meshes) {
+            mesh.material = this._material;
+        }
+
+        // Framing
+        this._camera.useFramingBehavior = true;
+
+        var framingBehavior = this._camera.getBehaviorByName("Framing") as FramingBehavior;
+        framingBehavior.framingTime = 0;
+        framingBehavior.elevationReturnTime = -1;
+
+        if (this._scene.meshes.length) {
+            var worldExtends = this._scene.getWorldExtends();
+            this._camera.lowerRadiusLimit = null;
+            this._camera.upperRadiusLimit = null;
+            framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
+        }
+
+        this._camera.pinchPrecision = 200 / this._camera.radius;
+        this._camera.upperRadiusLimit = 5 * this._camera.radius;
+
+        this._camera.wheelDeltaPercentage = 0.01;
+        this._camera.pinchDeltaPercentage = 0.01;
+
+        // Animations
+        this._handleAnimations();
+    }
+
+    private _refreshPreviewMesh() {    
+
+        if (this._currentType !== this._globalState.previewMeshType) {
+
+            this._currentType = this._globalState.previewMeshType;
+            if (this._meshes && this._meshes.length) {
+
+                for (var mesh of this._meshes) {
+                    mesh.dispose();
+                }
+            }
+
+            this._meshes = [];
         
         
-        switch (this._globalState.previewMeshType) {
-            case PreviewMeshType.Box:
-                this._dummy = Mesh.CreateBox("dummy-box", 2, this._scene);
-                break;
-            case PreviewMeshType.Sphere:
-                this._dummy = Mesh.CreateSphere("dummy-sphere", 32, 2, this._scene);
-                break;
-            case PreviewMeshType.Torus:
-                this._dummy = Mesh.CreateTorus("dummy-torus", 2, 0.5, 32, this._scene);
-                break;
-            case PreviewMeshType.Cylinder:
-                this._dummy = Mesh.CreateCylinder("dummy-cylinder", 2, 1, 1.2, 32, 1, this._scene);
-                break;                
-            case PreviewMeshType.Plane:
-                this._dummy = Mesh.CreateGround("dummy-plane", 2, 2, 128, this._scene);
-                break;                
+            switch (this._globalState.previewMeshType) {
+                case PreviewMeshType.Box:
+                    this._meshes.push(Mesh.CreateBox("dummy-box", 2, this._scene));
+                    break;
+                case PreviewMeshType.Sphere:
+                    this._meshes.push(Mesh.CreateSphere("dummy-sphere", 32, 2, this._scene));
+                    break;
+                case PreviewMeshType.Torus:
+                    this._meshes.push(Mesh.CreateTorus("dummy-torus", 2, 0.5, 32, this._scene));
+                    break;
+                case PreviewMeshType.Cylinder:
+                    this._meshes.push(Mesh.CreateCylinder("dummy-cylinder", 2, 1, 1.2, 32, 1, this._scene));
+                    break;                
+                case PreviewMeshType.Plane:
+                    this._meshes.push(Mesh.CreateGround("dummy-plane", 2, 2, 128, this._scene));
+                    break;         
+                case PreviewMeshType.Custom:
+                    SceneLoader.AppendAsync("file:", this._globalState.previewMeshFile, this._scene).then(() => {     
+                        this._meshes.push(...this._scene.meshes);
+                        this._prepareMeshes();
+                    });
+                    return;     
             }
             }
-        this._dummy.material = this._material;
+            
+            this._prepareMeshes();
+        }
     }
     }
 
 
     private _updatePreview(serializationObject: any) {
     private _updatePreview(serializationObject: any) {
@@ -95,20 +175,27 @@ export class PreviewManager {
 
 
         this._material = NodeMaterial.Parse(serializationObject, this._scene);
         this._material = NodeMaterial.Parse(serializationObject, this._scene);
         this._material.build();
         this._material.build();
-        this._dummy.material = this._material;
+
+        for (var mesh of this._meshes) {
+            mesh.material = this._material;
+        }
     }
     }
 
 
     public dispose() {
     public dispose() {
         this._nodeMaterial.onBuildObservable.remove(this._onBuildObserver);
         this._nodeMaterial.onBuildObservable.remove(this._onBuildObserver);
-        this._globalState.onPreviewMeshTypeChanged.remove(this._onPreviewMeshTypeChangedObserver);
+        this._globalState.onPreviewCommandActivated.remove(this._onPreviewCommandActivatedObserver);
         this._globalState.onUpdateRequiredObservable.remove(this._onUpdateRequiredObserver);
         this._globalState.onUpdateRequiredObservable.remove(this._onUpdateRequiredObserver);
+        this._globalState.onAnimationCommandActivated.remove(this._onAnimationCommandActivatedObserver);
+        this._globalState.onPreviewBackgroundChanged.remove(this._onPreviewBackgroundChangedObserver);
 
 
         if (this._material) {
         if (this._material) {
             this._material.dispose();
             this._material.dispose();
         }
         }
 
 
         this._camera.dispose();
         this._camera.dispose();
-        this._dummy.dispose();
+        for (var mesh of this._meshes) {
+            mesh.dispose();
+        }
         this._light.dispose();
         this._light.dispose();
         this._engine.dispose();
         this._engine.dispose();
     }
     }

+ 21 - 2
nodeEditor/src/components/preview/previewMeshControlComponent.tsx

@@ -2,7 +2,7 @@
 import * as React from "react";
 import * as React from "react";
 import { GlobalState } from '../../globalState';
 import { GlobalState } from '../../globalState';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faCircle, faRing, faCube, faHockeyPuck, faSquareFull } from '@fortawesome/free-solid-svg-icons';
+import { faCircle, faRing, faCube, faHockeyPuck, faSquareFull, faPlus } from '@fortawesome/free-solid-svg-icons';
 import { PreviewMeshType } from './previewMeshType';
 import { PreviewMeshType } from './previewMeshType';
 import { DataStorage } from '../../dataStorage';
 import { DataStorage } from '../../dataStorage';
 
 
@@ -18,13 +18,26 @@ export class PreviewMeshControlComponent extends React.Component<IPreviewMeshCon
         }
         }
 
 
         this.props.globalState.previewMeshType = newOne;
         this.props.globalState.previewMeshType = newOne;
-        this.props.globalState.onPreviewMeshTypeChanged.notifyObservers();
+        this.props.globalState.onPreviewCommandActivated.notifyObservers();
 
 
         DataStorage.StoreNumber("PreviewMeshType", newOne);
         DataStorage.StoreNumber("PreviewMeshType", newOne);
 
 
         this.forceUpdate();
         this.forceUpdate();
     }
     }
 
 
+    useCustomMesh(evt: any) {
+        var files: File[] = evt.target.files;
+        if (files && files.length) {
+            let file = files[0];
+
+            this.props.globalState.previewMeshFile = file;
+            this.props.globalState.previewMeshType = PreviewMeshType.Custom;
+            this.props.globalState.onPreviewCommandActivated.notifyObservers();        
+            this.forceUpdate();
+        }
+        (document.getElementById("file-picker")! as HTMLInputElement).value = "";
+    }
+
     render() {
     render() {
         return (
         return (
             <div id="preview-mesh-bar">
             <div id="preview-mesh-bar">
@@ -42,6 +55,12 @@ export class PreviewMeshControlComponent extends React.Component<IPreviewMeshCon
                 </div>
                 </div>
                 <div onClick={() => this.changeMeshType(PreviewMeshType.Plane)} className={"button" + (this.props.globalState.previewMeshType === PreviewMeshType.Plane ? " selected" : "")}>
                 <div onClick={() => this.changeMeshType(PreviewMeshType.Plane)} className={"button" + (this.props.globalState.previewMeshType === PreviewMeshType.Plane ? " selected" : "")}>
                     <FontAwesomeIcon icon={faSquareFull} />
                     <FontAwesomeIcon icon={faSquareFull} />
+                </div>                
+                <div className={"button align"}>
+                    <label htmlFor="file-picker" id="file-picker-label">
+                        <FontAwesomeIcon icon={faPlus} />
+                    </label>
+                    <input ref="file-picker" id="file-picker" type="file" onChange={evt => this.useCustomMesh(evt)} accept=".gltf, .glb, .babylon, .obj"/>
                 </div>
                 </div>
             </div>
             </div>
         );
         );

+ 2 - 1
nodeEditor/src/components/preview/previewMeshType.ts

@@ -3,5 +3,6 @@ export enum PreviewMeshType {
     Box, 
     Box, 
     Torus,
     Torus,
     Cylinder,
     Cylinder,
-    Plane
+    Plane,
+    Custom
 }
 }

+ 21 - 0
nodeEditor/src/components/propertyTab/properties/matrixPropertyTabComponent.tsx

@@ -0,0 +1,21 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
+import { MatrixLineComponent } from '../../../sharedComponents/matrixLineComponent';
+
+interface IMatrixPropertyTabComponentProps {
+    globalState: GlobalState;
+    inputBlock: InputBlock;
+}
+
+export class MatrixPropertyTabComponent extends React.Component<IMatrixPropertyTabComponentProps> {
+
+    render() {
+        return (
+            <MatrixLineComponent label="Value" target={this.props.inputBlock} propertyName="value" onChange={() => {
+                this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+            }}></MatrixLineComponent>
+        );
+    }
+}

+ 21 - 0
nodeEditor/src/components/propertyTab/properties/vector4PropertyTabComponent.tsx

@@ -0,0 +1,21 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
+import { Vector4LineComponent } from '../../../sharedComponents/vector4LineComponent';
+
+interface IVector4PropertyTabComponentProps {
+    globalState: GlobalState;
+    inputBlock: InputBlock;
+}
+
+export class Vector4PropertyTabComponent extends React.Component<IVector4PropertyTabComponentProps> {
+
+    render() {
+        return (
+            <Vector4LineComponent label="Value" target={this.props.inputBlock} propertyName="value" onChange={() => {
+                this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+            }}></Vector4LineComponent>
+        );
+    }
+}

+ 15 - 6
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -42,6 +42,15 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
         StringTools.DownloadAsFile(this.props.globalState.hostDocument, json, "nodeMaterial.json");
         StringTools.DownloadAsFile(this.props.globalState.hostDocument, json, "nodeMaterial.json");
     }
     }
 
 
+    customSave() {
+        this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Saving your material to Babylon.js snippet server...", isError: false});
+        this.props.globalState.customSave!.action(SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState)).then(() => {
+            this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Material saved successfully", isError: false});
+        }).catch(err => {
+            this.props.globalState.onLogRequiredObservable.notifyObservers({message: err, isError: true});
+        });
+    }
+
     render() {
     render() {
         if (this.state.currentNode) {
         if (this.state.currentNode) {
             return (
             return (
@@ -85,18 +94,18 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                         <ButtonLineComponent label="Save" onClick={() => {
                         <ButtonLineComponent label="Save" onClick={() => {
                             this.save();
                             this.save();
                         }} />
                         }} />
+                        {
+                            this.props.globalState.customSave && 
+                            <ButtonLineComponent label={this.props.globalState.customSave!.label} onClick={() => {
+                                this.customSave();
+                            }} />
+                        }
                         <ButtonLineComponent label="Generate code" onClick={() => {
                         <ButtonLineComponent label="Generate code" onClick={() => {
                             StringTools.DownloadAsFile(this.props.globalState.hostDocument, this.props.globalState.nodeMaterial!.generateCode(), "code.txt");
                             StringTools.DownloadAsFile(this.props.globalState.hostDocument, this.props.globalState.nodeMaterial!.generateCode(), "code.txt");
                         }} />
                         }} />
                         <ButtonLineComponent label="Export shaders" onClick={() => {
                         <ButtonLineComponent label="Export shaders" onClick={() => {
                             StringTools.DownloadAsFile(this.props.globalState.hostDocument, this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");
                             StringTools.DownloadAsFile(this.props.globalState.hostDocument, this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");
                         }} />
                         }} />
-                        {
-                            this.props.globalState.customSave && 
-                            <ButtonLineComponent label={this.props.globalState.customSave!.label} onClick={() => {
-                                this.props.globalState.customSave!.action(SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState));
-                            }} />
-                        }
                     </LineContainerComponent>
                     </LineContainerComponent>
                 </div>
                 </div>
             </div>
             </div>

+ 13 - 2
nodeEditor/src/globalState.ts

@@ -8,6 +8,7 @@ import { INodeLocationInfo } from './nodeLocationInfo';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { PreviewMeshType } from './components/preview/previewMeshType';
 import { PreviewMeshType } from './components/preview/previewMeshType';
 import { DataStorage } from './dataStorage';
 import { DataStorage } from './dataStorage';
+import { Color4 } from 'babylonjs/Maths/math.color';
 
 
 export class GlobalState {
 export class GlobalState {
     nodeMaterial: NodeMaterial;
     nodeMaterial: NodeMaterial;
@@ -21,14 +22,24 @@ export class GlobalState {
     onReOrganizedRequiredObservable = new Observable<void>();
     onReOrganizedRequiredObservable = new Observable<void>();
     onLogRequiredObservable = new Observable<LogEntry>();
     onLogRequiredObservable = new Observable<LogEntry>();
     onErrorMessageDialogRequiredObservable = new Observable<string>();
     onErrorMessageDialogRequiredObservable = new Observable<string>();
-    onPreviewMeshTypeChanged = new Observable<void>();
+    onPreviewCommandActivated = new Observable<void>();
+    onPreviewBackgroundChanged = new Observable<void>();
+    onAnimationCommandActivated = new Observable<void>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => NodeModel;
     onGetNodeFromBlock: (block: NodeMaterialBlock) => NodeModel;
     previewMeshType: PreviewMeshType;
     previewMeshType: PreviewMeshType;
+    previewMeshFile: File;
+    rotatePreview: boolean;
+    backgroundColor: Color4;
     blockKeyboardEvents = false;
     blockKeyboardEvents = false;
     
     
-    customSave?: {label: string, action: (data: string) => void};
+    customSave?: {label: string, action: (data: string) => Promise<void>};
 
 
     public constructor() {
     public constructor() {
         this.previewMeshType = DataStorage.ReadNumber("PreviewMeshType", PreviewMeshType.Box);
         this.previewMeshType = DataStorage.ReadNumber("PreviewMeshType", PreviewMeshType.Box);
+
+        let r = DataStorage.ReadNumber("BackgroundColorR", 0.37);
+        let g = DataStorage.ReadNumber("BackgroundColorG", 0.37);
+        let b = DataStorage.ReadNumber("BackgroundColorB", 0.37);
+        this.backgroundColor = new Color4(r, g, b, 1.0);
     }
     }
 }
 }

+ 4 - 3
nodeEditor/src/graphEditor.tsx

@@ -50,6 +50,7 @@ import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
 import { LightInformationNodeFactory } from './components/diagram/lightInformation/lightInformationNodeFactory';
 import { LightInformationNodeFactory } from './components/diagram/lightInformation/lightInformationNodeFactory';
 import { LightInformationNodeModel } from './components/diagram/lightInformation/lightInformationNodeModel';
 import { LightInformationNodeModel } from './components/diagram/lightInformation/lightInformationNodeModel';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
+import { PreviewAreaComponent } from './components/preview/previewAreaComponent';
 
 
 require("storm-react-diagrams/dist/style.min.css");
 require("storm-react-diagrams/dist/style.min.css");
 require("./main.scss");
 require("./main.scss");
@@ -385,6 +386,8 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
                                 link.output.connection.disconnectFrom(link.input.connection);
                                 link.output.connection.disconnectFrom(link.input.connection);
                                 link.input.syncWithNodeMaterialConnectionPoint(link.input.connection);
                                 link.input.syncWithNodeMaterialConnectionPoint(link.input.connection);
                                 link.output.syncWithNodeMaterialConnectionPoint(link.output.connection);
                                 link.output.syncWithNodeMaterialConnectionPoint(link.output.connection);
+                                
+                                this.props.globalState.onRebuildRequiredObservable.notifyObservers();
                             }
                             }
                         }
                         }
                     } else {
                     } else {
@@ -674,9 +677,7 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
                     <div className="right-panel">
                     <div className="right-panel">
                         <PropertyTabComponent globalState={this.props.globalState} />
                         <PropertyTabComponent globalState={this.props.globalState} />
                         <PreviewMeshControlComponent globalState={this.props.globalState} />
                         <PreviewMeshControlComponent globalState={this.props.globalState} />
-                        <div id="preview" style={{height: this._rightWidth + "px"}}>
-                            <canvas id="preview-canvas"/>
-                        </div>
+                        <PreviewAreaComponent globalState={this.props.globalState} width={this._rightWidth}/>
                     </div>
                     </div>
 
 
                     <LogComponent globalState={this.props.globalState} />
                     <LogComponent globalState={this.props.globalState} />

+ 59 - 20
nodeEditor/src/main.scss

@@ -41,7 +41,7 @@
     grid-row: 1 / span 2;
     grid-row: 1 / span 2;
     grid-column: 5;
     grid-column: 5;
     display: grid;
     display: grid;
-    grid-template-rows: 1fr 30px auto;
+    grid-template-rows: 1fr 30px auto 30px;
     grid-template-columns: 100%;
     grid-template-columns: 100%;
     height: 100%;
     height: 100%;
     overflow-y: auto;
     overflow-y: auto;
@@ -49,7 +49,32 @@
     #propertyTab {
     #propertyTab {
         grid-row: 1;
         grid-row: 1;
         grid-column: 1;
         grid-column: 1;
-    }
+    }        
+    
+    .button {
+        display: grid;
+        justify-content: center;
+        align-content: center;
+        height: 30px;
+        width: calc(100% / 6);
+        cursor: pointer;
+
+        &:hover {
+            background: rgb(51, 122, 183);
+            color: white;
+            opacity: 0.8;
+        }
+
+        &.selected {
+            background: rgb(51, 122, 183);
+            color: white;
+        }
+        
+        &.align {
+            justify-content: stretch;
+            text-align: center;
+        }
+    }    
 
 
     #preview-mesh-bar {
     #preview-mesh-bar {
         grid-row: 2;
         grid-row: 2;
@@ -57,27 +82,41 @@
         display: flex;
         display: flex;
         color: white;
         color: white;
         align-items: center;
         align-items: center;
-        font-size: 18px;
+        font-size: 18px;    
+
+        #file-picker {
+            display: none;
+        }
+
+        #file-picker-label {
+            width: 100%;
+            background: transparent;
+            cursor: pointer;            
+        }
+    }
+
+    #preview-config-bar {
+        grid-row: 4;
+        grid-column: 1;
+        display: flex;
+        flex-direction: row-reverse;
+        color: white;
+        align-items: center;
+        font-size: 18px;    
 
 
         .button {
         .button {
-            display: grid;
-            justify-content: center;
-            align-content: center;
-            height: 30px;
-            width: calc(100% / 4);
-            cursor: pointer;
-
-            &:hover {
-                background: rgb(51, 122, 183);
-                color: white;
-                opacity: 0.8;
-            }
+            width: 60px;
+        }
 
 
-            &.selected {
-                background: rgb(51, 122, 183);
-                color: white;
-            }
-        }        
+        #color-picker {
+            display: none;
+        }
+
+        #color-picker-label {
+            width: 100%;
+            background: transparent;
+            cursor: pointer;            
+        }
     }
     }
     
     
     #preview {
     #preview {

+ 2 - 2
nodeEditor/src/nodeEditor.ts

@@ -12,7 +12,7 @@ import { Observable } from 'babylonjs/Misc/observable';
 export interface INodeEditorOptions {
 export interface INodeEditorOptions {
     nodeMaterial: NodeMaterial,
     nodeMaterial: NodeMaterial,
     hostElement?: HTMLElement,
     hostElement?: HTMLElement,
-    customSave?: {label: string, action: (data: string) => void};
+    customSave?: {label: string, action: (data: string) => Promise<void>};
     customLoadObservable?: Observable<any>
     customLoadObservable?: Observable<any>
 }
 }
 
 
@@ -68,7 +68,7 @@ export class NodeEditor {
                     popupWindow.close();
                     popupWindow.close();
                 }
                 }
             })
             })
-            window.onbeforeunload = function(event) {
+            window.onbeforeunload = () => {
                 var popupWindow = (Popup as any)["node-editor"];
                 var popupWindow = (Popup as any)["node-editor"];
                 if (popupWindow) {
                 if (popupWindow) {
                     popupWindow.close();
                     popupWindow.close();

+ 87 - 0
nodeEditor/src/sharedComponents/matrixLineComponent.tsx

@@ -0,0 +1,87 @@
+import * as React from "react";
+import { Vector3, Matrix, Vector4 } from "babylonjs/Maths/math";
+import { Observable } from "babylonjs/Misc/observable";
+import { PropertyChangedEvent } from "./propertyChangedEvent";
+import { Vector4LineComponent } from './vector4LineComponent';
+
+interface IMatrixLineComponentProps {
+    label: string;
+    target: any;
+    propertyName: string;
+    step?: number;
+    onChange?: (newValue: Matrix) => void;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+}
+
+export class MatrixLineComponent extends React.Component<IMatrixLineComponentProps, { value: Matrix}> {
+   private _localChange = false;
+
+    constructor(props: IMatrixLineComponentProps) {
+        super(props);
+
+        let matrix: Matrix = this.props.target[this.props.propertyName].clone();
+
+        this.state = { value:matrix }
+    }
+
+    shouldComponentUpdate(nextProps: IMatrixLineComponentProps, nextState: { value: Matrix }) {
+        const nextPropsValue = nextProps.target[nextProps.propertyName];
+
+        if (!nextPropsValue.equals(nextState.value) || this._localChange) {
+            nextState.value = nextPropsValue.clone();
+            this._localChange = false;
+            return true;
+        }
+        return false;
+    }
+
+    raiseOnPropertyChanged(previousValue: Vector3) {
+        if (this.props.onChange) {
+            this.props.onChange(this.state.value);
+        }
+
+        if (!this.props.onPropertyChangedObservable) {
+            return;
+        }
+        this.props.onPropertyChangedObservable.notifyObservers({
+            object: this.props.target,
+            property: this.props.propertyName,
+            value: this.state.value,
+            initialValue: previousValue
+        });
+    }
+
+    updateMatrix() {
+        const store = this.props.target[this.props.propertyName].clone();
+        this.props.target[this.props.propertyName] = this.state.value;
+
+        this.setState({ value: store });
+
+        this.raiseOnPropertyChanged(store);
+    }
+
+    updateRow(value: Vector4, row: number) {
+        this._localChange = true;
+
+        this.state.value.setRow(row, value);
+        this.updateMatrix();
+    }
+
+    render() {
+        return (
+            <div className="vector3Line">
+                <div className="firstLine">
+                    <div className="label">
+                        {this.props.label}
+                    </div>
+                </div>
+                <div className="secondLine">
+                    <Vector4LineComponent label="Row #0" value={this.state.value.getRow(0)!} onChange={value => this.updateRow(value, 0)}/>
+                    <Vector4LineComponent label="Row #1" value={this.state.value.getRow(1)!} onChange={value => this.updateRow(value, 1)}/>
+                    <Vector4LineComponent label="Row #2" value={this.state.value.getRow(2)!} onChange={value => this.updateRow(value, 2)}/>
+                    <Vector4LineComponent label="Row #3" value={this.state.value.getRow(3)!} onChange={value => this.updateRow(value, 3)}/>
+                </div>
+            </div>
+        );
+    }
+}

+ 3 - 3
nodeEditor/src/sharedComponents/textInputLineComponent.tsx

@@ -19,7 +19,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     constructor(props: ITextInputLineComponentProps) {
     constructor(props: ITextInputLineComponentProps) {
         super(props);
         super(props);
 
 
-        this.state = { value: this.props.value || this.props.target[this.props.propertyName!] || "" }
+        this.state = { value: this.props.value !== undefined ? this.props.value : this.props.target[this.props.propertyName!] || "" }
     }
     }
 
 
     shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: { value: string }) {
     shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: { value: string }) {
@@ -28,7 +28,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
             return true;
             return true;
         }
         }
 
 
-        const newValue = nextProps.value || nextProps.target[nextProps.propertyName!];
+        const newValue = nextProps.value !== undefined ? nextProps.value : nextProps.target[nextProps.propertyName!];
         if (newValue !== nextState.value) {
         if (newValue !== nextState.value) {
             nextState.value = newValue || "";
             nextState.value = newValue || "";
             return true;
             return true;
@@ -57,7 +57,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     updateValue(value: string, raisePropertyChanged: boolean) {
     updateValue(value: string, raisePropertyChanged: boolean) {
 
 
         this._localChange = true;
         this._localChange = true;
-        const store = this.props.value || this.props.target[this.props.propertyName!];
+        const store = this.props.value !== undefined ? this.props.value : this.props.target[this.props.propertyName!];
         this.setState({ value: value });
         this.setState({ value: value });
 
 
         if (raisePropertyChanged) {
         if (raisePropertyChanged) {

+ 137 - 0
nodeEditor/src/sharedComponents/vector4LineComponent.tsx

@@ -0,0 +1,137 @@
+import * as React from "react";
+import { Vector4 } from "babylonjs/Maths/math";
+import { Observable } from "babylonjs/Misc/observable";
+
+import { NumericInputComponent } from "./numericInputComponent";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faMinus, faPlus } from "@fortawesome/free-solid-svg-icons";
+import { PropertyChangedEvent } from "./propertyChangedEvent";
+
+interface IVector4LineComponentProps {
+    label: string;
+    target?: any;
+    propertyName?: string;
+    value?: Vector4;
+    step?: number;
+    onChange?: (newvalue: Vector4) => void;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+}
+
+export class Vector4LineComponent extends React.Component<IVector4LineComponentProps, { isExpanded: boolean, value: Vector4 }> {
+
+    static defaultProps = {
+        step: 0.001, // cm
+    };
+
+    private _localChange = false;
+
+    constructor(props: IVector4LineComponentProps) {
+        super(props);
+
+        this.state = { isExpanded: false, value: (this.props.value || this.props.target[this.props.propertyName!]).clone() }
+    }
+
+    shouldComponentUpdate(nextProps: IVector4LineComponentProps, nextState: { isExpanded: boolean, value: Vector4 }) {
+        const nextPropsValue = nextProps.value || nextProps.target[nextProps.propertyName!];
+
+        if (!nextPropsValue.equals(nextState.value) || this._localChange) {
+            nextState.value = nextPropsValue.clone();
+            this._localChange = false;
+            return true;
+        }
+        return false;
+    }
+
+    switchExpandState() {
+        this._localChange = true;
+        this.setState({ isExpanded: !this.state.isExpanded });
+    }
+
+    raiseOnPropertyChanged(previousValue: Vector4) {
+        if (this.props.onChange) {
+            this.props.onChange(this.state.value);
+        }
+
+        if (!this.props.onPropertyChangedObservable || !this.props.propertyName) {
+            return;
+        }
+        this.props.onPropertyChangedObservable.notifyObservers({
+            object: this.props.target,
+            property: this.props.propertyName,
+            value: this.state.value,
+            initialValue: previousValue
+        });
+    }
+
+    updateVector4() {
+        const store = (this.props.value || this.props.target[this.props.propertyName!]).clone();
+        if (this.props.value) {
+            this.props.value.copyFrom(this.state.value);
+        } else {
+            this.props.target[this.props.propertyName!] = this.state.value;
+        }
+
+        this.forceUpdate();
+
+        this.raiseOnPropertyChanged(store);
+    }
+
+
+    updateStateX(value: number) {
+        this._localChange = true;
+
+        this.state.value.x = value;
+        this.updateVector4();
+    }
+
+    updateStateY(value: number) {
+        this._localChange = true;
+
+        this.state.value.y = value;
+        this.updateVector4();
+    }
+
+    updateStateZ(value: number) {
+        this._localChange = true;
+
+        this.state.value.z = value;
+        this.updateVector4();
+    }    
+    
+    updateStateW(value: number) {
+        this._localChange = true;
+
+        this.state.value.w = value;
+        this.updateVector4();
+    }
+
+    render() {
+        const chevron = this.state.isExpanded ? <FontAwesomeIcon icon={faMinus} /> : <FontAwesomeIcon icon={faPlus} />
+
+        return (
+            <div className="vector3Line">
+                <div className="firstLine">
+                    <div className="label">
+                        {this.props.label}
+                    </div>
+                    <div className="vector">
+                        {`X: ${this.state.value.x.toFixed(2)}, Y: ${this.state.value.y.toFixed(2)}, Z: ${this.state.value.z.toFixed(2)}, W: ${this.state.value.w.toFixed(2)}`}
+
+                    </div>
+                    <div className="expand hoverIcon" onClick={() => this.switchExpandState()} title="Expand">
+                        {chevron}
+                    </div>
+                </div>
+                {
+                    this.state.isExpanded &&
+                    <div className="secondLine">
+                        <NumericInputComponent label="x" step={this.props.step} value={this.state.value.x} onChange={value => this.updateStateX(value)} />
+                        <NumericInputComponent label="y" step={this.props.step} value={this.state.value.y} onChange={value => this.updateStateY(value)} />
+                        <NumericInputComponent label="z" step={this.props.step} value={this.state.value.z} onChange={value => this.updateStateZ(value)} />
+                        <NumericInputComponent label="w" step={this.props.step} value={this.state.value.w} onChange={value => this.updateStateW(value)} />
+                    </div>
+                }
+            </div>
+        );
+    }
+}

+ 2 - 26
nodeEditor/src/stringTools.ts

@@ -1,4 +1,5 @@
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPointTypes';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPointTypes';
+import { saveAs } from 'file-saver';
 
 
 export class StringTools {
 export class StringTools {
     /**
     /**
@@ -19,31 +20,6 @@ export class StringTools {
                 type: "application/octet-stream"
                 type: "application/octet-stream"
             });
             });
 
 
-        if (window.navigator.msSaveOrOpenBlob) {
-            window.navigator.msSaveOrOpenBlob(blob, filename);
-            return;
-        }
-
-        var file = new Blob([content], { type: "application/octet-stream" });
-
-        var reader = new FileReader();
-        reader.onload = function(e) {
-            var bdata = btoa(reader.result as string);
-
-            var datauri = 'data:text/plain;base64,' + bdata;
-            setTimeout(() => {
-                let link = document.createElement("a");
-                link.setAttribute("href", datauri);
-                link.setAttribute("download", filename);
-                link.target = "_self";
-                link.style.visibility = 'hidden';
-                document.body.appendChild(link);
-                link.click();
-                setTimeout(function() {
-                    document.body.removeChild(link);
-                }, 0);
-            }, 10);
-        };
-        reader.readAsBinaryString(file);
+        saveAs(blob, filename);        
     }
     }
 }
 }

+ 5 - 3
package.json

@@ -7,7 +7,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.1.0-alpha.17",
+    "version": "4.1.0-alpha.18",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -47,6 +47,7 @@
         "@types/react": "~16.7.3",
         "@types/react": "~16.7.3",
         "@types/react-dom": "~16.0.9",
         "@types/react-dom": "~16.0.9",
         "@types/sinon": "^4.1.3",
         "@types/sinon": "^4.1.3",
+        "@types/file-saver": "~2.0.1",
         "ajv": "^6.9.1",
         "ajv": "^6.9.1",
         "awesome-typescript-loader": "^5.2.1",
         "awesome-typescript-loader": "^5.2.1",
         "base64-font-loader": "0.0.4",
         "base64-font-loader": "0.0.4",
@@ -105,6 +106,7 @@
         "webpack-dev-server": "^3.1.14",
         "webpack-dev-server": "^3.1.14",
         "webpack-stream": "5.0.0",
         "webpack-stream": "5.0.0",
         "xhr2": "^0.1.4",
         "xhr2": "^0.1.4",
-        "xmlbuilder": "8.2.2"
+        "xmlbuilder": "8.2.2",
+        "file-saver": "~2.0.2"
     }
     }
-}
+}

+ 8 - 0
src/Cameras/VR/vrExperienceHelper.ts

@@ -522,6 +522,10 @@ export class VRExperienceHelper {
      * If the gaze trackers color should be updated when selecting meshes
      * If the gaze trackers color should be updated when selecting meshes
      */
      */
     public updateGazeTrackerColor = true;
     public updateGazeTrackerColor = true;
+    /**
+     * If the controller laser color should be updated when selecting meshes
+     */
+    public updateControllerLaserColor = true;
 
 
     /**
     /**
      * The gaze tracking mesh corresponding to the left controller
      * The gaze tracking mesh corresponding to the left controller
@@ -2014,6 +2018,10 @@ export class VRExperienceHelper {
      * @param color new color for the ray.
      * @param color new color for the ray.
      */
      */
     public changeLaserColor(color: Color3) {
     public changeLaserColor(color: Color3) {
+        if (!this.updateControllerLaserColor) {
+            return;
+        }
+
         if (this._leftController) {
         if (this._leftController) {
             this._leftController._setLaserPointerColor(color);
             this._leftController._setLaserPointerColor(color);
 
 

+ 12 - 1
src/Cameras/camera.ts

@@ -5,7 +5,7 @@ import { Observable } from "../Misc/observable";
 import { Nullable } from "../types";
 import { Nullable } from "../types";
 import { CameraInputsManager } from "./cameraInputsManager";
 import { CameraInputsManager } from "./cameraInputsManager";
 import { Scene } from "../scene";
 import { Scene } from "../scene";
-import { Matrix, Vector3 } from "../Maths/math.vector";
+import { Matrix, Vector3, Quaternion } from "../Maths/math.vector";
 import { Node } from "../node";
 import { Node } from "../node";
 import { Mesh } from "../Meshes/mesh";
 import { Mesh } from "../Meshes/mesh";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { AbstractMesh } from "../Meshes/abstractMesh";
@@ -1161,6 +1161,17 @@ export class Camera extends Node {
     }
     }
 
 
     /**
     /**
+     * Returns the current camera absolute rotation
+     */
+    public get absoluteRotation(): Quaternion {
+        var result = Quaternion.Zero();
+
+        this.getWorldMatrix().decompose(undefined, result);
+
+        return result;
+    }
+
+    /**
      * Gets the direction of the camera relative to a given local axis into a passed vector.
      * Gets the direction of the camera relative to a given local axis into a passed vector.
      * @param localAxis Defines the reference axis to provide a relative direction.
      * @param localAxis Defines the reference axis to provide a relative direction.
      * @param result Defines the vector to store the result in
      * @param result Defines the vector to store the result in

+ 2 - 2
src/Engines/engine.ts

@@ -512,14 +512,14 @@ export class Engine {
      */
      */
     // Not mixed with Version for tooling purpose.
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
     public static get NpmPackage(): string {
-        return "babylonjs@4.1.0-alpha.17";
+        return "babylonjs@4.1.0-alpha.18";
     }
     }
 
 
     /**
     /**
      * Returns the current version of the framework
      * Returns the current version of the framework
      */
      */
     public static get Version(): string {
     public static get Version(): string {
-        return "4.1.0-alpha.17";
+        return "4.1.0-alpha.18";
     }
     }
 
 
     /**
     /**

+ 76 - 9
src/Engines/nativeEngine.ts

@@ -18,6 +18,7 @@ import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetC
 import { IPipelineContext } from './IPipelineContext';
 import { IPipelineContext } from './IPipelineContext';
 import { WebRequest } from '../Misc/webRequest';
 import { WebRequest } from '../Misc/webRequest';
 import { NativeShaderProcessor } from './Native/nativeShaderProcessor';
 import { NativeShaderProcessor } from './Native/nativeShaderProcessor';
+import { Logger } from "../Misc/logger";
 
 
 interface INativeEngine {
 interface INativeEngine {
     requestAnimationFrame(callback: () => void): void;
     requestAnimationFrame(callback: () => void): void;
@@ -77,6 +78,10 @@ interface INativeEngine {
     setTexture(uniform: WebGLUniformLocation, texture: Nullable<WebGLTexture>): void;
     setTexture(uniform: WebGLUniformLocation, texture: Nullable<WebGLTexture>): void;
     deleteTexture(texture: Nullable<WebGLTexture>): void;
     deleteTexture(texture: Nullable<WebGLTexture>): void;
 
 
+    createFrameBuffer(texture: WebGLTexture, width: number, height: number, format: number, samplingMode: number, generateStencilBuffer: boolean, generateDepthBuffer: boolean, generateMipMaps: boolean): WebGLFramebuffer;
+    bindFrameBuffer(frameBuffer: WebGLFramebuffer): void;
+    unbindFrameBuffer(frameBuffer: WebGLFramebuffer): void;
+
     drawIndexed(fillMode: number, indexStart: number, indexCount: number): void;
     drawIndexed(fillMode: number, indexStart: number, indexCount: number): void;
     draw(fillMode: number, vertexStart: number, vertexCount: number): void;
     draw(fillMode: number, vertexStart: number, vertexCount: number): void;
 
 
@@ -144,6 +149,11 @@ class NativeAddressMode {
     public static readonly MIRROR_ONCE = 4;
     public static readonly MIRROR_ONCE = 4;
 }
 }
 
 
+class NativeTextureFormat {
+    public static readonly RGBA8 = 0;
+    public static readonly RGBA32F = 1;
+}
+
 /** @hidden */
 /** @hidden */
 declare var nativeEngine: INativeEngine;
 declare var nativeEngine: INativeEngine;
 
 
@@ -1079,7 +1089,19 @@ export class NativeEngine extends Engine {
         }
         }
     }
     }
 
 
-    public createRenderTargetTexture(size: any, options: boolean | RenderTargetCreationOptions): InternalTexture {
+    private static _GetNativeTextureFormat(format: number, type: number): number {
+        if (format == Engine.TEXTUREFORMAT_RGBA && type == Engine.TEXTURETYPE_UNSIGNED_INT) {
+            return NativeTextureFormat.RGBA8;
+        }
+        else if (format == Engine.TEXTUREFORMAT_RGBA && type == Engine.TEXTURETYPE_FLOAT) {
+            return NativeTextureFormat.RGBA32F;
+        }
+        else {
+            throw new Error("Unexpected texture format or type: format " + format + ", type " + type + ".");
+        }
+    }
+
+    public createRenderTargetTexture(size: number | { width: number, height: number }, options: boolean | RenderTargetCreationOptions): InternalTexture {
         let fullOptions = new RenderTargetCreationOptions();
         let fullOptions = new RenderTargetCreationOptions();
 
 
         if (options !== undefined && typeof options === "object") {
         if (options !== undefined && typeof options === "object") {
@@ -1087,21 +1109,46 @@ export class NativeEngine extends Engine {
             fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
             fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
             fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
             fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
             fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
             fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
-            fullOptions.samplingMode = options.samplingMode === undefined ? Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode;
+            fullOptions.samplingMode = options.samplingMode === undefined ? Engine.TEXTURE_TRILINEAR_SAMPLINGMODE : options.samplingMode;
+            fullOptions.format = options.format === undefined ? Engine.TEXTUREFORMAT_RGBA : options.format;
         } else {
         } else {
             fullOptions.generateMipMaps = <boolean>options;
             fullOptions.generateMipMaps = <boolean>options;
             fullOptions.generateDepthBuffer = true;
             fullOptions.generateDepthBuffer = true;
             fullOptions.generateStencilBuffer = false;
             fullOptions.generateStencilBuffer = false;
             fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
             fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
-            fullOptions.samplingMode = Texture.TRILINEAR_SAMPLINGMODE;
+            fullOptions.samplingMode = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE;
+            fullOptions.format = Engine.TEXTUREFORMAT_RGBA;
+        }
+
+        if (fullOptions.type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloatLinearFiltering) {
+            // if floating point linear (gl.FLOAT) then force to NEAREST_SAMPLINGMODE
+            fullOptions.samplingMode = Engine.TEXTURE_NEAREST_SAMPLINGMODE;
+        }
+        else if (fullOptions.type === Engine.TEXTURETYPE_HALF_FLOAT && !this._caps.textureHalfFloatLinearFiltering) {
+            // if floating point linear (HALF_FLOAT) then force to NEAREST_SAMPLINGMODE
+            fullOptions.samplingMode = Engine.TEXTURE_NEAREST_SAMPLINGMODE;
         }
         }
         var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
         var texture = new InternalTexture(this, InternalTexture.DATASOURCE_RENDERTARGET);
 
 
-        var width = size.width || size;
-        var height = size.height || size;
+        var width = (<{ width: number, height: number }>size).width || <number>size;
+        var height = (<{ width: number, height: number }>size).height || <number>size;
 
 
-        texture._depthStencilBuffer = {};
-        texture._framebuffer = {};
+        if (fullOptions.type === Engine.TEXTURETYPE_FLOAT && !this._caps.textureFloat) {
+            fullOptions.type = Engine.TEXTURETYPE_UNSIGNED_INT;
+            Logger.Warn("Float textures are not supported. Render target forced to TEXTURETYPE_UNSIGNED_BYTE type");
+        }
+
+        var framebuffer = this._native.createFrameBuffer(
+            texture._webGLTexture!,
+            width,
+            height,
+            NativeEngine._GetNativeTextureFormat(fullOptions.format, fullOptions.type),
+            fullOptions.samplingMode!,
+            fullOptions.generateStencilBuffer ? true : false,
+            fullOptions.generateDepthBuffer,
+            fullOptions.generateMipMaps ? true : false);
+
+        texture._framebuffer = framebuffer;
         texture.baseWidth = width;
         texture.baseWidth = width;
         texture.baseHeight = height;
         texture.baseHeight = height;
         texture.width = width;
         texture.width = width;
@@ -1111,6 +1158,7 @@ export class NativeEngine extends Engine {
         texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
         texture.generateMipMaps = fullOptions.generateMipMaps ? true : false;
         texture.samplingMode = fullOptions.samplingMode;
         texture.samplingMode = fullOptions.samplingMode;
         texture.type = fullOptions.type;
         texture.type = fullOptions.type;
+        texture.format = fullOptions.format;
         texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
         texture._generateDepthBuffer = fullOptions.generateDepthBuffer;
         texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
         texture._generateStencilBuffer = fullOptions.generateStencilBuffer ? true : false;
 
 
@@ -1128,11 +1176,30 @@ export class NativeEngine extends Engine {
     }
     }
 
 
     public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
     public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {
-        throw new Error("bindFramebuffer not yet implemented.");
+        if (faceIndex) {
+            throw new Error("Cuboid frame buffers are not yet supported in NativeEngine.");
+        }
+
+        if (requiredWidth || requiredHeight) {
+            throw new Error("Required width/height for frame buffers not yet supported in NativeEngine.");
+        }
+
+        if (forceFullscreenViewport) {
+            throw new Error("forceFullscreenViewport for frame buffers not yet supported in NativeEngine.");
+        }
+
+        this._native.bindFrameBuffer(texture._framebuffer!);
     }
     }
 
 
     public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
     public unBindFramebuffer(texture: InternalTexture, disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
-        throw new Error("unBindFramebuffer not yet implemented.");
+        if (disableGenerateMipMaps) {
+            Logger.Warn("Disabling mipmap generation not yet supported in NativeEngine. Ignoring.");
+        }
+
+        if (onBeforeUnbind) {
+            onBeforeUnbind();
+        }
+        this._native.unbindFrameBuffer(texture._framebuffer!);
     }
     }
 
 
     public createDynamicVertexBuffer(data: DataArray): DataBuffer {
     public createDynamicVertexBuffer(data: DataArray): DataBuffer {

+ 6 - 0
src/Helpers/photoDome.ts

@@ -75,6 +75,12 @@ export class PhotoDome extends TransformNode {
      * The surface used for the skybox
      * The surface used for the skybox
      */
      */
     protected _mesh: Mesh;
     protected _mesh: Mesh;
+    /**
+     * Gets the mesh used for the skybox.
+     */
+    public get mesh(): Mesh {
+        return this._mesh;
+    }
 
 
     /**
     /**
      * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".
      * The current fov(field of view) multiplier, 0.0 - 2.0. Defaults to 1.0. Lower values "zoom in" and higher values "zoom out".

+ 1 - 2
src/Materials/Node/Blocks/Dual/fogBlock.ts

@@ -121,9 +121,8 @@ export class FogBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
         super._buildBlock(state);
 
 
-        state.sharedData.blocksWithDefines.push(this);
-
         if (state.target === NodeMaterialBlockTargets.Fragment) {
         if (state.target === NodeMaterialBlockTargets.Fragment) {
+            state.sharedData.blocksWithDefines.push(this);
             state.sharedData.bindableBlocks.push(this);
             state.sharedData.bindableBlocks.push(this);
 
 
             state._emitFunctionFromInclude("fogFragmentDeclaration", `//${this.name}`, {
             state._emitFunctionFromInclude("fogFragmentDeclaration", `//${this.name}`, {

+ 2 - 9
src/Materials/Node/Blocks/Dual/lightBlock.ts

@@ -34,7 +34,7 @@ export class LightBlock extends NodeMaterialBlock {
         super(name, NodeMaterialBlockTargets.VertexAndFragment);
         super(name, NodeMaterialBlockTargets.VertexAndFragment);
 
 
         this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Vertex);
         this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Vertex);
-        this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Vertex);
+        this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false, NodeMaterialBlockTargets.Fragment);
 
 
         this.registerInput("cameraPosition", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Fragment);
         this.registerInput("cameraPosition", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -147,8 +147,6 @@ export class LightBlock extends NodeMaterialBlock {
 
 
     private _injectVertexCode(state: NodeMaterialBuildState) {
     private _injectVertexCode(state: NodeMaterialBuildState) {
         let worldPos = this.worldPosition;
         let worldPos = this.worldPosition;
-        let worldNormal = this.worldNormal;
-
         let comments = `//${this.name}`;
         let comments = `//${this.name}`;
 
 
         // Declaration
         // Declaration
@@ -175,11 +173,6 @@ export class LightBlock extends NodeMaterialBlock {
             state.compilationString += `${worldPosVaryingName} = ${worldPos.associatedVariableName};\r\n`;
             state.compilationString += `${worldPosVaryingName} = ${worldPos.associatedVariableName};\r\n`;
         }
         }
 
 
-        let worldNormalVaryingName = "v_" + worldNormal.associatedVariableName;
-        if (state._emitVaryingFromString(worldNormalVaryingName, "vec4")) {
-            state.compilationString += `${worldNormalVaryingName} = ${worldNormal.associatedVariableName};\r\n`;
-        }
-
         if (this.light) {
         if (this.light) {
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
                 replaceStrings: [
                 replaceStrings: [
@@ -249,7 +242,7 @@ export class LightBlock extends NodeMaterialBlock {
             state.compilationString += `float glossiness = 0.;\r\n`;
             state.compilationString += `float glossiness = 0.;\r\n`;
             state.compilationString += `vec3 diffuseBase = vec3(0., 0., 0.);\r\n`;
             state.compilationString += `vec3 diffuseBase = vec3(0., 0., 0.);\r\n`;
             state.compilationString += `vec3 specularBase = vec3(0., 0., 0.);\r\n`;
             state.compilationString += `vec3 specularBase = vec3(0., 0., 0.);\r\n`;
-            state.compilationString += `vec3 normalW = v_${this.worldNormal.associatedVariableName}.xyz;\r\n`;
+            state.compilationString += `vec3 normalW = ${this.worldNormal.associatedVariableName}.xyz;\r\n`;
         }
         }
 
 
         if (this.light) {
         if (this.light) {

+ 5 - 1
src/Materials/Node/Blocks/Dual/textureBlock.ts

@@ -109,6 +109,8 @@ export class TextureBlock extends NodeMaterialBlock {
     }
     }
 
 
     public get target() {
     public get target() {
+        // TextureBlock has a special optimizations for uvs that come from the vertex shaders as they can be packed into a single varyings.
+        // But we need to detect uvs coming from fragment then
         if (!this.uv.isConnected) {
         if (!this.uv.isConnected) {
             return NodeMaterialBlockTargets.VertexAndFragment;
             return NodeMaterialBlockTargets.VertexAndFragment;
         }
         }
@@ -251,7 +253,7 @@ export class TextureBlock extends NodeMaterialBlock {
         state.compilationString += `#ifdef ${this._defineName}\r\n`;
         state.compilationString += `#ifdef ${this._defineName}\r\n`;
         state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${this._transformedUVName}).${swizzle}${complement};\r\n`;
         state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${this._transformedUVName}).${swizzle}${complement};\r\n`;
         state.compilationString += `#else\r\n`;
         state.compilationString += `#else\r\n`;
-        state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${"vMain" + uvInput.associatedVariableName}).${swizzle}${complement};\r\n`;
+        state.compilationString += `${this._declareOutput(output, state)} = texture2D(${this._samplerName}, ${this._mainUVName}).${swizzle}${complement};\r\n`;
         state.compilationString += `#endif\r\n`;
         state.compilationString += `#endif\r\n`;
     }
     }
 
 
@@ -293,6 +295,8 @@ export class TextureBlock extends NodeMaterialBlock {
         }
         }
 
 
         var codeString = `${this._codeVariableName}.texture = new BABYLON.Texture("${this.texture.name}");\r\n`;
         var codeString = `${this._codeVariableName}.texture = new BABYLON.Texture("${this.texture.name}");\r\n`;
+        codeString += `${this._codeVariableName}.texture.wrapU = ${this.texture.wrapU};\r\n`;
+        codeString += `${this._codeVariableName}.texture.wrapV = ${this.texture.wrapV};\r\n`;
 
 
         return codeString;
         return codeString;
     }
     }

+ 2 - 1
src/Materials/Node/Blocks/Fragment/index.ts

@@ -1,4 +1,5 @@
 
 
 export * from "./fragmentOutputBlock";
 export * from "./fragmentOutputBlock";
 export * from "./alphaTestBlock";
 export * from "./alphaTestBlock";
-export * from "./imageProcessingBlock";
+export * from "./imageProcessingBlock";
+export * from "./perturbNormalBlock";

+ 182 - 0
src/Materials/Node/Blocks/Fragment/perturbNormalBlock.ts

@@ -0,0 +1,182 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
+import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
+import { _TypeStore } from '../../../../Misc/typeStore';
+import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
+import { InputBlock } from '../Input/inputBlock';
+import { Effect } from '../../../effect';
+import { Mesh } from '../../../../Meshes/mesh';
+import { Scene } from '../../../../scene';
+
+/**
+ * Block used to pertub normals based on a normal map
+ */
+export class PerturbNormalBlock extends NodeMaterialBlock {
+    private _tangentSpaceParameterName = "";
+
+    /** Gets or sets a boolean indicating that normal should be inverted on X axis */
+    public invertX = false;
+    /** Gets or sets a boolean indicating that normal should be inverted on Y axis */
+    public invertY = false;
+
+    /**
+     * Create a new PerturbNormalBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Neutral);
+
+        // Vertex
+        this.registerInput("worldPosition", NodeMaterialBlockConnectionPointTypes.Vector4, false);
+        this.registerInput("worldNormal", NodeMaterialBlockConnectionPointTypes.Vector4, false);
+        this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false);
+        this.registerInput("normalMapColor", NodeMaterialBlockConnectionPointTypes.Color3, false);
+        this.registerInput("strength", NodeMaterialBlockConnectionPointTypes.Float, false);
+
+        // Fragment
+        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "PerturbNormalBlock";
+    }
+
+    /**
+     * Gets the world position input component
+     */
+    public get worldPosition(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the world normal input component
+     */
+    public get worldNormal(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the uv input component
+     */
+    public get uv(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+    * Gets the normal map color input component
+    */
+    public get normalMapColor(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
+    /**
+    * Gets the strength input component
+    */
+    public get strength(): NodeMaterialConnectionPoint {
+        return this._inputs[4];
+    }
+
+    /**
+     * Gets the output component
+     */
+    public get output(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        defines.setValue("BUMP", true);
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
+        effect.setFloat2(this._tangentSpaceParameterName, this.invertX ? -1 : 1, this.invertY ? -1 : 1);
+    }
+
+    public autoConfigure(material: NodeMaterial) {
+        if (!this.uv.isConnected) {
+            let uvInput = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "uv");
+
+            if (!uvInput) {
+                uvInput = new InputBlock("uv");
+                uvInput.setAsAttribute();
+            }
+            uvInput.output.connectTo(this.uv);
+        }
+
+        if (!this.strength.isConnected) {
+            let strengthInput = new InputBlock("strength");
+            strengthInput.value = 1.0;
+            strengthInput.output.connectTo(this.strength);
+        }
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        let comments = `//${this.name}`;
+        let uv = this.uv;
+        let worldPosition = this.worldPosition;
+        let worldNormal = this.worldNormal;
+
+        state.sharedData.blocksWithDefines.push(this);
+        state.sharedData.bindableBlocks.push(this);
+
+        this._tangentSpaceParameterName = state._getFreeDefineName("tangentSpaceParameter");
+
+        state._emitUniformFromString(this._tangentSpaceParameterName, "vec2");
+
+        state._emitExtension("bump", "#extension GL_OES_standard_derivatives : enable");
+        state._emitFunctionFromInclude("bumpFragmentFunctions", comments, {
+            replaceStrings: [
+                { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
+                { search: /vTangentSpaceParams/g, replace: this._tangentSpaceParameterName},
+                { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"}
+            ]
+        });
+        state.compilationString += this._declareOutput(this.output, state) + " = vec4(0.);\r\n";
+        state.compilationString += state._emitCodeFromInclude("bumpFragment", comments, {
+            replaceStrings: [
+                { search: /perturbNormal\(TBN,vBumpUV\+uvOffset\)/g, replace: `perturbNormal(TBN, ${this.normalMapColor.associatedVariableName})` },
+                { search: /vBumpInfos.y/g, replace: `1.0 / ${this.strength.associatedVariableName}`},
+                { search: /vBumpUV/g, replace: uv.associatedVariableName},
+                { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
+                { search: /normalW=/g, replace: this.output.associatedVariableName + ".xyz = " },
+                { search: /normalW/g, replace: worldNormal.associatedVariableName + ".xyz" }
+            ]
+        });
+
+        return this;
+    }
+
+    protected _dumpPropertiesCode() {
+        var codeString = `${this._codeVariableName}.invertX = ${this.invertX};\r\n`;
+
+        codeString += `${this._codeVariableName}.invertY = ${this.invertY};\r\n`;
+
+        return codeString;
+    }
+
+    public serialize(): any {
+        let serializationObject = super.serialize();
+
+        serializationObject.invertX = this.invertX;
+        serializationObject.invertY = this.invertY;
+
+        return serializationObject;
+    }
+
+    public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
+        super._deserialize(serializationObject, scene, rootUrl);
+
+        this.invertX = serializationObject.invertX;
+        this.invertY = serializationObject.invertY;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.PerturbNormalBlock"] = PerturbNormalBlock;

+ 4 - 0
src/Materials/Node/Blocks/Input/inputBlock.ts

@@ -299,6 +299,10 @@ export class InputBlock extends NodeMaterialBlock {
         return `#ifdef ${define}\r\n`;
         return `#ifdef ${define}\r\n`;
     }
     }
 
 
+    public initialize(state: NodeMaterialBuildState) {
+        this.associatedVariableName = "";
+    }
+
     /**
     /**
      * Set the input block to its default value (based on its type)
      * Set the input block to its default value (based on its type)
      */
      */

+ 1 - 1
src/Materials/Node/Blocks/fresnelBlock.ts

@@ -91,7 +91,7 @@ export class FresnelBlock extends NodeMaterialBlock {
 
 
         state._emitFunctionFromInclude("fresnelFunction", comments, {removeIfDef: true});
         state._emitFunctionFromInclude("fresnelFunction", comments, {removeIfDef: true});
 
 
-        state.compilationString += this._declareOutput(this.fresnel, state) + ` = computeFresnelTerm(${this.viewDirection.associatedVariableName}, ${this.worldNormal.associatedVariableName}, ${this.bias.associatedVariableName}, ${this.power.associatedVariableName});\r\n`;
+        state.compilationString += this._declareOutput(this.fresnel, state) + ` = computeFresnelTerm(${this.viewDirection.associatedVariableName}.xyz, ${this.worldNormal.associatedVariableName}.xyz, ${this.bias.associatedVariableName}, ${this.power.associatedVariableName});\r\n`;
 
 
         return this;
         return this;
     }
     }

+ 1 - 1
src/Materials/Node/Blocks/index.ts

@@ -20,7 +20,7 @@ export * from "./lerpBlock";
 export * from "./divideBlock";
 export * from "./divideBlock";
 export * from "./subtractBlock";
 export * from "./subtractBlock";
 export * from "./stepBlock";
 export * from "./stepBlock";
-export * from "./oppositeBlock";
+export * from "./oneMinusBlock";
 export * from "./viewDirectionBlock";
 export * from "./viewDirectionBlock";
 export * from "./fresnelBlock";
 export * from "./fresnelBlock";
 export * from "./maxBlock";
 export * from "./maxBlock";

+ 6 - 5
src/Materials/Node/Blocks/oppositeBlock.ts

@@ -5,11 +5,11 @@ import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint
 import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
 import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
 import { _TypeStore } from '../../../Misc/typeStore';
 import { _TypeStore } from '../../../Misc/typeStore';
 /**
 /**
- * Block used to get the opposite of a value
+ * Block used to get the opposite (1 - x) of a value
  */
  */
-export class OppositeBlock extends NodeMaterialBlock {
+export class OneMinusBlock extends NodeMaterialBlock {
     /**
     /**
-     * Creates a new OppositeBlock
+     * Creates a new OneMinusBlock
      * @param name defines the block name
      * @param name defines the block name
      */
      */
     public constructor(name: string) {
     public constructor(name: string) {
@@ -26,7 +26,7 @@ export class OppositeBlock extends NodeMaterialBlock {
      * @returns the class name
      * @returns the class name
      */
      */
     public getClassName() {
     public getClassName() {
-        return "OppositeBlock";
+        return "OneMinusBlock";
     }
     }
 
 
     /**
     /**
@@ -54,4 +54,5 @@ export class OppositeBlock extends NodeMaterialBlock {
     }
     }
 }
 }
 
 
-_TypeStore.RegisteredTypes["BABYLON.OppositeBlock"] = OppositeBlock;
+_TypeStore.RegisteredTypes["BABYLON.OneMinusBlock"] = OneMinusBlock;
+_TypeStore.RegisteredTypes["BABYLON.OppositeBlock"] = OneMinusBlock; // Backward compatibility

+ 40 - 1
src/Materials/Node/Blocks/remapBlock.ts

@@ -28,6 +28,11 @@ export class RemapBlock extends NodeMaterialBlock {
         super(name, NodeMaterialBlockTargets.Neutral);
         super(name, NodeMaterialBlockTargets.Neutral);
 
 
         this.registerInput("input", NodeMaterialBlockConnectionPointTypes.AutoDetect);
         this.registerInput("input", NodeMaterialBlockConnectionPointTypes.AutoDetect);
+        this.registerInput("sourceMin", NodeMaterialBlockConnectionPointTypes.Float, true);
+        this.registerInput("sourceMax", NodeMaterialBlockConnectionPointTypes.Float, true);
+        this.registerInput("targetMin", NodeMaterialBlockConnectionPointTypes.Float, true);
+        this.registerInput("targetMax", NodeMaterialBlockConnectionPointTypes.Float, true);
+
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.BasedOnInput);
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.BasedOnInput);
 
 
         this._outputs[0]._typeConnectionSource = this._inputs[0];
         this._outputs[0]._typeConnectionSource = this._inputs[0];
@@ -49,6 +54,34 @@ export class RemapBlock extends NodeMaterialBlock {
     }
     }
 
 
     /**
     /**
+     * Gets the source min input component
+     */
+    public get sourceMin(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the source max input component
+     */
+    public get sourceMax(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+     * Gets the target min input component
+     */
+    public get targetMin(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
+    /**
+     * Gets the target max input component
+     */
+    public get targetMax(): NodeMaterialConnectionPoint {
+        return this._inputs[4];
+    }
+
+    /**
      * Gets the output component
      * Gets the output component
      */
      */
     public get output(): NodeMaterialConnectionPoint {
     public get output(): NodeMaterialConnectionPoint {
@@ -60,7 +93,13 @@ export class RemapBlock extends NodeMaterialBlock {
 
 
         let output = this._outputs[0];
         let output = this._outputs[0];
 
 
-        state.compilationString += this._declareOutput(output, state) + ` = ${this._writeFloat(this.targetRange.x)} + (${this._inputs[0].associatedVariableName} - ${this._writeFloat(this.sourceRange.x)}) * (${this._writeFloat(this.targetRange.y)} - ${this._writeFloat(this.targetRange.x)}) / (${this._writeFloat(this.sourceRange.y)} - ${this._writeFloat(this.sourceRange.x)});\r\n`;
+        let sourceMin = this.sourceMin.isConnected ? this.sourceMin.associatedVariableName : this._writeFloat(this.sourceRange.x);
+        let sourceMax = this.sourceMax.isConnected ? this.sourceMax.associatedVariableName : this._writeFloat(this.sourceRange.y);
+
+        let targetMin = this.targetMin.isConnected ? this.targetMin.associatedVariableName : this._writeFloat(this.targetRange.x);
+        let targetMax = this.targetMax.isConnected ? this.targetMax.associatedVariableName : this._writeFloat(this.targetRange.y);
+
+        state.compilationString += this._declareOutput(output, state) + ` = ${targetMin} + (${this._inputs[0].associatedVariableName} - ${sourceMin}) * (${targetMax} - ${targetMin}) / (${sourceMax} - ${sourceMin});\r\n`;
 
 
         return this;
         return this;
     }
     }

+ 4 - 3
src/Materials/Node/nodeMaterial.ts

@@ -71,6 +71,9 @@ export class NodeMaterialDefines extends MaterialDefines implements IImageProces
     public SAMPLER3DBGRMAP = false;
     public SAMPLER3DBGRMAP = false;
     public IMAGEPROCESSINGPOSTPROCESS = false;
     public IMAGEPROCESSINGPOSTPROCESS = false;
 
 
+    /** MISC. */
+    public BUMPDIRECTUV = 0;
+
     constructor() {
     constructor() {
         super();
         super();
         this.rebuild();
         this.rebuild();
@@ -464,9 +467,7 @@ export class NodeMaterial extends PushMaterial {
         }
         }
 
 
         for (var input of node.inputs) {
         for (var input of node.inputs) {
-            if (!node.isInput) {
-                input.associatedVariableName = "";
-            }
+            input.associatedVariableName = "";
 
 
             let connectedPoint = input.connectedPoint;
             let connectedPoint = input.connectedPoint;
             if (connectedPoint) {
             if (connectedPoint) {

+ 1 - 1
src/Materials/Node/nodeMaterialBlock.ts

@@ -399,7 +399,7 @@ export class NodeMaterialBlock {
         const otherBlockWasGeneratedInVertexShader = block._buildTarget === NodeMaterialBlockTargets.Vertex && block.target !== NodeMaterialBlockTargets.VertexAndFragment;
         const otherBlockWasGeneratedInVertexShader = block._buildTarget === NodeMaterialBlockTargets.Vertex && block.target !== NodeMaterialBlockTargets.VertexAndFragment;
 
 
         if (localBlockIsFragment && (
         if (localBlockIsFragment && (
-            ((block.target & this.target) === 0) ||
+            ((block.target & input.target) === 0) ||
             (this.target !== NodeMaterialBlockTargets.VertexAndFragment && otherBlockWasGeneratedInVertexShader)
             (this.target !== NodeMaterialBlockTargets.VertexAndFragment && otherBlockWasGeneratedInVertexShader)
             )) { // context switch! We need a varying
             )) { // context switch! We need a varying
             if ((!block.isInput && state.target !== block._buildTarget) // block was already emitted by vertex shader
             if ((!block.isInput && state.target !== block._buildTarget) // block was already emitted by vertex shader

+ 0 - 0
src/Materials/Node/nodeMaterialBuildState.ts


Деякі файли не було показано, через те що забагато файлів було змінено