Sfoglia il codice sorgente

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

PirateJC 5 anni fa
parent
commit
82ae9d4981
51 ha cambiato i file con 4116 aggiunte e 1000 eliminazioni
  1. 351 105
      dist/preview release/babylon.d.ts
  2. 2 2
      dist/preview release/babylon.js
  3. 877 155
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 730 217
      dist/preview release/babylon.module.d.ts
  6. 351 105
      dist/preview release/documentation.d.ts
  7. 3 0
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  8. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.js.map
  9. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  10. 3 0
      dist/preview release/materialsLibrary/babylonjs.materials.js
  11. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js.map
  12. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  13. 2 2
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  14. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  15. 15 4
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  16. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  17. 7 4
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  18. 730 217
      dist/preview release/viewer/babylon.module.d.ts
  19. 47 39
      dist/preview release/viewer/babylon.viewer.js
  20. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  21. 5 0
      dist/preview release/what's new.md
  22. 4 0
      materialsLibrary/src/custom/pbrCustomMaterial.ts
  23. 6 0
      nodeEditor/src/blockTools.ts
  24. 3 1
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  25. 2 1
      nodeEditor/src/diagram/display/textureDisplayManager.ts
  26. 1 0
      nodeEditor/src/diagram/displayLedger.ts
  27. 5 4
      nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx
  28. 1 0
      nodeEditor/src/diagram/propertyLedger.ts
  29. 13 13
      src/Audio/sound.ts
  30. 13 12
      src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts
  31. 2 2
      src/Materials/Node/Blocks/PBR/ambientOcclusionBlock.ts
  32. 1 1
      src/Materials/Node/Blocks/PBR/anisotropyBlock.ts
  33. 50 9
      src/Materials/Node/Blocks/PBR/clearCoatBlock.ts
  34. 2 0
      src/Materials/Node/Blocks/PBR/index.ts
  35. 75 29
      src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts
  36. 5 5
      src/Materials/Node/Blocks/PBR/reflectionBlock.ts
  37. 6 6
      src/Materials/Node/Blocks/PBR/reflectivityBlock.ts
  38. 338 0
      src/Materials/Node/Blocks/PBR/refractionBlock.ts
  39. 4 4
      src/Materials/Node/Blocks/PBR/sheenBlock.ts
  40. 267 0
      src/Materials/Node/Blocks/PBR/subSurfaceBlock.ts
  41. 7 2
      src/Materials/Node/nodeMaterial.ts
  42. 2 1
      src/Materials/Node/nodeMaterialBuildStateSharedData.ts
  43. 3 3
      src/Misc/assetsManager.ts
  44. 49 1
      src/Particles/solidParticle.ts
  45. 51 29
      src/Particles/solidParticleSystem.ts
  46. 2 4
      src/Shaders/ShadersInclude/pbrBlockSubSurface.fx
  47. 6 3
      src/Shaders/pbr.fragment.fx
  48. 25 0
      src/XR/motionController/webXRAbstractMotionController.ts
  49. 21 7
      src/XR/webXRDefaultExperience.ts
  50. 7 1
      src/XR/webXRInput.ts
  51. 14 4
      src/XR/webXRInputSource.ts

+ 351 - 105
dist/preview release/babylon.d.ts

@@ -27512,6 +27512,7 @@ declare module BABYLON {
         private _materialIndexesById;
         private _materialIndexesById;
         private _defaultMaterial;
         private _defaultMaterial;
         private _autoUpdateSubMeshes;
         private _autoUpdateSubMeshes;
+        private _tmpVertex;
         /**
         /**
          * Creates a SPS (Solid Particle System) object.
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -27914,13 +27915,13 @@ declare module BABYLON {
          * Updates a vertex of a particle : it can be overwritten by the user.
          * Updates a vertex of a particle : it can be overwritten by the user.
          * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
          * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
          * @param particle the current particle
          * @param particle the current particle
-         * @param vertex the current index of the current particle
+         * @param vertex the current vertex of the current particle : a SolidParticleVertex object
          * @param pt the index of the current vertex in the particle shape
          * @param pt the index of the current vertex in the particle shape
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
-         * @example : just set a vertex particle position
-         * @returns the updated vertex
+         * @example : just set a vertex particle position or color
+         * @returns the sps
          */
          */
-        updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3;
+        updateParticleVertex(particle: SolidParticle, vertex: SolidParticleVertex, pt: number): SolidParticleSystem;
         /**
         /**
          * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
          * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
          * This does nothing and may be overwritten by the user.
          * This does nothing and may be overwritten by the user.
@@ -28218,6 +28219,36 @@ declare module BABYLON {
          */
          */
         constructor(idx: number, ind: number, indLength: number, materialIndex: number);
         constructor(idx: number, ind: number, indLength: number, materialIndex: number);
     }
     }
+    /**
+     * Represents a solid particle vertex
+     */
+    export class SolidParticleVertex {
+        /**
+         * Vertex position
+         */
+        position: Vector3;
+        /**
+         * Vertex color
+         */
+        color: Color4;
+        /**
+         * Vertex UV
+         */
+        uv: Vector2;
+        /**
+         * Creates a new solid particle vertex
+         */
+        constructor();
+        /** Vertex x coordinate */
+        get x(): number;
+        set x(val: number);
+        /** Vertex y coordinate */
+        get y(): number;
+        set y(val: number);
+        /** Vertex z coordinate */
+        get z(): number;
+        set z(val: number);
+    }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
@@ -44304,6 +44335,12 @@ declare module BABYLON {
              */
              */
             pressed: boolean;
             pressed: boolean;
         }>;
         }>;
+        /**
+         * EXPERIMENTAL haptic support.
+         */
+        hapticActuators?: Array<{
+            pulse: (value: number, duration: number) => Promise<boolean>;
+        }>;
     }
     }
     /**
     /**
      * An Abstract Motion controller
      * An Abstract Motion controller
@@ -44410,6 +44447,17 @@ declare module BABYLON {
          * Backwards compatibility due to a deeply-integrated typo
          * Backwards compatibility due to a deeply-integrated typo
          */
          */
         get handness(): XREye;
         get handness(): XREye;
+        /**
+         * Pulse (vibrate) this controller
+         * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called
+         * Consecutive calls to this function will cancel the last pulse call
+         *
+         * @param value the strength of the pulse in 0.0...1.0 range
+         * @param duration Duration of the pulse in milliseconds
+         * @param hapticActuatorIndex optional index of actuator (will usually be 0)
+         * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued
+         */
+        pulse(value: number, duration: number, hapticActuatorIndex?: number): Promise<boolean>;
         protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh;
         /**
         /**
@@ -44646,6 +44694,11 @@ declare module BABYLON {
          * This can be used when creating your own profile or when testing different controllers
          * This can be used when creating your own profile or when testing different controllers
          */
          */
         forceControllerProfile?: string;
         forceControllerProfile?: string;
+        /**
+         * Defines a rendering group ID for meshes that will be loaded.
+         * This is for the default controllers only.
+         */
+        renderingGroupId?: number;
     }
     }
     /**
     /**
      * Represents an XR controller
      * Represents an XR controller
@@ -44749,6 +44802,10 @@ declare module BABYLON {
          * Should the controller model's components not move according to the user input
          * Should the controller model's components not move according to the user input
          */
          */
         disableControllerAnimation?: boolean;
         disableControllerAnimation?: boolean;
+        /**
+         * Optional options to pass to the controller. Will be overridden by the Input options where applicable
+         */
+        controllerOptions?: IWebXRControllerOptions;
     }
     }
     /**
     /**
      * XR input used to track XR inputs such as controllers/rays
      * XR input used to track XR inputs such as controllers/rays
@@ -45506,6 +45563,10 @@ declare module BABYLON {
          * When loading teleportation and pointer select, use stable versions instead of latest.
          * When loading teleportation and pointer select, use stable versions instead of latest.
          */
          */
         useStablePlugins?: boolean;
         useStablePlugins?: boolean;
+        /**
+         * An optional rendering group id that will be set globally for teleportation, pointer selection and default controller meshes
+         */
+        renderingGroupId?: number;
     }
     }
     /**
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -57683,7 +57744,8 @@ declare module BABYLON {
         protected _reflectionVectorName: string;
         protected _reflectionVectorName: string;
         /** @hidden */
         /** @hidden */
         _reflectionCoordsName: string;
         _reflectionCoordsName: string;
