Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into bug-fix-preview-popout

Kyle Belfort 5 years ago
parent
commit
c6ce6b241b
29 changed files with 463 additions and 96 deletions
  1. 19 1
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 99 50
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 38 2
      dist/preview release/babylon.module.d.ts
  6. 19 1
      dist/preview release/documentation.d.ts
  7. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  8. 3 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  10. 2 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  11. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  12. 51 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  13. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  14. 5 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  15. 38 2
      dist/preview release/viewer/babylon.module.d.ts
  16. 11 11
      dist/preview release/viewer/babylon.viewer.js
  17. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  18. 2 1
      dist/preview release/what's new.md
  19. 1 1
      inspector/src/components/actionTabs/lines/checkBoxLineComponent.tsx
  20. 4 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx
  21. 84 0
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  22. 16 4
      src/Cameras/XR/features/WebXRPlaneDetector.ts
  23. 7 1
      src/Cameras/XR/webXRCamera.ts
  24. 11 0
      src/Cameras/XR/webXRDefaultExperience.ts
  25. 23 8
      src/Cameras/XR/webXRExperienceHelper.ts
  26. 5 4
      src/Cameras/XR/webXRSessionManager.ts
  27. 11 0
      src/Materials/Node/Blocks/Vertex/instancesBlock.ts
  28. BIN
      tests/validation/ReferenceImages/node-material0.png
  29. 7 1
      tests/validation/config.json

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

