瀏覽代碼

Merge branch 'master' into handles

Alejandro Toledo 5 年之前
父節點
當前提交
ee6ada86ac
共有 59 個文件被更改,包括 2584 次插入362 次删除
  1. 103 1
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 425 57
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 221 2
      dist/preview release/babylon.module.d.ts
  6. 151 2
      dist/preview release/documentation.d.ts
  7. 151 20
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  8. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  9. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  10. 151 20
      dist/preview release/loaders/babylon.glTFFileLoader.js
  11. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  12. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  13. 48 1
      dist/preview release/loaders/babylonjs.loaders.d.ts
  14. 151 20
      dist/preview release/loaders/babylonjs.loaders.js
  15. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  16. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  17. 102 2
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  18. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  19. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  20. 18 2
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  21. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  22. 4 2
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  23. 1 1
      dist/preview release/packagesSizeBaseLine.json
  24. 221 2
      dist/preview release/viewer/babylon.module.d.ts
  25. 129 117
      dist/preview release/viewer/babylon.viewer.js
  26. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  27. 102 2
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  28. 4 2
      dist/preview release/what's new.md
  29. 154 0
      loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts
  30. 1 0
      loaders/src/glTF/2.0/Extensions/index.ts
  31. 1 1
      loaders/src/glTF/2.0/glTFLoaderExtension.ts
  32. 11 0
      nodeEditor/src/blockTools.ts
  33. 5 2
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  34. 2 0
      nodeEditor/src/diagram/display/inputDisplayManager.ts
  35. 1 1
      package.json
  36. 1 1
      readme.md
  37. 5 0
      src/Cameras/targetCamera.ts
  38. 8 0
      src/Engines/thinEngine.ts
  39. 9 7
      src/Materials/Node/Blocks/Dual/textureBlock.ts
  40. 110 0
      src/Materials/Node/Blocks/Fragment/fragCoordBlock.ts
  41. 2 0
      src/Materials/Node/Blocks/Fragment/index.ts
  42. 98 0
      src/Materials/Node/Blocks/Fragment/screenSizeBlock.ts
  43. 3 0
      src/Materials/Node/Blocks/Input/inputBlock.ts
  44. 3 12
      src/Materials/Node/Blocks/PBR/clearCoatBlock.ts
  45. 58 27
      src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts
  46. 11 1
      src/Materials/Node/Blocks/PBR/reflectionBlock.ts
  47. 46 4
      src/Materials/Node/Blocks/PBR/reflectivityBlock.ts
  48. 1 1
      src/Materials/Node/Blocks/PBR/refractionBlock.ts
  49. 1 10
      src/Materials/Node/Blocks/PBR/sheenBlock.ts
  50. 8 1
      src/Particles/gpuParticleSystem.ts
  51. 8 1
      src/Particles/particleSystem.ts
  52. 3 1
      src/Physics/Plugins/cannonJSPlugin.ts
  53. 5 0
      src/Shaders/ShadersInclude/helperFunctions.fx
  54. 14 11
      src/Shaders/gpuRenderParticles.vertex.fx
  55. 11 8
      src/Shaders/particles.vertex.fx
  56. 2 0
      src/XR/webXREnterExitUI.ts
  57. 1 6
      src/XR/webXRExperienceHelper.ts
  58. 二進制
      tests/validation/ReferenceImages/node-material-pbr-1.png
  59. 5 0
      tests/validation/config.json

+ 103 - 1
dist/preview release/babylon.d.ts

@@ -61016,6 +61016,87 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      */
     export class FogBlock extends NodeMaterialBlock {
@@ -62553,6 +62634,8 @@ declare module BABYLON {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -62714,6 +62797,15 @@ declare module BABYLON {
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -62761,12 +62853,14 @@ declare module BABYLON {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -63078,6 +63172,14 @@ declare module BABYLON {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;

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


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


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


+ 221 - 2
dist/preview release/babylon.module.d.ts

@@ -63963,6 +63963,96 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/derivativeBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
 }
+declare module "babylonjs/Materials/Node/Blocks/Fragment/fragCoordBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module "babylonjs/Materials/Node/Blocks/Fragment/screenSizeBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { Effect } from "babylonjs/Materials/effect";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
@@ -63970,6 +64060,8 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/discardBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/frontFacingBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/derivativeBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/fragCoordBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/screenSizeBlock";
 }
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
@@ -65693,6 +65785,8 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectionBlock" {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -65864,10 +65958,23 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock" {
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     import { Scene } from "babylonjs/scene";
+    import { Nullable } from "babylonjs/types";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    import { SubMesh } from "babylonjs/Meshes/subMesh";
+    import { Effect } from "babylonjs/Materials/effect";
     /**
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -65915,12 +66022,14 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock" {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -66264,6 +66373,14 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock" {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;
@@ -138202,6 +138319,87 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      */
     export class FogBlock extends NodeMaterialBlock {
@@ -139739,6 +139937,8 @@ declare module BABYLON {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -139900,6 +140100,15 @@ declare module BABYLON {
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -139947,12 +140156,14 @@ declare module BABYLON {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -140264,6 +140475,14 @@ declare module BABYLON {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;

+ 151 - 2
dist/preview release/documentation.d.ts

@@ -61016,6 +61016,87 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      */
     export class FogBlock extends NodeMaterialBlock {
@@ -62553,6 +62634,8 @@ declare module BABYLON {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -62714,6 +62797,15 @@ declare module BABYLON {
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -62761,12 +62853,14 @@ declare module BABYLON {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -63078,6 +63172,14 @@ declare module BABYLON {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;
@@ -79095,7 +79197,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -79794,6 +79896,53 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
+declare module BABYLON.GLTF2.Loader.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization)
      */
     export class KHR_mesh_quantization implements IGLTFLoaderExtension {

+ 151 - 20
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1120,6 +1120,131 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 
 /***/ }),
 
+/***/ "./glTF/2.0/Extensions/KHR_materials_variants.ts":
+/*!*******************************************************!*\
+  !*** ./glTF/2.0/Extensions/KHR_materials_variants.ts ***!
+  \*******************************************************/
+/*! exports provided: KHR_materials_variants */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return KHR_materials_variants; });
+/* harmony import */ var _glTFLoader__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFLoader */ "./glTF/2.0/glTFLoader.ts");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/mesh */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__);
+
+
+var NAME = "KHR_materials_variants";
+/**
+ * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+ * !!! Experimental Extension Subject to Changes !!!
+ */
+var KHR_materials_variants = /** @class */ (function () {
+    /** @hidden */
+    function KHR_materials_variants(loader) {
+        /**
+         * The name of this extension.
+         */
+        this.name = NAME;
+        this._tagsToMap = {};
+        this._loader = loader;
+        this.enabled = this._loader.isExtensionUsed(NAME);
+    }
+    /** @hidden */
+    KHR_materials_variants.prototype.dispose = function () {
+        delete this._loader;
+    };
+    /**
+     * Return a list of available variants for this asset.
+     * @returns {string[]}
+     */
+    KHR_materials_variants.prototype.getVariants = function () {
+        return Object.keys(this._tagsToMap);
+    };
+    /**
+     * Select a variant by providing a list of variant tag names.
+     *
+     * @param {(string | string[])} variantName
+     */
+    KHR_materials_variants.prototype.selectVariant = function (variantName) {
+        var _this = this;
+        if (variantName instanceof Array) {
+            variantName.forEach(function (name) { return _this.selectVariantTag(name); });
+        }
+        else {
+            this.selectVariantTag(variantName);
+        }
+    };
+    /**
+     * Select a variant by providing a single variant tag.
+     *
+     * @param {string} variantName
+     */
+    KHR_materials_variants.prototype.selectVariantTag = function (variantName) {
+        // If the name is valid, switch all meshes to use materials defined by the tags
+        var variantMappings = this._tagsToMap[variantName];
+        if (variantMappings === undefined) {
+            return;
+        }
+        variantMappings.forEach(function (mapping) {
+            if (mapping.material) {
+                mapping.mesh.material = mapping.material;
+                return;
+            }
+            mapping.materialPromise.then(function (material) {
+                mapping.mesh.material = material;
+            });
+        });
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype.onLoading = function () {
+        var extensions = this._loader.gltf.extensions;
+        if (extensions && extensions[this.name]) {
+            var extension = extensions[this.name];
+            this.defaultVariant = extension.default;
+        }
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
+        var _this = this;
+        return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, primitive, this.name, function (extensionContext, extension) {
+            var assignMesh = function (babylonMesh) {
+                assign(babylonMesh);
+                var babylonDrawMode = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"]._GetDrawMode(context, primitive.mode);
+                // For each mapping, look at the tags and make a new entry for them
+                extension.mapping.forEach(function (mapping) {
+                    mapping.tags.forEach(function (tag, index) {
+                        var tagMapping = _this._tagsToMap[tag] || [];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
+                        var meshEntry = {
+                            mesh: babylonMesh,
+                            materialPromise: Promise.resolve(null)
+                        };
+                        if (babylonMesh instanceof babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__["Mesh"]) {
+                            meshEntry.materialPromise = _this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (material) {
+                                meshEntry.material = material;
+                            });
+                        }
+                        tagMapping.push(meshEntry);
+                        _this._tagsToMap[tag] = tagMapping;
+                    });
+                });
+            };
+            _this._loader._disableInstancedMesh++;
+            var promise = _this._loader._loadMeshPrimitiveAsync(context, name, node, mesh, primitive, assignMesh);
+            _this._loader._disableInstancedMesh--;
+            return promise;
+        });
+    };
+    return KHR_materials_variants;
+}());
+
+_glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].RegisterExtension(NAME, function (loader) { return new KHR_materials_variants(loader); });
+
+
+/***/ }),
+
 /***/ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts":
 /*!******************************************************!*\
   !*** ./glTF/2.0/Extensions/KHR_mesh_quantization.ts ***!
@@ -2017,7 +2142,7 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 /*!**************************************!*\
   !*** ./glTF/2.0/Extensions/index.ts ***!
   \**************************************/
-/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -2052,32 +2177,35 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./KHR_materials_ior */ "./glTF/2.0/Extensions/KHR_materials_ior.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__["KHR_materials_ior"]; });
 
-/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__["KHR_mesh_quantization"]; });
+/* harmony import */ var _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_materials_variants */ "./glTF/2.0/Extensions/KHR_materials_variants.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__["KHR_materials_variants"]; });
+
+/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__["KHR_mesh_quantization"]; });
 
-/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__["KHR_texture_basisu"]; });
+/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_basisu"]; });
 
-/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_transform"]; });
+/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__["KHR_texture_transform"]; });
 
-/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__["KHR_xmp"]; });
+/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__["KHR_xmp"]; });
 
-/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__["MSFT_audio_emitter"]; });
+/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__["MSFT_audio_emitter"]; });
 
-/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__["MSFT_lod"]; });
+/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__["MSFT_lod"]; });
 
-/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__["MSFT_minecraftMesh"]; });
+/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__["MSFT_minecraftMesh"]; });
 
-/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__["MSFT_sRGBFactors"]; });
+/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__["MSFT_sRGBFactors"]; });
 
-/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__["ExtrasAsMetadata"]; });
+/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__["ExtrasAsMetadata"]; });
 
 
 
@@ -2098,6 +2226,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 
 
 /***/ }),
@@ -4263,7 +4392,7 @@ _glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFFileLoader"]._CreateGLTF2Loade
 /*!***************************!*\
   !*** ./glTF/2.0/index.ts ***!
   \***************************/
-/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4294,6 +4423,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_ior"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_variants"]; });
+
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_mesh_quantization"]; });
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_texture_basisu"]; });

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


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


+ 151 - 20
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3700,6 +3700,131 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 
 /***/ }),
 