-        protected _reflectionMatrixName: string;
+        /** @hidden */
+        _reflectionMatrixName: string;
         protected _reflectionColorName: string;
         protected _reflectionColorName: string;
         /**
         /**
          * Gets or sets the texture associated with the node
          * Gets or sets the texture associated with the node
@@ -57769,6 +57831,184 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Defines a connection point to be used for points with a custom object type
+     */
+    export class NodeMaterialConnectionPointCustomObject<T extends NodeMaterialBlock> extends NodeMaterialConnectionPoint {
+        private _blockType;
+        private _blockName;
+        private _nameForCheking?;
+        /**
+         * Creates a new connection point
+         * @param name defines the connection point name
+         * @param ownerBlock defines the block hosting this connection point
+         * @param direction defines the direction of the connection point
+         */
+        constructor(name: string, ownerBlock: NodeMaterialBlock, direction: NodeMaterialConnectionPointDirection, _blockType: new (...args: any[]) => T, _blockName: string, _nameForCheking?: string | undefined);
+        /**
+         * Gets a number indicating if the current point can be connected to another point
+         * @param connectionPoint defines the other connection point
+         * @returns a number defining the compatibility state
+         */
+        checkCompatibilityState(connectionPoint: NodeMaterialConnectionPoint): NodeMaterialConnectionPointCompatibilityStates;
+        /**
+         * Creates a block suitable to be used as an input for this input point.
+         * If null is returned, a block based on the point type will be created.
+         * @returns The returned string parameter is the name of the output point of NodeMaterialBlock (first parameter of the returned array) that can be connected to the input
+         */
+        createCustomInputBlock(): Nullable<[NodeMaterialBlock, string]>;
+    }
+}
+declare module BABYLON {
+    /**
+     * Enum defining the type of properties that can be edited in the property pages in the NME
+     */
+    export enum PropertyTypeForEdition {
+        /** property is a boolean */
+        Boolean = 0,
+        /** property is a float */
+        Float = 1,
+        /** property is a Vector2 */
+        Vector2 = 2,
+        /** property is a list of values */
+        List = 3
+    }
+    /**
+     * Interface that defines an option in a variable of type list
+     */
+    export interface IEditablePropertyListOption {
+        /** label of the option */
+        "label": string;
+        /** value of the option */
+        "value": number;
+    }
+    /**
+     * Interface that defines the options available for an editable property
+     */
+    export interface IEditablePropertyOption {
+        /** min value */
+        "min"?: number;
+        /** max value */
+        "max"?: number;
+        /** notifiers: indicates which actions to take when the property is changed */
+        "notifiers"?: {
+            /** the material should be rebuilt */
+            "rebuild"?: boolean;
+            /** the preview should be updated */
+            "update"?: boolean;
+        };
+        /** list of the options for a variable of type list */
+        "options"?: IEditablePropertyListOption[];
+    }
+    /**
+     * Interface that describes an editable property
+     */
+    export interface IPropertyDescriptionForEdition {
+        /** name of the property */
+        "propertyName": string;
+        /** display name of the property */
+        "displayName": string;
+        /** type of the property */
+        "type": PropertyTypeForEdition;
+        /** group of the property - all properties with the same group value will be displayed in a specific section */
+        "groupName": string;
+        /** options for the property */
+        "options": IEditablePropertyOption;
+    }
+    /**
+     * Decorator that flags a property in a node material block as being editable
+     */
+    export function editableInPropertyPage(displayName: string, propertyType?: PropertyTypeForEdition, groupName?: string, options?: IEditablePropertyOption): (target: any, propertyKey: string) => void;
+}
+declare module BABYLON {
+    /**
+     * Block used to implement the refraction part of the sub surface module of the PBR material
+     */
+    export class RefractionBlock extends NodeMaterialBlock {
+        /** @hidden */
+        _define3DName: string;
+        /** @hidden */
+        _refractionMatrixName: string;
+        /** @hidden */
+        _defineLODRefractionAlpha: string;
+        /** @hidden */
+        _defineLinearSpecularRefraction: string;
+        /** @hidden */
+        _defineOppositeZ: string;
+        /** @hidden */
+        _cubeSamplerName: string;
+        /** @hidden */
+        _2DSamplerName: string;
+        /** @hidden */
+        _vRefractionMicrosurfaceInfosName: string;
+        /** @hidden */
+        _vRefractionInfosName: string;
+        private _scene;
+        /**
+         * This parameters will make the material used its opacity to control how much it is refracting aginst not.
+         * Materials half opaque for instance using refraction could benefit from this control.
+         */
+        linkRefractionWithTransparency: boolean;
+        /**
+         * Controls if refraction needs to be inverted on Y. This could be useful for procedural texture.
+         */
+        invertRefractionY: boolean;
+        /**
+         * Gets or sets the texture associated with the node
+         */
+        texture: Nullable<BaseTexture>;
+        /**
+         * Create a new RefractionBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the intensity input component
+         */
+        get intensity(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the index of refraction input component
+         */
+        get indexOfRefraction(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the tint at distance input component
+         */
+        get tintAtDistance(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the view input component
+         */
+        get view(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the refraction object output component
+         */
+        get refraction(): NodeMaterialConnectionPoint;
+        /**
+         * Returns true if the block has a texture
+         */
+        get hasTexture(): boolean;
+        protected _getTexture(): Nullable<BaseTexture>;
+        autoConfigure(material: NodeMaterial): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        isReady(): boolean;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
+        /**
+         * Gets the main code of the block (fragment side)
+         * @param state current state of the node material building
+         * @returns the shader code
+         */
+        getCode(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Interface used to configure the node material editor
      * Interface used to configure the node material editor
      */
      */
     export interface INodeMaterialEditorOptions {
     export interface INodeMaterialEditorOptions {
@@ -57808,7 +58048,7 @@ declare module BABYLON {
         /** MISC. */
         /** MISC. */
         BUMPDIRECTUV: number;
         BUMPDIRECTUV: number;
         constructor();
         constructor();
-        setValue(name: string, value: any): void;
+        setValue(name: string, value: any, markAsUnprocessedIfDirty?: boolean): void;
     }
     }
     /**
     /**
      * Class used to configure NodeMaterial
      * Class used to configure NodeMaterial
@@ -58026,7 +58266,7 @@ declare module BABYLON {
          * Gets the list of texture blocks
          * Gets the list of texture blocks
          * @returns an array of texture blocks
          * @returns an array of texture blocks
          */
          */
-        getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock)[];
+        getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock | RefractionBlock)[];
         /**
         /**
          * Specifies if the material uses a texture
          * Specifies if the material uses a texture
          * @param texture defines the texture to check against the material
          * @param texture defines the texture to check against the material
@@ -58224,7 +58464,7 @@ declare module BABYLON {
         /**
         /**
          * Input blocks
          * Input blocks
          */
          */
-        textureBlocks: (ReflectionTextureBaseBlock | TextureBlock)[];
+        textureBlocks: (ReflectionTextureBaseBlock | TextureBlock | RefractionBlock)[];
         /**
         /**
          * Bindable blocks (Blocks that need to set data to the effect)
          * Bindable blocks (Blocks that need to set data to the effect)
          */
          */
@@ -59215,67 +59455,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Enum defining the type of properties that can be edited in the property pages in the NME
-     */
-    export enum PropertyTypeForEdition {
-        /** property is a boolean */
-        Boolean = 0,
-        /** property is a float */
-        Float = 1,
-        /** property is a Vector2 */
-        Vector2 = 2,
-        /** property is a list of values */
-        List = 3
-    }
-    /**
-     * Interface that defines an option in a variable of type list
-     */
-    export interface IEditablePropertyListOption {
-        /** label of the option */
-        "label": string;
-        /** value of the option */
-        "value": number;
-    }
-    /**
-     * Interface that defines the options available for an editable property
-     */
-    export interface IEditablePropertyOption {
-        /** min value */
-        "min"?: number;
-        /** max value */
-        "max"?: number;
-        /** notifiers: indicates which actions to take when the property is changed */
-        "notifiers"?: {
-            /** the material should be rebuilt */
-            "rebuild"?: boolean;
-            /** the preview should be updated */
-            "update"?: boolean;
-        };
-        /** list of the options for a variable of type list */
-        "options"?: IEditablePropertyListOption[];
-    }
-    /**
-     * Interface that describes an editable property
-     */
-    export interface IPropertyDescriptionForEdition {
-        /** name of the property */
-        "propertyName": string;
-        /** display name of the property */
-        "displayName": string;
-        /** type of the property */
-        "type": PropertyTypeForEdition;
-        /** group of the property - all properties with the same group value will be displayed in a specific section */
-        "groupName": string;
-        /** options for the property */
-        "options": IEditablePropertyOption;
-    }
-    /**
-     * Decorator that flags a property in a node material block as being editable
-     */
-    export function editableInPropertyPage(displayName: string, propertyType?: PropertyTypeForEdition, groupName?: string, options?: IEditablePropertyOption): (target: any, propertyKey: string) => void;
-}
-declare module BABYLON {
-    /**
      * Block used to pertub normals based on a normal map
      * Block used to pertub normals based on a normal map
      */
      */
     export class PerturbNormalBlock extends NodeMaterialBlock {
     export class PerturbNormalBlock extends NodeMaterialBlock {
@@ -61078,35 +61257,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Defines a connection point to be used for points with a custom object type
-     */
-    export class NodeMaterialConnectionPointCustomObject<T extends NodeMaterialBlock> extends NodeMaterialConnectionPoint {
-        private _blockType;
-        private _blockName;
-        private _nameForCheking?;
-        /**
-         * Creates a new connection point
-         * @param name defines the connection point name
-         * @param ownerBlock defines the block hosting this connection point
-         * @param direction defines the direction of the connection point
-         */
-        constructor(name: string, ownerBlock: NodeMaterialBlock, direction: NodeMaterialConnectionPointDirection, _blockType: new (...args: any[]) => T, _blockName: string, _nameForCheking?: string | undefined);
-        /**
-         * Gets a number indicating if the current point can be connected to another point
-         * @param connectionPoint defines the other connection point
-         * @returns a number defining the compatibility state
-         */
-        checkCompatibilityState(connectionPoint: NodeMaterialConnectionPoint): NodeMaterialConnectionPointCompatibilityStates;
-        /**
-         * Creates a block suitable to be used as an input for this input point.
-         * If null is returned, a block based on the point type will be created.
-         * @returns The returned string parameter is the name of the output point of NodeMaterialBlock (first parameter of the returned array) that can be connected to the input
-         */
-        createCustomInputBlock(): Nullable<[NodeMaterialBlock, string]>;
-    }
-}
-declare module BABYLON {
-    /**
      * Block used to implement the ambient occlusion module of the PBR material
      * Block used to implement the ambient occlusion module of the PBR material
      */
      */
     export class AmbientOcclusionBlock extends NodeMaterialBlock {
     export class AmbientOcclusionBlock extends NodeMaterialBlock {
@@ -61524,21 +61674,102 @@ declare module BABYLON {
          */
          */
         get tintTexture(): NodeMaterialConnectionPoint;
         get tintTexture(): NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the world tangent input component
+         */
+        get worldTangent(): NodeMaterialConnectionPoint;
+        /**
          * Gets the clear coat object output component
          * Gets the clear coat object output component
          */
          */
         get clearcoat(): NodeMaterialConnectionPoint;
         get clearcoat(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
+        private _generateTBNSpace;
         /**
         /**
          * Gets the main code of the block (fragment side)
          * Gets the main code of the block (fragment side)
          * @param state current state of the node material building
          * @param state current state of the node material building
          * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
          * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
          * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
          * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
          * @param worldPosVarName name of the variable holding the world position
          * @param worldPosVarName name of the variable holding the world position
+         * @param generateTBNSpace if true, the code needed to create the TBN coordinate space is generated
+         * @param vTBNAvailable indicate that the vTBN variable is already existing because it has already been generated by another block (PerturbNormal or Anisotropy)
+         * @param worldNormalVarName name of the variable holding the world normal
+         * @returns the shader code
+         */
+        static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string, generateTBNSpace: boolean, vTBNAvailable: boolean, worldNormalVarName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to implement the sub surface module of the PBR material
+     */
+    export class SubSurfaceBlock extends NodeMaterialBlock {
+        /**
+         * Create a new SubSurfaceBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Stores the intensity of the different subsurface effects in the thickness texture.
+         * * the green channel is the translucency intensity.
+         * * the blue channel is the scattering intensity.
+         * * the alpha channel is the refraction intensity.
+         */
+        useMaskFromThicknessTexture: boolean;
+        /**
+         * Initialize the block and prepare the context for build
+         * @param state defines the state that will be used for the build
+         */
+        initialize(state: NodeMaterialBuildState): void;
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the min thickness input component
+         */
+        get minThickness(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the max thickness input component
+         */
+        get maxThickness(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the thickness texture component
+         */
+        get thicknessTexture(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the tint color input component
+         */
+        get tintColor(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the translucency intensity input component
+         */
+        get translucencyIntensity(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the translucency diffusion distance input component
+         */
+        get translucencyDiffusionDistance(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the refraction object parameters
+         */
+        get refraction(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the sub surface object output component
+         */
+        get subsurface(): NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        /**
+         * Gets the main code of the block (fragment side)
+         * @param state current state of the node material building
+         * @param ssBlock instance of a SubSurfaceBlock or null if the code must be generated without an active sub surface module
+         * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
+         * @param worldPosVarName name of the variable holding the world position
          * @returns the shader code
          * @returns the shader code
          */
          */
-        static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string;
+        static GetCode(state: NodeMaterialBuildState, ssBlock: Nullable<SubSurfaceBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
@@ -61563,6 +61794,21 @@ declare module BABYLON {
          */
          */
         constructor(name: string);
         constructor(name: string);
         /**
         /**
+         * Intensity of the direct lights e.g. the four lights available in your scene.
+         * This impacts both the direct diffuse and specular highlights.
+         */
+        directIntensity: number;
+        /**
+         * Intensity of the environment e.g. how much the environment will light the object
+         * either through harmonics for rough material or through the refelction for shiny ones.
+         */
+        environmentIntensity: number;
+        /**
+         * This is a special control allowing the reduction of the specular highlights coming from the
+         * four lights of the scene. Those highlights may not be needed in full environment lighting.
+         */
+        specularIntensity: number;
+        /**
          * Defines the  falloff type used in this material.
          * Defines the  falloff type used in this material.
          * It by default is Physical.
          * It by default is Physical.
          */
          */
@@ -61708,7 +61954,7 @@ declare module BABYLON {
         /**
         /**
          * Gets the sub surface object parameters
          * Gets the sub surface object parameters
          */
          */
-        get subSurface(): NodeMaterialConnectionPoint;
+        get subsurface(): NodeMaterialConnectionPoint;
         /**
         /**
          * Gets the anisotropy object parameters
          * Gets the anisotropy object parameters
          */
          */
@@ -69047,9 +69293,9 @@ declare module BABYLON {
          */
          */
         rootUrl: string;
         rootUrl: string;
         /**
         /**
-         * Defines the filename of the scene to load from
+         * Defines the filename or File of the scene to load from
          */
          */
-        sceneFilename: string;
+        sceneFilename: string | File;
         /**
         /**
          * Gets the list of loaded meshes
          * Gets the list of loaded meshes
          */
          */
@@ -69079,7 +69325,7 @@ declare module BABYLON {
          * @param name defines the name of the task
          * @param name defines the name of the task
          * @param meshesNames defines the list of mesh's names you want to load
          * @param meshesNames defines the list of mesh's names you want to load
          * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
          * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
-         * @param sceneFilename defines the filename of the scene to load from
+         * @param sceneFilename defines the filename or File of the scene to load from
          */
          */
         constructor(
         constructor(
         /**
         /**
@@ -69095,9 +69341,9 @@ declare module BABYLON {
          */
          */
         rootUrl: string, 
         rootUrl: string, 
         /**
         /**
-         * Defines the filename of the scene to load from
+         * Defines the filename or File of the scene to load from
          */
          */
-        sceneFilename: string);
+        sceneFilename: string | File);
         /**
         /**
          * Execute the current task
          * Execute the current task
          * @param scene defines the scene where you want your assets to be loaded
          * @param scene defines the scene where you want your assets to be loaded

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


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


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


File diff suppressed because it is too large
+ 730 - 217
dist/preview release/babylon.module.d.ts


+ 351 - 105
dist/preview release/documentation.d.ts

@@ -27512,6 +27512,7 @@ declare module BABYLON {
         private _materialIndexesById;
         private _materialIndexesById;
         private _defaultMaterial;
         private _defaultMaterial;
         private _autoUpdateSubMeshes;
         private _autoUpdateSubMeshes;
+        private _tmpVertex;
         /**
         /**
          * Creates a SPS (Solid Particle System) object.
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -27914,13 +27915,13 @@ declare module BABYLON {
          * Updates a vertex of a particle : it can be overwritten by the user.
          * Updates a vertex of a particle : it can be overwritten by the user.
          * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
          * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
          * @param particle the current particle
          * @param particle the current particle
-         * @param vertex the current index of the current particle
+         * @param vertex the current vertex of the current particle : a SolidParticleVertex object
          * @param pt the index of the current vertex in the particle shape
          * @param pt the index of the current vertex in the particle shape
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
-         * @example : just set a vertex particle position
-         * @returns the updated vertex
+         * @example : just set a vertex particle position or color
+         * @returns the sps
          */
          */
-        updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3;
+        updateParticleVertex(particle: SolidParticle, vertex: SolidParticleVertex, pt: number): SolidParticleSystem;
         /**
         /**
          * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
          * This will be called before any other treatment by `setParticles()` and will be passed three parameters.
          * This does nothing and may be overwritten by the user.
          * This does nothing and may be overwritten by the user.
@@ -28218,6 +28219,36 @@ declare module BABYLON {
          */
          */
         constructor(idx: number, ind: number, indLength: number, materialIndex: number);
         constructor(idx: number, ind: number, indLength: number, materialIndex: number);
     }
     }
+    /**
+     * Represents a solid particle vertex
+     */
+    export class SolidParticleVertex {
+        /**
+         * Vertex position
+         */
+        position: Vector3;
+        /**
+         * Vertex color
+         */
+        color: Color4;
+        /**
+         * Vertex UV
+         */
+        uv: Vector2;
+        /**
+         * Creates a new solid particle vertex
+         */
+        constructor();
+        /** Vertex x coordinate */
+        get x(): number;
+        set x(val: number);
+        /** Vertex y coordinate */
+        get y(): number;
+        set y(val: number);
+        /** Vertex z coordinate */
+        get z(): number;
+        set z(val: number);
+    }
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
@@ -44304,6 +44335,12 @@ declare module BABYLON {
              */
              */
             pressed: boolean;
             pressed: boolean;
         }>;
         }>;
+        /**
+         * EXPERIMENTAL haptic support.
+         */
+        hapticActuators?: Array<{
+            pulse: (value: number, duration: number) => Promise<boolean>;
+        }>;
     }
     }
     /**
     /**
      * An Abstract Motion controller
      * An Abstract Motion controller
@@ -44410,6 +44447,17 @@ declare module BABYLON {
          * Backwards compatibility due to a deeply-integrated typo
          * Backwards compatibility due to a deeply-integrated typo
          */
          */
         get handness(): XREye;
         get handness(): XREye;
+        /**
+         * Pulse (vibrate) this controller
+         * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called
+         * Consecutive calls to this function will cancel the last pulse call
+         *
+         * @param value the strength of the pulse in 0.0...1.0 range
+         * @param duration Duration of the pulse in milliseconds
+         * @param hapticActuatorIndex optional index of actuator (will usually be 0)
+         * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued
+         */
+        pulse(value: number, duration: number, hapticActuatorIndex?: number): Promise<boolean>;
         protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh;
         protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh;
         /**
         /**
@@ -44646,6 +44694,11 @@ declare module BABYLON {
          * This can be used when creating your own profile or when testing different controllers
          * This can be used when creating your own profile or when testing different controllers
          */
          */
         forceControllerProfile?: string;
         forceControllerProfile?: string;
+        /**
+         * Defines a rendering group ID for meshes that will be loaded.
+         * This is for the default controllers only.
+         */
+        renderingGroupId?: number;
     }
     }
     /**
     /**
      * Represents an XR controller
      * Represents an XR controller
@@ -44749,6 +44802,10 @@ declare module BABYLON {
          * Should the controller model's components not move according to the user input
          * Should the controller model's components not move according to the user input
          */
          */
         disableControllerAnimation?: boolean;
         disableControllerAnimation?: boolean;
+        /**
+         * Optional options to pass to the controller. Will be overridden by the Input options where applicable
+         */
+        controllerOptions?: IWebXRControllerOptions;
     }
     }
     /**
     /**
      * XR input used to track XR inputs such as controllers/rays
      * XR input used to track XR inputs such as controllers/rays
@@ -45506,6 +45563,10 @@ declare module BABYLON {
          * When loading teleportation and pointer select, use stable versions instead of latest.
          * When loading teleportation and pointer select, use stable versions instead of latest.
          */
          */
         useStablePlugins?: boolean;
         useStablePlugins?: boolean;
+        /**
+         * An optional rendering group id that will be set globally for teleportation, pointer selection and default controller meshes
+         */
+        renderingGroupId?: number;
     }
     }
     /**
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -57683,7 +57744,8 @@ declare module BABYLON {
         protected _reflectionVectorName: string;
         protected _reflectionVectorName: string;
         /** @hidden */
         /** @hidden */
         _reflectionCoordsName: string;
         _reflectionCoordsName: string;
-        protected _reflectionMatrixName: string;
+        /** @hidden */
+        _reflectionMatrixName: string;
         protected _reflectionColorName: string;
         protected _reflectionColorName: string;
         /**
         /**
          * Gets or sets the texture associated with the node
          * Gets or sets the texture associated with the node
@@ -57769,6 +57831,184 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
+     * Defines a connection point to be used for points with a custom object type
+     */
+    export class NodeMaterialConnectionPointCustomObject<T extends NodeMaterialBlock> extends NodeMaterialConnectionPoint {
+        private _blockType;
+        private _blockName;
+        private _nameForCheking?;
+        /**
+         * Creates a new connection point
+         * @param name defines the connection point name
+         * @param ownerBlock defines the block hosting this connection point
+         * @param direction defines the direction of the connection point
+         */
+        constructor(name: string, ownerBlock: NodeMaterialBlock, direction: NodeMaterialConnectionPointDirection, _blockType: new (...args: any[]) => T, _blockName: string, _nameForCheking?: string | undefined);
+        /**
+         * Gets a number indicating if the current point can be connected to another point
+         * @param connectionPoint defines the other connection point
+         * @returns a number defining the compatibility state
+         */
+        checkCompatibilityState(connectionPoint: NodeMaterialConnectionPoint): NodeMaterialConnectionPointCompatibilityStates;
+        /**
+         * Creates a block suitable to be used as an input for this input point.
+         * If null is returned, a block based on the point type will be created.
+         * @returns The returned string parameter is the name of the output point of NodeMaterialBlock (first parameter of the returned array) that can be connected to the input
+         */
+        createCustomInputBlock(): Nullable<[NodeMaterialBlock, string]>;
+    }
+}
+declare module BABYLON {
+    /**
+     * Enum defining the type of properties that can be edited in the property pages in the NME
+     */
+    export enum PropertyTypeForEdition {
+        /** property is a boolean */
+        Boolean = 0,
+        /** property is a float */
+        Float = 1,
+        /** property is a Vector2 */
+        Vector2 = 2,
+        /** property is a list of values */
+        List = 3
+    }
+    /**
+     * Interface that defines an option in a variable of type list
+     */
+    export interface IEditablePropertyListOption {
+        /** label of the option */
+        "label": string;
+        /** value of the option */
+        "value": number;
+    }
+    /**
+     * Interface that defines the options available for an editable property
+     */
+    export interface IEditablePropertyOption {
+        /** min value */
+        "min"?: number;
+        /** max value */
+        "max"?: number;
+        /** notifiers: indicates which actions to take when the property is changed */
+        "notifiers"?: {
+            /** the material should be rebuilt */
+            "rebuild"?: boolean;
+            /** the preview should be updated */
+            "update"?: boolean;
+        };
+        /** list of the options for a variable of type list */
+        "options"?: IEditablePropertyListOption[];
+    }
+    /**
+     * Interface that describes an editable property
+     */
+    export interface IPropertyDescriptionForEdition {
+        /** name of the property */
+        "propertyName": string;
+        /** display name of the property */
+        "displayName": string;
+        /** type of the property */
+        "type": PropertyTypeForEdition;
+        /** group of the property - all properties with the same group value will be displayed in a specific section */
+        "groupName": string;
+        /** options for the property */
+        "options": IEditablePropertyOption;
+    }
+    /**
+     * Decorator that flags a property in a node material block as being editable
+     */
+    export function editableInPropertyPage(displayName: string, propertyType?: PropertyTypeForEdition, groupName?: string, options?: IEditablePropertyOption): (target: any, propertyKey: string) => void;
+}
+declare module BABYLON {
+    /**
+     * Block used to implement the refraction part of the sub surface module of the PBR material
+     */
+    export class RefractionBlock extends NodeMaterialBlock {
+        /** @hidden */
+        _define3DName: string;
+        /** @hidden */
+        _refractionMatrixName: string;
+        /** @hidden */
+        _defineLODRefractionAlpha: string;
+        /** @hidden */
+        _defineLinearSpecularRefraction: string;
+        /** @hidden */
+        _defineOppositeZ: string;
+        /** @hidden */
+        _cubeSamplerName: string;
+        /** @hidden */
+        _2DSamplerName: string;
+        /** @hidden */
+        _vRefractionMicrosurfaceInfosName: string;
+        /** @hidden */
+        _vRefractionInfosName: string;
+        private _scene;
+        /**
+         * This parameters will make the material used its opacity to control how much it is refracting aginst not.
+         * Materials half opaque for instance using refraction could benefit from this control.
+         */
+        linkRefractionWithTransparency: boolean;
+        /**
+         * Controls if refraction needs to be inverted on Y. This could be useful for procedural texture.
+         */
+        invertRefractionY: boolean;
+        /**
+         * Gets or sets the texture associated with the node
+         */
+        texture: Nullable<BaseTexture>;
+        /**
+         * Create a new RefractionBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the intensity input component
+         */
+        get intensity(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the index of refraction input component
+         */
+        get indexOfRefraction(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the tint at distance input component
+         */
+        get tintAtDistance(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the view input component
+         */
+        get view(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the refraction object output component
+         */
+        get refraction(): NodeMaterialConnectionPoint;
+        /**
+         * Returns true if the block has a texture
+         */
+        get hasTexture(): boolean;
+        protected _getTexture(): Nullable<BaseTexture>;
+        autoConfigure(material: NodeMaterial): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        isReady(): boolean;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
+        /**
+         * Gets the main code of the block (fragment side)
+         * @param state current state of the node material building
+         * @returns the shader code
+         */
+        getCode(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+        protected _dumpPropertiesCode(): string;
+        serialize(): any;
+        _deserialize(serializationObject: any, scene: Scene, rootUrl: string): void;
+    }
+}
+declare module BABYLON {
+    /**
      * Interface used to configure the node material editor
      * Interface used to configure the node material editor
      */
      */
     export interface INodeMaterialEditorOptions {
     export interface INodeMaterialEditorOptions {
@@ -57808,7 +58048,7 @@ declare module BABYLON {
         /** MISC. */
         /** MISC. */
         BUMPDIRECTUV: number;
         BUMPDIRECTUV: number;
         constructor();
         constructor();
-        setValue(name: string, value: any): void;
+        setValue(name: string, value: any, markAsUnprocessedIfDirty?: boolean): void;
     }
     }
     /**
     /**
      * Class used to configure NodeMaterial
      * Class used to configure NodeMaterial
@@ -58026,7 +58266,7 @@ declare module BABYLON {
          * Gets the list of texture blocks
          * Gets the list of texture blocks
          * @returns an array of texture blocks
          * @returns an array of texture blocks
          */
          */
-        getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock)[];
+        getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock | RefractionBlock)[];
         /**
         /**
          * Specifies if the material uses a texture
          * Specifies if the material uses a texture
          * @param texture defines the texture to check against the material
          * @param texture defines the texture to check against the material
@@ -58224,7 +58464,7 @@ declare module BABYLON {
         /**
         /**
          * Input blocks
          * Input blocks
          */
          */
-        textureBlocks: (ReflectionTextureBaseBlock | TextureBlock)[];
+        textureBlocks: (ReflectionTextureBaseBlock | TextureBlock | RefractionBlock)[];
         /**
         /**
          * Bindable blocks (Blocks that need to set data to the effect)
          * Bindable blocks (Blocks that need to set data to the effect)
          */
          */
@@ -59215,67 +59455,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Enum defining the type of properties that can be edited in the property pages in the NME
-     */
-    export enum PropertyTypeForEdition {
-        /** property is a boolean */
-        Boolean = 0,
-        /** property is a float */
-        Float = 1,
-        /** property is a Vector2 */
-        Vector2 = 2,
-        /** property is a list of values */
-        List = 3
-    }
-    /**
-     * Interface that defines an option in a variable of type list
-     */
-    export interface IEditablePropertyListOption {
-        /** label of the option */
-        "label": string;
-        /** value of the option */
-        "value": number;
-    }
-    /**
-     * Interface that defines the options available for an editable property
-     */
-    export interface IEditablePropertyOption {
-        /** min value */
-        "min"?: number;
-        /** max value */
-        "max"?: number;
-        /** notifiers: indicates which actions to take when the property is changed */
-        "notifiers"?: {
-            /** the material should be rebuilt */
-            "rebuild"?: boolean;
-            /** the preview should be updated */
-            "update"?: boolean;
-        };
-        /** list of the options for a variable of type list */
-        "options"?: IEditablePropertyListOption[];
-    }
-    /**
-     * Interface that describes an editable property
-     */
-    export interface IPropertyDescriptionForEdition {
-        /** name of the property */
-        "propertyName": string;
-        /** display name of the property */
-        "displayName": string;
-        /** type of the property */
-        "type": PropertyTypeForEdition;
-        /** group of the property - all properties with the same group value will be displayed in a specific section */
-        "groupName": string;
-        /** options for the property */
-        "options": IEditablePropertyOption;
-    }
-    /**
-     * Decorator that flags a property in a node material block as being editable
-     */
-    export function editableInPropertyPage(displayName: string, propertyType?: PropertyTypeForEdition, groupName?: string, options?: IEditablePropertyOption): (target: any, propertyKey: string) => void;
-}
-declare module BABYLON {
-    /**
      * Block used to pertub normals based on a normal map
      * Block used to pertub normals based on a normal map
      */
      */
     export class PerturbNormalBlock extends NodeMaterialBlock {
     export class PerturbNormalBlock extends NodeMaterialBlock {
@@ -61078,35 +61257,6 @@ declare module BABYLON {
 }
 }
 declare module BABYLON {
 declare module BABYLON {
     /**
     /**
-     * Defines a connection point to be used for points with a custom object type
-     */
-    export class NodeMaterialConnectionPointCustomObject<T extends NodeMaterialBlock> extends NodeMaterialConnectionPoint {
-        private _blockType;
-        private _blockName;
-        private _nameForCheking?;
-        /**
-         * Creates a new connection point
-         * @param name defines the connection point name
-         * @param ownerBlock defines the block hosting this connection point
-         * @param direction defines the direction of the connection point
-         */
-        constructor(name: string, ownerBlock: NodeMaterialBlock, direction: NodeMaterialConnectionPointDirection, _blockType: new (...args: any[]) => T, _blockName: string, _nameForCheking?: string | undefined);
-        /**
-         * Gets a number indicating if the current point can be connected to another point
-         * @param connectionPoint defines the other connection point
-         * @returns a number defining the compatibility state
-         */
-        checkCompatibilityState(connectionPoint: NodeMaterialConnectionPoint): NodeMaterialConnectionPointCompatibilityStates;
-        /**
-         * Creates a block suitable to be used as an input for this input point.
-         * If null is returned, a block based on the point type will be created.
-         * @returns The returned string parameter is the name of the output point of NodeMaterialBlock (first parameter of the returned array) that can be connected to the input
-         */
-        createCustomInputBlock(): Nullable<[NodeMaterialBlock, string]>;
-    }
-}
-declare module BABYLON {
-    /**
      * Block used to implement the ambient occlusion module of the PBR material
      * Block used to implement the ambient occlusion module of the PBR material
      */
      */
     export class AmbientOcclusionBlock extends NodeMaterialBlock {
     export class AmbientOcclusionBlock extends NodeMaterialBlock {
@@ -61524,21 +61674,102 @@ declare module BABYLON {
          */
          */
         get tintTexture(): NodeMaterialConnectionPoint;
         get tintTexture(): NodeMaterialConnectionPoint;
         /**
         /**
+         * Gets the world tangent input component
+         */
+        get worldTangent(): NodeMaterialConnectionPoint;
+        /**
          * Gets the clear coat object output component
          * Gets the clear coat object output component
          */
          */
         get clearcoat(): NodeMaterialConnectionPoint;
         get clearcoat(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
         bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh): void;
+        private _generateTBNSpace;
         /**
         /**
          * Gets the main code of the block (fragment side)
          * Gets the main code of the block (fragment side)
          * @param state current state of the node material building
          * @param state current state of the node material building
          * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
          * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
          * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
          * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
          * @param worldPosVarName name of the variable holding the world position
          * @param worldPosVarName name of the variable holding the world position
+         * @param generateTBNSpace if true, the code needed to create the TBN coordinate space is generated
+         * @param vTBNAvailable indicate that the vTBN variable is already existing because it has already been generated by another block (PerturbNormal or Anisotropy)
+         * @param worldNormalVarName name of the variable holding the world normal
+         * @returns the shader code
+         */
+        static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string, generateTBNSpace: boolean, vTBNAvailable: boolean, worldNormalVarName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to implement the sub surface module of the PBR material
+     */
+    export class SubSurfaceBlock extends NodeMaterialBlock {
+        /**
+         * Create a new SubSurfaceBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Stores the intensity of the different subsurface effects in the thickness texture.
+         * * the green channel is the translucency intensity.
+         * * the blue channel is the scattering intensity.
+         * * the alpha channel is the refraction intensity.
+         */
+        useMaskFromThicknessTexture: boolean;
+        /**
+         * Initialize the block and prepare the context for build
+         * @param state defines the state that will be used for the build
+         */
+        initialize(state: NodeMaterialBuildState): void;
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the min thickness input component
+         */
+        get minThickness(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the max thickness input component
+         */
+        get maxThickness(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the thickness texture component
+         */
+        get thicknessTexture(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the tint color input component
+         */
+        get tintColor(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the translucency intensity input component
+         */
+        get translucencyIntensity(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the translucency diffusion distance input component
+         */
+        get translucencyDiffusionDistance(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the refraction object parameters
+         */
+        get refraction(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the sub surface object output component
+         */
+        get subsurface(): NodeMaterialConnectionPoint;
+        autoConfigure(material: NodeMaterial): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
+        /**
+         * Gets the main code of the block (fragment side)
+         * @param state current state of the node material building
+         * @param ssBlock instance of a SubSurfaceBlock or null if the code must be generated without an active sub surface module
+         * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
+         * @param worldPosVarName name of the variable holding the world position
          * @returns the shader code
          * @returns the shader code
          */
          */
-        static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string;
+        static GetCode(state: NodeMaterialBuildState, ssBlock: Nullable<SubSurfaceBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
     }
 }
 }
@@ -61563,6 +61794,21 @@ declare module BABYLON {
          */
          */
         constructor(name: string);
         constructor(name: string);
         /**
         /**
+         * Intensity of the direct lights e.g. the four lights available in your scene.
+         * This impacts both the direct diffuse and specular highlights.
+         */
+        directIntensity: number;
+        /**
+         * Intensity of the environment e.g. how much the environment will light the object
+         * either through harmonics for rough material or through the refelction for shiny ones.
+         */
+        environmentIntensity: number;
+        /**
+         * This is a special control allowing the reduction of the specular highlights coming from the
+         * four lights of the scene. Those highlights may not be needed in full environment lighting.
+         */
+        specularIntensity: number;
+        /**
          * Defines the  falloff type used in this material.
          * Defines the  falloff type used in this material.
          * It by default is Physical.
          * It by default is Physical.
          */
          */
@@ -61708,7 +61954,7 @@ declare module BABYLON {
         /**
         /**
          * Gets the sub surface object parameters
          * Gets the sub surface object parameters
          */
          */
-        get subSurface(): NodeMaterialConnectionPoint;
+        get subsurface(): NodeMaterialConnectionPoint;
         /**
         /**
          * Gets the anisotropy object parameters
          * Gets the anisotropy object parameters
          */
          */
@@ -69047,9 +69293,9 @@ declare module BABYLON {
          */
          */
         rootUrl: string;
         rootUrl: string;
         /**
         /**
-         * Defines the filename of the scene to load from
+         * Defines the filename or File of the scene to load from
          */
          */
-        sceneFilename: string;
+        sceneFilename: string | File;
         /**
         /**
          * Gets the list of loaded meshes
          * Gets the list of loaded meshes
          */
          */
@@ -69079,7 +69325,7 @@ declare module BABYLON {
          * @param name defines the name of the task
          * @param name defines the name of the task
          * @param meshesNames defines the list of mesh's names you want to load
          * @param meshesNames defines the list of mesh's names you want to load
          * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
          * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
-         * @param sceneFilename defines the filename of the scene to load from
+         * @param sceneFilename defines the filename or File of the scene to load from
          */
          */
         constructor(
         constructor(
         /**
         /**
@@ -69095,9 +69341,9 @@ declare module BABYLON {
          */
          */
         rootUrl: string, 
         rootUrl: string, 
         /**
         /**
-         * Defines the filename of the scene to load from
+         * Defines the filename or File of the scene to load from
          */
          */
-        sceneFilename: string);
+        sceneFilename: string | File);
         /**
         /**
          * Execute the current task
          * Execute the current task
          * @param scene defines the scene where you want your assets to be loaded
          * @param scene defines the scene where you want your assets to be loaded

+ 3 - 0
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -645,6 +645,9 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
         _this.customShaderNameResolve = _this.Builder;
         _this.customShaderNameResolve = _this.Builder;
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockReflectivity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockFinalColorComposition"]);
         return _this;
         return _this;
     }
     }
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {

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


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


+ 3 - 0
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -1033,6 +1033,9 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
         _this.customShaderNameResolve = _this.Builder;
         _this.customShaderNameResolve = _this.Builder;
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockReflectivity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockFinalColorComposition"]);
         return _this;
         return _this;
     }
     }
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {

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


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


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts


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


+ 15 - 4
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -59436,6 +59436,8 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
 
 
 
+
+
 var BlockTools = /** @class */ (function () {
 var BlockTools = /** @class */ (function () {
     function BlockTools() {
     function BlockTools() {
     }
     }
@@ -59809,6 +59811,10 @@ var BlockTools = /** @class */ (function () {
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ReflectionBlock"]("Reflection");
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ReflectionBlock"]("Reflection");
             case "ClearCoatBlock":
             case "ClearCoatBlock":
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ClearCoatBlock"]("ClearCoat");
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ClearCoatBlock"]("ClearCoat");
+            case "RefractionBlock":
+                return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["RefractionBlock"]("Refraction");
+            case "SubSurfaceBlock":
+                return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["SubSurfaceBlock"]("SubSurface");
         }
         }
         return null;
         return null;
     };
     };
@@ -60052,7 +60058,7 @@ var NodeListComponent = /** @class */ (function (_super) {
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock", "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock", "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
-            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "SheenBlock"],
+            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "RefractionBlock", "SheenBlock", "SubSurfaceBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],
@@ -60191,6 +60197,8 @@ var NodeListComponent = /** @class */ (function (_super) {
         "AnisotropyBlock": "PBR Anisotropy block",
         "AnisotropyBlock": "PBR Anisotropy block",
         "ReflectionBlock": "PBR Reflection block",
         "ReflectionBlock": "PBR Reflection block",
         "ClearCoatBlock": "PBR ClearCoat block",
         "ClearCoatBlock": "PBR ClearCoat block",
+        "RefractionBlock": "PBR Refraction block",
+        "SubSurfaceBlock": "PBR SubSurface block",
     };
     };
     return NodeListComponent;
     return NodeListComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -61888,6 +61896,7 @@ DisplayLedger.RegisteredControls["TrigonometryBlock"] = _display_trigonometryDis
 DisplayLedger.RegisteredControls["TextureBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["TextureBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["ReflectionBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["ReflectionBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
+DisplayLedger.RegisteredControls["RefractionBlock"] = _display_textureDisplayManager__WEBPACK_IMPORTED_MODULE_6__["TextureDisplayManager"];
 DisplayLedger.RegisteredControls["DiscardBlock"] = _display_discardDisplayManager__WEBPACK_IMPORTED_MODULE_7__["DiscardDisplayManager"];
 DisplayLedger.RegisteredControls["DiscardBlock"] = _display_discardDisplayManager__WEBPACK_IMPORTED_MODULE_7__["DiscardDisplayManager"];
 
 
 
 
@@ -65764,6 +65773,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
 
 
 
+
 var TexturePropertyTabComponent = /** @class */ (function (_super) {
 var TexturePropertyTabComponent = /** @class */ (function (_super) {
     Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TexturePropertyTabComponent, _super);
     Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(TexturePropertyTabComponent, _super);
     function TexturePropertyTabComponent(props) {
     function TexturePropertyTabComponent(props) {
@@ -65814,7 +65824,7 @@ var TexturePropertyTabComponent = /** @class */ (function (_super) {
         }
         }
         if (!texture) {
         if (!texture) {
             if (!this.state.loadAsCubeTexture) {
             if (!this.state.loadAsCubeTexture) {
-                this.textureBlock.texture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"](null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"]);
+                this.textureBlock.texture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"](null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["RefractionBlock"]);
                 texture = this.textureBlock.texture;
                 texture = this.textureBlock.texture;
                 texture.coordinatesMode = babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"].EQUIRECTANGULAR_MODE;
                 texture.coordinatesMode = babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"].EQUIRECTANGULAR_MODE;
             }
             }
@@ -65854,7 +65864,7 @@ var TexturePropertyTabComponent = /** @class */ (function (_super) {
         var _this = this;
         var _this = this;
         this._prepareTexture();
         this._prepareTexture();
         var texture = this.textureBlock.texture;
         var texture = this.textureBlock.texture;
-        if (texture.isCube || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"]) {
+        if (texture.isCube || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["RefractionBlock"]) {
             var extension = undefined;
             var extension = undefined;
             if (url.toLowerCase().indexOf(".dds") > 0) {
             if (url.toLowerCase().indexOf(".dds") > 0) {
                 extension = ".dds";
                 extension = ".dds";
@@ -65876,7 +65886,7 @@ var TexturePropertyTabComponent = /** @class */ (function (_super) {
             url = texture.name;
             url = texture.name;
         }
         }
         url = url.replace(/\?nocache=\d+/, "");
         url = url.replace(/\?nocache=\d+/, "");
-        var isInReflectionMode = this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"];
+        var isInReflectionMode = this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionTextureBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["ReflectionBlock"] || this.textureBlock instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["RefractionBlock"];
         var reflectionModeOptions = [
         var reflectionModeOptions = [
             {
             {
                 label: "Cubic", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"].CUBIC_MODE
                 label: "Cubic", value: babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_3__["Texture"].CUBIC_MODE
@@ -66147,6 +66157,7 @@ PropertyLedger.RegisteredControls["LightInformationBlock"] = _properties_lightIn
 PropertyLedger.RegisteredControls["TextureBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["TextureBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["ReflectionBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["ReflectionBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
+PropertyLedger.RegisteredControls["RefractionBlock"] = _properties_texturePropertyTabComponent__WEBPACK_IMPORTED_MODULE_5__["TexturePropertyTabComponent"];
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = _properties_trigonometryNodePropertyComponent__WEBPACK_IMPORTED_MODULE_6__["TrigonometryPropertyTabComponent"];
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = _properties_trigonometryNodePropertyComponent__WEBPACK_IMPORTED_MODULE_6__["TrigonometryPropertyTabComponent"];
 
 
 
 

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


File diff suppressed because it is too large
+ 7 - 4
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts


File diff suppressed because it is too large
+ 730 - 217
dist/preview release/viewer/babylon.module.d.ts


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


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


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

@@ -15,6 +15,7 @@
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 - Added initial code for DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 - Added initial code for DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
+- The Mesh Asset Task also accepts File as sceneInput ([RaananW](https://github.com/RaananW))
 - Added support preserving vert colors for CSG objects ([PirateJC](https://github.com/PirateJC))
 - Added support preserving vert colors for CSG objects ([PirateJC](https://github.com/PirateJC))
 
 
 ### Engine
 ### Engine
@@ -90,6 +91,8 @@
 - Pointer Selection feature now uses `selectstart` and `selectend` events when gamepad and motion controller are not present ([#7989](https://github.com/BabylonJS/Babylon.js/issues/7989)) ([RaananW](https://github.com/RaananW))
 - Pointer Selection feature now uses `selectstart` and `selectend` events when gamepad and motion controller are not present ([#7989](https://github.com/BabylonJS/Babylon.js/issues/7989)) ([RaananW](https://github.com/RaananW))
 - Removed forced `autoClear` = false settings ([RaananW](https://github.com/RaananW))
 - Removed forced `autoClear` = false settings ([RaananW](https://github.com/RaananW))
 - Added a warning that WebXR can only be served over HTTPS ([RaananW](https://github.com/RaananW))
 - Added a warning that WebXR can only be served over HTTPS ([RaananW](https://github.com/RaananW))
+- Default (XR-global) rendering group ID can be defined when initializing a default experience ([RaananW](https://github.com/RaananW))
+- Added support for (experimental) haptic actuators ([#8068](https://github.com/BabylonJS/Babylon.js/issues/8068)) ([RaananW](https://github.com/RaananW))
 
 
 ### Collisions
 ### Collisions
 
 
@@ -106,6 +109,7 @@
 ### Particles
 ### Particles
 
 
 - Added local space support for GPU particles ([CraigFeldpsar](https://github.com/craigfeldspar))
 - Added local space support for GPU particles ([CraigFeldpsar](https://github.com/craigfeldspar))
+- Added ability to update also colors and uvs of solid particle vertices ([jerome](https://github.com/jbousquie))
 
 
 ### Build
 ### Build
 
 
@@ -163,3 +167,4 @@
 ## Breaking changes
 ## Breaking changes
 
 
 - `EffectRenderer.render` now takes a `RenderTargetTexture` or an `InternalTexture` as the output texture and only a single `EffectWrapper` for its first argument ([Popov72](https://github.com/Popov72))
 - `EffectRenderer.render` now takes a `RenderTargetTexture` or an `InternalTexture` as the output texture and only a single `EffectWrapper` for its first argument ([Popov72](https://github.com/Popov72))
+- Sound's `updateOptions` takes `options.length` and `options.offset` as seconds and not milliseconds ([RaananW](https://github.com/RaananW))

+ 4 - 0
materialsLibrary/src/custom/pbrCustomMaterial.ts

@@ -173,6 +173,10 @@ export class PBRCustomMaterial extends PBRMaterial {
 
 
         this.FragmentShader = Effect.ShadersStore["pbrPixelShader"];
         this.FragmentShader = Effect.ShadersStore["pbrPixelShader"];
         this.VertexShader = Effect.ShadersStore["pbrVertexShader"];
         this.VertexShader = Effect.ShadersStore["pbrVertexShader"];
+
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, Effect.IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, Effect.IncludesShadersStore["pbrBlockReflectivity"]);
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, Effect.IncludesShadersStore["pbrBlockFinalColorComposition"]);
     }
     }
 
 
     public AddUniform(name: string, kind: string, param: any): PBRCustomMaterial {
     public AddUniform(name: string, kind: string, param: any): PBRCustomMaterial {

+ 6 - 0
nodeEditor/src/blockTools.ts

@@ -69,6 +69,8 @@ import { ReflectivityBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectiv
 import { AnisotropyBlock } from 'babylonjs/Materials/Node/Blocks/PBR/anisotropyBlock';
 import { AnisotropyBlock } from 'babylonjs/Materials/Node/Blocks/PBR/anisotropyBlock';
 import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
 import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
 import { ClearCoatBlock } from 'babylonjs/Materials/Node/Blocks/PBR/clearCoatBlock';
 import { ClearCoatBlock } from 'babylonjs/Materials/Node/Blocks/PBR/clearCoatBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
+import { SubSurfaceBlock } from 'babylonjs/Materials/Node/Blocks/PBR/subSurfaceBlock';
 
 
 export class BlockTools {
 export class BlockTools {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
@@ -453,6 +455,10 @@ export class BlockTools {
                 return new ReflectionBlock("Reflection");
                 return new ReflectionBlock("Reflection");
             case "ClearCoatBlock":
             case "ClearCoatBlock":
                 return new ClearCoatBlock("ClearCoat");
                 return new ClearCoatBlock("ClearCoat");
+            case "RefractionBlock":
+                return new RefractionBlock("Refraction");
+            case "SubSurfaceBlock":
+                return new SubSurfaceBlock("SubSurface");
         }
         }
 
 
         return null;
         return null;

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

@@ -124,6 +124,8 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         "AnisotropyBlock": "PBR Anisotropy block",
         "AnisotropyBlock": "PBR Anisotropy block",
         "ReflectionBlock": "PBR Reflection block",
         "ReflectionBlock": "PBR Reflection block",
         "ClearCoatBlock": "PBR ClearCoat block",
         "ClearCoatBlock": "PBR ClearCoat block",
+        "RefractionBlock": "PBR Refraction block",
+        "SubSurfaceBlock": "PBR SubSurface block",
     };
     };
 
 
     constructor(props: INodeListComponentProps) {
     constructor(props: INodeListComponentProps) {
@@ -152,7 +154,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
-            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "SheenBlock"],
+            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "RefractionBlock", "SheenBlock", "SubSurfaceBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],

+ 2 - 1
nodeEditor/src/diagram/display/textureDisplayManager.ts

@@ -1,6 +1,7 @@
 import { IDisplayManager } from './displayManager';
 import { IDisplayManager } from './displayManager';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { TextureLineComponent } from '../../sharedComponents/textureLineComponent';
 import { TextureLineComponent } from '../../sharedComponents/textureLineComponent';
 
 
@@ -25,7 +26,7 @@ export class TextureDisplayManager implements IDisplayManager {
     }
     }
 
 
     public updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void {       
     public updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void {       
-        const textureBlock = block as TextureBlock | ReflectionTextureBlock;
+        const textureBlock = block as TextureBlock | ReflectionTextureBlock | RefractionBlock;
 
 
         if (!this._previewCanvas) {
         if (!this._previewCanvas) {
             contentArea.classList.add("texture-block");
             contentArea.classList.add("texture-block");

+ 1 - 0
nodeEditor/src/diagram/displayLedger.ts

@@ -21,4 +21,5 @@ DisplayLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryDisplayManag
 DisplayLedger.RegisteredControls["TextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["TextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionBlock"] = TextureDisplayManager;
+DisplayLedger.RegisteredControls["RefractionBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["DiscardBlock"] = DiscardDisplayManager;
 DisplayLedger.RegisteredControls["DiscardBlock"] = DiscardDisplayManager;

+ 5 - 4
nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx

@@ -15,10 +15,11 @@ import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponen
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
 import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
 import { GeneralPropertyTabComponent, GenericPropertyTabComponent } from './genericNodePropertyComponent';
 import { GeneralPropertyTabComponent, GenericPropertyTabComponent } from './genericNodePropertyComponent';
 
 
-type ReflectionTexture = ReflectionTextureBlock | ReflectionBlock;
+type ReflectionTexture = ReflectionTextureBlock | ReflectionBlock | RefractionBlock;
 
 
 export class TexturePropertyTabComponent extends React.Component<IPropertyComponentProps, {isEmbedded: boolean, loadAsCubeTexture: boolean}> {
 export class TexturePropertyTabComponent extends React.Component<IPropertyComponentProps, {isEmbedded: boolean, loadAsCubeTexture: boolean}> {
 
 
@@ -79,7 +80,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
 
 
         if (!texture) {
         if (!texture) {
             if (!this.state.loadAsCubeTexture) {
             if (!this.state.loadAsCubeTexture) {
-                this.textureBlock.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock);
+                this.textureBlock.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock);
                 texture = this.textureBlock.texture;
                 texture = this.textureBlock.texture;
                 texture.coordinatesMode = Texture.EQUIRECTANGULAR_MODE;
                 texture.coordinatesMode = Texture.EQUIRECTANGULAR_MODE;
             } else {
             } else {
@@ -122,7 +123,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
         this._prepareTexture();
         this._prepareTexture();
 
 
         let texture = this.textureBlock.texture as BaseTexture;       
         let texture = this.textureBlock.texture as BaseTexture;       
-        if (texture.isCube || this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock) {
+        if (texture.isCube || this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock) {
             let extension: string | undefined = undefined;
             let extension: string | undefined = undefined;
             if (url.toLowerCase().indexOf(".dds") > 0) {
             if (url.toLowerCase().indexOf(".dds") > 0) {
                 extension = ".dds";
                 extension = ".dds";
@@ -146,7 +147,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
 
 
         url = url.replace(/\?nocache=\d+/, "");
         url = url.replace(/\?nocache=\d+/, "");
 
 
-        let isInReflectionMode = this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock;
+        let isInReflectionMode = this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock;
 
 
         var reflectionModeOptions: {label: string, value: number}[] = [
         var reflectionModeOptions: {label: string, value: number}[] = [
             {
             {

+ 1 - 0
nodeEditor/src/diagram/propertyLedger.ts

@@ -20,4 +20,5 @@ PropertyLedger.RegisteredControls["LightInformationBlock"] = LightInformationPro
 PropertyLedger.RegisteredControls["TextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["TextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionBlock"] = TexturePropertyTabComponent;
+PropertyLedger.RegisteredControls["RefractionBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryPropertyTabComponent;
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryPropertyTabComponent;

+ 13 - 13
src/Audio/sound.ts

@@ -216,14 +216,14 @@ export class Sound {
             if (options.volume !== undefined) {
             if (options.volume !== undefined) {
                 this._volume = options.volume;
                 this._volume = options.volume;
             }
             }
-            this.spatialSound = options.spatialSound || false;
-            this.maxDistance = options.maxDistance || 100;
-            this.useCustomAttenuation = options.useCustomAttenuation || false;
+            this.spatialSound = options.spatialSound ?? false;
+            this.maxDistance = options.maxDistance ?? 100;
+            this.useCustomAttenuation = options.useCustomAttenuation ?? false;
             this.rolloffFactor = options.rolloffFactor || 1;
             this.rolloffFactor = options.rolloffFactor || 1;
             this.refDistance = options.refDistance || 1;
             this.refDistance = options.refDistance || 1;
             this.distanceModel = options.distanceModel || "linear";
             this.distanceModel = options.distanceModel || "linear";
             this._playbackRate = options.playbackRate || 1;
             this._playbackRate = options.playbackRate || 1;
-            this._streaming = options.streaming || false;
+            this._streaming = options.streaming ?? false;
             this._length = options.length;
             this._length = options.length;
             this._offset = options.offset;
             this._offset = options.offset;
         }
         }
@@ -452,15 +452,15 @@ export class Sound {
      */
      */
     public updateOptions(options: ISoundOptions): void {
     public updateOptions(options: ISoundOptions): void {
         if (options) {
         if (options) {
-            this.loop = options.loop || this.loop;
-            this.maxDistance = options.maxDistance || this.maxDistance;
-            this.useCustomAttenuation = options.useCustomAttenuation || this.useCustomAttenuation;
-            this.rolloffFactor = options.rolloffFactor || this.rolloffFactor;
-            this.refDistance = options.refDistance || this.refDistance;
-            this.distanceModel = options.distanceModel || this.distanceModel;
-            this._playbackRate = options.playbackRate || this._playbackRate;
-            this._length = options.length ? options.length / 1000 : undefined;
-            this._offset = options.offset ? options.offset / 1000 : undefined;
+            this.loop = options.loop ?? this.loop;
+            this.maxDistance = options.maxDistance ?? this.maxDistance;
+            this.useCustomAttenuation = options.useCustomAttenuation ?? this.useCustomAttenuation;
+            this.rolloffFactor = options.rolloffFactor ?? this.rolloffFactor;
+            this.refDistance = options.refDistance ?? this.refDistance;
+            this.distanceModel = options.distanceModel ?? this.distanceModel;
+            this._playbackRate = options.playbackRate ?? this._playbackRate;
+            this._length = options.length ?? undefined;
+            this._offset = options.offset ?? undefined;
             this._updateSpatialParameters();
             this._updateSpatialParameters();
             if (this.isPlaying) {
             if (this.isPlaying) {
                 if (this._streaming && this._htmlAudioElement) {
                 if (this._streaming && this._htmlAudioElement) {

+ 13 - 12
src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts

@@ -55,7 +55,8 @@ export abstract class ReflectionTextureBaseBlock extends NodeMaterialBlock {
     protected _reflectionVectorName: string;
     protected _reflectionVectorName: string;
     /** @hidden */
     /** @hidden */
     public _reflectionCoordsName: string;
     public _reflectionCoordsName: string;
-    protected _reflectionMatrixName: string;
+    /** @hidden */
+    public _reflectionMatrixName: string;
     protected _reflectionColorName: string;
     protected _reflectionColorName: string;
 
 
     /**
     /**
@@ -156,17 +157,17 @@ export abstract class ReflectionTextureBaseBlock extends NodeMaterialBlock {
             return;
             return;
         }
         }
 
 
-        defines.setValue(this._define3DName, texture.isCube);
-        defines.setValue(this._defineLocalCubicName, (<any>texture).boundingBoxSize ? true : false);
-        defines.setValue(this._defineExplicitName, texture.coordinatesMode === Constants.TEXTURE_EXPLICIT_MODE);
-        defines.setValue(this._defineSkyboxName, texture.coordinatesMode === Constants.TEXTURE_SKYBOX_MODE);
-        defines.setValue(this._defineCubicName, texture.coordinatesMode === Constants.TEXTURE_CUBIC_MODE);
-        defines.setValue(this._defineSphericalName, texture.coordinatesMode === Constants.TEXTURE_SPHERICAL_MODE);
-        defines.setValue(this._definePlanarName, texture.coordinatesMode === Constants.TEXTURE_PLANAR_MODE);
-        defines.setValue(this._defineProjectionName, texture.coordinatesMode === Constants.TEXTURE_PROJECTION_MODE);
-        defines.setValue(this._defineEquirectangularName, texture.coordinatesMode === Constants.TEXTURE_EQUIRECTANGULAR_MODE);
-        defines.setValue(this._defineEquirectangularFixedName, texture.coordinatesMode === Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MODE);
-        defines.setValue(this._defineMirroredEquirectangularFixedName, texture.coordinatesMode === Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE);
+        defines.setValue(this._define3DName, texture.isCube, true);
+        defines.setValue(this._defineLocalCubicName, (<any>texture).boundingBoxSize ? true : false, true);
+        defines.setValue(this._defineExplicitName, texture.coordinatesMode === Constants.TEXTURE_EXPLICIT_MODE, true);
+        defines.setValue(this._defineSkyboxName, texture.coordinatesMode === Constants.TEXTURE_SKYBOX_MODE, true);
+        defines.setValue(this._defineCubicName, texture.coordinatesMode === Constants.TEXTURE_CUBIC_MODE, true);
+        defines.setValue(this._defineSphericalName, texture.coordinatesMode === Constants.TEXTURE_SPHERICAL_MODE, true);
+        defines.setValue(this._definePlanarName, texture.coordinatesMode === Constants.TEXTURE_PLANAR_MODE, true);
+        defines.setValue(this._defineProjectionName, texture.coordinatesMode === Constants.TEXTURE_PROJECTION_MODE, true);
+        defines.setValue(this._defineEquirectangularName, texture.coordinatesMode === Constants.TEXTURE_EQUIRECTANGULAR_MODE, true);
+        defines.setValue(this._defineEquirectangularFixedName, texture.coordinatesMode === Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MODE, true);
+        defines.setValue(this._defineMirroredEquirectangularFixedName, texture.coordinatesMode === Constants.TEXTURE_FIXED_EQUIRECTANGULAR_MIRRORED_MODE, true);
     }
     }
 
 
     public isReady() {
     public isReady() {

+ 2 - 2
src/Materials/Node/Blocks/PBR/ambientOcclusionBlock.ts

@@ -108,8 +108,8 @@ export class AmbientOcclusionBlock extends NodeMaterialBlock {
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
         super.prepareDefines(mesh, nodeMaterial, defines);
         super.prepareDefines(mesh, nodeMaterial, defines);
 
 
-        defines.setValue("AMBIENT", this.texture.isConnected);
-        defines.setValue("AMBIENTINGRAYSCALE", this.useAmbientInGrayScale);
+        defines.setValue("AMBIENT", this.texture.isConnected, true);
+        defines.setValue("AMBIENTINGRAYSCALE", this.useAmbientInGrayScale, true);
     }
     }
 
 
     protected _buildBlock(state: NodeMaterialBuildState) {
     protected _buildBlock(state: NodeMaterialBuildState) {

+ 1 - 1
src/Materials/Node/Blocks/PBR/anisotropyBlock.ts

@@ -181,7 +181,7 @@ export class AnisotropyBlock extends NodeMaterialBlock {
         super.prepareDefines(mesh, nodeMaterial, defines);
         super.prepareDefines(mesh, nodeMaterial, defines);
 
 
         defines.setValue("ANISOTROPIC", true);
         defines.setValue("ANISOTROPIC", true);
-        defines.setValue("ANISOTROPIC_TEXTURE", this.texture.isConnected);
+        defines.setValue("ANISOTROPIC_TEXTURE", this.texture.isConnected, true);
     }
     }
 
 
     protected _buildBlock(state: NodeMaterialBuildState) {
     protected _buildBlock(state: NodeMaterialBuildState) {

+ 50 - 9
src/Materials/Node/Blocks/PBR/clearCoatBlock.ts

@@ -43,6 +43,7 @@ export class ClearCoatBlock extends NodeMaterialBlock {
         this.registerInput("tintAtDistance", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintAtDistance", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintThickness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintThickness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("worldTangent", NodeMaterialBlockConnectionPointTypes.Vector4, true);
 
 
         this.registerOutput("clearcoat", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
         this.registerOutput("clearcoat", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Output, ClearCoatBlock, "ClearCoatBlock"));
             new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Output, ClearCoatBlock, "ClearCoatBlock"));
@@ -139,6 +140,13 @@ export class ClearCoatBlock extends NodeMaterialBlock {
     }
     }
 
 
     /**
     /**
+     * Gets the world tangent input component
+     */
+    public get worldTangent(): NodeMaterialConnectionPoint {
+        return this._inputs[10];
+    }
+
+    /**
      * Gets the clear coat object output component
      * Gets the clear coat object output component
      */
      */
     public get clearcoat(): NodeMaterialConnectionPoint {
     public get clearcoat(): NodeMaterialConnectionPoint {
@@ -157,12 +165,11 @@ export class ClearCoatBlock extends NodeMaterialBlock {
         super.prepareDefines(mesh, nodeMaterial, defines);
         super.prepareDefines(mesh, nodeMaterial, defines);
 
 
         defines.setValue("CLEARCOAT", true);
         defines.setValue("CLEARCOAT", true);
-        defines.setValue("CLEARCOAT_TEXTURE", this.texture.isConnected);
-        defines.setValue("CLEARCOAT_TINT", this.tintColor.isConnected || this.tintThickness.isConnected || this.tintAtDistance.isConnected || this.tintTexture.isConnected);
-        defines.setValue("CLEARCOAT_TINT_TEXTURE", this.tintTexture.isConnected);
-        defines.setValue("CLEARCOAT_BUMP", this.bumpTexture.isConnected);
-        defines.setValue("CLEARCOAT_DEFAULTIOR", this.ior.isConnected ? this.ior.connectInputBlock!.value === 1.5 : false);
-
+        defines.setValue("CLEARCOAT_TEXTURE", this.texture.isConnected, true);
+        defines.setValue("CLEARCOAT_TINT", this.tintColor.isConnected || this.tintThickness.isConnected || this.tintAtDistance.isConnected || this.tintTexture.isConnected, true);
+        defines.setValue("CLEARCOAT_TINT_TEXTURE", this.tintTexture.isConnected, true);
+        defines.setValue("CLEARCOAT_BUMP", this.bumpTexture.isConnected, true);
+        defines.setValue("CLEARCOAT_DEFAULTIOR", this.ior.isConnected ? this.ior.connectInputBlock!.value === 1.5 : false, true);
     }
     }
 
 
     public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
     public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
@@ -189,15 +196,44 @@ export class ClearCoatBlock extends NodeMaterialBlock {
         }
         }
     }
     }
 
 
+    private _generateTBNSpace(state: NodeMaterialBuildState, worldPositionVarName: string, worldNormalVarName: string) {
+        let code = "";
+
+        let comments = `//${this.name}`;
+        let worldTangent = this.worldTangent;
+
+        state._emitExtension("derivatives", "#extension GL_OES_standard_derivatives : enable");
+
+        let tangentReplaceString = { search: /defined\(TANGENT\)/g, replace: worldTangent.isConnected ? "defined(TANGENT)" : "defined(IGNORE)" };
+
+        if (worldTangent.isConnected) {
+            code += `vec3 tbnNormal = normalize(${worldNormalVarName}.xyz);\r\n`;
+            code += `vec3 tbnTangent = normalize(${worldTangent.associatedVariableName}.xyz);\r\n`;
+            code += `vec3 tbnBitangent = cross(tbnNormal, tbnTangent);\r\n`;
+            code += `mat3 vTBN = mat3(tbnTangent, tbnBitangent, tbnNormal);\r\n`;
+        }
+
+        state._emitFunctionFromInclude("bumpFragmentMainFunctions", comments, {
+            replaceStrings: [
+                tangentReplaceString,
+            ]
+        });
+
+        return code;
+    }
+
     /**
     /**
      * Gets the main code of the block (fragment side)
      * Gets the main code of the block (fragment side)
      * @param state current state of the node material building
      * @param state current state of the node material building
      * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
      * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
      * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
      * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
      * @param worldPosVarName name of the variable holding the world position
      * @param worldPosVarName name of the variable holding the world position
+     * @param generateTBNSpace if true, the code needed to create the TBN coordinate space is generated
+     * @param vTBNAvailable indicate that the vTBN variable is already existing because it has already been generated by another block (PerturbNormal or Anisotropy)
+     * @param worldNormalVarName name of the variable holding the world normal
      * @returns the shader code
      * @returns the shader code
      */
      */
-    public static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string {
+    public static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string, generateTBNSpace: boolean, vTBNAvailable: boolean, worldNormalVarName: string): string {
         let code = "";
         let code = "";
 
 
         const intensity = ccBlock?.intensity.isConnected ? ccBlock.intensity.associatedVariableName : "1.";
         const intensity = ccBlock?.intensity.isConnected ? ccBlock.intensity.associatedVariableName : "1.";
@@ -216,7 +252,12 @@ export class ClearCoatBlock extends NodeMaterialBlock {
             state._emitUniformFromString("vClearCoatTangentSpaceParams", "vec2");
             state._emitUniformFromString("vClearCoatTangentSpaceParams", "vec2");
         }
         }
 
 
-        code = `clearcoatOutParams clearcoatOut;
+        if (generateTBNSpace && ccBlock) {
+            code += ccBlock._generateTBNSpace(state, worldPosVarName, worldNormalVarName);
+            vTBNAvailable = ccBlock.worldTangent.isConnected;
+        }
+
+        code += `clearcoatOutParams clearcoatOut;
 
 
         #ifdef CLEARCOAT
         #ifdef CLEARCOAT
             vec2 vClearCoatParams = vec2(${intensity}, ${roughness});
             vec2 vClearCoatParams = vec2(${intensity}, ${roughness});
@@ -243,7 +284,7 @@ export class ClearCoatBlock extends NodeMaterialBlock {
                 vec2(0., 1.),
                 vec2(0., 1.),
                 ${bumpTexture},
                 ${bumpTexture},
                 ${uv},
                 ${uv},
-                #if defined(TANGENT) && defined(NORMAL)
+                #if defined(${vTBNAvailable ? "TANGENT" : "IGNORE"}) && defined(NORMAL)
                     vTBN,
                     vTBN,
                 #else
                 #else
                     vClearCoatTangentSpaceParams,
                     vClearCoatTangentSpaceParams,

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

@@ -5,3 +5,5 @@ export * from "./reflectivityBlock";
 export * from "./anisotropyBlock";
 export * from "./anisotropyBlock";
 export * from "./reflectionBlock";
 export * from "./reflectionBlock";
 export * from "./clearCoatBlock";
 export * from "./clearCoatBlock";
+export * from "./refractionBlock";
+export * from "./subSurfaceBlock";

+ 75 - 29
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -26,6 +26,9 @@ import { MaterialFlags } from '../../../materialFlags';
 import { AnisotropyBlock } from './anisotropyBlock';
 import { AnisotropyBlock } from './anisotropyBlock';
 import { ReflectionBlock } from './reflectionBlock';
 import { ReflectionBlock } from './reflectionBlock';
 import { ClearCoatBlock } from './clearCoatBlock';
 import { ClearCoatBlock } from './clearCoatBlock';
+import { SubSurfaceBlock } from './subSurfaceBlock';
+import { RefractionBlock } from './refractionBlock';
+import { PerturbNormalBlock } from '../Fragment/perturbNormalBlock';
 
 
 const mapOutputToVariable: { [name: string] : [string, string] } = {
 const mapOutputToVariable: { [name: string] : [string, string] } = {
     "ambient":      ["finalAmbient", ""],
     "ambient":      ["finalAmbient", ""],
@@ -84,9 +87,10 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Input, ReflectionBlock, "ReflectionBlock"));
             new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Input, ReflectionBlock, "ReflectionBlock"));
         this.registerInput("sheen", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
         this.registerInput("sheen", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("sheen", this, NodeMaterialConnectionPointDirection.Input, SheenBlock, "SheenBlock"));
             new NodeMaterialConnectionPointCustomObject("sheen", this, NodeMaterialConnectionPointDirection.Input, SheenBlock, "SheenBlock"));
-        this.registerInput("clearCoat", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
+        this.registerInput("clearcoat", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Input, ClearCoatBlock, "ClearCoatBlock"));
             new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Input, ClearCoatBlock, "ClearCoatBlock"));
-        this.registerInput("subSurface", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("subsurface", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Input, SubSurfaceBlock, "SubSurfaceBlock"));
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
 
 
@@ -106,6 +110,27 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     }
     }
 
 
     /**
     /**
+     * Intensity of the direct lights e.g. the four lights available in your scene.
+     * This impacts both the direct diffuse and specular highlights.
+     */
+    @editableInPropertyPage("Direct lights", PropertyTypeForEdition.Float, "INTENSITY", { min: 0, max: 1, "notifiers": { "update": true }})
+    public directIntensity: number = 1.0;
+
+    /**
+     * Intensity of the environment e.g. how much the environment will light the object
+     * either through harmonics for rough material or through the refelction for shiny ones.
+     */
+    @editableInPropertyPage("Environment lights", PropertyTypeForEdition.Float, "INTENSITY", { min: 0, max: 1, "notifiers": { "update": true }})
+    public environmentIntensity: number = 1.0;
+
+    /**
+     * This is a special control allowing the reduction of the specular highlights coming from the
+     * four lights of the scene. Those highlights may not be needed in full environment lighting.
+     */
+    @editableInPropertyPage("Specular highlights", PropertyTypeForEdition.Float, "INTENSITY", { min: 0, max: 1, "notifiers": { "update": true }})
+    public specularIntensity: number = 1.0;
+
+    /**
      * Defines the  falloff type used in this material.
      * Defines the  falloff type used in this material.
      * It by default is Physical.
      * It by default is Physical.
      */
      */
@@ -431,7 +456,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     /**
     /**
      * Gets the sub surface object parameters
      * Gets the sub surface object parameters
      */
      */
-    public get subSurface(): NodeMaterialConnectionPoint {
+    public get subsurface(): NodeMaterialConnectionPoint {
         return this._inputs[13];
         return this._inputs[13];
     }
     }
 
 
@@ -549,14 +574,14 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         // General
         // General
         defines.setValue("PBR", true);
         defines.setValue("PBR", true);
         defines.setValue("METALLICWORKFLOW", true);
         defines.setValue("METALLICWORKFLOW", true);
-        defines.setValue("DEBUGMODE", this.debugMode);
+        defines.setValue("DEBUGMODE", this.debugMode, true);
         defines.setValue("NORMALXYSCALE", true);
         defines.setValue("NORMALXYSCALE", true);
-        defines.setValue("BUMP", this.perturbedNormal.isConnected);
+        defines.setValue("BUMP", this.perturbedNormal.isConnected, true);
         defines.setValue("LODBASEDMICROSFURACE", this._scene.getEngine().getCaps().textureLOD);
         defines.setValue("LODBASEDMICROSFURACE", this._scene.getEngine().getCaps().textureLOD);
 
 
         // Albedo & Opacity
         // Albedo & Opacity
-        defines.setValue("ALBEDO", this.baseTexture.isConnected);
-        defines.setValue("OPACITY", this.opacityTexture.isConnected);
+        defines.setValue("ALBEDO", this.baseTexture.isConnected, true);
+        defines.setValue("OPACITY", this.opacityTexture.isConnected, true);
 
 
         // Lighting & colors
         // Lighting & colors
         if (this.lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_STANDARD) {
         if (this.lightFalloff === PBRBaseMaterial.LIGHTFALLOFF_STANDARD) {
@@ -571,28 +596,28 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         }
         }
 
 
         // Transparency
         // Transparency
-        defines.setValue("ALPHABLEND", this.useAlphaBlending);
-        defines.setValue("ALPHAFROMALBEDO", this.useAlphaFromAlbedoTexture);
-        defines.setValue("ALPHATEST", this.useAlphaTest);
-        defines.setValue("ALPHATESTVALUE", this.alphaTestCutoff);
-        defines.setValue("OPACITYRGB", this.opacityRGB);
+        defines.setValue("ALPHABLEND", this.useAlphaBlending, true);
+        defines.setValue("ALPHAFROMALBEDO", this.useAlphaFromAlbedoTexture, true);
+        defines.setValue("ALPHATEST", this.useAlphaTest, true);
+        defines.setValue("ALPHATESTVALUE", this.alphaTestCutoff, true);
+        defines.setValue("OPACITYRGB", this.opacityRGB, true);
 
 
         // Rendering
         // Rendering
-        defines.setValue("RADIANCEOVERALPHA", this.useRadianceOverAlpha);
-        defines.setValue("SPECULAROVERALPHA", this.useSpecularOverAlpha);
-        defines.setValue("SPECULARAA", this._scene.getEngine().getCaps().standardDerivatives && this.enableSpecularAntiAliasing);
+        defines.setValue("RADIANCEOVERALPHA", this.useRadianceOverAlpha, true);
+        defines.setValue("SPECULAROVERALPHA", this.useSpecularOverAlpha, true);
+        defines.setValue("SPECULARAA", this._scene.getEngine().getCaps().standardDerivatives && this.enableSpecularAntiAliasing, true);
 
 
         // Advanced
         // Advanced
         defines.setValue("BRDF_V_HEIGHT_CORRELATED", true);
         defines.setValue("BRDF_V_HEIGHT_CORRELATED", true);
-        defines.setValue("MS_BRDF_ENERGY_CONSERVATION", this.useEnergyConservation);
-        defines.setValue("RADIANCEOCCLUSION", this.useRadianceOcclusion);
-        defines.setValue("HORIZONOCCLUSION", this.useHorizonOcclusion);
-        defines.setValue("UNLIT", this.unlit);
-        defines.setValue("FORCENORMALFORWARD", this.forceNormalForward);
+        defines.setValue("MS_BRDF_ENERGY_CONSERVATION", this.useEnergyConservation, true);
+        defines.setValue("RADIANCEOCCLUSION", this.useRadianceOcclusion, true);
+        defines.setValue("HORIZONOCCLUSION", this.useHorizonOcclusion, true);
+        defines.setValue("UNLIT", this.unlit, true);
+        defines.setValue("FORCENORMALFORWARD", this.forceNormalForward, true);
 
 
         if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) {
         if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) {
             defines.setValue("ENVIRONMENTBRDF", true);
             defines.setValue("ENVIRONMENTBRDF", true);
-            defines.setValue("ENVIRONMENTBRDF_RGBD", this._environmentBRDFTexture.isRGBD);
+            defines.setValue("ENVIRONMENTBRDF_RGBD", this._environmentBRDFTexture.isRGBD, true);
         } else {
         } else {
             defines.setValue("ENVIRONMENTBRDF" , false);
             defines.setValue("ENVIRONMENTBRDF" , false);
             defines.setValue("ENVIRONMENTBRDF_RGBD", false);
             defines.setValue("ENVIRONMENTBRDF_RGBD", false);
@@ -664,6 +689,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         const invertNormal = (scene.useRightHandedSystem === (scene._mirroredCameraPosition != null));
         const invertNormal = (scene.useRightHandedSystem === (scene._mirroredCameraPosition != null));
 
 
         effect.setFloat(this._invertNormalName, invertNormal ? -1 : 1);
         effect.setFloat(this._invertNormalName, invertNormal ? -1 : 1);
+
+        effect.setFloat4("vLightingIntensity", this.directIntensity, 1, this.environmentIntensity * this._scene.environmentIntensity, this.specularIntensity);
     }
     }
 
 
     private _injectVertexCode(state: NodeMaterialBuildState) {
     private _injectVertexCode(state: NodeMaterialBuildState) {
@@ -836,13 +863,12 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state._emitFunctionFromInclude("pbrBlockAmbientOcclusion", comments);
         state._emitFunctionFromInclude("pbrBlockAmbientOcclusion", comments);
         state._emitFunctionFromInclude("pbrBlockAlphaFresnel", comments);
         state._emitFunctionFromInclude("pbrBlockAlphaFresnel", comments);
         state._emitFunctionFromInclude("pbrBlockAnisotropic", comments);
         state._emitFunctionFromInclude("pbrBlockAnisotropic", comments);
-        state._emitFunctionFromInclude("pbrBlockSubSurface", comments);
 
 
         //
         //
         // code
         // code
         //
         //
 
 
-        state.compilationString += `vec4 vLightingIntensity = vec4(1.);\r\n`;
+        state._emitUniformFromString("vLightingIntensity", "vec4");
 
 
         // _____________________________ Geometry Information ____________________________
         // _____________________________ Geometry Information ____________________________
         this._vNormalWName = state._getFreeVariableName("vNormalW");
         this._vNormalWName = state._getFreeVariableName("vNormalW");
@@ -945,8 +971,16 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
 
         // _____________________________ Clear Coat ____________________________
         // _____________________________ Clear Coat ____________________________
         const clearcoatBlock = this.clearcoat.isConnected ? this.clearcoat.connectedPoint?.ownerBlock as ClearCoatBlock : null;
         const clearcoatBlock = this.clearcoat.isConnected ? this.clearcoat.connectedPoint?.ownerBlock as ClearCoatBlock : null;
+        const generateTBNSpace = !this.perturbedNormal.isConnected && !this.anisotropy.isConnected;
+        const isTangentConnectedToPerturbNormal = this.perturbedNormal.isConnected && (this.perturbedNormal.connectedPoint?.ownerBlock as PerturbNormalBlock).worldTangent.isConnected;
+        const isTangentConnectedToAnisotropy = this.anisotropy.isConnected && (this.anisotropy.connectedPoint?.ownerBlock as AnisotropyBlock).worldTangent.isConnected;
+        let vTBNAvailable = isTangentConnectedToPerturbNormal || (!this.perturbedNormal.isConnected && isTangentConnectedToAnisotropy);
 
 
-        state.compilationString += ClearCoatBlock.GetCode(state, clearcoatBlock, reflectionBlock, worldPosVarName);
+        state.compilationString += ClearCoatBlock.GetCode(state, clearcoatBlock, reflectionBlock, worldPosVarName, generateTBNSpace, vTBNAvailable, this.worldNormal.associatedVariableName);
+
+        if (generateTBNSpace) {
+            vTBNAvailable = clearcoatBlock?.worldTangent.isConnected ?? false;
+        }
 
 
         state._emitFunctionFromInclude("pbrBlockClearcoat", comments, {
         state._emitFunctionFromInclude("pbrBlockClearcoat", comments, {
             replaceStrings: [
             replaceStrings: [
@@ -957,6 +991,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
                 { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
                 { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
                 { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
                 { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
                 { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
                 { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+                { search: /defined\(TANGENT\)/g, replace: vTBNAvailable ? "defined(TANGENT)" : "defined(IGNORE)" },
             ]
             ]
         });
         });
 
 
@@ -969,11 +1004,22 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         });
         });
 
 
         // ___________________________________ SubSurface ______________________________________
         // ___________________________________ SubSurface ______________________________________
-        state.compilationString += `subSurfaceOutParams subSurfaceOut;
-            #ifdef SUBSURFACE
-            #else
-                subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
-            #endif\r\n`;
+        const subsurfaceBlock = this.subsurface.isConnected ? this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock : null;
+        const refractionBlock = this.subsurface.isConnected ? (this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock).refraction.connectedPoint?.ownerBlock as RefractionBlock : null;
+
+        state.compilationString += SubSurfaceBlock.GetCode(state, subsurfaceBlock, reflectionBlock, worldPosVarName);
+
+        state._emitFunctionFromInclude("pbrBlockSubSurface", comments, {
+            replaceStrings: [
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+                { search: /REFLECTIONMAP_OPPOSITEZ/g, replace: reflectionBlock?._defineOppositeZ ?? "REFLECTIONMAP_OPPOSITEZ" },
+                { search: /REFLECTIONMAP_PROJECTION/g, replace: reflectionBlock?._defineProjectionName ?? "REFLECTIONMAP_PROJECTION" },
+                { search: /SS_REFRACTIONMAP_3D/g, replace: refractionBlock?._define3DName ?? "SS_REFRACTIONMAP_3D" },
+                { search: /SS_LODINREFRACTIONALPHA/g, replace: refractionBlock?._defineLODRefractionAlpha ?? "SS_LODINREFRACTIONALPHA" },
+                { search: /SS_LINEARSPECULARREFRACTION/g, replace: refractionBlock?._defineLinearSpecularRefraction ?? "SS_LINEARSPECULARREFRACTION" },
+                { search: /SS_REFRACTIONMAP_OPPOSITEZ/g, replace: refractionBlock?._defineOppositeZ ?? "SS_REFRACTIONMAP_OPPOSITEZ" },
+            ]
+        });
 
 
         // _____________________________ Direct Lighting Info __________________________________
         // _____________________________ Direct Lighting Info __________________________________
         state.compilationString += state._emitCodeFromInclude("pbrBlockDirectLighting", comments);
         state.compilationString += state._emitCodeFromInclude("pbrBlockDirectLighting", comments);

+ 5 - 5
src/Materials/Node/Blocks/PBR/reflectionBlock.ts

@@ -168,17 +168,17 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         const reflectionTexture = this._getTexture();
         const reflectionTexture = this._getTexture();
         const reflection = reflectionTexture && reflectionTexture.getTextureMatrix;
         const reflection = reflectionTexture && reflectionTexture.getTextureMatrix;
 
 
-        defines.setValue("REFLECTION", reflection);
+        defines.setValue("REFLECTION", reflection, true);
 
 
         if (!reflection) {
         if (!reflection) {
             return;
             return;
         }
         }
 
 
-        defines.setValue(this._defineLODReflectionAlpha, reflectionTexture!.lodLevelInAlpha);
-        defines.setValue(this._defineLinearSpecularReflection, reflectionTexture!.linearSpecularLOD);
-        defines.setValue(this._defineOppositeZ, this._scene.useRightHandedSystem ? !reflectionTexture!.invertZ : reflectionTexture!.invertZ);
+        defines.setValue(this._defineLODReflectionAlpha, reflectionTexture!.lodLevelInAlpha, true);
+        defines.setValue(this._defineLinearSpecularReflection, reflectionTexture!.linearSpecularLOD, true);
+        defines.setValue(this._defineOppositeZ, this._scene.useRightHandedSystem ? !reflectionTexture!.invertZ : reflectionTexture!.invertZ, true);
 
 
-        defines.setValue("SPHERICAL_HARMONICS", this.useSphericalHarmonics);
+        defines.setValue("SPHERICAL_HARMONICS", this.useSphericalHarmonics, true);
 
 
         if (reflectionTexture && reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
         if (reflectionTexture && reflectionTexture.coordinatesMode !== Texture.SKYBOX_MODE) {
             if (reflectionTexture.isCube) {
             if (reflectionTexture.isCube) {

+ 6 - 6
src/Materials/Node/Blocks/PBR/reflectivityBlock.ts

@@ -155,12 +155,12 @@ export class ReflectivityBlock extends NodeMaterialBlock {
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
         super.prepareDefines(mesh, nodeMaterial, defines);
         super.prepareDefines(mesh, nodeMaterial, defines);
 
 
-        defines.setValue("REFLECTIVITY", this.texture.isConnected);
-        defines.setValue("AOSTOREINMETALMAPRED", this.useAmbientOcclusionFromMetallicTextureRed);
-        defines.setValue("METALLNESSSTOREINMETALMAPBLUE", this.useMetallnessFromMetallicTextureBlue);
-        defines.setValue("ROUGHNESSSTOREINMETALMAPALPHA", this.useRoughnessFromMetallicTextureAlpha);
-        defines.setValue("ROUGHNESSSTOREINMETALMAPGREEN",  !this.useRoughnessFromMetallicTextureAlpha && this.useRoughnessFromMetallicTextureGreen);
-        defines.setValue("METALLICF0FACTORFROMMETALLICMAP", this.useMetallicF0FactorFromMetallicTexture);
+        defines.setValue("REFLECTIVITY", this.texture.isConnected, true);
+        defines.setValue("AOSTOREINMETALMAPRED", this.useAmbientOcclusionFromMetallicTextureRed, true);
+        defines.setValue("METALLNESSSTOREINMETALMAPBLUE", this.useMetallnessFromMetallicTextureBlue, true);
+        defines.setValue("ROUGHNESSSTOREINMETALMAPALPHA", this.useRoughnessFromMetallicTextureAlpha, true);
+        defines.setValue("ROUGHNESSSTOREINMETALMAPGREEN",  !this.useRoughnessFromMetallicTextureAlpha && this.useRoughnessFromMetallicTextureGreen, true);
+        defines.setValue("METALLICF0FACTORFROMMETALLICMAP", this.useMetallicF0FactorFromMetallicTexture, true);
     }
     }
 
 
     protected _buildBlock(state: NodeMaterialBuildState) {
     protected _buildBlock(state: NodeMaterialBuildState) {

+ 338 - 0
src/Materials/Node/Blocks/PBR/refractionBlock.ts

@@ -0,0 +1,338 @@
+import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
+import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
+import { _TypeStore } from '../../../../Misc/typeStore';
+import { InputBlock } from '../Input/inputBlock';
+import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
+import { Nullable } from '../../../../types';
+import { BaseTexture } from '../../../Textures/baseTexture';
+import { Mesh } from '../../../../Meshes/mesh';
+import { SubMesh } from '../../../../Meshes/subMesh';
+import { Effect } from '../../../effect';
+import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
+import { Scene } from '../../../../scene';
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { CubeTexture } from '../../../Textures/cubeTexture';
+import { Texture } from '../../../Textures/texture';
+import { NodeMaterialSystemValues } from '../../Enums/nodeMaterialSystemValues';
+
+/**
+ * Block used to implement the refraction part of the sub surface module of the PBR material
+ */
+export class RefractionBlock extends NodeMaterialBlock {
+
+    /** @hidden */
+    public _define3DName: string;
+    /** @hidden */
+    public _refractionMatrixName: string;
+    /** @hidden */
+    public _defineLODRefractionAlpha: string;
+    /** @hidden */
+    public _defineLinearSpecularRefraction: string;
+    /** @hidden */
+    public _defineOppositeZ: string;
+    /** @hidden */
+    public _cubeSamplerName: string;
+    /** @hidden */
+    public _2DSamplerName: string;
+    /** @hidden */
+    public _vRefractionMicrosurfaceInfosName: string;
+    /** @hidden */
+    public _vRefractionInfosName: string;
+
+    private _scene: Scene;
+
+    /**
+     * This parameters will make the material used its opacity to control how much it is refracting aginst not.
+     * Materials half opaque for instance using refraction could benefit from this control.
+     */
+    @editableInPropertyPage("Link refraction to transparency", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
+    public linkRefractionWithTransparency: boolean = false;
+
+    /**
+     * Controls if refraction needs to be inverted on Y. This could be useful for procedural texture.
+     */
+    @editableInPropertyPage("Invert refraction Y", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
+    public invertRefractionY: boolean = false;
+
+    /**
+     * Gets or sets the texture associated with the node
+     */
+    public texture: Nullable<BaseTexture>;
+
+    /**
+     * Create a new RefractionBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this._isUnique = true;
+
+        this.registerInput("intensity", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("indexOfRefraction", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintAtDistance", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Fragment);
+
+        this.registerOutput("refraction", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("refraction", this, NodeMaterialConnectionPointDirection.Output, RefractionBlock, "RefractionBlock"));
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "RefractionBlock";
+    }
+
+    /**
+     * Gets the intensity input component
+     */
+    public get intensity(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the index of refraction input component
+     */
+    public get indexOfRefraction(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the tint at distance input component
+     */
+    public get tintAtDistance(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+     * Gets the view input component
+     */
+    public get view(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
+    /**
+     * Gets the refraction object output component
+     */
+    public get refraction(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    /**
+     * Returns true if the block has a texture
+     */
+    public get hasTexture(): boolean {
+        return !!this._getTexture();
+    }
+
+    protected _getTexture(): Nullable<BaseTexture> {
+        if (this.texture) {
+            return this.texture;
+        }
+
+        return this._scene.environmentTexture;
+    }
+
+    public autoConfigure(material: NodeMaterial) {
+        if (!this.intensity.isConnected) {
+            let intensityInput = new InputBlock("Refraction intensity", NodeMaterialBlockTargets.Fragment, NodeMaterialBlockConnectionPointTypes.Float);
+            intensityInput.value = 1;
+            intensityInput.output.connectTo(this.intensity);
+        }
+
+        if (!this.view.isConnected) {
+            let viewInput = material.getInputBlockByPredicate((b) => b.systemValue === NodeMaterialSystemValues.View);
+
+            if (!viewInput) {
+                viewInput = new InputBlock("view");
+                viewInput.setAsSystemValue(NodeMaterialSystemValues.View);
+            }
+            viewInput.output.connectTo(this.view);
+        }
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        super.prepareDefines(mesh, nodeMaterial, defines);
+
+        const refractionTexture = this._getTexture();
+        const refraction = refractionTexture && refractionTexture.getTextureMatrix;
+
+        defines.setValue("SS_REFRACTION", refraction, true);
+
+        if (!refraction) {
+            return;
+        }
+
+        defines.setValue(this._define3DName, refractionTexture!.isCube, true);
+        defines.setValue(this._defineLODRefractionAlpha, refractionTexture!.lodLevelInAlpha, true);
+        defines.setValue(this._defineLinearSpecularRefraction, refractionTexture!.linearSpecularLOD, true);
+        defines.setValue(this._defineOppositeZ, this._scene.useRightHandedSystem ? !refractionTexture!.invertZ : refractionTexture!.invertZ, true);
+
+        defines.setValue("SS_LINKREFRACTIONTOTRANSPARENCY", this.linkRefractionWithTransparency, true);
+    }
+
+    public isReady() {
+        const texture = this._getTexture();
+
+        if (texture && !texture.isReadyOrNotBlocking()) {
+            return false;
+        }
+
+        return true;
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
+        super.bind(effect, nodeMaterial, mesh);
+
+        const refractionTexture = this._getTexture();
+
+        if (!refractionTexture) {
+            return;
+        }
+
+        if (refractionTexture.isCube) {
+            effect.setTexture(this._cubeSamplerName, refractionTexture);
+        } else {
+            effect.setTexture(this._2DSamplerName, refractionTexture);
+        }
+
+        effect.setMatrix(this._refractionMatrixName, refractionTexture.getReflectionTextureMatrix());
+
+        let depth = 1.0;
+        if (!refractionTexture.isCube) {
+            if ((<any>refractionTexture).depth) {
+                depth = (<any>refractionTexture).depth;
+            }
+        }
+
+        const indexOfRefraction = this.indexOfRefraction.connectInputBlock?.value ?? 1.0;
+
+        effect.setFloat4(this._vRefractionInfosName, refractionTexture.level, 1 / indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
+
+        effect.setFloat3(this._vRefractionMicrosurfaceInfosName, refractionTexture.getSize().width, refractionTexture.lodGenerationScale, refractionTexture.lodGenerationOffset);
+    }
+
+    /**
+     * Gets the main code of the block (fragment side)
+     * @param state current state of the node material building
+     * @returns the shader code
+     */
+    public getCode(state: NodeMaterialBuildState): string {
+        let code = "";
+
+        state.sharedData.blockingBlocks.push(this);
+        state.sharedData.textureBlocks.push(this);
+
+        // Samplers
+        this._cubeSamplerName = state._getFreeVariableName(this.name + "CubeSampler");
+        state.samplers.push(this._cubeSamplerName);
+
+        this._2DSamplerName = state._getFreeVariableName(this.name + "2DSampler");
+        state.samplers.push(this._2DSamplerName);
+
+        this._define3DName = state._getFreeDefineName("SS_REFRACTIONMAP_3D");
+
+        state._samplerDeclaration += `#ifdef ${this._define3DName}\r\n`;
+        state._samplerDeclaration += `uniform samplerCube ${this._cubeSamplerName};\r\n`;
+        state._samplerDeclaration += `#else\r\n`;
+        state._samplerDeclaration += `uniform sampler2D ${this._2DSamplerName};\r\n`;
+        state._samplerDeclaration += `#endif\r\n`;
+
+        // Fragment
+        state.sharedData.blocksWithDefines.push(this);
+        state.sharedData.bindableBlocks.push(this);
+
+        this._defineLODRefractionAlpha = state._getFreeDefineName("SS_LODINREFRACTIONALPHA");
+        this._defineLinearSpecularRefraction = state._getFreeDefineName("SS_LINEARSPECULARREFRACTION");
+        this._defineOppositeZ = state._getFreeDefineName("SS_REFRACTIONMAP_OPPOSITEZ");
+
+        this._refractionMatrixName = state._getFreeVariableName("refractionMatrix");
+
+        state._emitUniformFromString(this._refractionMatrixName, "mat4");
+
+        state._emitFunction("sampleRefraction", `
+            #ifdef ${this._define3DName}
+                #define sampleRefraction(s, c) textureCube(s, c)
+            #else
+                #define sampleRefraction(s, c) texture2D(s, c)
+            #endif\r\n`, `//${this.name}`);
+
+        state._emitFunction("sampleRefractionLod", `
+            #ifdef ${this._define3DName}
+                #define sampleRefractionLod(s, c, l) textureCubeLodEXT(s, c, l)
+            #else
+                #define sampleRefractionLod(s, c, l) texture2DLodEXT(s, c, l)
+            #endif\r\n`, `//${this.name}`);
+
+        this._vRefractionMicrosurfaceInfosName = state._getFreeVariableName("vRefractionMicrosurfaceInfos");
+
+        state._emitUniformFromString(this._vRefractionMicrosurfaceInfosName, "vec3");
+
+        this._vRefractionInfosName = state._getFreeVariableName("vRefractionInfos");
+
+        state._emitUniformFromString(this._vRefractionInfosName, "vec4");
+
+        return code;
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        this._scene = state.sharedData.scene;
+
+        return this;
+    }
+
+    protected _dumpPropertiesCode() {
+        let codeString: string = super._dumpPropertiesCode();
+
+        if (this.texture) {
+            if (this.texture.isCube) {
+                codeString = `${this._codeVariableName}.texture = new BABYLON.CubeTexture("${this.texture.name}");\r\n`;
+            } else {
+                codeString = `${this._codeVariableName}.texture = new BABYLON.Texture("${this.texture.name}");\r\n`;
+            }
+            codeString += `${this._codeVariableName}.texture.coordinatesMode = ${this.texture.coordinatesMode};\r\n`;
+        }
+
+        codeString += `${this._codeVariableName}.linkRefractionWithTransparency = ${this.linkRefractionWithTransparency};\r\n`;
+        codeString += `${this._codeVariableName}.invertRefractionY = ${this.invertRefractionY};\r\n`;
+
+        return codeString;
+    }
+
+    public serialize(): any {
+        let serializationObject = super.serialize();
+
+        if (this.texture) {
+            serializationObject.texture = this.texture.serialize();
+        }
+
+        serializationObject.linkRefractionWithTransparency = this.linkRefractionWithTransparency;
+        serializationObject.invertRefractionY = this.invertRefractionY;
+
+        return serializationObject;
+    }
+
+    public _deserialize(serializationObject: any, scene: Scene, rootUrl: string) {
+        super._deserialize(serializationObject, scene, rootUrl);
+
+        if (serializationObject.texture) {
+            rootUrl = serializationObject.texture.url.indexOf("data:") === 0 ? "" : rootUrl;
+            if (serializationObject.texture.isCube) {
+                this.texture = CubeTexture.Parse(serializationObject.texture, scene, rootUrl);
+            } else {
+                this.texture = Texture.Parse(serializationObject.texture, scene, rootUrl);
+            }
+        }
+
+        this.linkRefractionWithTransparency = serializationObject.linkRefractionWithTransparency;
+        this.invertRefractionY = serializationObject.invertRefractionY;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.RefractionBlock"] = RefractionBlock;

+ 4 - 4
src/Materials/Node/Blocks/PBR/sheenBlock.ts

@@ -107,10 +107,10 @@ export class SheenBlock extends NodeMaterialBlock {
         super.prepareDefines(mesh, nodeMaterial, defines);
         super.prepareDefines(mesh, nodeMaterial, defines);
 
 
         defines.setValue("SHEEN", true);
         defines.setValue("SHEEN", true);
-        defines.setValue("SHEEN_LINKWITHALBEDO", this.linkSheenWithAlbedo);
-        defines.setValue("SHEEN_ROUGHNESS", this.roughness.isConnected);
-        defines.setValue("SHEEN_ALBEDOSCALING", this.albedoScaling);
-        defines.setValue("SHEEN_TEXTURE", this.texture.isConnected);
+        defines.setValue("SHEEN_LINKWITHALBEDO", this.linkSheenWithAlbedo, true);
+        defines.setValue("SHEEN_ROUGHNESS", this.roughness.isConnected, true);
+        defines.setValue("SHEEN_ALBEDOSCALING", this.albedoScaling, true);
+        defines.setValue("SHEEN_TEXTURE", this.texture.isConnected, true);
     }
     }
 
 
     /**
     /**

+ 267 - 0
src/Materials/Node/Blocks/PBR/subSurfaceBlock.ts

@@ -0,0 +1,267 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
+import { _TypeStore } from '../../../../Misc/typeStore';
+import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
+import { InputBlock } from '../Input/inputBlock';
+import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
+import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
+import { ReflectionBlock } from './reflectionBlock';
+import { Nullable } from '../../../../types';
+import { RefractionBlock } from './refractionBlock';
+
+/**
+ * Block used to implement the sub surface module of the PBR material
+ */
+export class SubSurfaceBlock extends NodeMaterialBlock {
+
+    /**
+     * Create a new SubSurfaceBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this._isUnique = true;
+
+        this.registerInput("minThickness", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("maxThickness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("thicknessTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("translucencyIntensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("translucencyDiffusionDistance", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("refraction", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("refraction", this, NodeMaterialConnectionPointDirection.Input, RefractionBlock, "RefractionBlock"));
+
+        this.registerOutput("subsurface", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Output, SubSurfaceBlock, "SubSurfaceBlock"));
+    }
+
+    /**
+     * Stores the intensity of the different subsurface effects in the thickness texture.
+     * * the green channel is the translucency intensity.
+     * * the blue channel is the scattering intensity.
+     * * the alpha channel is the refraction intensity.
+     */
+    @editableInPropertyPage("Mask from thickness texture", PropertyTypeForEdition.Boolean, "PROPERTIES", { "notifiers": { "update": true }})
+    public useMaskFromThicknessTexture: boolean = false;
+
+    /**
+     * Initialize the block and prepare the context for build
+     * @param state defines the state that will be used for the build
+     */
+    public initialize(state: NodeMaterialBuildState) {
+        state._excludeVariableName("subSurfaceOut");
+        state._excludeVariableName("vThicknessParam");
+        state._excludeVariableName("vTintColor");
+        state._excludeVariableName("vSubSurfaceIntensity");
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "SubSurfaceBlock";
+    }
+
+    /**
+     * Gets the min thickness input component
+     */
+    public get minThickness(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the max thickness input component
+     */
+    public get maxThickness(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the thickness texture component
+     */
+    public get thicknessTexture(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+     * Gets the tint color input component
+     */
+    public get tintColor(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
+    /**
+     * Gets the translucency intensity input component
+     */
+    public get translucencyIntensity(): NodeMaterialConnectionPoint {
+        return this._inputs[4];
+    }
+
+    /**
+     * Gets the translucency diffusion distance input component
+     */
+    public get translucencyDiffusionDistance(): NodeMaterialConnectionPoint {
+        return this._inputs[5];
+    }
+
+    /**
+     * Gets the refraction object parameters
+     */
+    public get refraction(): NodeMaterialConnectionPoint {
+        return this._inputs[6];
+    }
+
+    /**
+     * Gets the sub surface object output component
+     */
+    public get subsurface(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    public autoConfigure(material: NodeMaterial) {
+        if (!this.minThickness.isConnected) {
+            let minThicknessInput = new InputBlock("SubSurface min thickness", NodeMaterialBlockTargets.Fragment, NodeMaterialBlockConnectionPointTypes.Float);
+            minThicknessInput.value = 0;
+            minThicknessInput.output.connectTo(this.minThickness);
+        }
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        super.prepareDefines(mesh, nodeMaterial, defines);
+
+        const translucencyEnabled = this.translucencyDiffusionDistance.isConnected || this.translucencyIntensity.isConnected;
+
+        defines.setValue("SUBSURFACE", translucencyEnabled || this.refraction.isConnected, true);
+        defines.setValue("SS_TRANSLUCENCY", translucencyEnabled, true);
+        defines.setValue("SS_THICKNESSANDMASK_TEXTURE", this.thicknessTexture.isConnected, true);
+        defines.setValue("SS_MASK_FROM_THICKNESS_TEXTURE", this.useMaskFromThicknessTexture, true);
+    }
+
+    /**
+     * Gets the main code of the block (fragment side)
+     * @param state current state of the node material building
+     * @param ssBlock instance of a SubSurfaceBlock or null if the code must be generated without an active sub surface module
+     * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
+     * @param worldPosVarName name of the variable holding the world position
+     * @returns the shader code
+     */
+    public static GetCode(state: NodeMaterialBuildState, ssBlock: Nullable<SubSurfaceBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string {
+        let code = "";
+
+        const minThickness = ssBlock?.minThickness.isConnected ? ssBlock.minThickness.associatedVariableName : "0.";
+        const maxThickness = ssBlock?.maxThickness.isConnected ? ssBlock.maxThickness.associatedVariableName : "1.";
+        const thicknessTexture = ssBlock?.thicknessTexture.isConnected ? ssBlock.thicknessTexture.associatedVariableName : "vec4(0.)";
+        const tintColor = ssBlock?.tintColor.isConnected ? ssBlock.tintColor.associatedVariableName : "vec3(1.)";
+        const translucencyIntensity = ssBlock?.translucencyIntensity.isConnected ? ssBlock?.translucencyIntensity.associatedVariableName : "1.";
+        const translucencyDiffusionDistance = ssBlock?.translucencyDiffusionDistance.isConnected ? ssBlock?.translucencyDiffusionDistance.associatedVariableName : "vec3(1.)";
+
+        const refractionBlock: Nullable<RefractionBlock> = (ssBlock?.refraction.isConnected ? ssBlock?.refraction.connectedPoint?.ownerBlock : null) as Nullable<RefractionBlock>;
+
+        const refractionTintAtDistance = refractionBlock?.tintAtDistance.isConnected ? refractionBlock.tintAtDistance.associatedVariableName : "1.";
+        const refractionIntensity = refractionBlock?.intensity.isConnected ? refractionBlock.intensity.associatedVariableName : "1.";
+        const refractionView = refractionBlock?.view.isConnected ? refractionBlock.view.associatedVariableName : "";
+
+        code += refractionBlock?.getCode(state) ?? "";
+
+        code += `subSurfaceOutParams subSurfaceOut;
+
+        #ifdef SUBSURFACE
+            vec2 vThicknessParam = vec2(${minThickness}, ${maxThickness} - ${minThickness});
+            vec4 vTintColor = vec4(${tintColor}, ${refractionTintAtDistance});
+            vec3 vSubSurfaceIntensity = vec3(${refractionIntensity}, ${translucencyIntensity}, 0.);
+
+            subSurfaceBlock(
+                vSubSurfaceIntensity,
+                vThicknessParam,
+                vTintColor,
+                normalW,
+                specularEnvironmentReflectance,
+            #ifdef SS_THICKNESSANDMASK_TEXTURE
+                ${thicknessTexture},
+            #endif
+            #ifdef REFLECTION
+                #ifdef SS_TRANSLUCENCY
+                    ${reflectionBlock?._reflectionMatrixName},
+                    #ifdef USESPHERICALFROMREFLECTIONMAP
+                        #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
+                            reflectionOut.irradianceVector,
+                        #endif
+                    #endif
+                    #ifdef USEIRRADIANCEMAP
+                        irradianceSampler,
+                    #endif
+                #endif
+            #endif
+            #ifdef SS_REFRACTION
+                ${worldPosVarName}.xyz,
+                viewDirectionW,
+                ${refractionView},
+                surfaceAlbedo,
+                ${refractionBlock?._vRefractionInfosName ?? ""},
+                ${refractionBlock?._refractionMatrixName ?? ""},
+                ${refractionBlock?._vRefractionMicrosurfaceInfosName ?? ""},
+                vLightingIntensity,
+                #ifdef SS_LINKREFRACTIONTOTRANSPARENCY
+                    alpha,
+                #endif
+                #ifdef ${refractionBlock?._defineLODRefractionAlpha ?? "IGNORE"}
+                    NdotVUnclamped,
+                #endif
+                #ifdef ${refractionBlock?._defineLinearSpecularRefraction ?? "IGNORE"}
+                    roughness,
+                #else
+                    alphaG,
+                #endif
+                #ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
+                    ${refractionBlock?._cubeSamplerName ?? ""},
+                #else
+                    ${refractionBlock?._2DSamplerName ?? ""},
+                #endif
+                #ifndef LODBASEDMICROSFURACE
+                    #ifdef ${refractionBlock?._define3DName ?? "IGNORE"}
+                        ${refractionBlock?._cubeSamplerName ?? ""},
+                        ${refractionBlock?._cubeSamplerName ?? ""},
+                    #else
+                        ${refractionBlock?._2DSamplerName ?? ""},
+                        ${refractionBlock?._2DSamplerName ?? ""},
+                    #endif
+                #endif
+                #ifdef ANISOTROPIC
+                    anisotropicOut,
+                #endif
+            #endif
+            #ifdef SS_TRANSLUCENCY
+                ${translucencyDiffusionDistance},
+            #endif
+                subSurfaceOut
+            );
+
+            #ifdef SS_REFRACTION
+                surfaceAlbedo = subSurfaceOut.surfaceAlbedo;
+                #ifdef SS_LINKREFRACTIONTOTRANSPARENCY
+                    alpha = subSurfaceOut.alpha;
+                #endif
+            #endif
+        #else
+            subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
+        #endif\r\n`;
+
+        return code;
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        if (state.target === NodeMaterialBlockTargets.Fragment) {
+            state.sharedData.blocksWithDefines.push(this);
+        }
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.SubSurfaceBlock"] = SubSurfaceBlock;

+ 7 - 2
src/Materials/Node/nodeMaterial.ts

@@ -27,6 +27,7 @@ import { _TypeStore } from '../../Misc/typeStore';
 import { SerializationHelper } from '../../Misc/decorators';
 import { SerializationHelper } from '../../Misc/decorators';
 import { TextureBlock } from './Blocks/Dual/textureBlock';
 import { TextureBlock } from './Blocks/Dual/textureBlock';
 import { ReflectionTextureBaseBlock } from './Blocks/Dual/reflectionTextureBaseBlock';
 import { ReflectionTextureBaseBlock } from './Blocks/Dual/reflectionTextureBaseBlock';
+import { RefractionBlock } from './Blocks/PBR/refractionBlock';
 import { EffectFallbacks } from '../effectFallbacks';
 import { EffectFallbacks } from '../effectFallbacks';
 import { WebRequest } from '../../Misc/webRequest';
 import { WebRequest } from '../../Misc/webRequest';
 import { Effect } from '../effect';
 import { Effect } from '../effect';
@@ -87,11 +88,15 @@ export class NodeMaterialDefines extends MaterialDefines implements IImageProces
         this.rebuild();
         this.rebuild();
     }
     }
 
 
-    public setValue(name: string, value: any) {
+    public setValue(name: string, value: any, markAsUnprocessedIfDirty = false) {
         if (this[name] === undefined) {
         if (this[name] === undefined) {
             this._keys.push(name);
             this._keys.push(name);
         }
         }
 
 
+        if (markAsUnprocessedIfDirty && this[name] !== value) {
+            this.markAsUnprocessed();
+        }
+
         this[name] = value;
         this[name] = value;
     }
     }
 }
 }
@@ -945,7 +950,7 @@ export class NodeMaterial extends PushMaterial {
      * Gets the list of texture blocks
      * Gets the list of texture blocks
      * @returns an array of texture blocks
      * @returns an array of texture blocks
      */
      */
-    public getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock)[] {
+    public getTextureBlocks(): (TextureBlock | ReflectionTextureBaseBlock | RefractionBlock)[] {
         if (!this._sharedData) {
         if (!this._sharedData) {
             return [];
             return [];
         }
         }

+ 2 - 1
src/Materials/Node/nodeMaterialBuildStateSharedData.ts

@@ -3,6 +3,7 @@ import { NodeMaterialBlock } from './nodeMaterialBlock';
 import { InputBlock } from './Blocks/Input/inputBlock';
 import { InputBlock } from './Blocks/Input/inputBlock';
 import { TextureBlock } from './Blocks/Dual/textureBlock';
 import { TextureBlock } from './Blocks/Dual/textureBlock';
 import { ReflectionTextureBaseBlock } from './Blocks/Dual/reflectionTextureBaseBlock';
 import { ReflectionTextureBaseBlock } from './Blocks/Dual/reflectionTextureBaseBlock';
+import { RefractionBlock } from './Blocks/PBR/refractionBlock';
 import { Scene } from '../../scene';
 import { Scene } from '../../scene';
 
 
 /**
 /**
@@ -32,7 +33,7 @@ export class NodeMaterialBuildStateSharedData {
     /**
     /**
      * Input blocks
      * Input blocks
      */
      */
-    public textureBlocks = new Array<TextureBlock | ReflectionTextureBaseBlock>();
+    public textureBlocks = new Array<TextureBlock | ReflectionTextureBaseBlock | RefractionBlock>();
 
 
     /**
     /**
      * Bindable blocks (Blocks that need to set data to the effect)
      * Bindable blocks (Blocks that need to set data to the effect)

+ 3 - 3
src/Misc/assetsManager.ts

@@ -248,7 +248,7 @@ export class MeshAssetTask extends AbstractAssetTask {
      * @param name defines the name of the task
      * @param name defines the name of the task
      * @param meshesNames defines the list of mesh's names you want to load
      * @param meshesNames defines the list of mesh's names you want to load
      * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
      * @param rootUrl defines the root url to use as a base to load your meshes and associated resources
-     * @param sceneFilename defines the filename of the scene to load from
+     * @param sceneFilename defines the filename or File of the scene to load from
      */
      */
     constructor(
     constructor(
         /**
         /**
@@ -264,9 +264,9 @@ export class MeshAssetTask extends AbstractAssetTask {
          */
          */
         public rootUrl: string,
         public rootUrl: string,
         /**
         /**
-         * Defines the filename of the scene to load from
+         * Defines the filename or File of the scene to load from
          */
          */
-        public sceneFilename: string) {
+        public sceneFilename: string | File) {
         super(name);
         super(name);
     }
     }
 
 

+ 49 - 1
src/Particles/solidParticle.ts

@@ -1,5 +1,5 @@
 import { Nullable } from "../types";
 import { Nullable } from "../types";
-import { Vector3, Matrix, TmpVectors, Quaternion, Vector4 } from "../Maths/math.vector";
+import { Vector3, Matrix, TmpVectors, Quaternion, Vector4, Vector2 } from "../Maths/math.vector";
 import { Color4 } from '../Maths/math.color';
 import { Color4 } from '../Maths/math.color';
 import { Mesh } from "../Meshes/mesh";
 import { Mesh } from "../Meshes/mesh";
 import { BoundingInfo } from "../Culling/boundingInfo";
 import { BoundingInfo } from "../Culling/boundingInfo";
@@ -393,3 +393,51 @@ export class DepthSortedParticle {
         this.materialIndex = materialIndex;
         this.materialIndex = materialIndex;
     }
     }
 }
 }
+
+/**
+ * Represents a solid particle vertex
+ */
+export class SolidParticleVertex {
+    /**
+     * Vertex position
+     */
+    public position: Vector3;
+    /**
+     * Vertex color
+     */
+    public color: Color4;
+    /**
+     * Vertex UV
+     */
+    public uv: Vector2;
+    /**
+     * Creates a new solid particle vertex
+     */
+    constructor() {
+        this.position = Vector3.Zero();
+        this.color = new Color4(1.0, 1.0, 1.0, 1.0);
+        this.uv = Vector2.Zero();
+    }
+    // Getters and Setters for back-compatibility
+    /** Vertex x coordinate */
+    public get x(): number {
+        return this.position.x;
+    }
+    public set x(val: number) {
+        this.position.x = val;
+    }
+    /** Vertex y coordinate */
+    public get y(): number {
+        return this.position.y;
+    }
+    public set y(val: number) {
+        this.position.y = val;
+    }
+    /** Vertex z coordinate */
+    public get z(): number {
+        return this.position.z;
+    }
+    public set z(val: number) {
+        this.position.z = val;
+    }
+}

+ 51 - 29
src/Particles/solidParticleSystem.ts

@@ -7,7 +7,7 @@ import { Mesh } from "../Meshes/mesh";
 import { DiscBuilder } from "../Meshes/Builders/discBuilder";
 import { DiscBuilder } from "../Meshes/Builders/discBuilder";
 import { EngineStore } from "../Engines/engineStore";
 import { EngineStore } from "../Engines/engineStore";
 import { Scene, IDisposable } from "../scene";
 import { Scene, IDisposable } from "../scene";
-import { DepthSortedParticle, SolidParticle, ModelShape } from "./solidParticle";
+import { DepthSortedParticle, SolidParticle, ModelShape, SolidParticleVertex } from "./solidParticle";
 import { TargetCamera } from "../Cameras/targetCamera";
 import { TargetCamera } from "../Cameras/targetCamera";
 import { BoundingInfo } from "../Culling/boundingInfo";
 import { BoundingInfo } from "../Culling/boundingInfo";
 import { Axis } from '../Maths/math.axis';
 import { Axis } from '../Maths/math.axis';
@@ -148,6 +148,7 @@ export class SolidParticleSystem implements IDisposable {
     private _materialIndexesById: any;
     private _materialIndexesById: any;
     private _defaultMaterial: Material;
     private _defaultMaterial: Material;
     private _autoUpdateSubMeshes: boolean = false;
     private _autoUpdateSubMeshes: boolean = false;
+    private _tmpVertex: SolidParticleVertex;
 
 
     /**
     /**
      * Creates a SPS (Solid Particle System) object.
      * Creates a SPS (Solid Particle System) object.
@@ -196,6 +197,7 @@ export class SolidParticleSystem implements IDisposable {
             this._materials = [];
             this._materials = [];
             this._materialIndexesById = {};
             this._materialIndexesById = {};
         }
         }
+        this._tmpVertex = new SolidParticleVertex();
     }
     }
 
 
     /**
     /**
@@ -521,7 +523,10 @@ export class SolidParticleSystem implements IDisposable {
         }
         }
 
 
         const rotMatrix = TmpVectors.Matrix[0];
         const rotMatrix = TmpVectors.Matrix[0];
-        const tmpVertex = TmpVectors.Vector3[0];
+        const tmpVertex = this._tmpVertex;
+        const tmpVector = tmpVertex.position;
+        const tmpColor = tmpVertex.color;
+        const tmpUV = tmpVertex.uv;
         const tmpRotated = TmpVectors.Vector3[1];
         const tmpRotated = TmpVectors.Vector3[1];
         const pivotBackTranslation = TmpVectors.Vector3[2];
         const pivotBackTranslation = TmpVectors.Vector3[2];
         const scaledPivot = TmpVectors.Vector3[3];
         const scaledPivot = TmpVectors.Vector3[3];
@@ -539,24 +544,30 @@ export class SolidParticleSystem implements IDisposable {
 
 
         var someVertexFunction = (options && options.vertexFunction);
         var someVertexFunction = (options && options.vertexFunction);
         for (i = 0; i < shape.length; i++) {
         for (i = 0; i < shape.length; i++) {
-            tmpVertex.copyFrom(shape[i]);
+            tmpVector.copyFrom(shape[i]);
+            if (copy.color) {
+                tmpColor.copyFrom(copy.color);
+            }
+            if (meshUV) {
+                tmpUV.copyFromFloats(meshUV[u], meshUV[u + 1]);
+            }
             if (someVertexFunction) {
             if (someVertexFunction) {
                 options.vertexFunction(copy, tmpVertex, i);
                 options.vertexFunction(copy, tmpVertex, i);
             }
             }
 
 
-            tmpVertex.multiplyInPlace(copy.scaling).subtractInPlace(scaledPivot);
-            Vector3.TransformCoordinatesToRef(tmpVertex, rotMatrix, tmpRotated);
+            tmpVector.multiplyInPlace(copy.scaling).subtractInPlace(scaledPivot);
+            Vector3.TransformCoordinatesToRef(tmpVector, rotMatrix, tmpRotated);
             tmpRotated.addInPlace(pivotBackTranslation).addInPlace(copy.position);
             tmpRotated.addInPlace(pivotBackTranslation).addInPlace(copy.position);
             positions.push(tmpRotated.x, tmpRotated.y, tmpRotated.z);
             positions.push(tmpRotated.x, tmpRotated.y, tmpRotated.z);
 
 
             if (meshUV) {
             if (meshUV) {
                 const copyUvs = copy.uvs;
                 const copyUvs = copy.uvs;
-                uvs.push((copyUvs.z - copyUvs.x) * meshUV[u] + copyUvs.x, (copyUvs.w - copyUvs.y) * meshUV[u + 1] + copyUvs.y);
+                uvs.push((copyUvs.z - copyUvs.x) * tmpUV.x + copyUvs.x, (copyUvs.w - copyUvs.y) * tmpUV.y + copyUvs.y);
                 u += 2;
                 u += 2;
             }
             }
 
 
             if (copy.color) {
             if (copy.color) {
-                this._color = copy.color;
+                this._color.copyFrom(tmpColor);
             } else {
             } else {
                 const color = this._color;
                 const color = this._color;
                 if (meshCol && meshCol[c] !== undefined) {
                 if (meshCol && meshCol[c] !== undefined) {
@@ -575,8 +586,8 @@ export class SolidParticleSystem implements IDisposable {
             c += 4;
             c += 4;
 
 
             if (!this.recomputeNormals && meshNor) {
             if (!this.recomputeNormals && meshNor) {
-                Vector3.TransformNormalFromFloatsToRef(meshNor[n], meshNor[n + 1], meshNor[n + 2], rotMatrix, tmpVertex);
-                normals.push(tmpVertex.x, tmpVertex.y, tmpVertex.z);
+                Vector3.TransformNormalFromFloatsToRef(meshNor[n], meshNor[n + 1], meshNor[n + 2], rotMatrix, tmpVector);
+                normals.push(tmpVector.x, tmpVector.y, tmpVector.z);
                 n += 3;
                 n += 3;
             }
             }
         }
         }
@@ -948,6 +959,11 @@ export class SolidParticleSystem implements IDisposable {
         const maximum = tempVectors[9].setAll(-Number.MAX_VALUE);
         const maximum = tempVectors[9].setAll(-Number.MAX_VALUE);
         const camInvertedPosition = tempVectors[10].setAll(0);
         const camInvertedPosition = tempVectors[10].setAll(0);
 
 
+        const tmpVertex = this._tmpVertex;
+        const tmpVector = tmpVertex.position;
+        const tmpColor = tmpVertex.color;
+        const tmpUV = tmpVertex.uv;
+
         // cases when the World Matrix is to be computed first
         // cases when the World Matrix is to be computed first
         if (this.billboard || this._depthSort) {
         if (this.billboard || this._depthSort) {
             this.mesh.computeWorldMatrix(true);
             this.mesh.computeWorldMatrix(true);
@@ -956,9 +972,9 @@ export class SolidParticleSystem implements IDisposable {
         // if the particles will always face the camera
         // if the particles will always face the camera
         if (this.billboard) {
         if (this.billboard) {
             // compute the camera position and un-rotate it by the current mesh rotation
             // compute the camera position and un-rotate it by the current mesh rotation
-            const tmpVertex = tempVectors[0];
-            this._camera.getDirectionToRef(Axis.Z, tmpVertex);
-            Vector3.TransformNormalToRef(tmpVertex, invertedMatrix, camAxisZ);
+            const tmpVector0 = tempVectors[0];
+            this._camera.getDirectionToRef(Axis.Z, tmpVector0);
+            Vector3.TransformNormalToRef(tmpVector0, invertedMatrix, camAxisZ);
             camAxisZ.normalize();
             camAxisZ.normalize();
             // same for camera up vector extracted from the cam view matrix
             // same for camera up vector extracted from the cam view matrix
             var view = this._camera.getViewMatrix(true);
             var view = this._camera.getViewMatrix(true);
@@ -1115,17 +1131,24 @@ export class SolidParticleSystem implements IDisposable {
                     idx = index + pt * 3;
                     idx = index + pt * 3;
                     colidx = colorIndex + pt * 4;
                     colidx = colorIndex + pt * 4;
                     uvidx = uvIndex + pt * 2;
                     uvidx = uvIndex + pt * 2;
+                    const iu  = 2 * pt;
+                    const iv = iu + 1;
 
 
-                    const tmpVertex = tempVectors[0];
-                    tmpVertex.copyFrom(shape[pt]);
+                    tmpVector.copyFrom(shape[pt]);
+                    if (this._computeParticleColor && particle.color) {
+                        tmpColor.copyFrom(particle.color);
+                    }
+                    if (this._computeParticleTexture) {
+                        tmpUV.copyFromFloats(shapeUV[iu], shapeUV[iv]);
+                    }
                     if (this._computeParticleVertex) {
                     if (this._computeParticleVertex) {
                         this.updateParticleVertex(particle, tmpVertex, pt);
                         this.updateParticleVertex(particle, tmpVertex, pt);
                     }
                     }
 
 
                     // positions
                     // positions
-                    const vertexX = tmpVertex.x * particleScaling.x - scaledPivot.x;
-                    const vertexY = tmpVertex.y * particleScaling.y - scaledPivot.y;
-                    const vertexZ = tmpVertex.z * particleScaling.z - scaledPivot.z;
+                    const vertexX = tmpVector.x * particleScaling.x - scaledPivot.x;
+                    const vertexY = tmpVector.y * particleScaling.y - scaledPivot.y;
+                    const vertexZ = tmpVector.z * particleScaling.z - scaledPivot.z;
 
 
                     let rotatedX = vertexX * particleRotationMatrix[0] + vertexY * particleRotationMatrix[3] + vertexZ * particleRotationMatrix[6];
                     let rotatedX = vertexX * particleRotationMatrix[0] + vertexY * particleRotationMatrix[3] + vertexZ * particleRotationMatrix[6];
                     let rotatedY = vertexX * particleRotationMatrix[1] + vertexY * particleRotationMatrix[4] + vertexZ * particleRotationMatrix[7];
                     let rotatedY = vertexX * particleRotationMatrix[1] + vertexY * particleRotationMatrix[4] + vertexZ * particleRotationMatrix[7];
@@ -1160,18 +1183,17 @@ export class SolidParticleSystem implements IDisposable {
                     }
                     }
 
 
                     if (this._computeParticleColor && particle.color) {
                     if (this._computeParticleColor && particle.color) {
-                        const color = particle.color;
                         const colors32 = this._colors32;
                         const colors32 = this._colors32;
-                        colors32[colidx] = color.r;
-                        colors32[colidx + 1] = color.g;
-                        colors32[colidx + 2] = color.b;
-                        colors32[colidx + 3] = color.a;
+                        colors32[colidx] = tmpColor.r;
+                        colors32[colidx + 1] = tmpColor.g;
+                        colors32[colidx + 2] = tmpColor.b;
+                        colors32[colidx + 3] = tmpColor.a;
                     }
                     }
 
 
                     if (this._computeParticleTexture) {
                     if (this._computeParticleTexture) {
                         const uvs = particle.uvs;
                         const uvs = particle.uvs;
-                        uvs32[uvidx] = shapeUV[pt * 2] * (uvs.z - uvs.x) + uvs.x;
-                        uvs32[uvidx + 1] = shapeUV[pt * 2 + 1] * (uvs.w - uvs.y) + uvs.y;
+                        uvs32[uvidx] = tmpUV.x * (uvs.z - uvs.x) + uvs.x;
+                        uvs32[uvidx + 1] = tmpUV.y * (uvs.w - uvs.y) + uvs.y;
                     }
                     }
                 }
                 }
             }
             }
@@ -1805,14 +1827,14 @@ export class SolidParticleSystem implements IDisposable {
      * Updates a vertex of a particle : it can be overwritten by the user.
      * Updates a vertex of a particle : it can be overwritten by the user.
      * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
      * This will be called on each vertex particle by `setParticles()` if `computeParticleVertex` is set to true only.
      * @param particle the current particle
      * @param particle the current particle
-     * @param vertex the current index of the current particle
+     * @param vertex the current vertex of the current particle : a SolidParticleVertex object
      * @param pt the index of the current vertex in the particle shape
      * @param pt the index of the current vertex in the particle shape
      * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
      * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#update-each-particle-shape
-     * @example : just set a vertex particle position
-     * @returns the updated vertex
+     * @example : just set a vertex particle position or color
+     * @returns the sps
      */
      */
-    public updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3 {
-        return vertex;
+    public updateParticleVertex(particle: SolidParticle, vertex: SolidParticleVertex, pt: number): SolidParticleSystem {
+        return this;
     }
     }
 
 
     /**
     /**

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

@@ -26,14 +26,13 @@ struct subSurfaceOutParams
 
 
 #ifdef SUBSURFACE
 #ifdef SUBSURFACE
     void subSurfaceBlock(
     void subSurfaceBlock(
+        const in vec3 vSubSurfaceIntensity,
         const in vec2 vThicknessParam,
         const in vec2 vThicknessParam,
         const in vec4 vTintColor,
         const in vec4 vTintColor,
         const in vec3 normalW,
         const in vec3 normalW,
         const in vec3 specularEnvironmentReflectance,
         const in vec3 specularEnvironmentReflectance,
     #ifdef SS_THICKNESSANDMASK_TEXTURE
     #ifdef SS_THICKNESSANDMASK_TEXTURE
-        const in vec2 vThicknessUV,
-        const in vec2 uvOffset,
-        const in sampler2D thicknessSampler,
+        const in vec4 thicknessMap,
     #endif
     #endif
     #ifdef REFLECTION
     #ifdef REFLECTION
         #ifdef SS_TRANSLUCENCY
         #ifdef SS_TRANSLUCENCY
@@ -116,7 +115,6 @@ struct subSurfaceOutParams
     #endif
     #endif
 
 
     #ifdef SS_THICKNESSANDMASK_TEXTURE
     #ifdef SS_THICKNESSANDMASK_TEXTURE
-        vec4 thicknessMap = texture2D(thicknessSampler, vThicknessUV + uvOffset);
         float thickness = thicknessMap.r * vThicknessParam.y + vThicknessParam.x;
         float thickness = thicknessMap.r * vThicknessParam.y + vThicknessParam.x;
 
 
         #if DEBUGMODE > 0
         #if DEBUGMODE > 0

+ 6 - 3
src/Shaders/pbr.fragment.fx

@@ -385,15 +385,18 @@ void main(void) {
     subSurfaceOutParams subSurfaceOut;
     subSurfaceOutParams subSurfaceOut;
 
 
     #ifdef SUBSURFACE
     #ifdef SUBSURFACE
+        #ifdef SS_THICKNESSANDMASK_TEXTURE
+            vec4 thicknessMap = texture2D(thicknessSampler, vThicknessUV + uvOffset);
+        #endif
+
         subSurfaceBlock(
         subSurfaceBlock(
+            vSubSurfaceIntensity,
             vThicknessParam,
             vThicknessParam,
             vTintColor,
             vTintColor,
             normalW,
             normalW,
             specularEnvironmentReflectance,
             specularEnvironmentReflectance,
         #ifdef SS_THICKNESSANDMASK_TEXTURE
         #ifdef SS_THICKNESSANDMASK_TEXTURE
-            vThicknessUV,
-            uvOffset,
-            thicknessSampler,
+            thicknessMap,
         #endif
         #endif
         #ifdef REFLECTION
         #ifdef REFLECTION
             #ifdef SS_TRANSLUCENCY
             #ifdef SS_TRANSLUCENCY

+ 25 - 0
src/XR/motionController/webXRAbstractMotionController.ts

@@ -214,6 +214,13 @@ export interface IMinimalMotionControllerObject {
          */
          */
         pressed: boolean;
         pressed: boolean;
     }>;
     }>;
+
+    /**
+     * EXPERIMENTAL haptic support.
+     */
+    hapticActuators?: Array<{
+        pulse: (value: number, duration: number) => Promise<boolean>
+    }>;
 }
 }
 
 
 /**
 /**
@@ -390,6 +397,24 @@ export abstract class WebXRAbstractMotionController implements IDisposable {
         return this.handedness;
         return this.handedness;
     }
     }
 
 
+    /**
+     * Pulse (vibrate) this controller
+     * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called
+     * Consecutive calls to this function will cancel the last pulse call
+     *
+     * @param value the strength of the pulse in 0.0...1.0 range
+     * @param duration Duration of the pulse in milliseconds
+     * @param hapticActuatorIndex optional index of actuator (will usually be 0)
+     * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued
+     */
+    public pulse(value: number, duration: number, hapticActuatorIndex: number = 0): Promise<boolean> {
+        if (this.gamepadObject.hapticActuators && this.gamepadObject.hapticActuators[hapticActuatorIndex]) {
+            return this.gamepadObject.hapticActuators[hapticActuatorIndex].pulse(value, duration);
+        } else {
+            return Promise.resolve(false);
+        }
+    }
+
     // Look through all children recursively. This will return null if no mesh exists with the given name.
     // Look through all children recursively. This will return null if no mesh exists with the given name.
     protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh {
     protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh {
         return <AbstractMesh>node.getChildren((n) => n.name === name, false)[0];
         return <AbstractMesh>node.getChildren((n) => n.name === name, false)[0];

+ 21 - 7
src/XR/webXRDefaultExperience.ts

@@ -1,12 +1,12 @@
 import { WebXRExperienceHelper } from "./webXRExperienceHelper";
 import { WebXRExperienceHelper } from "./webXRExperienceHelper";
 import { Scene } from '../scene';
 import { Scene } from '../scene';
 import { WebXRInput, IWebXRInputOptions } from './webXRInput';
 import { WebXRInput, IWebXRInputOptions } from './webXRInput';
-import { WebXRControllerPointerSelection } from './features/WebXRControllerPointerSelection';
+import { WebXRControllerPointerSelection, IWebXRControllerPointerSelectionOptions } from './features/WebXRControllerPointerSelection';
 import { WebXRRenderTarget } from './webXRTypes';
 import { WebXRRenderTarget } from './webXRTypes';
 import { WebXREnterExitUI, WebXREnterExitUIOptions } from './webXREnterExitUI';
 import { WebXREnterExitUI, WebXREnterExitUIOptions } from './webXREnterExitUI';
 import { AbstractMesh } from '../Meshes/abstractMesh';
 import { AbstractMesh } from '../Meshes/abstractMesh';
 import { WebXRManagedOutputCanvasOptions } from './webXRManagedOutputCanvas';
 import { WebXRManagedOutputCanvasOptions } from './webXRManagedOutputCanvas';
-import { WebXRMotionControllerTeleportation } from './features/WebXRControllerTeleportation';
+import { WebXRMotionControllerTeleportation, IWebXRTeleportationOptions } from './features/WebXRControllerTeleportation';
 import { Logger } from '../Misc/logger';
 import { Logger } from '../Misc/logger';
 
 
 /**
 /**
@@ -47,6 +47,11 @@ export class WebXRDefaultExperienceOptions {
      * When loading teleportation and pointer select, use stable versions instead of latest.
      * When loading teleportation and pointer select, use stable versions instead of latest.
      */
      */
     public useStablePlugins?: boolean;
     public useStablePlugins?: boolean;
+
+    /**
+     * An optional rendering group id that will be set globally for teleportation, pointer selection and default controller meshes
+     */
+    public renderingGroupId?: number;
 }
 }
 
 
 /**
 /**
@@ -99,16 +104,25 @@ export class WebXRDefaultExperience {
             }
             }
 
 
             // Add controller support
             // Add controller support
-            result.input = new WebXRInput(xrHelper.sessionManager, xrHelper.camera, options.inputOptions);
-            result.pointerSelection = <WebXRControllerPointerSelection>result.baseExperience.featuresManager.enableFeature(WebXRControllerPointerSelection.Name, options.useStablePlugins ? "stable" : "latest", {
-                xrInput: result.input
+            result.input = new WebXRInput(xrHelper.sessionManager, xrHelper.camera, {
+                controllerOptions: {
+                    renderingGroupId: options.renderingGroupId
+                },
+                ...(options.inputOptions || {})
+            });
+            result.pointerSelection = <WebXRControllerPointerSelection>result.baseExperience.featuresManager.enableFeature(WebXRControllerPointerSelection.Name, options.useStablePlugins ? "stable" : "latest",
+            <IWebXRControllerPointerSelectionOptions>{
+                xrInput: result.input,
+                renderingGroupId: options.renderingGroupId
             });
             });
 
 
             // Add default teleportation, including rotation
             // Add default teleportation, including rotation
             if (!options.disableTeleportation) {
             if (!options.disableTeleportation) {
-                result.teleportation = <WebXRMotionControllerTeleportation>result.baseExperience.featuresManager.enableFeature(WebXRMotionControllerTeleportation.Name, options.useStablePlugins ? "stable" : "latest", {
+                result.teleportation = <WebXRMotionControllerTeleportation>result.baseExperience.featuresManager.enableFeature(WebXRMotionControllerTeleportation.Name, options.useStablePlugins ? "stable" : "latest",
+                <IWebXRTeleportationOptions>{
                     floorMeshes: options.floorMeshes,
                     floorMeshes: options.floorMeshes,
-                    xrInput: result.input
+                    xrInput: result.input,
+                    renderingGroupId: options.renderingGroupId
                 });
                 });
                 result.teleportation.setSelectionFeature(result.pointerSelection);
                 result.teleportation.setSelectionFeature(result.pointerSelection);
             }
             }

+ 7 - 1
src/XR/webXRInput.ts

@@ -1,7 +1,7 @@
 import { Nullable } from "../types";
 import { Nullable } from "../types";
 import { Observer, Observable } from "../Misc/observable";
 import { Observer, Observable } from "../Misc/observable";
 import { IDisposable } from "../scene";
 import { IDisposable } from "../scene";
-import { WebXRInputSource } from './webXRInputSource';
+import { WebXRInputSource, IWebXRControllerOptions } from './webXRInputSource';
 import { WebXRSessionManager } from './webXRSessionManager';
 import { WebXRSessionManager } from './webXRSessionManager';
 import { WebXRCamera } from './webXRCamera';
 import { WebXRCamera } from './webXRCamera';
 import { WebXRMotionControllerManager } from './motionController/webXRMotionControllerManager';
 import { WebXRMotionControllerManager } from './motionController/webXRMotionControllerManager';
@@ -38,6 +38,11 @@ export interface IWebXRInputOptions {
      * Should the controller model's components not move according to the user input
      * Should the controller model's components not move according to the user input
      */
      */
     disableControllerAnimation?: boolean;
     disableControllerAnimation?: boolean;
+
+    /**
+     * Optional options to pass to the controller. Will be overridden by the Input options where applicable
+     */
+    controllerOptions?: IWebXRControllerOptions;
 }
 }
 /**
 /**
  * XR input used to track XR inputs such as controllers/rays
  * XR input used to track XR inputs such as controllers/rays
@@ -115,6 +120,7 @@ export class WebXRInput implements IDisposable {
         for (let input of addInputs) {
         for (let input of addInputs) {
             if (sources.indexOf(input) === -1) {
             if (sources.indexOf(input) === -1) {
                 let controller = new WebXRInputSource(this.xrSessionManager.scene, input, {
                 let controller = new WebXRInputSource(this.xrSessionManager.scene, input, {
+                    ...(this.options.controllerOptions || {}),
                     forceControllerProfile: this.options.forceInputProfile,
                     forceControllerProfile: this.options.forceInputProfile,
                     doNotLoadControllerMesh: this.options.doNotLoadControllerMeshes,
                     doNotLoadControllerMesh: this.options.doNotLoadControllerMeshes,
                     disableMotionControllerAnimation: this.options.disableControllerAnimation
                     disableMotionControllerAnimation: this.options.disableControllerAnimation

+ 14 - 4
src/XR/webXRInputSource.ts

@@ -26,6 +26,11 @@ export interface IWebXRControllerOptions {
      * This can be used when creating your own profile or when testing different controllers
      * This can be used when creating your own profile or when testing different controllers
      */
      */
     forceControllerProfile?: string;
     forceControllerProfile?: string;
+    /**
+     * Defines a rendering group ID for meshes that will be loaded.
+     * This is for the default controllers only.
+     */
+    renderingGroupId?: number;
 }
 }
 
 
 /**
 /**
@@ -97,10 +102,15 @@ export class WebXRInputSource {
                 // should the model be loaded?
                 // should the model be loaded?
                 if (!this._options.doNotLoadControllerMesh) {
                 if (!this._options.doNotLoadControllerMesh) {
                     this.motionController.loadModel().then((success) => {
                     this.motionController.loadModel().then((success) => {
-                        if (success) {
-                            this.onMeshLoadedObservable.notifyObservers(this.motionController!.rootMesh!);
-                            this.motionController!.rootMesh!.parent = this.grip || this.pointer;
-                            this.motionController!.disableAnimation = !!this._options.disableMotionControllerAnimation;
+                        if (success && this.motionController && this.motionController.rootMesh) {
+                            if (this._options.renderingGroupId) {
+                                // anything other than 0?
+                                this.motionController.rootMesh.renderingGroupId = this._options.renderingGroupId;
+                                this.motionController.rootMesh.getChildMeshes(false).forEach((mesh) => mesh.renderingGroupId = this._options.renderingGroupId!);
+                            }
+                            this.onMeshLoadedObservable.notifyObservers(this.motionController.rootMesh);
+                            this.motionController.rootMesh.parent = this.grip || this.pointer;
+                            this.motionController.disableAnimation = !!this._options.disableMotionControllerAnimation;
                         }
                         }
                     });
                     });
                 }
                 }