@@ -42583,7 +42583,7 @@ declare module BABYLON {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -42620,6 +42620,11 @@ declare module BABYLON {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -44501,6 +44506,12 @@ declare module BABYLON {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -45091,6 +45102,8 @@ declare module BABYLON {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -45149,6 +45162,7 @@ declare module BABYLON {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -58186,6 +58200,10 @@ declare module BABYLON {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;

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


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


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


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

@@ -44065,7 +44065,7 @@ declare module "babylonjs/Cameras/XR/webXRSessionManager" {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -44106,6 +44106,11 @@ declare module "babylonjs/Cameras/XR/webXRCamera" {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -46063,6 +46068,12 @@ declare module "babylonjs/Cameras/XR/webXRDefaultExperience" {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -46692,6 +46703,8 @@ declare module "babylonjs/Cameras/XR/features/WebXRPlaneDetector" {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -46750,6 +46763,7 @@ declare module "babylonjs/Cameras/XR/features/WebXRPlaneDetector" {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -60934,6 +60948,10 @@ declare module "babylonjs/Materials/Node/Blocks/Vertex/instancesBlock" {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
@@ -115081,7 +115099,7 @@ declare module BABYLON {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -115118,6 +115136,11 @@ declare module BABYLON {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -116999,6 +117022,12 @@ declare module BABYLON {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -117589,6 +117618,8 @@ declare module BABYLON {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -117647,6 +117678,7 @@ declare module BABYLON {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -130684,6 +130716,10 @@ declare module BABYLON {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;

+ 19 - 1
dist/preview release/documentation.d.ts

@@ -42583,7 +42583,7 @@ declare module BABYLON {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -42620,6 +42620,11 @@ declare module BABYLON {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -44501,6 +44506,12 @@ declare module BABYLON {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -45091,6 +45102,8 @@ declare module BABYLON {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -45149,6 +45162,7 @@ declare module BABYLON {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -58186,6 +58200,10 @@ declare module BABYLON {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;

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


+ 3 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -40881,7 +40881,7 @@ var CheckBoxLineComponent = /** @class */ (function (_super) {
             currentState = nextProps.isSelected();
         }
         else {
-            currentState = nextProps.target[nextProps.propertyName] === true;
+            currentState = nextProps.target[nextProps.propertyName] == true;
         }
         if (currentState !== nextState.isSelected || this._localChange) {
             nextState.isSelected = currentState;
@@ -46155,6 +46155,8 @@ var TexturePropertyGridComponent = /** @class */ (function (_super) {
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Is 2D array", value: texture.is2DArray ? "Yes" : "No" }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Is cube", value: texture.isCube ? "Yes" : "No" }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Is render target", value: texture.isRenderTarget ? "Yes" : "No" }),
+                (texture instanceof babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_2__["Texture"]) &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Stored as inverted on Y", value: texture.invertY ? "Yes" : "No" }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_5__["TextLineComponent"], { label: "Has mipmaps", value: !texture.noMipmap ? "Yes" : "No" }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_4__["SliderLineComponent"], { label: "UV set", target: texture, propertyName: "coordinatesIndex", minimum: 0, maximum: 3, step: 1, onPropertyChangedObservable: this.props.onPropertyChangedObservable, decimalCount: 0 }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_9__["OptionsLineComponent"], { label: "Mode", options: coordinatesMode, target: texture, propertyName: "coordinatesMode", onPropertyChangedObservable: this.props.onPropertyChangedObservable, onSelect: function (value) { return texture.updateSamplingMode(value); } }),

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


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

@@ -1140,6 +1140,8 @@ declare module NODEEDITOR {
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
+        processInputBlockUpdate(ib: BABYLON.InputBlock): void;
+        renderInputBlock(block: BABYLON.InputBlock): JSX.Element | null;
         load(file: File): void;
         save(): void;
         customSave(): void;

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


+ 51 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js

@@ -52727,6 +52727,19 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _diagram_graphFrame__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../diagram/graphFrame */ "./diagram/graphFrame.ts");
 /* harmony import */ var _sharedComponents_textLineComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../sharedComponents/textLineComponent */ "./sharedComponents/textLineComponent.tsx");
 /* harmony import */ var _diagram_properties_framePropertyComponent__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../../diagram/properties/framePropertyComponent */ "./diagram/properties/framePropertyComponent.tsx");
+/* harmony import */ var _sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../../sharedComponents/color3LineComponent */ "./sharedComponents/color3LineComponent.tsx");
+/* harmony import */ var _sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../../sharedComponents/floatLineComponent */ "./sharedComponents/floatLineComponent.tsx");
+/* harmony import */ var _sharedComponents_color4LineComponent__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../../sharedComponents/color4LineComponent */ "./sharedComponents/color4LineComponent.tsx");
+/* harmony import */ var _sharedComponents_vector2LineComponent__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../../sharedComponents/vector2LineComponent */ "./sharedComponents/vector2LineComponent.tsx");
+/* harmony import */ var _sharedComponents_vector3LineComponent__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../../sharedComponents/vector3LineComponent */ "./sharedComponents/vector3LineComponent.tsx");
+/* harmony import */ var _sharedComponents_vector4LineComponent__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ../../sharedComponents/vector4LineComponent */ "./sharedComponents/vector4LineComponent.tsx");
+
+
+
+
+
+
+
 
 
 
@@ -52765,6 +52778,37 @@ var PropertyTabComponent = /** @class */ (function (_super) {
             }
         });
     };
+    PropertyTabComponent.prototype.processInputBlockUpdate = function (ib) {
+        this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+        if (ib.isConstant) {
+            this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+        }
+    };
+    PropertyTabComponent.prototype.renderInputBlock = function (block) {
+        var _this = this;
+        switch (block.type) {
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Float:
+                var cantDisplaySlider = (isNaN(block.min) || isNaN(block.max) || block.min === block.max);
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { key: block.name },
+                    block.isBoolean &&
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_8__["CheckBoxLineComponent"], { key: block.name, label: block.name, target: block, propertyName: "value", onValueChanged: function () { return _this.processInputBlockUpdate(block); } }),
+                    !block.isBoolean && cantDisplaySlider &&
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_floatLineComponent__WEBPACK_IMPORTED_MODULE_16__["FloatLineComponent"], { key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }),
+                    !block.isBoolean && !cantDisplaySlider &&
+                        react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_sliderLineComponent__WEBPACK_IMPORTED_MODULE_11__["SliderLineComponent"], { key: block.name, label: block.name, target: block, propertyName: "value", step: (block.max - block.min) / 100.0, minimum: block.min, maximum: block.max, onChange: function () { return _this.processInputBlockUpdate(block); } })));
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Color3:
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_color3LineComponent__WEBPACK_IMPORTED_MODULE_15__["Color3LineComponent"], { globalState: this.props.globalState, key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }));
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Color4:
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_color4LineComponent__WEBPACK_IMPORTED_MODULE_17__["Color4LineComponent"], { globalState: this.props.globalState, key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }));
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Vector2:
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_vector2LineComponent__WEBPACK_IMPORTED_MODULE_18__["Vector2LineComponent"], { globalState: this.props.globalState, key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }));
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Vector3:
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_vector3LineComponent__WEBPACK_IMPORTED_MODULE_19__["Vector3LineComponent"], { globalState: this.props.globalState, key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }));
+            case babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["NodeMaterialBlockConnectionPointTypes"].Vector4:
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_vector4LineComponent__WEBPACK_IMPORTED_MODULE_20__["Vector4LineComponent"], { globalState: this.props.globalState, key: block.name, label: block.name, target: block, propertyName: "value", onChange: function () { return _this.processInputBlockUpdate(block); } }));
+        }
+        return null;
+    };
     PropertyTabComponent.prototype.load = function (file) {
         var _this = this;
         babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_6__["Tools"].ReadFile(file, function (data) {
@@ -52844,7 +52888,13 @@ var PropertyTabComponent = /** @class */ (function (_super) {
                         } }),
                     react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_buttonLineComponent__WEBPACK_IMPORTED_MODULE_2__["ButtonLineComponent"], { label: "Export shaders", onClick: function () {
                             _stringTools__WEBPACK_IMPORTED_MODULE_4__["StringTools"].DownloadAsFile(_this.props.globalState.hostDocument, _this.props.globalState.nodeMaterial.compiledShaders, "shaders.txt");
-                        } })))));
+                        } })),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sharedComponents_lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__["LineContainerComponent"], { title: "INPUTS" }, this.props.globalState.nodeMaterial.getInputBlocks().map(function (ib) {
+                    if (!ib.isUniform) {
+                        return null;
+                    }
+                    return _this.renderInputBlock(ib);
+                })))));
     };
     return PropertyTabComponent;
 }(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));

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


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