+/***/ "./glTF/2.0/Extensions/KHR_materials_variants.ts":
+/*!*******************************************************!*\
+  !*** ./glTF/2.0/Extensions/KHR_materials_variants.ts ***!
+  \*******************************************************/
+/*! exports provided: KHR_materials_variants */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return KHR_materials_variants; });
+/* harmony import */ var _glTFLoader__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFLoader */ "./glTF/2.0/glTFLoader.ts");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/mesh */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__);
+
+
+var NAME = "KHR_materials_variants";
+/**
+ * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+ * !!! Experimental Extension Subject to Changes !!!
+ */
+var KHR_materials_variants = /** @class */ (function () {
+    /** @hidden */
+    function KHR_materials_variants(loader) {
+        /**
+         * The name of this extension.
+         */
+        this.name = NAME;
+        this._tagsToMap = {};
+        this._loader = loader;
+        this.enabled = this._loader.isExtensionUsed(NAME);
+    }
+    /** @hidden */
+    KHR_materials_variants.prototype.dispose = function () {
+        delete this._loader;
+    };
+    /**
+     * Return a list of available variants for this asset.
+     * @returns {string[]}
+     */
+    KHR_materials_variants.prototype.getVariants = function () {
+        return Object.keys(this._tagsToMap);
+    };
+    /**
+     * Select a variant by providing a list of variant tag names.
+     *
+     * @param {(string | string[])} variantName
+     */
+    KHR_materials_variants.prototype.selectVariant = function (variantName) {
+        var _this = this;
+        if (variantName instanceof Array) {
+            variantName.forEach(function (name) { return _this.selectVariantTag(name); });
+        }
+        else {
+            this.selectVariantTag(variantName);
+        }
+    };
+    /**
+     * Select a variant by providing a single variant tag.
+     *
+     * @param {string} variantName
+     */
+    KHR_materials_variants.prototype.selectVariantTag = function (variantName) {
+        // If the name is valid, switch all meshes to use materials defined by the tags
+        var variantMappings = this._tagsToMap[variantName];
+        if (variantMappings === undefined) {
+            return;
+        }
+        variantMappings.forEach(function (mapping) {
+            if (mapping.material) {
+                mapping.mesh.material = mapping.material;
+                return;
+            }
+            mapping.materialPromise.then(function (material) {
+                mapping.mesh.material = material;
+            });
+        });
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype.onLoading = function () {
+        var extensions = this._loader.gltf.extensions;
+        if (extensions && extensions[this.name]) {
+            var extension = extensions[this.name];
+            this.defaultVariant = extension.default;
+        }
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
+        var _this = this;
+        return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, primitive, this.name, function (extensionContext, extension) {
+            var assignMesh = function (babylonMesh) {
+                assign(babylonMesh);
+                var babylonDrawMode = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"]._GetDrawMode(context, primitive.mode);
+                // For each mapping, look at the tags and make a new entry for them
+                extension.mapping.forEach(function (mapping) {
+                    mapping.tags.forEach(function (tag, index) {
+                        var tagMapping = _this._tagsToMap[tag] || [];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
+                        var meshEntry = {
+                            mesh: babylonMesh,
+                            materialPromise: Promise.resolve(null)
+                        };
+                        if (babylonMesh instanceof babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__["Mesh"]) {
+                            meshEntry.materialPromise = _this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (material) {
+                                meshEntry.material = material;
+                            });
+                        }
+                        tagMapping.push(meshEntry);
+                        _this._tagsToMap[tag] = tagMapping;
+                    });
+                });
+            };
+            _this._loader._disableInstancedMesh++;
+            var promise = _this._loader._loadMeshPrimitiveAsync(context, name, node, mesh, primitive, assignMesh);
+            _this._loader._disableInstancedMesh--;
+            return promise;
+        });
+    };
+    return KHR_materials_variants;
+}());
+
+_glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].RegisterExtension(NAME, function (loader) { return new KHR_materials_variants(loader); });
+
+
+/***/ }),
+
 /***/ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts":
 /*!******************************************************!*\
   !*** ./glTF/2.0/Extensions/KHR_mesh_quantization.ts ***!
@@ -4597,7 +4722,7 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 /*!**************************************!*\
   !*** ./glTF/2.0/Extensions/index.ts ***!
   \**************************************/
-/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4632,32 +4757,35 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./KHR_materials_ior */ "./glTF/2.0/Extensions/KHR_materials_ior.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__["KHR_materials_ior"]; });
 
-/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__["KHR_mesh_quantization"]; });
+/* harmony import */ var _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_materials_variants */ "./glTF/2.0/Extensions/KHR_materials_variants.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__["KHR_materials_variants"]; });
+
+/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__["KHR_mesh_quantization"]; });
 
-/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__["KHR_texture_basisu"]; });
+/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_basisu"]; });
 
-/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_transform"]; });
+/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__["KHR_texture_transform"]; });
 
-/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__["KHR_xmp"]; });
+/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__["KHR_xmp"]; });
 
-/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__["MSFT_audio_emitter"]; });
+/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__["MSFT_audio_emitter"]; });
 
-/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__["MSFT_lod"]; });
+/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__["MSFT_lod"]; });
 
-/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__["MSFT_minecraftMesh"]; });
+/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__["MSFT_minecraftMesh"]; });
 
-/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__["MSFT_sRGBFactors"]; });
+/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__["MSFT_sRGBFactors"]; });
 
-/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__["ExtrasAsMetadata"]; });
+/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__["ExtrasAsMetadata"]; });
 
 
 
@@ -4678,6 +4806,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 
 
 /***/ }),
@@ -6843,7 +6972,7 @@ _glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFFileLoader"]._CreateGLTF2Loade
 /*!***************************!*\
   !*** ./glTF/2.0/index.ts ***!
   \***************************/
-/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -6874,6 +7003,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_ior"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_variants"]; });
+
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_mesh_quantization"]; });
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_texture_basisu"]; });

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


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


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

@@ -1213,7 +1213,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -1912,6 +1912,53 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
+declare module BABYLON.GLTF2.Loader.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization)
      */
     export class KHR_mesh_quantization implements IGLTFLoaderExtension {

+ 151 - 20
dist/preview release/loaders/babylonjs.loaders.js

@@ -5080,6 +5080,131 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 
 /***/ }),
 
+/***/ "./glTF/2.0/Extensions/KHR_materials_variants.ts":
+/*!*******************************************************!*\
+  !*** ./glTF/2.0/Extensions/KHR_materials_variants.ts ***!
+  \*******************************************************/
+/*! exports provided: KHR_materials_variants */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return KHR_materials_variants; });
+/* harmony import */ var _glTFLoader__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFLoader */ "./glTF/2.0/glTFLoader.ts");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/mesh */ "babylonjs/Misc/tools");
+/* harmony import */ var babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__);
+
+
+var NAME = "KHR_materials_variants";
+/**
+ * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+ * !!! Experimental Extension Subject to Changes !!!
+ */
+var KHR_materials_variants = /** @class */ (function () {
+    /** @hidden */
+    function KHR_materials_variants(loader) {
+        /**
+         * The name of this extension.
+         */
+        this.name = NAME;
+        this._tagsToMap = {};
+        this._loader = loader;
+        this.enabled = this._loader.isExtensionUsed(NAME);
+    }
+    /** @hidden */
+    KHR_materials_variants.prototype.dispose = function () {
+        delete this._loader;
+    };
+    /**
+     * Return a list of available variants for this asset.
+     * @returns {string[]}
+     */
+    KHR_materials_variants.prototype.getVariants = function () {
+        return Object.keys(this._tagsToMap);
+    };
+    /**
+     * Select a variant by providing a list of variant tag names.
+     *
+     * @param {(string | string[])} variantName
+     */
+    KHR_materials_variants.prototype.selectVariant = function (variantName) {
+        var _this = this;
+        if (variantName instanceof Array) {
+            variantName.forEach(function (name) { return _this.selectVariantTag(name); });
+        }
+        else {
+            this.selectVariantTag(variantName);
+        }
+    };
+    /**
+     * Select a variant by providing a single variant tag.
+     *
+     * @param {string} variantName
+     */
+    KHR_materials_variants.prototype.selectVariantTag = function (variantName) {
+        // If the name is valid, switch all meshes to use materials defined by the tags
+        var variantMappings = this._tagsToMap[variantName];
+        if (variantMappings === undefined) {
+            return;
+        }
+        variantMappings.forEach(function (mapping) {
+            if (mapping.material) {
+                mapping.mesh.material = mapping.material;
+                return;
+            }
+            mapping.materialPromise.then(function (material) {
+                mapping.mesh.material = material;
+            });
+        });
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype.onLoading = function () {
+        var extensions = this._loader.gltf.extensions;
+        if (extensions && extensions[this.name]) {
+            var extension = extensions[this.name];
+            this.defaultVariant = extension.default;
+        }
+    };
+    /** @hidden */
+    KHR_materials_variants.prototype._loadMeshPrimitiveAsync = function (context, name, node, mesh, primitive, assign) {
+        var _this = this;
+        return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, primitive, this.name, function (extensionContext, extension) {
+            var assignMesh = function (babylonMesh) {
+                assign(babylonMesh);
+                var babylonDrawMode = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"]._GetDrawMode(context, primitive.mode);
+                // For each mapping, look at the tags and make a new entry for them
+                extension.mapping.forEach(function (mapping) {
+                    mapping.tags.forEach(function (tag, index) {
+                        var tagMapping = _this._tagsToMap[tag] || [];
+                        var material = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get("#/materials/", _this._loader.gltf.materials, mapping.material);
+                        var meshEntry = {
+                            mesh: babylonMesh,
+                            materialPromise: Promise.resolve(null)
+                        };
+                        if (babylonMesh instanceof babylonjs_Meshes_mesh__WEBPACK_IMPORTED_MODULE_1__["Mesh"]) {
+                            meshEntry.materialPromise = _this._loader._loadMaterialAsync("#/materials/" + mapping.material, material, babylonMesh, babylonDrawMode, function (material) {
+                                meshEntry.material = material;
+                            });
+                        }
+                        tagMapping.push(meshEntry);
+                        _this._tagsToMap[tag] = tagMapping;
+                    });
+                });
+            };
+            _this._loader._disableInstancedMesh++;
+            var promise = _this._loader._loadMeshPrimitiveAsync(context, name, node, mesh, primitive, assignMesh);
+            _this._loader._disableInstancedMesh--;
+            return promise;
+        });
+    };
+    return KHR_materials_variants;
+}());
+
+_glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].RegisterExtension(NAME, function (loader) { return new KHR_materials_variants(loader); });
+
+
+/***/ }),
+
 /***/ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts":
 /*!******************************************************!*\
   !*** ./glTF/2.0/Extensions/KHR_mesh_quantization.ts ***!
@@ -5977,7 +6102,7 @@ _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].RegisterExtension(NAME, f
 /*!**************************************!*\
   !*** ./glTF/2.0/Extensions/index.ts ***!
   \**************************************/
-/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -6012,32 +6137,35 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./KHR_materials_ior */ "./glTF/2.0/Extensions/KHR_materials_ior.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _KHR_materials_ior__WEBPACK_IMPORTED_MODULE_9__["KHR_materials_ior"]; });
 
-/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_10__["KHR_mesh_quantization"]; });
+/* harmony import */ var _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./KHR_materials_variants */ "./glTF/2.0/Extensions/KHR_materials_variants.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _KHR_materials_variants__WEBPACK_IMPORTED_MODULE_10__["KHR_materials_variants"]; });
+
+/* harmony import */ var _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_mesh_quantization */ "./glTF/2.0/Extensions/KHR_mesh_quantization.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _KHR_mesh_quantization__WEBPACK_IMPORTED_MODULE_11__["KHR_mesh_quantization"]; });
 
-/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_11__["KHR_texture_basisu"]; });
+/* harmony import */ var _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_basisu */ "./glTF/2.0/Extensions/KHR_texture_basisu.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _KHR_texture_basisu__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_basisu"]; });
 
-/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_12__["KHR_texture_transform"]; });
+/* harmony import */ var _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_texture_transform */ "./glTF/2.0/Extensions/KHR_texture_transform.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_transform", function() { return _KHR_texture_transform__WEBPACK_IMPORTED_MODULE_13__["KHR_texture_transform"]; });
 
-/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_13__["KHR_xmp"]; });
+/* harmony import */ var _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./KHR_xmp */ "./glTF/2.0/Extensions/KHR_xmp.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_xmp", function() { return _KHR_xmp__WEBPACK_IMPORTED_MODULE_14__["KHR_xmp"]; });
 
-/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_14__["MSFT_audio_emitter"]; });
+/* harmony import */ var _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_audio_emitter */ "./glTF/2.0/Extensions/MSFT_audio_emitter.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_audio_emitter", function() { return _MSFT_audio_emitter__WEBPACK_IMPORTED_MODULE_15__["MSFT_audio_emitter"]; });
 
-/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_15__["MSFT_lod"]; });
+/* harmony import */ var _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_lod */ "./glTF/2.0/Extensions/MSFT_lod.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_lod", function() { return _MSFT_lod__WEBPACK_IMPORTED_MODULE_16__["MSFT_lod"]; });
 
-/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_16__["MSFT_minecraftMesh"]; });
+/* harmony import */ var _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_minecraftMesh */ "./glTF/2.0/Extensions/MSFT_minecraftMesh.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_minecraftMesh", function() { return _MSFT_minecraftMesh__WEBPACK_IMPORTED_MODULE_17__["MSFT_minecraftMesh"]; });
 
-/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_17__["MSFT_sRGBFactors"]; });
+/* harmony import */ var _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./MSFT_sRGBFactors */ "./glTF/2.0/Extensions/MSFT_sRGBFactors.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "MSFT_sRGBFactors", function() { return _MSFT_sRGBFactors__WEBPACK_IMPORTED_MODULE_18__["MSFT_sRGBFactors"]; });
 
-/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
-/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_18__["ExtrasAsMetadata"]; });
+/* harmony import */ var _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./ExtrasAsMetadata */ "./glTF/2.0/Extensions/ExtrasAsMetadata.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ExtrasAsMetadata", function() { return _ExtrasAsMetadata__WEBPACK_IMPORTED_MODULE_19__["ExtrasAsMetadata"]; });
 
 
 
@@ -6058,6 +6186,7 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
 
 
 /***/ }),
@@ -8223,7 +8352,7 @@ _glTFFileLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFFileLoader"]._CreateGLTF2Loade
 /*!***************************!*\
   !*** ./glTF/2.0/index.ts ***!
   \***************************/
-/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
+/*! exports provided: ArrayItem, GLTFLoader, EXT_lights_image_based, EXT_mesh_gpu_instancing, KHR_draco_mesh_compression, KHR_lights, KHR_materials_pbrSpecularGlossiness, KHR_materials_unlit, KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_specular, KHR_materials_ior, KHR_materials_variants, KHR_mesh_quantization, KHR_texture_basisu, KHR_texture_transform, KHR_xmp, MSFT_audio_emitter, MSFT_lod, MSFT_minecraftMesh, MSFT_sRGBFactors, ExtrasAsMetadata */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -8254,6 +8383,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_ior", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_ior"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_variants", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_variants"]; });
+
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_mesh_quantization", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_mesh_quantization"]; });
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_texture_basisu", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_1__["KHR_texture_basisu"]; });

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


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


+ 102 - 2
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1285,7 +1285,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -2050,6 +2050,58 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_ior" {
         private _loadIorPropertiesAsync;
     }
 }
+declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants" {
+    import { Nullable } from "babylonjs/types";
+    import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
+    import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
+    import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+    import { INode, IMeshPrimitive, IMesh } from "babylonjs-loaders/glTF/2.0/glTFLoaderInterfaces";
+    /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_mesh_quantization" {
     import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
     import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