@@ -1379,6 +1379,7 @@ declare module "babylonjs-node-editor/components/propertyTab/propertyTabComponen
     import { Nullable } from 'babylonjs/types';
     import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
     import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
+    import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
     interface IPropertyTabComponentProps {
         globalState: GlobalState;
     }
@@ -1388,6 +1389,8 @@ declare module "babylonjs-node-editor/components/propertyTab/propertyTabComponen
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
+        processInputBlockUpdate(ib: InputBlock): void;
+        renderInputBlock(block: InputBlock): JSX.Element | null;
         load(file: File): void;
         save(): void;
         customSave(): void;
@@ -2735,6 +2738,8 @@ declare module NODEEDITOR {
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
+        processInputBlockUpdate(ib: BABYLON.InputBlock): void;
+        renderInputBlock(block: BABYLON.InputBlock): JSX.Element | null;
         load(file: File): void;
         save(): void;
         customSave(): void;

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

@@ -44065,7 +44065,7 @@ declare module "babylonjs/Cameras/XR/webXRSessionManager" {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -44106,6 +44106,11 @@ declare module "babylonjs/Cameras/XR/webXRCamera" {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -46063,6 +46068,12 @@ declare module "babylonjs/Cameras/XR/webXRDefaultExperience" {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -46692,6 +46703,8 @@ declare module "babylonjs/Cameras/XR/features/WebXRPlaneDetector" {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -46750,6 +46763,7 @@ declare module "babylonjs/Cameras/XR/features/WebXRPlaneDetector" {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -60934,6 +60948,10 @@ declare module "babylonjs/Materials/Node/Blocks/Vertex/instancesBlock" {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
@@ -115081,7 +115099,7 @@ declare module BABYLON {
         /**
          * Checks if a session would be supported for the creation options specified
          * @param sessionMode session mode to check if supported eg. immersive-vr
-         * @returns true if supported
+         * @returns A Promise that resolves to true if supported and false if not
          */
         isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean>;
         /**
@@ -115118,6 +115136,11 @@ declare module BABYLON {
      */
     export class WebXRCamera extends FreeCamera {
         private _xrSessionManager;
+        /**
+         * Should position compensation execute on first frame.
+         * This is used when copying the position from a native (non XR) camera
+         */
+        compensateOnFirstFrame: boolean;
         private _firstFrame;
         private _referencedPosition;
         private _referenceQuaternion;
@@ -116999,6 +117022,12 @@ declare module BABYLON {
          * Should teleportation not initialize. defaults to false.
          */
         disableTeleportation?: boolean;
+        /**
+         * If set to true, the first frame will not be used to reset position
+         * The first frame is mainly used when copying transformation from the old camera
+         * Mainly used in AR
+         */
+        ignoreNativeCameraTransformation?: boolean;
     }
     /**
      * Default experience which provides a similar setup to the previous webVRExperience
@@ -117589,6 +117618,8 @@ declare module BABYLON {
     /**
      * A babylon interface for a webxr plane.
      * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
      */
     export interface IWebXRPlane {
         /**
@@ -117647,6 +117678,7 @@ declare module BABYLON {
          * @param _options configuration to use when constructing this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        private _init;
         protected _onXRFrame(frame: XRFrame): void;
         /**
          * Dispose this feature and all of the resources attached
@@ -130684,6 +130716,10 @@ declare module BABYLON {
          * Gets the output component
          */
         get output(): NodeMaterialConnectionPoint;
+        /**
+         * Gets the isntanceID component
+         */
+        get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
         prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;

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


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


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

@@ -199,7 +199,7 @@
 - Teleportation and controller selection are now WebXR features. ([#7290](https://github.com/BabylonJS/Babylon.js/issues/7290)) ([RaananW](https://github.com/RaananW/))
 - Teleportation allows selecting direction before teleporting when using thumbstick or touchpad. ([#7290](https://github.com/BabylonJS/Babylon.js/issues/7290)) ([RaananW](https://github.com/RaananW/))
 - It is now possible to force a certain profile type for the controllers ([#7348](https://github.com/BabylonJS/Babylon.js/issues/7375)) ([RaananW](https://github.com/RaananW/))
-- WebXR camera is initialized on the first frame ([#7389](https://github.com/BabylonJS/Babylon.js/issues/7389)) ([RaananW](https://github.com/RaananW/))
+- WebXR camera is initialized on the first frame, including copying transformation from native camera (except for in AR) ([#7389](https://github.com/BabylonJS/Babylon.js/issues/7389)) ([RaananW](https://github.com/RaananW/))
 - Selection has gaze mode (which can be forced) and touch-screen support ([#7395](https://github.com/BabylonJS/Babylon.js/issues/7395)) ([RaananW](https://github.com/RaananW/))
 - Laser pointers can be excluded from lighting influence so that they are always visible in both WebXR and WebVR ([#7323](https://github.com/BabylonJS/Babylon.js/issues/7323)) ([RaananW](https://github.com/RaananW/))
 
@@ -302,6 +302,7 @@
 - Fixed an issue with teleportation detach and attach ([#7419](https://github.com/BabylonJS/Babylon.js/issues/7419)) ([RaananW](https://github.com/RaananW/))
 - Physics compound calculations were incorrect ([#7407](https://github.com/BabylonJS/Babylon.js/issues/7407)) ([RaananW](https://github.com/RaananW/))
 - Fix bug NME bug where preview area crashes on pop up when NME is opened from playground ([Kyle Belfort](https://github.com/belfortk))
+- Fixed an issue with isSessionSupported return value being ignored ([#7501](https://github.com/BabylonJS/Babylon.js/issues/7501)) ([RaananW](https://github.com/RaananW/))
 
 ## Breaking changes
 

+ 1 - 1
inspector/src/components/actionTabs/lines/checkBoxLineComponent.tsx

@@ -34,7 +34,7 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
         if (this.props.isSelected) {
             currentState = nextProps.isSelected!();
         } else {
-            currentState = nextProps.target[nextProps.propertyName!] === true;
+            currentState = nextProps.target[nextProps.propertyName!] == true;
         }
 
         if (currentState !== nextState.isSelected || this._localChange) {

+ 4 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/texturePropertyGridComponent.tsx

@@ -172,6 +172,10 @@ export class TexturePropertyGridComponent extends React.Component<ITextureProper
                     <TextLineComponent label="Is 2D array" value={texture.is2DArray ? "Yes" : "No"} />
                     <TextLineComponent label="Is cube" value={texture.isCube ? "Yes" : "No"} />
                     <TextLineComponent label="Is render target" value={texture.isRenderTarget ? "Yes" : "No"} />
+                    {
+                        (texture instanceof Texture) && 
+                        <TextLineComponent label="Stored as inverted on Y" value={texture.invertY ? "Yes" : "No"} />
+                    }
                     <TextLineComponent label="Has mipmaps" value={!texture.noMipmap ? "Yes" : "No"} />
                     <SliderLineComponent label="UV set" target={texture} propertyName="coordinatesIndex" minimum={0} maximum={3} step={1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} decimalCount={0} />
                     <OptionsLineComponent label="Mode" options={coordinatesMode} target={texture} propertyName="coordinatesMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} onSelect={(value) => texture.updateSamplingMode(value)} />

+ 84 - 0
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -16,6 +16,14 @@ import { GraphFrame } from '../../diagram/graphFrame';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
+import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
+import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
+import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
+import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
+import { Color4LineComponent } from '../../sharedComponents/color4LineComponent';
+import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponent';
+import { Vector3LineComponent } from '../../sharedComponents/vector3LineComponent';
+import { Vector4LineComponent } from '../../sharedComponents/vector4LineComponent';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
@@ -41,6 +49,72 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
         });
     }
 
+    processInputBlockUpdate(ib: InputBlock) {
+        this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+
+        if (ib.isConstant) {
+            this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+        }
+    }
+
+    renderInputBlock(block: InputBlock) {
+        switch (block.type) {
+            case NodeMaterialBlockConnectionPointTypes.Float:
+                    let cantDisplaySlider = (isNaN(block.min) || isNaN(block.max) || block.min === block.max);
+                    return (
+                        <div key={block.name}>                            
+                            {
+                                block.isBoolean &&
+                                <CheckBoxLineComponent key={block.name} label={block.name} target={block} propertyName="value" 
+                                onValueChanged={() => this.processInputBlockUpdate(block)}/>
+                            }
+                            {
+                                !block.isBoolean && cantDisplaySlider &&
+                                <FloatLineComponent key={block.name} label={block.name} target={block} propertyName="value" 
+                                onChange={() => this.processInputBlockUpdate(block)}/>
+                            }        
+                            {
+                                !block.isBoolean && !cantDisplaySlider &&
+                                <SliderLineComponent key={block.name} label={block.name} target={block} propertyName="value" 
+                                step={(block.max - block.min) / 100.0} minimum={block.min} maximum={block.max}
+                                onChange={() => this.processInputBlockUpdate(block)}/>
+                            }
+                        </div>
+                    );  
+            case NodeMaterialBlockConnectionPointTypes.Color3:
+                return (
+                    <Color3LineComponent globalState={this.props.globalState} key={block.name} label={block.name} target={block} 
+                        propertyName="value" 
+                        onChange={() => this.processInputBlockUpdate(block)}
+                    />
+                )     
+            case NodeMaterialBlockConnectionPointTypes.Color4:
+                return (
+                    <Color4LineComponent globalState={this.props.globalState} key={block.name} label={block.name} target={block} propertyName="value" 
+                    onChange={() => this.processInputBlockUpdate(block)}/>
+                )                         
+            case NodeMaterialBlockConnectionPointTypes.Vector2:
+                return (
+                        <Vector2LineComponent globalState={this.props.globalState} key={block.name} label={block.name} target={block} 
+                        propertyName="value" 
+                        onChange={() => this.processInputBlockUpdate(block)}/>
+                    )                                
+            case NodeMaterialBlockConnectionPointTypes.Vector3:
+                return (
+                    <Vector3LineComponent globalState={this.props.globalState} key={block.name} label={block.name} target={block} 
+                    propertyName="value" 
+                    onChange={() => this.processInputBlockUpdate(block)}/>
+                )
+            case NodeMaterialBlockConnectionPointTypes.Vector4:
+                return (
+                    <Vector4LineComponent globalState={this.props.globalState} key={block.name} label={block.name} target={block} 
+                    propertyName="value" 
+                    onChange={() => this.processInputBlockUpdate(block)}/>
+                )
+            }
+        return null;
+    }
+
     load(file: File) {
         Tools.ReadFile(file, (data) => {
             let decoder = new TextDecoder("utf-8");
@@ -152,6 +226,16 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                         <ButtonLineComponent label="Export shaders" onClick={() => {
                             StringTools.DownloadAsFile(this.props.globalState.hostDocument, this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");
                         }} />
+                    </LineContainerComponent>                    
+                    <LineContainerComponent title="INPUTS">   
+                    {
+                        this.props.globalState.nodeMaterial.getInputBlocks().map(ib => {
+                            if (!ib.isUniform) {
+                                return null;
+                            }
+                            return this.renderInputBlock(ib);
+                        })
+                    }
                     </LineContainerComponent>
                 </div>
             </div>

+ 16 - 4
src/Cameras/XR/features/WebXRPlaneDetector.ts

@@ -18,6 +18,8 @@ export interface IWebXRPlaneDetectorOptions {
 /**
  * A babylon interface for a webxr plane.
  * A Plane is actually a polygon, built from N points in space
+ *
+ * Supported in chrome 79, not supported in canary 81 ATM
  */
 export interface IWebXRPlane {
     /**
@@ -84,16 +86,26 @@ export class WebXRPlaneDetector extends WebXRAbstractFeature {
     constructor(_xrSessionManager: WebXRSessionManager, private _options: IWebXRPlaneDetectorOptions = {}) {
         super(_xrSessionManager);
         if (this._xrSessionManager.session) {
-            this._xrSessionManager.session.updateWorldTrackingState({ planeDetectionState: { enabled: true } });
-            this._enabled = true;
+            this._init();
         } else {
             this._xrSessionManager.onXRSessionInit.addOnce(() => {
-                this._xrSessionManager.session.updateWorldTrackingState({ planeDetectionState: { enabled: true } });
-                this._enabled = true;
+                this._init();
             });
         }
     }
 
+    private _init() {
+        if (!this._xrSessionManager.session.updateWorldTrackingState) {
+            // fail silently
+            return;
+        }
+        this._xrSessionManager.session.updateWorldTrackingState({ planeDetectionState: { enabled: true } });
+        this._enabled = true;
+        if (this._detectedPlanes.length) {
+            this._detectedPlanes = [];
+        }
+    }
+
     protected _onXRFrame(frame: XRFrame) {
         if (!this.attached || !this._enabled || !frame) { return; }
         // const timestamp = this.xrSessionManager.currentTimestamp;

+ 7 - 1
src/Cameras/XR/webXRCamera.ts

@@ -12,6 +12,12 @@ import { Viewport } from '../../Maths/math.viewport';
  */
 export class WebXRCamera extends FreeCamera {
 
+    /**
+     * Should position compensation execute on first frame.
+     * This is used when copying the position from a native (non XR) camera
+     */
+    public compensateOnFirstFrame: boolean = true;
+
     private _firstFrame = false;
     private _referencedPosition: Vector3 = new Vector3();
     private _referenceQuaternion: Quaternion = Quaternion.Identity();
@@ -37,7 +43,7 @@ export class WebXRCamera extends FreeCamera {
             this._referencedPosition.copyFromFloats(0, 0, 0);
             this._referenceQuaternion.copyFromFloats(0, 0, 0, 1);
             // first frame - camera's y position should be 0 for the correct offset
-            this._firstFrame = true;
+            this._firstFrame = this.compensateOnFirstFrame;
 
         });
 

+ 11 - 0
src/Cameras/XR/webXRDefaultExperience.ts

@@ -42,6 +42,13 @@ export class WebXRDefaultExperienceOptions {
      * Should teleportation not initialize. defaults to false.
      */
     public disableTeleportation?: boolean;
+
+    /**
+     * If set to true, the first frame will not be used to reset position
+     * The first frame is mainly used when copying transformation from the old camera
+     * Mainly used in AR
+     */
+    public ignoreNativeCameraTransformation?: boolean;
 }
 
 /**
@@ -86,6 +93,10 @@ export class WebXRDefaultExperience {
         return WebXRExperienceHelper.CreateAsync(scene).then((xrHelper) => {
             result.baseExperience = xrHelper;
 
+            if (options.ignoreNativeCameraTransformation) {
+                result.baseExperience.camera.compensateOnFirstFrame = false;
+            }
+
             // Add controller support
             result.input = new WebXRInput(xrHelper.sessionManager, xrHelper.camera, options.inputOptions);
             result.pointerSelection = <WebXRControllerPointerSelection>result.baseExperience.featuresManager.enableFeature(WebXRControllerPointerSelection.Name, "latest", {

+ 23 - 8
src/Cameras/XR/webXRExperienceHelper.ts

@@ -6,6 +6,7 @@ import { WebXRSessionManager } from "./webXRSessionManager";
 import { WebXRCamera } from "./webXRCamera";
 import { WebXRState, WebXRRenderTarget } from './webXRTypes';
 import { WebXRFeaturesManager } from './webXRFeaturesManager';
+import { Logger } from '../../Misc/logger';
 
 /**
  * Base set of functionality needed to create an XR experince (WebXRSessionManager, Camera, StateManagement, etc.)
@@ -104,14 +105,21 @@ export class WebXRExperienceHelper implements IDisposable {
      */
     public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget = this.sessionManager.getWebXRRenderTarget()): Promise<WebXRSessionManager> {
         if (!this._supported) {
-            throw "XR not available";
+            throw "WebXR not supported";
         }
         this._setState(WebXRState.ENTERING_XR);
         let sessionCreationOptions: XRSessionInit = {
             optionalFeatures: (referenceSpaceType !== "viewer" && referenceSpaceType !== "local") ? [referenceSpaceType] : []
         };
+        // we currently recommend "local" space in AR
+        if (sessionMode === "immersive-ar" && referenceSpaceType !== "local") {
+            Logger.Warn("We recommend using 'local' reference space type when using 'immersive-ar' session mode");
+        }
         // make sure that the session mode is supported
-        return this.sessionManager.isSessionSupportedAsync(sessionMode).then(() => {
+        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.setReferenceSpaceTypeAsync(referenceSpaceType);
@@ -129,7 +137,13 @@ export class WebXRExperienceHelper implements IDisposable {
             // Overwrite current scene settings
             this.scene.autoClear = false;
 
-            this._nonXRToXRCamera();
+            this.scene.activeCamera = this.camera;
+            // do not compensate when AR session is used
+            if (sessionMode !== 'immersive-ar') {
+                this._nonXRToXRCamera();
+            } else {
+                this.camera.compensateOnFirstFrame = false;
+            }
 
             this.sessionManager.onXRSessionEnded.addOnce(() => {
                 // Reset camera rigs output render target to ensure sessions render target is not drawn after it ends
@@ -140,10 +154,12 @@ export class WebXRExperienceHelper implements IDisposable {
                 // Restore scene settings
                 this.scene.autoClear = this._originalSceneAutoClear;
                 this.scene.activeCamera = this._nonVRCamera;
-                if ((<any>this._nonVRCamera).setPosition) {
-                    (<any>this._nonVRCamera).setPosition(this.camera.position);
-                } else {
-                    this._nonVRCamera!.position.copyFrom(this.camera.position);
+                if (sessionMode !== 'immersive-ar' && this.camera.compensateOnFirstFrame) {
+                    if ((<any>this._nonVRCamera).setPosition) {
+                        (<any>this._nonVRCamera).setPosition(this.camera.position);
+                    } else {
+                        this._nonVRCamera!.position.copyFrom(this.camera.position);
+                    }
                 }
 
                 this._setState(WebXRState.NOT_IN_XR);
@@ -177,7 +193,6 @@ export class WebXRExperienceHelper implements IDisposable {
     }
 
     private _nonXRToXRCamera() {
-        this.scene.activeCamera = this.camera;
         this.camera.setTransformationFromNonVRCamera(this._nonVRCamera!);
         this.onInitialXRPoseSetObservable.notifyObservers(this.camera);
     }

+ 5 - 4
src/Cameras/XR/webXRSessionManager.ts

@@ -268,9 +268,9 @@ export class WebXRSessionManager implements IDisposable {
     /**
      * Checks if a session would be supported for the creation options specified
      * @param sessionMode session mode to check if supported eg. immersive-vr
-     * @returns true if supported
+     * @returns A Promise that resolves to true if supported and false if not
      */
-    public isSessionSupportedAsync(sessionMode: XRSessionMode) {
+    public isSessionSupportedAsync(sessionMode: XRSessionMode): Promise<boolean> {
         return WebXRSessionManager.IsSessionSupportedAsync(sessionMode);
     }
 
@@ -344,8 +344,9 @@ export class WebXRSessionManager implements IDisposable {
         if (!functionToUse) {
             return Promise.resolve(false);
         } else {
-            return functionToUse.call((navigator as any).xr, sessionMode).then(() => {
-                return Promise.resolve(true);
+            return functionToUse.call((navigator as any).xr, sessionMode).then((result: boolean) => {
+                const returnValue = (typeof result === "undefined") ? true : result;
+                return Promise.resolve(returnValue);
             }).catch((e: any) => {
                 Logger.Warn(e);
                 return Promise.resolve(false);

+ 11 - 0
src/Materials/Node/Blocks/Vertex/instancesBlock.ts

@@ -28,6 +28,7 @@ export class InstancesBlock extends NodeMaterialBlock {
         this.registerInput("world", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Matrix);
+        this.registerOutput("instanceID", NodeMaterialBlockConnectionPointTypes.Float);
     }
 
     /**
@@ -80,6 +81,13 @@ export class InstancesBlock extends NodeMaterialBlock {
         return this._outputs[0];
     }
 
+    /**
+     * Gets the isntanceID component
+     */
+    public get instanceID(): NodeMaterialConnectionPoint {
+        return this._outputs[1];
+    }
+
     public autoConfigure(material: NodeMaterial) {
         if (!this.world0.connectedPoint) {
             let world0Input = material.getInputBlockByPredicate((b) => b.isAttribute && b.name === "world0");
@@ -150,6 +158,7 @@ export class InstancesBlock extends NodeMaterialBlock {
 
         // Emit code
         let output = this._outputs[0];
+        let instanceID = this._outputs[1];
         let world0 = this.world0;
         let world1 = this.world1;
         let world2 = this.world2;
@@ -157,8 +166,10 @@ export class InstancesBlock extends NodeMaterialBlock {
 
         state.compilationString += `#ifdef INSTANCES\r\n`;
         state.compilationString += this._declareOutput(output, state) + ` = mat4(${world0.associatedVariableName}, ${world1.associatedVariableName}, ${world2.associatedVariableName}, ${world3.associatedVariableName});\r\n`;
+        state.compilationString += this._declareOutput(instanceID, state) + ` = float(gl_InstanceID);\r\n`;
         state.compilationString += `#else\r\n`;
         state.compilationString += this._declareOutput(output, state) + ` = ${this.world.associatedVariableName};\r\n`;
+        state.compilationString += this._declareOutput(instanceID, state) + ` = 0.0;\r\n`;
         state.compilationString += `#endif\r\n`;
         return this;
     }

BIN
tests/validation/ReferenceImages/node-material0.png


+ 7 - 1
tests/validation/config.json

@@ -5,7 +5,13 @@
             "title": "Black and White post-process",
             "playgroundId": "#N55Q2M#0",
             "referenceImage": "bwpp.png"
-        },       
+        },             
+        {
+            "title": "Node material #0",
+            "playgroundId": "#M5VQE9#13",
+            "referenceImage": "node-material0.png",
+            "renderCount": 200
+        },    
         {
             "title": "Node material #1",
             "playgroundId": "#QJ71C6#0",