@@ -2346,6 +2398,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/index" {
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_sheen";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_specular";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_ior";
+    export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_mesh_quantization";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_basisu";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform";
@@ -3949,7 +4002,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -4648,6 +4701,53 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
+declare module BABYLON.GLTF2.Loader.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization)
      */
     export class KHR_mesh_quantization implements IGLTFLoaderExtension {

File diff suppressed because it is too large
+ 1 - 1
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


+ 18 - 2
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -58271,6 +58271,8 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
+
+
 var BlockTools = /** @class */ (function () {
     function BlockTools() {
     }
@@ -58674,10 +58676,19 @@ var BlockTools = /** @class */ (function () {
                 u.setAsAttribute("particle_texturemask");
                 return u;
             }
+            case "ParticlePositionWorldBlock": {
+                var pos = new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["InputBlock"]("PositionWorld");
+                pos.setAsAttribute("particle_positionw");
+                return pos;
+            }
             case "ParticleRampGradientBlock":
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ParticleRampGradientBlock"]("ParticleRampGradient");
             case "ParticleBlendMultiplyBlock":
                 return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ParticleBlendMultiplyBlock"]("ParticleBlendMultiply");
+            case "FragCoordBlock":
+                return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["FragCoordBlock"]("FragCoord");
+            case "ScreenSizeBlock":
+                return new babylonjs_Materials_Node_Blocks_Fragment_discardBlock__WEBPACK_IMPORTED_MODULE_0__["ScreenSizeBlock"]("ScreenSize");
         }
         return null;
     };
@@ -58921,7 +58932,7 @@ var NodeListComponent = /** @class */ (function (_super) {
             Animation: ["BonesBlock", "MorphTargetsBlock"],
             Color_Management: ["ReplaceColorBlock", "PosterizeBlock", "GradientBlock", "DesaturateBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
-            Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock"],
+            Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock", "FragCoordBlock", "ScreenSizeBlock"],
             Interpolation: ["LerpBlock", "StepBlock", "SmoothStepBlock", "NLerpBlock"],
             Math__Standard: ["AddBlock", "DivideBlock", "MaxBlock", "MinBlock", "ModBlock", "MultiplyBlock", "NegateBlock", "OneMinusBlock", "ReciprocalBlock", "ScaleBlock", "SignBlock", "SqrtBlock", "SubtractBlock"],
             Math__Scientific: ["AbsBlock", "ArcCosBlock", "ArcSinBlock", "ArcTanBlock", "ArcTan2Block", "CosBlock", "DegreesToRadiansBlock", "ExpBlock", "Exp2Block", "FractBlock", "LogBlock", "PowBlock", "RadiansToDegreesBlock", "SawToothWaveBlock", "SinBlock", "SquareWaveBlock", "TanBlock", "TriangleWaveBlock"],
@@ -58930,7 +58941,7 @@ var NodeListComponent = /** @class */ (function (_super) {
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock", "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
-            Particle: ["ParticleBlendMultiplyBlock", "ParticleColorBlock", "ParticleRampGradientBlock", "ParticleTextureBlock", "ParticleTextureMaskBlock", "ParticleUVBlock"],
+            Particle: ["ParticleBlendMultiplyBlock", "ParticleColorBlock", "ParticlePositionWorldBlock", "ParticleRampGradientBlock", "ParticleTextureBlock", "ParticleTextureMaskBlock", "ParticleUVBlock"],
             PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "RefractionBlock", "SheenBlock", "SubSurfaceBlock"],
             PostProcess: ["Position2DBlock", "CurrentScreenBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
@@ -59099,6 +59110,9 @@ var NodeListComponent = /** @class */ (function (_super) {
         "ParticleTextureMaskBlock": "The particle texture mask",
         "ParticleRampGradientBlock": "The particle ramp gradient block",
         "ParticleBlendMultiplyBlock": "The particle blend multiply block",
+        "ParticlePositionWorldBlock": "The world position of the particle",
+        "FragCoordBlock": "The gl_FragCoord predefined variable that contains the window relative coordinate (x, y, z, 1/w)",
+        "ScreenSizeBlock": "The size (in pixels) of the screen window",
     };
     return NodeListComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
@@ -60708,12 +60722,14 @@ var inputNameToAttributeValue = {
     "particle_uv": "uv",
     "particle_color": "color",
     "particle_texturemask": "textureMask",
+    "particle_positionw": "positionW",
 };
 var inputNameToAttributeName = {
     "position2d": "postprocess",
     "particle_uv": "particle",
     "particle_color": "particle",
     "particle_texturemask": "particle",
+    "particle_positionw": "particle",
 };
 var InputDisplayManager = /** @class */ (function () {
     function InputDisplayManager() {

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
+ 4 - 2
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts


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

@@ -1 +1 @@
-{"thinEngineOnly":115966,"engineOnly":152369,"sceneOnly":505481,"minGridMaterial":648073,"minStandardMaterial":791267}
+{"thinEngineOnly":115966,"engineOnly":152369,"sceneOnly":505481,"minGridMaterial":648156,"minStandardMaterial":791350}

+ 221 - 2
dist/preview release/viewer/babylon.module.d.ts

@@ -63963,6 +63963,96 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/derivativeBlock" {
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
 }
+declare module "babylonjs/Materials/Node/Blocks/Fragment/fragCoordBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module "babylonjs/Materials/Node/Blocks/Fragment/screenSizeBlock" {
+    import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
+    import { NodeMaterialBuildState } from "babylonjs/Materials/Node/nodeMaterialBuildState";
+    import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
+    import { Effect } from "babylonjs/Materials/effect";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
 declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock";
@@ -63970,6 +64060,8 @@ declare module "babylonjs/Materials/Node/Blocks/Fragment/index" {
     export * from "babylonjs/Materials/Node/Blocks/Fragment/discardBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/frontFacingBlock";
     export * from "babylonjs/Materials/Node/Blocks/Fragment/derivativeBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/fragCoordBlock";
+    export * from "babylonjs/Materials/Node/Blocks/Fragment/screenSizeBlock";
 }
 declare module "babylonjs/Materials/Node/Blocks/Dual/fogBlock" {
     import { NodeMaterialBlock } from "babylonjs/Materials/Node/nodeMaterialBlock";
@@ -65693,6 +65785,8 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectionBlock" {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -65864,10 +65958,23 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock" {
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     import { NodeMaterialConnectionPoint } from "babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint";
     import { Scene } from "babylonjs/scene";
+    import { Nullable } from "babylonjs/types";
+    import { Mesh } from "babylonjs/Meshes/mesh";
+    import { SubMesh } from "babylonjs/Meshes/subMesh";
+    import { Effect } from "babylonjs/Materials/effect";
     /**
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -65915,12 +66022,14 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock" {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -66264,6 +66373,14 @@ declare module "babylonjs/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock" {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;
@@ -138202,6 +138319,87 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Block used to make gl_FragCoord available
+     */
+    export class FragCoordBlock extends NodeMaterialBlock {
+        /**
+         * Creates a new FragCoordBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyz component
+         */
+        get xyz(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the xyzw component
+         */
+        get xyzw(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the z component
+         */
+        get z(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the w component
+         */
+        get output(): NodeMaterialConnectionPoint;
+        protected writeOutputs(state: NodeMaterialBuildState): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
+     * Block used to get the screen sizes
+     */
+    export class ScreenSizeBlock extends NodeMaterialBlock {
+        private _varName;
+        private _scene;
+        /**
+         * Creates a new ScreenSizeBlock
+         * @param name defines the block name
+         */
+        constructor(name: string);
+        /**
+         * Gets the current class name
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Gets the xy component
+         */
+        get xy(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the x component
+         */
+        get x(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the y component
+         */
+        get y(): NodeMaterialConnectionPoint;
+        bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh): void;
+        protected writeOutputs(state: NodeMaterialBuildState, varName: string): string;
+        protected _buildBlock(state: NodeMaterialBuildState): this;
+    }
+}
+declare module BABYLON {
+    /**
      * Block used to add support for scene fog
      */
     export class FogBlock extends NodeMaterialBlock {
@@ -139739,6 +139937,8 @@ declare module BABYLON {
         _vReflectionMicrosurfaceInfosName: string;
         /** @hidden */
         _vReflectionInfosName: string;
+        /** @hidden */
+        _vReflectionFilteringInfoName: string;
         private _scene;
         /**
          * The three properties below are set by the main PBR block prior to calling methods of this class.
@@ -139900,6 +140100,15 @@ declare module BABYLON {
      * Block used to implement the reflectivity module of the PBR material
      */
     export class ReflectivityBlock extends NodeMaterialBlock {
+        private _metallicReflectanceColor;
+        private _metallicF0Factor;
+        /** @hidden */
+        _vMetallicReflectanceFactorsName: string;
+        /**
+         * The property below is set by the main PBR block prior to calling methods of this class.
+        */
+        /** @hidden */
+        indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
         /**
          * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
          */
@@ -139947,12 +140156,14 @@ declare module BABYLON {
          * Gets the reflectivity object output component
          */
         get reflectivity(): NodeMaterialConnectionPoint;
+        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
          * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
          * @returns the shader code
          */
-        getCode(aoIntensityVarName: string): string;
+        getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
         protected _dumpPropertiesCode(): string;
@@ -140264,6 +140475,14 @@ declare module BABYLON {
          */
         enableSpecularAntiAliasing: boolean;
         /**
+         * Enables realtime filtering on the texture.
+         */
+        realTimeFiltering: boolean;
+        /**
+         * Quality switch for realtime filtering
+         */
+        realTimeFilteringQuality: number;
+        /**
          * Defines if the material uses energy conservation.
          */
         useEnergyConservation: boolean;

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


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


+ 102 - 2
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -1285,7 +1285,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -2050,6 +2050,58 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_ior" {
         private _loadIorPropertiesAsync;
     }
 }
+declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants" {
+    import { Nullable } from "babylonjs/types";
+    import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
+    import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
+    import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+    import { INode, IMeshPrimitive, IMesh } from "babylonjs-loaders/glTF/2.0/glTFLoaderInterfaces";
+    /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_mesh_quantization" {
     import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
     import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
@@ -2346,6 +2398,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/index" {
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_sheen";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_specular";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_ior";
+    export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_variants";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_mesh_quantization";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_basisu";
     export * from "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform";
@@ -3949,7 +4002,7 @@ declare module BABYLON.GLTF2 {
          * @param assign A function called synchronously after parsing the glTF properties
          * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
          */
-        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+        _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties.
@@ -4648,6 +4701,53 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
+     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+     * !!! Experimental Extension Subject to Changes !!!
+     */
+    export class KHR_materials_variants implements IGLTFLoaderExtension {
+        /**
+         * The name of this extension.
+         */
+        readonly name: string;
+        /**
+         * Defines whether this extension is enabled.
+         */
+        enabled: boolean;
+        private _loader;
+        /**
+         * The default variant name.
+         */
+        defaultVariant: string | undefined;
+        private _tagsToMap;
+        /** @hidden */
+        constructor(loader: GLTFLoader);
+        /** @hidden */
+        dispose(): void;
+        /**
+         * Return a list of available variants for this asset.
+         * @returns {string[]}
+         */
+        getVariants(): string[];
+        /**
+         * Select a variant by providing a list of variant tag names.
+         *
+         * @param {(string | string[])} variantName
+         */
+        selectVariant(variantName: string | string[]): void;
+        /**
+         * Select a variant by providing a single variant tag.
+         *
+         * @param {string} variantName
+         */
+        selectVariantTag(variantName: string): void;
+        /** @hidden */
+        onLoading(): void;
+        /** @hidden */
+        _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
+    }
+}
+declare module BABYLON.GLTF2.Loader.Extensions {
+    /**
      * [Specification](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization)
      */
     export class KHR_mesh_quantization implements IGLTFLoaderExtension {

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

@@ -45,6 +45,8 @@
 - Added a modulo block ([ageneau](https://github.com/ageneau))
 - Fix bug where frame port labels would be the names of incorrect nodes ([belfortk](https://github.com/belfortk))
 - Fix bug where long comments on collapsed frames broke port alignment ([belfortk](https://github.com/belfortk))
+- Add the `FragCoord` and `ScreenSize` blocks ([Popov72](https://github.com/Popov72))
+- Particle systems: add the `ParticlePositionWorld` block ([Popov72](https://github.com/Popov72))
 
 ### Inspector
 
@@ -84,6 +86,7 @@
 - Added support for KHR_materials_ior for glTF loader. ([Sebavan](https://github.com/sebavan/))
 - Added support for KHR_materials_specular for glTF loader. ([Sebavan](https://github.com/sebavan/))
 - Added support for KHR_xmp for glTF loader. ([Sebavan](https://github.com/sebavan/))
+- Added support for KHR_materials_variants for glTF loader. ([MiiBond](https://github.com/MiiBond/))
 
 ### Navigation
 
@@ -141,7 +144,6 @@
 
 - .HDR environment files will now give accurate PBR reflections ([CraigFeldpsar](https://github.com/craigfeldspar))
 
-
 ### Audio
 
 - Added support of `metadata` in `Sound` class. ([julien-moreau](https://github.com/julien-moreau))
@@ -207,7 +209,7 @@
 - Make sure bone matrices are up to date when calling `TransformNode.attachToBone` ([Popov72](https://github.com/Popov72))
 - Fix display problem with transparent objects and SSAO2 pipeline (bug in the `GeometryBufferRenderer`) ([Popov72](https://github.com/Popov72))
 - Fixed `Sound` not accepting a `TransformNode` as a source for spatial sound ([Poolminer](https://github.com/Poolminer))
-- Fixed an issue with transformation set after physics body was created using cannon.js ([#7928](https://github.com/BabylonJS/Babylon.js/issues/7928)) ([RaananW](https://github.com/RaananW))
+- Fixed an issue with transformation set after physics body was created using cannon.js (excluding height and plane) ([#7928](https://github.com/BabylonJS/Babylon.js/issues/7928)) ([RaananW](https://github.com/RaananW))
 - Fix bug when using `ShadowOnlyMaterial` with Cascaded Shadow Map and `autoCalcDepthBounds` is `true` ([Popov72](https://github.com/Popov72))
 - Fix OBJ serializer default scene scene handedness causing [OBJ Mirror export](https://forum.babylonjs.com/t/obj-export-mirrored/10835/10)
 - Fix bug when using shadows + instances + transparent meshes + `transparencyShadow = false` ([Popov72](https://github.com/Popov72))

+ 154 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_variants.ts

@@ -0,0 +1,154 @@
+import { Nullable } from "babylonjs/types";
+import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
+import { GLTFLoader, ArrayItem } from "../glTFLoader";
+
+import { Material } from 'babylonjs/Materials/material';
+import { Mesh } from 'babylonjs/Meshes/mesh';
+import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { INode, IMeshPrimitive, IMesh } from '../glTFLoaderInterfaces';
+
+const NAME = "KHR_materials_variants";
+
+interface IKHRMaterialVariantsMapping {
+    tags: string[];
+    material: number;
+}
+
+interface IKHRMaterialVariants {
+    mapping: IKHRMaterialVariantsMapping[];
+}
+
+interface IKHRMaterialVariantsTop {
+    default?: string;
+}
+
+/**
+ * Interface for the mapping from variant tag name to a mesh and material.
+ */
+interface VariantMapping {
+    mesh: AbstractMesh;
+    materialPromise: Promise<Nullable<Material>>;
+    material?: Material;
+}
+
+/**
+ * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1681)
+ * !!! Experimental Extension Subject to Changes !!!
+ */
+export class KHR_materials_variants implements IGLTFLoaderExtension {
+    /**
+     * The name of this extension.
+     */
+    public readonly name = NAME;
+
+    /**
+     * Defines whether this extension is enabled.
+     */
+    public enabled: boolean;
+
+    private _loader: GLTFLoader;
+
+    /**
+     * The default variant name.
+     */
+    public defaultVariant: string | undefined;
+
+    private _tagsToMap: { [key: string]: VariantMapping[]; } = {};
+
+    /** @hidden */
+    constructor(loader: GLTFLoader) {
+        this._loader = loader;
+        this.enabled = this._loader.isExtensionUsed(NAME);
+    }
+
+    /** @hidden */
+    public dispose() {
+        delete this._loader;
+    }
+
+    /**
+     * Return a list of available variants for this asset.
+     * @returns {string[]}
+     */
+    public getVariants(): string[] {
+        return Object.keys(this._tagsToMap);
+    }
+
+    /**
+     * Select a variant by providing a list of variant tag names.
+     *
+     * @param {(string | string[])} variantName
+     */
+    public selectVariant(variantName: string | string[]) {
+        if (variantName instanceof Array) {
+            variantName.forEach((name) => this.selectVariantTag(name));
+        } else {
+            this.selectVariantTag(variantName);
+        }
+    }
+
+    /**
+     * Select a variant by providing a single variant tag.
+     *
+     * @param {string} variantName
+     */
+    public selectVariantTag(variantName: string) {
+        // If the name is valid, switch all meshes to use materials defined by the tags
+        const variantMappings = this._tagsToMap[variantName];
+        if (variantMappings === undefined) {
+            return;
+        }
+        variantMappings.forEach((mapping: VariantMapping) => {
+            if (mapping.material) {
+                mapping.mesh.material = mapping.material;
+                return;
+            }
+            mapping.materialPromise.then((material) => {
+                mapping.mesh.material = material;
+            });
+        });
+    }
+
+    /** @hidden */
+    public onLoading(): void {
+        const extensions = this._loader.gltf.extensions;
+        if (extensions && extensions[this.name]) {
+            const extension = extensions[this.name] as IKHRMaterialVariantsTop;
+            this.defaultVariant = extension.default;
+        }
+    }
+
+    /** @hidden */
+    public _loadMeshPrimitiveAsync(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>> {
+        return GLTFLoader.LoadExtensionAsync<IKHRMaterialVariants, AbstractMesh>(context, primitive, this.name, (extensionContext, extension) => {
+            const assignMesh = (babylonMesh: AbstractMesh) => {
+                assign(babylonMesh);
+                const babylonDrawMode = (GLTFLoader as any)._GetDrawMode(context, primitive.mode);
+                // For each mapping, look at the tags and make a new entry for them
+                extension.mapping.forEach((mapping: IKHRMaterialVariantsMapping) => {
+                    mapping.tags.forEach((tag: string, index: number) => {
+                        const tagMapping = this._tagsToMap[tag] || [];
+                        const material = ArrayItem.Get(`#/materials/`, this._loader.gltf.materials, mapping.material);
+                        const meshEntry: VariantMapping = {
+                            mesh: babylonMesh,
+                            materialPromise: Promise.resolve(null)
+                        };
+                        if (babylonMesh instanceof Mesh) {
+                            meshEntry.materialPromise = this._loader._loadMaterialAsync(`#/materials/${mapping.material}`, material, babylonMesh!, babylonDrawMode, (material) => {
+                                meshEntry.material = material;
+                            });
+                        }
+                        tagMapping.push(meshEntry);
+                        this._tagsToMap[tag] = tagMapping;
+                    });
+                });
+            };
+            this._loader._disableInstancedMesh++;
+            const promise = this._loader._loadMeshPrimitiveAsync(context, name, node, mesh, primitive, assignMesh);
+            this._loader._disableInstancedMesh--;
+            return promise;
+        });
+    }
+}
+
+GLTFLoader.RegisterExtension(NAME, (loader) => new KHR_materials_variants(loader));

+ 1 - 0
loaders/src/glTF/2.0/Extensions/index.ts

@@ -8,6 +8,7 @@ export * from "./KHR_materials_clearcoat";
 export * from "./KHR_materials_sheen";
 export * from "./KHR_materials_specular";
 export * from "./KHR_materials_ior";
+export * from "./KHR_materials_variants";
 export * from "./KHR_mesh_quantization";
 export * from "./KHR_texture_basisu";
 export * from "./KHR_texture_transform";

+ 1 - 1
loaders/src/glTF/2.0/glTFLoaderExtension.ts

@@ -72,7 +72,7 @@ export interface IGLTFLoaderExtension extends IGLTFBaseLoaderExtension, IDisposa
      * @param assign A function called synchronously after parsing the glTF properties
      * @returns A promise that resolves with the loaded mesh when the load is complete or null if not handled
      */
-    _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Promise<AbstractMesh>;
+    _loadMeshPrimitiveAsync?(context: string, name: string, node: INode, mesh: IMesh, primitive: IMeshPrimitive, assign: (babylonMesh: AbstractMesh) => void): Nullable<Promise<AbstractMesh>>;
 
     /**
      * @hidden

+ 11 - 0
nodeEditor/src/blockTools.ts

@@ -77,6 +77,8 @@ import { ParticleTextureBlock } from 'babylonjs/Materials/Node/Blocks/Particle/p
 import { ParticleRampGradientBlock } from 'babylonjs/Materials/Node/Blocks/Particle/particleRampGradientBlock';
 import { ParticleBlendMultiplyBlock } from 'babylonjs/Materials/Node/Blocks/Particle/particleBlendMultiplyBlock';
 import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
+import { FragCoordBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fragCoordBlock';
+import { ScreenSizeBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/screenSizeBlock';
 
 export class BlockTools {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
@@ -491,10 +493,19 @@ export class BlockTools {
                 u.setAsAttribute("particle_texturemask");
                 return u;
             }
+            case "ParticlePositionWorldBlock": {
+                let pos = new InputBlock("PositionWorld");
+                pos.setAsAttribute("particle_positionw");
+                return pos;
+            }
             case "ParticleRampGradientBlock":
                 return new ParticleRampGradientBlock("ParticleRampGradient");
             case "ParticleBlendMultiplyBlock":
                 return new ParticleBlendMultiplyBlock("ParticleBlendMultiply");
+            case "FragCoordBlock":
+                return new FragCoordBlock("FragCoord");
+            case "ScreenSizeBlock":
+                return new ScreenSizeBlock("ScreenSize");
         }
 
         return null;

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

@@ -140,6 +140,9 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         "ParticleTextureMaskBlock": "The particle texture mask",
         "ParticleRampGradientBlock": "The particle ramp gradient block",
         "ParticleBlendMultiplyBlock": "The particle blend multiply block",
+        "ParticlePositionWorldBlock": "The world position of the particle",
+        "FragCoordBlock": "The gl_FragCoord predefined variable that contains the window relative coordinate (x, y, z, 1/w)",
+        "ScreenSizeBlock": "The size (in pixels) of the screen window",
     };
 
     constructor(props: INodeListComponentProps) {
@@ -167,7 +170,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Animation: ["BonesBlock", "MorphTargetsBlock"],
             Color_Management: ["ReplaceColorBlock", "PosterizeBlock", "GradientBlock", "DesaturateBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
-            Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock"],
+            Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock", "FragCoordBlock", "ScreenSizeBlock"],
             Interpolation: ["LerpBlock", "StepBlock", "SmoothStepBlock", "NLerpBlock"],
             Math__Standard: ["AddBlock", "DivideBlock", "MaxBlock", "MinBlock", "ModBlock", "MultiplyBlock", "NegateBlock", "OneMinusBlock", "ReciprocalBlock", "ScaleBlock", "SignBlock", "SqrtBlock", "SubtractBlock"],
             Math__Scientific: ["AbsBlock", "ArcCosBlock", "ArcSinBlock", "ArcTanBlock", "ArcTan2Block", "CosBlock", "DegreesToRadiansBlock", "ExpBlock", "Exp2Block", "FractBlock", "LogBlock", "PowBlock", "RadiansToDegreesBlock", "SawToothWaveBlock", "SinBlock", "SquareWaveBlock", "TanBlock", "TriangleWaveBlock"],
@@ -176,7 +179,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
-            Particle: ["ParticleBlendMultiplyBlock", "ParticleColorBlock", "ParticleRampGradientBlock", "ParticleTextureBlock", "ParticleTextureMaskBlock", "ParticleUVBlock"],
+            Particle: ["ParticleBlendMultiplyBlock", "ParticleColorBlock", "ParticlePositionWorldBlock", "ParticleRampGradientBlock", "ParticleTextureBlock", "ParticleTextureMaskBlock", "ParticleUVBlock"],
             PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "RefractionBlock", "SheenBlock", "SubSurfaceBlock"],
             PostProcess: ["Position2DBlock", "CurrentScreenBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],

+ 2 - 0
nodeEditor/src/diagram/display/inputDisplayManager.ts

@@ -14,6 +14,7 @@ const inputNameToAttributeValue: { [name: string] : string } = {
     "particle_uv" : "uv",
     "particle_color" : "color",
     "particle_texturemask": "textureMask",
+    "particle_positionw" : "positionW",
 };
 
 const inputNameToAttributeName: { [name: string] : string } = {
@@ -21,6 +22,7 @@ const inputNameToAttributeName: { [name: string] : string } = {
     "particle_uv" : "particle",
     "particle_color" : "particle",
     "particle_texturemask": "particle",
+    "particle_positionw": "particle",
 };
 
 export class InputDisplayManager implements IDisplayManager {

+ 1 - 1
package.json

@@ -110,4 +110,4 @@
         "xhr2": "^0.1.4",
         "xmlbuilder": "8.2.2"
     }
-}
+}

+ 1 - 1
readme.md

@@ -111,7 +111,7 @@ If you want to contribute, please read our [contribution guidelines](https://git
 - [Examples](https://doc.babylonjs.com/examples)
 
 ## Contributing
-Please see the [Contributing Guidelines](./contributing.md)
+Please see the [Contributing Guidelines](./contributing.md).
 
 ## Useful links
 

+ 5 - 0
src/Cameras/targetCamera.ts

@@ -312,6 +312,11 @@ export class TargetCamera extends Camera {
 
         // Rotate
         if (needToRotate) {
+            //rotate, if quaternion is set and rotation was used
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.toEulerAnglesToRef(this.rotation);
+            }
+
             this.rotation.x += this.cameraRotation.x * directionMultiplier;
             this.rotation.y += this.cameraRotation.y * directionMultiplier;
 

+ 8 - 0
src/Engines/thinEngine.ts

@@ -106,6 +106,10 @@ export interface EngineOptions extends WebGLContextAttributes {
      * Defines that engine should compile shaders with high precision floats (if supported). True by default
      */
     useHighPrecisionFloats?: boolean;
+    /**
+     * Make the canvas XR Compatible for XR sessions
+     */
+    xrCompatible?: boolean;
 }
 
 /**
@@ -516,6 +520,10 @@ export class ThinEngine {
                 this.premultipliedAlpha = false;
             }
 
+            if (options.xrCompatible === undefined) {
+                options.xrCompatible = true;
+            }
+
             this._doNotHandleContextLost = options.doNotHandleContextLost ? true : false;
 
             // Exceptions

+ 9 - 7
src/Materials/Node/Blocks/Dual/textureBlock.ts

@@ -332,13 +332,15 @@ export class TextureBlock extends NodeMaterialBlock {
 
         state.compilationString += `${this._declareOutput(output, state)} = ${this._tempTextureRead}.${swizzle}${complement};\r\n`;
 
-        state.compilationString += `#ifdef ${this._linearDefineName}\r\n`;
-        state.compilationString += `${output.associatedVariableName} = toGammaSpace(${output.associatedVariableName});\r\n`;
-        state.compilationString += `#endif\r\n`;
-
-        state.compilationString += `#ifdef ${this._gammaDefineName}\r\n`;
-        state.compilationString += `${output.associatedVariableName} = toLinearSpace(${output.associatedVariableName});\r\n`;
-        state.compilationString += `#endif\r\n`;
+        if (swizzle !== 'a') { // no conversion if the output is "a" (alpha)
+            state.compilationString += `#ifdef ${this._linearDefineName}\r\n`;
+            state.compilationString += `${output.associatedVariableName} = toGammaSpace(${output.associatedVariableName});\r\n`;
+            state.compilationString += `#endif\r\n`;
+
+            state.compilationString += `#ifdef ${this._gammaDefineName}\r\n`;
+            state.compilationString += `${output.associatedVariableName} = toLinearSpace(${output.associatedVariableName});\r\n`;
+            state.compilationString += `#endif\r\n`;
+        }
     }
 
     protected _buildBlock(state: NodeMaterialBuildState) {

+ 110 - 0
src/Materials/Node/Blocks/Fragment/fragCoordBlock.ts

@@ -0,0 +1,110 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
+import { _TypeStore } from '../../../../Misc/typeStore';
+
+/**
+ * Block used to make gl_FragCoord available
+ */
+export class FragCoordBlock extends NodeMaterialBlock {
+    /**
+     * Creates a new FragCoordBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this.registerOutput("xy", NodeMaterialBlockConnectionPointTypes.Vector2, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("xyz", NodeMaterialBlockConnectionPointTypes.Vector3, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("xyzw", NodeMaterialBlockConnectionPointTypes.Vector4, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("x", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("y", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("z", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("w", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "FragCoordBlock";
+    }
+
+    /**
+     * Gets the xy component
+     */
+    public get xy(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    /**
+     * Gets the xyz component
+     */
+    public get xyz(): NodeMaterialConnectionPoint {
+        return this._outputs[1];
+    }
+
+    /**
+     * Gets the xyzw component
+     */
+    public get xyzw(): NodeMaterialConnectionPoint {
+        return this._outputs[2];
+    }
+
+    /**
+     * Gets the x component
+     */
+    public get x(): NodeMaterialConnectionPoint {
+        return this._outputs[3];
+    }
+
+    /**
+     * Gets the y component
+     */
+    public get y(): NodeMaterialConnectionPoint {
+        return this._outputs[4];
+    }
+
+    /**
+     * Gets the z component
+     */
+    public get z(): NodeMaterialConnectionPoint {
+        return this._outputs[5];
+    }
+
+    /**
+     * Gets the w component
+     */
+    public get output(): NodeMaterialConnectionPoint {
+        return this._outputs[6];
+    }
+
+    protected writeOutputs(state: NodeMaterialBuildState): string {
+        let code = "";
+
+        for (var output of this._outputs) {
+            if (output.hasEndpoints) {
+                code += `${this._declareOutput(output, state)} = gl_FragCoord.${output.name};\r\n`;
+            }
+        }
+
+        return code;
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        if (state.target === NodeMaterialBlockTargets.Vertex) {
+            throw "FragCoordBlock must only be used in a fragment shader";
+        }
+
+        state.compilationString += this.writeOutputs(state);
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.FragCoordBlock"] = FragCoordBlock;

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

@@ -5,3 +5,5 @@ export * from "./perturbNormalBlock";
 export * from "./discardBlock";
 export * from "./frontFacingBlock";
 export * from "./derivativeBlock";
+export * from "./fragCoordBlock";
+export * from "./screenSizeBlock";

+ 98 - 0
src/Materials/Node/Blocks/Fragment/screenSizeBlock.ts

@@ -0,0 +1,98 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
+import { _TypeStore } from '../../../../Misc/typeStore';
+import { Effect } from '../../../effect';
+import { NodeMaterial } from '../../nodeMaterial';
+import { Mesh } from '../../../../Meshes/mesh';
+import { Scene } from '../../../../scene';
+
+/**
+ * Block used to get the screen sizes
+ */
+export class ScreenSizeBlock extends NodeMaterialBlock {
+    private _varName: string;
+    private _scene: Scene;
+
+    /**
+     * Creates a new ScreenSizeBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this.registerOutput("xy", NodeMaterialBlockConnectionPointTypes.Vector2, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("x", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("y", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "ScreenSizeBlock";
+    }
+
+    /**
+     * Gets the xy component
+     */
+    public get xy(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    /**
+     * Gets the x component
+     */
+    public get x(): NodeMaterialConnectionPoint {
+        return this._outputs[1];
+    }
+
+    /**
+     * Gets the y component
+     */
+    public get y(): NodeMaterialConnectionPoint {
+        return this._outputs[2];
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
+        const engine = this._scene.getEngine();
+
+        effect.setFloat2(this._varName, engine.getRenderWidth(), engine.getRenderWidth());
+    }
+
+    protected writeOutputs(state: NodeMaterialBuildState, varName: string): string {
+        let code = "";
+
+        for (var output of this._outputs) {
+            if (output.hasEndpoints) {
+                code += `${this._declareOutput(output, state)} = ${varName}.${output.name};\r\n`;
+            }
+        }
+
+        return code;
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        this._scene = state.sharedData.scene;
+
+        if (state.target === NodeMaterialBlockTargets.Vertex) {
+            throw "ScreenSizeBlock must only be used in a fragment shader";
+        }
+
+        state.sharedData.bindableBlocks.push(this);
+
+        this._varName = state._getFreeVariableName("screenSize");
+        state._emitUniformFromString(this._varName, "vec2");
+
+        state.compilationString += this.writeOutputs(state, this._varName);
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.ScreenSizeBlock"] = ScreenSizeBlock;

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

@@ -20,12 +20,14 @@ const remapAttributeName: { [name: string]: string }  = {
     "particle_uv": "vUV",
     "particle_color": "vColor",
     "particle_texturemask": "textureMask",
+    "particle_positionw": "vPositionW",
 };
 
 const attributeInFragmentOnly: { [name: string]: boolean }  = {
     "particle_uv": true,
     "particle_color": true,
     "particle_texturemask": true,
+    "particle_positionw": true,
 };
 
 const attributeAsUniform: { [name: string]: boolean }  = {
@@ -108,6 +110,7 @@ export class InputBlock extends NodeMaterialBlock {
                     case "position":
                     case "normal":
                     case "tangent":
+                    case "particle_positionw":
                         this._type = NodeMaterialBlockConnectionPointTypes.Vector3;
                         return this._type;
                     case "uv":

+ 3 - 12
src/Materials/Node/Blocks/PBR/clearCoatBlock.ts

@@ -42,7 +42,6 @@ export class ClearCoatBlock extends NodeMaterialBlock {
         this.registerInput("tintColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintAtDistance", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("tintThickness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
-        this.registerInput("tintTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("worldTangent", NodeMaterialBlockConnectionPointTypes.Vector4, true);
 
         this.registerOutput("clearcoat", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
@@ -133,17 +132,10 @@ export class ClearCoatBlock extends NodeMaterialBlock {
     }
 
     /**
-     * Gets the tint texture input component
-     */
-    public get tintTexture(): NodeMaterialConnectionPoint {
-        return this._inputs[9];
-    }
-
-    /**
      * Gets the world tangent input component
      */
     public get worldTangent(): NodeMaterialConnectionPoint {
-        return this._inputs[10];
+        return this._inputs[9];
     }
 
     /**
@@ -166,8 +158,7 @@ export class ClearCoatBlock extends NodeMaterialBlock {
 
         defines.setValue("CLEARCOAT", true);
         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_TINT", this.tintColor.isConnected || this.tintThickness.isConnected || this.tintAtDistance.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);
     }
@@ -245,7 +236,7 @@ export class ClearCoatBlock extends NodeMaterialBlock {
         const tintColor = ccBlock?.tintColor.isConnected ? ccBlock.tintColor.associatedVariableName : "vec3(1.)";
         const tintThickness = ccBlock?.tintThickness.isConnected ? ccBlock.tintThickness.associatedVariableName : "1.";
         const tintAtDistance = ccBlock?.tintAtDistance.isConnected ? ccBlock.tintAtDistance.associatedVariableName : "1.";
-        const tintTexture = ccBlock?.tintTexture.isConnected ? ccBlock.tintTexture.associatedVariableName : "vec4(0.)";
+        const tintTexture = "vec4(0.)";
 
         if (ccBlock) {
             state._emitUniformFromString("vClearCoatRefractionParams", "vec4");

+ 58 - 27
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -29,6 +29,7 @@ import { ClearCoatBlock } from './clearCoatBlock';
 import { SubSurfaceBlock } from './subSurfaceBlock';
 import { RefractionBlock } from './refractionBlock';
 import { PerturbNormalBlock } from '../Fragment/perturbNormalBlock';
+import { Constants } from '../../../../Engines/constants';
 
 const mapOutputToVariable: { [name: string] : [string, string] } = {
     "ambient":      ["finalAmbient", ""],
@@ -76,7 +77,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         this.registerInput("perturbedNormal", NodeMaterialBlockConnectionPointTypes.Vector4, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("cameraPosition", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Fragment);
         this.registerInput("baseColor", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
-        this.registerInput("baseTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("opacityTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("ambientColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("reflectivity", NodeMaterialBlockConnectionPointTypes.Object, false, NodeMaterialBlockTargets.Fragment,
@@ -195,6 +195,22 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     public enableSpecularAntiAliasing: boolean = false;
 
     /**
+     * Enables realtime filtering on the texture.
+     */
+    @editableInPropertyPage("Realtime filtering", PropertyTypeForEdition.Boolean, "RENDERING", { "notifiers": { "update": true }})
+    public realTimeFiltering: boolean = false;
+
+    /**
+     * Quality switch for realtime filtering
+     */
+    @editableInPropertyPage("Realtime filtering quality", PropertyTypeForEdition.List, "RENDERING", { "notifiers": { "update": true }, "options": [
+        { label: "Low", value: Constants.TEXTURE_FILTERING_QUALITY_LOW },
+        { label: "Medium", value: Constants.TEXTURE_FILTERING_QUALITY_MEDIUM },
+        { label: "High", value: Constants.TEXTURE_FILTERING_QUALITY_HIGH },
+    ]})
+    public realTimeFilteringQuality = Constants.TEXTURE_FILTERING_QUALITY_LOW;
+
+    /**
      * Defines if the material uses energy conservation.
      */
     @editableInPropertyPage("Energy Conservation", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
@@ -398,73 +414,66 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     }
 
     /**
-     * Gets the base texture input component
-     */
-    public get baseTexture(): NodeMaterialConnectionPoint {
-        return this._inputs[5];
-    }
-
-    /**
      * Gets the opacity texture input component
      */
     public get opacityTexture(): NodeMaterialConnectionPoint {
-        return this._inputs[6];
+        return this._inputs[5];
     }
 
     /**
      * Gets the ambient color input component
      */
     public get ambientColor(): NodeMaterialConnectionPoint {
-        return this._inputs[7];
+        return this._inputs[6];
     }
 
     /**
      * Gets the reflectivity object parameters
      */
     public get reflectivity(): NodeMaterialConnectionPoint {
-        return this._inputs[8];
+        return this._inputs[7];
     }
 
     /**
      * Gets the ambient occlusion object parameters
      */
     public get ambientOcclusion(): NodeMaterialConnectionPoint {
-        return this._inputs[9];
+        return this._inputs[8];
     }
 
     /**
      * Gets the reflection object parameters
      */
     public get reflection(): NodeMaterialConnectionPoint {
-        return this._inputs[10];
+        return this._inputs[9];
     }
 
     /**
      * Gets the sheen object parameters
      */
     public get sheen(): NodeMaterialConnectionPoint {
-        return this._inputs[11];
+        return this._inputs[10];
     }
 
     /**
      * Gets the clear coat object parameters
      */
     public get clearcoat(): NodeMaterialConnectionPoint {
-        return this._inputs[12];
+        return this._inputs[11];
     }
 
     /**
      * Gets the sub surface object parameters
      */
     public get subsurface(): NodeMaterialConnectionPoint {
-        return this._inputs[13];
+        return this._inputs[12];
     }
 
     /**
      * Gets the anisotropy object parameters
      */
     public get anisotropy(): NodeMaterialConnectionPoint {
-        return this._inputs[14];
+        return this._inputs[13];
     }
 
     /**
@@ -580,7 +589,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         defines.setValue("LODBASEDMICROSFURACE", this._scene.getEngine().getCaps().textureLOD);
 
         // Albedo & Opacity
-        defines.setValue("ALBEDO", this.baseTexture.isConnected, true);
         defines.setValue("OPACITY", this.opacityTexture.isConnected, true);
 
         // Lighting & colors
@@ -606,6 +614,12 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         defines.setValue("RADIANCEOVERALPHA", this.useRadianceOverAlpha, true);
         defines.setValue("SPECULAROVERALPHA", this.useSpecularOverAlpha, true);
         defines.setValue("SPECULARAA", this._scene.getEngine().getCaps().standardDerivatives && this.enableSpecularAntiAliasing, true);
+        defines.setValue("REALTIME_FILTERING", this.realTimeFiltering, true);
+        defines.setValue("NUM_SAMPLES", "" + this.realTimeFilteringQuality, true);
+
+        if (this._scene.getEngine().webGLVersion > 1) {
+            defines.setValue("NUM_SAMPLES", this.realTimeFilteringQuality + "u", true);
+        }
 
         // Advanced
         defines.setValue("BRDF_V_HEIGHT_CORRELATED", true);
@@ -756,13 +770,12 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         let code = `albedoOpacityOutParams albedoOpacityOut;\r\n`;
 
         const albedoColor = this.baseColor.isConnected ? this.baseColor.associatedVariableName : "vec4(1., 1., 1., 1.)";
-        const albedoTexture = this.baseTexture.isConnected ? this.baseTexture.associatedVariableName : "";
         const opacityTexture = this.opacityTexture.isConnected ? this.opacityTexture.associatedVariableName : "";
 
         code += `albedoOpacityBlock(
                 ${albedoColor},
             #ifdef ALBEDO
-                ${albedoTexture},
+                vec4(1.),
                 vec2(1., 1.),
             #endif
             #ifdef OPACITY
@@ -834,6 +847,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         }
 
         state._emitFunctionFromInclude("helperFunctions", comments);
+        state._emitFunctionFromInclude("importanceSampling", comments);
         state._emitFunctionFromInclude("pbrHelperFunctions", comments);
         state._emitFunctionFromInclude("imageProcessingFunctions", comments);
 
@@ -851,6 +865,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state._emitFunctionFromInclude("pbrDirectLightingFalloffFunctions", comments);
         state._emitFunctionFromInclude("pbrBRDFFunctions", comments);
+        state._emitFunctionFromInclude("hdrFilteringFunctions", comments);
 
         state._emitFunctionFromInclude("pbrDirectLightingFunctions", comments, {
             replaceStrings: [
@@ -913,9 +928,18 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             #else\r\n`;
 
         // _____________________________ Reflectivity _______________________________
+        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;
+
+        const reflectivityBlock = this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock> ?? null;
+
+        if (reflectivityBlock) {
+            reflectivityBlock.indexOfRefractionConnectionPoint = refractionBlock?.indexOfRefraction ?? null;
+        }
+
         const aoIntensity = aoBlock?.intensity.isConnected ? aoBlock.intensity.associatedVariableName : "1.";
 
-        state.compilationString += (this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock>)?.getCode(aoIntensity) ?? "";
+        state.compilationString += reflectivityBlock?.getCode(state, aoIntensity) ?? "";
 
         // _____________________________ Geometry info _________________________________
         state.compilationString += state._emitCodeFromInclude("pbrBlockGeometryInfo", comments, {
@@ -949,12 +973,16 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
                 { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
                 { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
                 { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+                { search: /vReflectionFilteringInfo/g, replace: reflectionBlock?._vReflectionFilteringInfoName ?? "vReflectionFilteringInfo" },
             ]
         });
 
         // ___________________ Compute Reflectance aka R0 F0 info _________________________
-        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments);
-
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments, {
+            replaceStrings: [
+                { search: /metallicReflectanceFactors/g, replace: reflectivityBlock?._vMetallicReflectanceFactorsName ?? "metallicReflectanceFactors" },
+            ]
+        });
         // ________________________________ Sheen ______________________________
         const sheenBlock = this.sheen.isConnected ? this.sheen.connectedPoint?.ownerBlock as SheenBlock : null;
 
@@ -1006,9 +1034,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         });
 
         // ___________________________________ SubSurface ______________________________________
-        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, {
@@ -1080,7 +1105,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             replaceStrings: [
                 { search: /vNormalW/g, replace: this._vNormalWName },
                 { search: /vPositionW/g, replace: worldPosVarName },
-                { search: /albedoTexture\.rgb;/g, replace: this.baseTexture.associatedVariableName + ".rgb;\r\ngl_FragColor.rgb = toGammaSpace(gl_FragColor.rgb);\r\n" },
+                { search: /albedoTexture\.rgb;/g, replace: "vec3(1.);\r\ngl_FragColor.rgb = toGammaSpace(gl_FragColor.rgb);\r\n" },
                 { search: /opacityMap/g, replace: this.opacityTexture.associatedVariableName },
             ]
         });
@@ -1121,6 +1146,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         codeString += `${this._codeVariableName}.useRadianceOverAlpha = ${this.useRadianceOverAlpha};\r\n`;
         codeString += `${this._codeVariableName}.useSpecularOverAlpha = ${this.useSpecularOverAlpha};\r\n`;
         codeString += `${this._codeVariableName}.enableSpecularAntiAliasing = ${this.enableSpecularAntiAliasing};\r\n`;
+        codeString += `${this._codeVariableName}.realTimeFiltering = ${this.realTimeFiltering};\r\n`;
+        codeString += `${this._codeVariableName}.realTimeFilteringQuality = ${this.realTimeFilteringQuality};\r\n`;
         codeString += `${this._codeVariableName}.useEnergyConservation = ${this.useEnergyConservation};\r\n`;
         codeString += `${this._codeVariableName}.useRadianceOcclusion = ${this.useRadianceOcclusion};\r\n`;
         codeString += `${this._codeVariableName}.useHorizonOcclusion = ${this.useHorizonOcclusion};\r\n`;
@@ -1149,6 +1176,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         serializationObject.useRadianceOverAlpha = this.useRadianceOverAlpha;
         serializationObject.useSpecularOverAlpha = this.useSpecularOverAlpha;
         serializationObject.enableSpecularAntiAliasing = this.enableSpecularAntiAliasing;
+        serializationObject.realTimeFiltering = this.realTimeFiltering;
+        serializationObject.realTimeFilteringQuality = this.realTimeFilteringQuality;
         serializationObject.useEnergyConservation = this.useEnergyConservation;
         serializationObject.useRadianceOcclusion = this.useRadianceOcclusion;
         serializationObject.useHorizonOcclusion = this.useHorizonOcclusion;
@@ -1177,6 +1206,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         this.useRadianceOverAlpha = serializationObject.useRadianceOverAlpha;
         this.useSpecularOverAlpha = serializationObject.useSpecularOverAlpha;
         this.enableSpecularAntiAliasing = serializationObject.enableSpecularAntiAliasing;
+        this.realTimeFiltering = !!serializationObject.realTimeFiltering;
+        this.realTimeFilteringQuality = serializationObject.realTimeFilteringQuality ?? Constants.TEXTURE_FILTERING_QUALITY_LOW;
         this.useEnergyConservation = serializationObject.useEnergyConservation;
         this.useRadianceOcclusion = serializationObject.useRadianceOcclusion;
         this.useHorizonOcclusion = serializationObject.useHorizonOcclusion;

+ 11 - 1
src/Materials/Node/Blocks/PBR/reflectionBlock.ts

@@ -15,6 +15,7 @@ import { SubMesh } from '../../../../Meshes/subMesh';
 import { Effect } from '../../../effect';
 import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
 import { Scene } from '../../../../scene';
+import { Scalar } from '../../../../Maths/math.scalar';
 
 /**
  * Block used to implement the reflection module of the PBR material
@@ -30,6 +31,8 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
     public _vReflectionMicrosurfaceInfosName: string;
     /** @hidden */
     public _vReflectionInfosName: string;
+    /** @hidden */
+    public _vReflectionFilteringInfoName: string;
     private _scene: Scene;
 
     /**
@@ -211,7 +214,10 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
             effect.setTexture(this._2DSamplerName, reflectionTexture);
         }
 
-        effect.setFloat3(this._vReflectionMicrosurfaceInfosName, reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
+        const width = reflectionTexture.getSize().width;
+
+        effect.setFloat3(this._vReflectionMicrosurfaceInfosName, width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
+        effect.setFloat2(this._vReflectionFilteringInfoName, width, Scalar.Log2(width));
 
         const defines = subMesh._materialDefines as  NodeMaterialDefines;
 
@@ -346,6 +352,10 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
 
         this._vReflectionInfosName = state._getFreeVariableName("vReflectionInfos");
 
+        this._vReflectionFilteringInfoName = state._getFreeVariableName("vReflectionFilteringInfo");
+
+        state._emitUniformFromString(this._vReflectionFilteringInfoName, "vec2");
+
         code += `#ifdef REFLECTION
             vec2 ${this._vReflectionInfosName} = vec2(1., 0.);
 

+ 46 - 4
src/Materials/Node/Blocks/PBR/reflectivityBlock.ts

@@ -9,12 +9,31 @@ import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
 import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
 import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
 import { Scene } from '../../../../scene';
+import { Nullable } from '../../../../types';
+import { Color3 } from '../../../../Maths/math.color';
+import { TmpColors } from '../../../../Maths/math.color';
+import { Mesh } from '../../../../Meshes/mesh';
+import { SubMesh } from '../../../../Meshes/subMesh';
+import { Effect } from '../../../effect';
 
 /**
  * Block used to implement the reflectivity module of the PBR material
  */
 export class ReflectivityBlock extends NodeMaterialBlock {
 
+    private _metallicReflectanceColor: Color3 = Color3.White();
+    private _metallicF0Factor = 1;
+
+    /** @hidden */
+    public _vMetallicReflectanceFactorsName: string;
+
+    /**
+     * The property below is set by the main PBR block prior to calling methods of this class.
+    */
+
+    /** @hidden */
+    public indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
+
     /**
      * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
      */
@@ -103,24 +122,46 @@ export class ReflectivityBlock extends NodeMaterialBlock {
         return this._outputs[0];
     }
 
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
+        super.bind(effect, nodeMaterial, mesh);
+
+        const outside_ior = 1; // consider air as clear coat and other layers would remap in the shader.
+        const ior = this.indexOfRefractionConnectionPoint?.connectInputBlock?.value ?? 1.5;
+
+        // We are here deriving our default reflectance from a common value for none metallic surface.
+        // Based of the schlick fresnel approximation model
+        // for dielectrics.
+        const f0 = Math.pow((ior - outside_ior) / (ior + outside_ior), 2);
+
+        // Tweak the default F0 and F90 based on our given setup
+        this._metallicReflectanceColor.scaleToRef(f0 * this._metallicF0Factor, TmpColors.Color3[0]);
+        const metallicF90 = this._metallicF0Factor;
+
+        effect.setColor4(this._vMetallicReflectanceFactorsName, TmpColors.Color3[0], metallicF90);
+    }
+
     /**
      * Gets the main code of the block (fragment side)
+     * @param state current state of the node material building
      * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
      * @returns the shader code
      */
-    public getCode(aoIntensityVarName: string): string {
+    public getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string {
         const metalRoughTexture = this.texture.isConnected ? this.texture.connectedPoint?.associatedVariableName : null;
 
-        // note: metallic F0 factor = 0.04
+        this._vMetallicReflectanceFactorsName = state._getFreeVariableName("vMetallicReflectanceFactors");
+
+        state._emitUniformFromString(this._vMetallicReflectanceFactorsName, "vec4");
+
+        // note: metallic F0 factor = 1
         let code = `vec3 baseColor = surfaceAlbedo;
-            vec4 metallicReflectanceFactors = vec4(1.);
             reflectivityOutParams reflectivityOut;
 
             reflectivityBlock(
                 vec4(${this.metallic.associatedVariableName}, ${this.roughness.associatedVariableName}, 0., 0.),
             #ifdef METALLICWORKFLOW
                 surfaceAlbedo,
-                metallicReflectanceFactors,
+                ${this._vMetallicReflectanceFactorsName},
             #endif
             #ifdef REFLECTIVITY
                 vec3(0., 0., ${aoIntensityVarName}),
@@ -161,6 +202,7 @@ export class ReflectivityBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         if (state.target === NodeMaterialBlockTargets.Fragment) {
             state.sharedData.blocksWithDefines.push(this);
+            state.sharedData.bindableBlocks.push(this);
         }
 
         return this;

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

@@ -213,7 +213,7 @@ export class RefractionBlock extends NodeMaterialBlock {
             }
         }
 
-        const indexOfRefraction = this.indexOfRefraction.connectInputBlock?.value ?? 1.0;
+        const indexOfRefraction = this.indexOfRefraction.connectInputBlock?.value ?? 1.5;
 
         effect.setFloat4(this._vRefractionInfosName, refractionTexture.level, 1 / indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
 

+ 1 - 10
src/Materials/Node/Blocks/PBR/sheenBlock.ts

@@ -29,7 +29,6 @@ export class SheenBlock extends NodeMaterialBlock {
         this.registerInput("intensity", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("roughness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
-        this.registerInput("texture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
 
         this.registerOutput("sheen", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("sheen", this, NodeMaterialConnectionPointDirection.Output, SheenBlock, "SheenBlock"));
@@ -90,13 +89,6 @@ export class SheenBlock extends NodeMaterialBlock {
     }
 
     /**
-     * Gets the texture input component
-     */
-    public get texture(): NodeMaterialConnectionPoint {
-        return this._inputs[3];
-    }
-
-    /**
      * Gets the sheen object output component
      */
     public get sheen(): NodeMaterialConnectionPoint {
@@ -110,7 +102,6 @@ export class SheenBlock extends NodeMaterialBlock {
         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);
     }
 
     /**
@@ -124,7 +115,7 @@ export class SheenBlock extends NodeMaterialBlock {
         const color = this.color.isConnected ? this.color.associatedVariableName : "vec3(1.)";
         const intensity = this.intensity.isConnected ? this.intensity.associatedVariableName : "1.";
         const roughness = this.roughness.isConnected ? this.roughness.associatedVariableName : "0.";
-        const texture = this.texture.isConnected ? this.texture.associatedVariableName : "vec4(0.)";
+        const texture = "vec4(0.)";
 
         code = `#ifdef SHEEN
             sheenOutParams sheenOut;

+ 8 - 1
src/Particles/gpuParticleSystem.ts

@@ -1196,6 +1196,8 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
                     defines.push("#define BILLBOARDSTRETCHED");
                     break;
                 case ParticleSystem.BILLBOARDMODE_ALL:
+                    defines.push("#define BILLBOARDMODE_ALL");
+                    break;
                 default:
                     break;
             }
@@ -1509,11 +1511,16 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
                 effect.setVector3("eyePosition", camera.globalPosition);
             }
 
+            const defines = effect.defines;
+
             if (this._scene.clipPlane || this._scene.clipPlane2 || this._scene.clipPlane3 || this._scene.clipPlane4 || this._scene.clipPlane5 || this._scene.clipPlane6) {
+                MaterialHelper.BindClipPlane(effect, this._scene);
+            }
+
+            if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
                 var invView = viewMatrix.clone();
                 invView.invert();
                 effect.setMatrix("invView", invView);
-                MaterialHelper.BindClipPlane(effect, this._scene);
             }
 
             // image processing

+ 8 - 1
src/Particles/particleSystem.ts

@@ -1656,6 +1656,8 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
                     defines.push("#define BILLBOARDSTRETCHED");
                     break;
                 case ParticleSystem.BILLBOARDMODE_ALL:
+                    defines.push("#define BILLBOARDMODE_ALL");
+                    break;
                 default:
                     break;
             }
@@ -1902,11 +1904,16 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
             effect.setTexture("rampSampler", this._rampGradientsTexture);
         }
 
+        const defines = effect.defines;
+
         if (this._scene.clipPlane || this._scene.clipPlane2 || this._scene.clipPlane3 || this._scene.clipPlane4 || this._scene.clipPlane5 || this._scene.clipPlane6) {
+            MaterialHelper.BindClipPlane(effect, this._scene);
+        }
+
+        if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
             var invView = viewMatrix.clone();
             invView.invert();
             effect.setMatrix("invView", invView);
-            MaterialHelper.BindClipPlane(effect, this._scene);
         }
 
         engine.bindBuffers(this._vertexBuffers, this._indexBuffer, effect);

+ 3 - 1
src/Physics/Plugins/cannonJSPlugin.ts

@@ -59,7 +59,9 @@ export class CannonJSPlugin implements IPhysicsEnginePlugin {
         if (this._firstFrame) {
             this._firstFrame = false;
             for (const impostor of impostors) {
-                impostor.beforeStep();
+                if (!(impostor.type == PhysicsImpostor.HeightmapImpostor || impostor.type === PhysicsImpostor.PlaneImpostor)) {
+                    impostor.beforeStep();
+                }
             }
         }
         this.world.step(this._useDeltaForWorldStep ? delta : this._fixedTimeStep);

+ 5 - 0
src/Shaders/ShadersInclude/helperFunctions.fx

@@ -43,6 +43,11 @@ mat3 inverseMat3(mat3 inMatrix) {
               b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
 }
 
+float toLinearSpace(float color)
+{
+    return pow(color, LinearEncodePowerApprox);
+}
+
 vec3 toLinearSpace(vec3 color)
 {
     return pow(color, vec3(LinearEncodePowerApprox));

+ 14 - 11
src/Shaders/gpuRenderParticles.vertex.fx

@@ -28,8 +28,9 @@ in vec2 uv;
 
 out vec2 vUV;
 out vec4 vColor;
+out vec3 vPositionW;
 
-#if defined(CLIPPLANE) || defined(CLIPPLANE2) || defined(CLIPPLANE3) || defined(CLIPPLANE4) || defined(CLIPPLANE5) || defined(CLIPPLANE6)
+#if defined(BILLBOARD) && !defined(BILLBOARDY) && !defined(BILLBOARDSTRETCHED)
 uniform mat4 invView;
 #endif
 
@@ -99,7 +100,7 @@ void main() {
 		vec2 uvOffset = vec2(uv.x , 1.0 - uv.y);
 		vUV = (uvOffset + vec2(columnOffset, rowOffset)) * uvScale;
 	#else
-   	vUV = uv;
+   	    vUV = uv;
 	#endif
   float ratio = age / life;
 #ifdef COLORGRADIENTS
@@ -121,18 +122,18 @@ void main() {
 
 		vec3 yaxis = (position + worldOffset) - eyePosition;
 		yaxis.y = 0.;
-		vec3 worldPos = rotate(normalize(yaxis), rotatedCorner.xyz);
+		vPositionW = rotate(normalize(yaxis), rotatedCorner.xyz);
 
-		vec4 viewPosition = (view * vec4(worldPos, 1.0));
+		vec4 viewPosition = (view * vec4(vPositionW, 1.0));
 	#elif defined(BILLBOARDSTRETCHED)
 		rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
 		rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 		rotatedCorner.z = 0.;
 
 		vec3 toCamera = (position + worldOffset) - eyePosition;
-		vec3 worldPos = rotateAlign(toCamera, rotatedCorner.xyz);
+		vPositionW = rotateAlign(toCamera, rotatedCorner.xyz);
 
-		vec4 viewPosition = (view * vec4(worldPos, 1.0));
+		vec4 viewPosition = (view * vec4(vPositionW, 1.0));
 	#else
 		// Rotate
 		rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
@@ -145,26 +146,28 @@ void main() {
 		#else
 			vec4 viewPosition = view * vec4((position + worldOffset), 1.0) + rotatedCorner;
 		#endif
+
+        vPositionW = (invView * viewPosition).xyz;
 	#endif
 
 #else
-  // Rotate
+    // Rotate
 	vec3 rotatedCorner;
 	rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
 	rotatedCorner.y = 0.;
 	rotatedCorner.z = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 
 	vec3 yaxis = normalize(initialDirection);
-	vec3 worldPos = rotate(yaxis, rotatedCorner);
+	vPositionW = rotate(yaxis, rotatedCorner);
 
-  // Expand position
-  vec4 viewPosition = view * vec4(worldPos, 1.0);
+    // Expand position
+    vec4 viewPosition = view * vec4(vPositionW, 1.0);
 #endif
 	gl_Position = projection * viewPosition;
 
 	// Clip plane
 #if defined(CLIPPLANE) || defined(CLIPPLANE2) || defined(CLIPPLANE3) || defined(CLIPPLANE4) || defined(CLIPPLANE5) || defined(CLIPPLANE6)
-	vec4 worldPos = invView * viewPosition;
+    vec4 worldPos = vec4(vPositionW, 1.0);
 #endif
 	#include<clipPlaneVertex>
 }

+ 11 - 8
src/Shaders/particles.vertex.fx

@@ -29,12 +29,13 @@ uniform vec3 particlesInfos; // x (number of rows) y(number of columns) z(rowSiz
 // Output
 varying vec2 vUV;
 varying vec4 vColor;
+varying vec3 vPositionW;
 
 #ifdef RAMPGRADIENT
 varying vec4 remapRanges;
 #endif
 
-#if defined(CLIPPLANE) || defined(CLIPPLANE2) || defined(CLIPPLANE3) || defined(CLIPPLANE4) || defined(CLIPPLANE5) || defined(CLIPPLANE6)
+#if defined(BILLBOARD) && !defined(BILLBOARDY) && !defined(BILLBOARDSTRETCHED)
 uniform mat4 invView;
 #endif
 #include<clipPlaneVertexDeclaration>
@@ -91,24 +92,26 @@ void main(void) {
 	vec3 yaxis = position - eyePosition;
 	yaxis.y = 0.;
 
-	vec3 worldPos = rotate(normalize(yaxis), rotatedCorner);
+	vPositionW = rotate(normalize(yaxis), rotatedCorner);
 
-	vec3 viewPos = (view * vec4(worldPos, 1.0)).xyz;
+	vec3 viewPos = (view * vec4(vPositionW, 1.0)).xyz;
 #elif defined(BILLBOARDSTRETCHED)
 	rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
 	rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 	rotatedCorner.z = 0.;
 
 	vec3 toCamera = position - eyePosition;
-	vec3 worldPos = rotateAlign(toCamera, rotatedCorner);
+	vPositionW = rotateAlign(toCamera, rotatedCorner);
 
-	vec3 viewPos = (view * vec4(worldPos, 1.0)).xyz;
+	vec3 viewPos = (view * vec4(vPositionW, 1.0)).xyz;
 #else
 	rotatedCorner.x = cornerPos.x * cos(angle) - cornerPos.y * sin(angle);
 	rotatedCorner.y = cornerPos.x * sin(angle) + cornerPos.y * cos(angle);
 	rotatedCorner.z = 0.;
 
 	vec3 viewPos = (view * vec4(position, 1.0)).xyz + rotatedCorner;
+
+    vPositionW = (invView * vec4(viewPos, 1)).xyz;
 #endif
 
 #ifdef RAMPGRADIENT
@@ -125,9 +128,9 @@ void main(void) {
 	rotatedCorner.y = 0.;
 
 	vec3 yaxis = normalize(direction);
-	vec3 worldPos = rotate(yaxis, rotatedCorner);
+	vPositionW = rotate(yaxis, rotatedCorner);
 
-	gl_Position = projection * view * vec4(worldPos, 1.0);
+	gl_Position = projection * view * vec4(vPositionW, 1.0);
 #endif
 	vColor = color;
 
@@ -144,7 +147,7 @@ void main(void) {
 
 	// Clip plane
 #if defined(CLIPPLANE) || defined(CLIPPLANE2) || defined(CLIPPLANE3) || defined(CLIPPLANE4) || defined(CLIPPLANE5) || defined(CLIPPLANE6)
-	vec4 worldPos = invView * vec4(viewPos, 1.0);
+    vec4 worldPos = vec4(vPositionW, 1.0);
 #endif
 	#include<clipPlaneVertex>
 

+ 2 - 0
src/XR/webXREnterExitUI.ts

@@ -170,6 +170,8 @@ export class WebXREnterExitUI implements IDisposable {
                             }
                         }
                     };
+                } else {
+                    Tools.Warn(`Session mode "${ui._buttons[i].sessionMode}" not supported in browser`);
                 }
             });
             return ui;

+ 1 - 6
src/XR/webXRExperienceHelper.ts

@@ -108,12 +108,7 @@ export class WebXRExperienceHelper implements IDisposable {
             Logger.Warn("We recommend using 'unbounded' reference space type when using 'immersive-ar' session mode");
         }
         // make sure that the session mode is supported
-        return this.sessionManager.isSessionSupportedAsync(sessionMode).then((supported) => {
-            if (!supported) {
-                throw new Error(`Session mode "${sessionMode}" not supported in browser`);
-            }
-            return this.sessionManager.initializeSessionAsync(sessionMode, sessionCreationOptions);
-        }).then(() => {
+        return this.sessionManager.initializeSessionAsync(sessionMode, sessionCreationOptions).then(() => {
             return this.sessionManager.setReferenceSpaceTypeAsync(referenceSpaceType);
         }).then(() => {
             return renderTarget.initializeXRLayerAsync(this.sessionManager.session);

二進制
tests/validation/ReferenceImages/node-material-pbr-1.png


+ 5 - 0
tests/validation/config.json

@@ -67,6 +67,11 @@
             "referenceImage": "node-material6.png"
         },    
         {
+            "title": "Node material PBR 1",
+            "playgroundId": "#D8AK3Z#6",
+            "referenceImage": "node-material-pbr-1.png"
+        },    
+        {
             "title": "Basis loader",
             "playgroundId": "#4RN0VF#0",
             "referenceImage": "basis.png"