Jelajahi Sumber

Merge pull request #9530 from BabylonJS/master

Nightly
mergify[bot] 4 tahun lalu
induk
melakukan
8e85571350
61 mengubah file dengan 3559 tambahan dan 412 penghapusan
  1. 8 1
      Playground/libs/babylon.manager.d.ts
  2. 11 11
      Playground/libs/babylon.manager.js
  3. 2 1
      Playground/src/components/rendererComponent.tsx
  4. 200 2
      dist/preview release/babylon.d.ts
  5. 1 1
      dist/preview release/babylon.js
  6. 531 131
      dist/preview release/babylon.max.js
  7. 1 1
      dist/preview release/babylon.max.js.map
  8. 387 4
      dist/preview release/babylon.module.d.ts
  9. 259 5
      dist/preview release/documentation.d.ts
  10. 59 3
      dist/preview release/gui/babylon.gui.d.ts
  11. 701 115
      dist/preview release/gui/babylon.gui.js
  12. 1 1
      dist/preview release/gui/babylon.gui.js.map
  13. 2 2
      dist/preview release/gui/babylon.gui.min.js
  14. 119 6
      dist/preview release/gui/babylon.gui.module.d.ts
  15. 2 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  17. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  18. 2 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  19. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  20. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  21. 2 1
      dist/preview release/loaders/babylonjs.loaders.js
  22. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  23. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  24. 1 1
      dist/preview release/packagesSizeBaseLine.json
  25. 387 4
      dist/preview release/viewer/babylon.module.d.ts
  26. 21 13
      dist/preview release/viewer/babylon.viewer.js
  27. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  28. 4 0
      dist/preview release/what's new.md
  29. 23 0
      gui/src/2D/advancedDynamicTexture.ts
  30. 5 0
      gui/src/2D/controls/checkbox.ts
  31. 5 0
      gui/src/2D/controls/colorpicker.ts
  32. 38 0
      gui/src/2D/controls/container.ts
  33. 147 3
      gui/src/2D/controls/control.ts
  34. 11 0
      gui/src/2D/controls/displayGrid.ts
  35. 2 0
      gui/src/2D/controls/ellipse.ts
  36. 15 0
      gui/src/2D/controls/image.ts
  37. 18 0
      gui/src/2D/controls/inputText.ts
  38. 7 0
      gui/src/2D/controls/line.ts
  39. 2 0
      gui/src/2D/controls/multiLine.ts
  40. 6 0
      gui/src/2D/controls/radioButton.ts
  41. 3 0
      gui/src/2D/controls/rectangle.ts
  42. 10 0
      gui/src/2D/controls/sliders/baseSlider.ts
  43. 2 0
      gui/src/2D/controls/sliders/imageBasedSlider.ts
  44. 2 0
      gui/src/2D/controls/sliders/imageScrollBar.ts
  45. 3 0
      gui/src/2D/controls/sliders/scrollBar.ts
  46. 6 0
      gui/src/2D/controls/sliders/slider.ts
  47. 25 0
      gui/src/2D/controls/stackPanel.ts
  48. 12 0
      gui/src/2D/controls/textBlock.ts
  49. 2 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts
  50. 24 19
      sandbox/src/components/renderingZone.tsx
  51. 6 0
      sandbox/src/sandbox.tsx
  52. 8 5
      src/Engines/Processors/shaderProcessor.ts
  53. 29 0
      src/Engines/engineFactory.ts
  54. 1 0
      src/Engines/index.ts
  55. 9 2
      src/Engines/thinEngine.ts
  56. 32 4
      src/Engines/webgpuEngine.ts
  57. 21 0
      src/LibDeclarations/webxr.d.ts
  58. 303 0
      src/XR/features/WebXRImageTracking.ts
  59. 1 0
      src/XR/features/index.ts
  60. 52 61
      src/XR/webXRExperienceHelper.ts
  61. 20 4
      src/XR/webXRFeaturesManager.ts

+ 8 - 1
Playground/libs/babylon.manager.d.ts

@@ -194,6 +194,8 @@ declare module BABYLON {
         static RegisterClickAction(scene: BABYLON.Scene, mesh: BABYLON.AbstractMesh, func: () => void): BABYLON.IAction;
         /** Unregisters an on pick trigger click action */
         static UnregisterClickAction(mesh: BABYLON.AbstractMesh, action: BABYLON.IAction): boolean;
+        /** Starts a targeted float animation for tweening.  */
+        static StartTweenAnimation(scene: BABYLON.Scene, name: string, targetObject: any, targetProperty: string, startValue: number, endValue: number, speedRatio?: number, frameRate?: number, loopMode?: number, easingFunction?: BABYLON.EasingFunction, onAnimationComplete?: () => void): BABYLON.Animatable;
         /** Get first material with name. (Uses starts with text searching) */
         static GetMaterialWithName(scene: BABYLON.Scene, name: string): BABYLON.Material;
         /** Get all materials with name. (Uses starts with text searching) */
@@ -207,7 +209,7 @@ declare module BABYLON {
         /** Creates an instance of the specified mesh asset into the scene. (Mesh Instance) */
         static CreateInstancedMesh(container: BABYLON.AssetContainer, meshName: string, instanceName: string): BABYLON.InstancedMesh;
         /** Registers a script componment with the scene manager. */
-        static RegisterScriptComponent(instance: BABYLON.ScriptComponent, klass: string, validate?: boolean): void;
+        static RegisterScriptComponent(instance: BABYLON.ScriptComponent, alias: string, validate?: boolean): void;
         /** Destroys a script component instance. */
         static DestroyScriptComponent(instance: BABYLON.ScriptComponent): void;
         /** Finds a script component on the transform with the specfied class name. */
@@ -1461,6 +1463,10 @@ declare module BABYLON {
         static SampleAnimationQuaternion(animation: BABYLON.Animation, frame: number): BABYLON.Quaternion;
         /** Set the passed matrix "result" as the sampled key frame value for the specfied animation track. */
         static SampleAnimationMatrix(animation: BABYLON.Animation, frame: number): BABYLON.Matrix;
+        /** Creates a targeted float animation for tweening.  */
+        static CreateFloatAnimation(name: string, targetProperty: string, startValue: number, endValue: number, frameRate?: number, loopMode?: number): BABYLON.Animation;
+        /** Gets the last key frame index value. */
+        static GetLastKeyFrameIndex(animation: BABYLON.Animation): number;
         /** Private internal frame interpolation helper */
         private static InterpolateAnimation;
         /** Initialize default shader material properties */
@@ -1931,6 +1937,7 @@ declare module BABYLON {
         animationFirstRun: boolean;
         animationEndFrame: boolean;
         animationLoopFrame: boolean;
+        animationLoopEvents: any;
         animationStateMachine: BABYLON.MachineState;
     }
     interface IAnimationCurve {

File diff ditekan karena terlalu besar
+ 11 - 11
Playground/libs/babylon.manager.js


+ 2 - 1
Playground/src/components/rendererComponent.tsx

@@ -5,6 +5,7 @@ import { Nullable } from "babylonjs/types";
 import { Scene } from "babylonjs/scene";
 import { Utilities } from "../tools/utilities";
 import { DownloadManager } from "../tools/downloadManager";
+import { WebGPUEngine } from "babylonjs";
 
 require("../scss/rendering.scss");
 
@@ -94,7 +95,7 @@ export class RenderingComponent extends React.Component<IRenderingComponentProps
 
         const displayInspector = this._scene?.debugLayer.isVisible();
 
-        const useWebGPU = location.href.indexOf("webgpu") !== -1 ;
+        const useWebGPU = location.href.indexOf("webgpu") !== -1 && WebGPUEngine.IsSupported;
 
         if (this._engine) {
             try {

+ 200 - 2
dist/preview release/babylon.d.ts

@@ -39884,6 +39884,10 @@ declare module BABYLON {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -44760,6 +44764,10 @@ declare module BABYLON {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -44825,6 +44833,11 @@ declare module BABYLON {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -44845,6 +44858,13 @@ declare module BABYLON {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -53517,6 +53537,10 @@ declare module BABYLON {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -53562,6 +53586,10 @@ declare module BABYLON {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -53677,14 +53705,14 @@ declare module BABYLON {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module BABYLON {
@@ -59928,6 +59956,20 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
+declare module BABYLON {
+    /**
      * Gather the list of clipboard event types as constants.
      */
     export class ClipboardEventTypes {
@@ -79784,6 +79826,141 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
+declare module BABYLON {
+    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -81539,6 +81716,7 @@ interface XRLayer extends EventTarget {}
 interface XRSessionInit {
     optionalFeatures?: string[];
     requiredFeatures?: string[];
+    trackedImages?: XRTrackedImageInit[];
 }
 
 interface XRSessionEvent extends Event {
@@ -81638,6 +81816,8 @@ interface XRFrame {
     worldInformation?: XRWorldInformation;
     // Hand tracking
     getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose;
+    // Image tracking
+    getImageTrackingResults?(): Array<XRImageTrackingResult>;
 }
 
 interface XRInputSourceEvent extends Event {
@@ -81709,6 +81889,9 @@ interface XRSession {
 
     // legacy plane detection
     updateWorldTrackingState?(options: { planeDetectionState?: { enabled: boolean } }): void;
+
+    // image tracking
+    getTrackedImageScores?(): XRImageTrackingScore[];
 }
 
 interface XRViewerPose extends XRPose {
@@ -81840,6 +82023,21 @@ interface XRHand extends Iterable<XRJointSpace> {
     readonly LITTLE_PHALANX_DISTAL: number;
     readonly LITTLE_PHALANX_TIP: number;
 }
+
+type XRImageTrackingState = "tracked" | "emulated";
+type XRImageTrackingScore = "untrackable" | "trackable";
+
+interface XRTrackedImageInit {
+    image: ImageBitmap;
+    widthInMeters: number;
+}
+
+interface XRImageTrackingResult {
+    readonly imageSpace: XRSpace;
+    readonly index: number;
+    readonly trackingState: XRImageTrackingState;
+    readonly measuredWidthInMeters: number;
+}
 
 // This file contains native only extensions for WebXR. These APIs are not supported in the browser yet.
 // They are intended for use with either Babylon Native https://github.com/BabylonJS/BabylonNative or

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/babylon.js


File diff ditekan karena terlalu besar
+ 531 - 131
dist/preview release/babylon.max.js


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 387 - 4
dist/preview release/babylon.module.d.ts

@@ -41406,6 +41406,10 @@ declare module "babylonjs/Engines/thinEngine" {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -46396,6 +46400,10 @@ declare module "babylonjs/Engines/webgpuEngine" {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -46461,6 +46469,11 @@ declare module "babylonjs/Engines/webgpuEngine" {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -46481,6 +46494,13 @@ declare module "babylonjs/Engines/webgpuEngine" {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -55600,6 +55620,10 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -55645,6 +55669,10 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -55760,14 +55788,14 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module "babylonjs/XR/webXRExperienceHelper" {
@@ -62464,6 +62492,21 @@ declare module "babylonjs/Engines/nativeEngine" {
         private _getNativeAttribType;
     }
 }
+declare module "babylonjs/Engines/engineFactory" {
+    import { ThinEngine } from "babylonjs/Engines/thinEngine";
+    /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
 declare module "babylonjs/Engines/index" {
     export * from "babylonjs/Engines/constants";
     export * from "babylonjs/Engines/engineCapabilities";
@@ -62482,6 +62525,7 @@ declare module "babylonjs/Engines/index" {
     export * from "babylonjs/Engines/Processors/shaderCodeInliner";
     export * from "babylonjs/Engines/performanceConfigurator";
     export * from "babylonjs/Engines/engineFeatures";
+    export * from "babylonjs/Engines/engineFactory";
 }
 declare module "babylonjs/Events/clipboardEvents" {
     /**
@@ -84140,6 +84184,146 @@ declare module "babylonjs/XR/features/WebXRMeshDetector" {
         private _updateVertexDataWithXRMesh;
     }
 }
+declare module "babylonjs/XR/features/WebXRImageTracking" {
+    import { WebXRSessionManager } from "babylonjs/XR/webXRSessionManager";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { WebXRAbstractFeature } from "babylonjs/XR/features/WebXRAbstractFeature";
+    import { Matrix } from "babylonjs/Maths/math.vector";
+    import { Nullable } from "babylonjs/types";
+    /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
 declare module "babylonjs/XR/features/index" {
     export * from "babylonjs/XR/features/WebXRAbstractFeature";
     export * from "babylonjs/XR/features/WebXRHitTestLegacy";
@@ -84153,6 +84337,7 @@ declare module "babylonjs/XR/features/index" {
     export * from "babylonjs/XR/features/WebXRFeaturePointSystem";
     export * from "babylonjs/XR/features/WebXRHandTracking";
     export * from "babylonjs/XR/features/WebXRMeshDetector";
+    export * from "babylonjs/XR/features/WebXRImageTracking";
 }
 declare module "babylonjs/XR/motionController/webXRMicrosoftMixedRealityController" {
     import { WebXRAbstractMotionController, IMinimalMotionControllerObject, MotionControllerHandedness } from "babylonjs/XR/motionController/webXRAbstractMotionController";
@@ -124381,6 +124566,10 @@ declare module BABYLON {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -129257,6 +129446,10 @@ declare module BABYLON {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -129322,6 +129515,11 @@ declare module BABYLON {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -129342,6 +129540,13 @@ declare module BABYLON {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -138014,6 +138219,10 @@ declare module BABYLON {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -138059,6 +138268,10 @@ declare module BABYLON {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -138174,14 +138387,14 @@ declare module BABYLON {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module BABYLON {
@@ -144425,6 +144638,20 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
+declare module BABYLON {
+    /**
      * Gather the list of clipboard event types as constants.
      */
     export class ClipboardEventTypes {
@@ -164281,6 +164508,141 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
+declare module BABYLON {
+    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -166036,6 +166398,7 @@ interface XRLayer extends EventTarget {}
 interface XRSessionInit {
     optionalFeatures?: string[];
     requiredFeatures?: string[];
+    trackedImages?: XRTrackedImageInit[];
 }
 
 interface XRSessionEvent extends Event {
@@ -166135,6 +166498,8 @@ interface XRFrame {
     worldInformation?: XRWorldInformation;
     // Hand tracking
     getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose;
+    // Image tracking
+    getImageTrackingResults?(): Array<XRImageTrackingResult>;
 }
 
 interface XRInputSourceEvent extends Event {
@@ -166206,6 +166571,9 @@ interface XRSession {
 
     // legacy plane detection
     updateWorldTrackingState?(options: { planeDetectionState?: { enabled: boolean } }): void;
+
+    // image tracking
+    getTrackedImageScores?(): XRImageTrackingScore[];
 }
 
 interface XRViewerPose extends XRPose {
@@ -166337,6 +166705,21 @@ interface XRHand extends Iterable<XRJointSpace> {
     readonly LITTLE_PHALANX_DISTAL: number;
     readonly LITTLE_PHALANX_TIP: number;
 }
+
+type XRImageTrackingState = "tracked" | "emulated";
+type XRImageTrackingScore = "untrackable" | "trackable";
+
+interface XRTrackedImageInit {
+    image: ImageBitmap;
+    widthInMeters: number;
+}
+
+interface XRImageTrackingResult {
+    readonly imageSpace: XRSpace;
+    readonly index: number;
+    readonly trackingState: XRImageTrackingState;
+    readonly measuredWidthInMeters: number;
+}
 
 // This file contains native only extensions for WebXR. These APIs are not supported in the browser yet.
 // They are intended for use with either Babylon Native https://github.com/BabylonJS/BabylonNative or

+ 259 - 5
dist/preview release/documentation.d.ts

@@ -39884,6 +39884,10 @@ declare module BABYLON {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -44760,6 +44764,10 @@ declare module BABYLON {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -44825,6 +44833,11 @@ declare module BABYLON {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -44845,6 +44858,13 @@ declare module BABYLON {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -53517,6 +53537,10 @@ declare module BABYLON {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -53562,6 +53586,10 @@ declare module BABYLON {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -53677,14 +53705,14 @@ declare module BABYLON {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module BABYLON {
@@ -59928,6 +59956,20 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
+declare module BABYLON {
+    /**
      * Gather the list of clipboard event types as constants.
      */
     export class ClipboardEventTypes {
@@ -79784,6 +79826,141 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
+declare module BABYLON {
+    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -81539,6 +81716,7 @@ interface XRLayer extends EventTarget {}
 interface XRSessionInit {
     optionalFeatures?: string[];
     requiredFeatures?: string[];
+    trackedImages?: XRTrackedImageInit[];
 }
 
 interface XRSessionEvent extends Event {
@@ -81638,6 +81816,8 @@ interface XRFrame {
     worldInformation?: XRWorldInformation;
     // Hand tracking
     getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose;
+    // Image tracking
+    getImageTrackingResults?(): Array<XRImageTrackingResult>;
 }
 
 interface XRInputSourceEvent extends Event {
@@ -81709,6 +81889,9 @@ interface XRSession {
 
     // legacy plane detection
     updateWorldTrackingState?(options: { planeDetectionState?: { enabled: boolean } }): void;
+
+    // image tracking
+    getTrackedImageScores?(): XRImageTrackingScore[];
 }
 
 interface XRViewerPose extends XRPose {
@@ -81840,6 +82023,21 @@ interface XRHand extends Iterable<XRJointSpace> {
     readonly LITTLE_PHALANX_DISTAL: number;
     readonly LITTLE_PHALANX_TIP: number;
 }
+
+type XRImageTrackingState = "tracked" | "emulated";
+type XRImageTrackingScore = "untrackable" | "trackable";
+
+interface XRTrackedImageInit {
+    image: ImageBitmap;
+    widthInMeters: number;
+}
+
+interface XRImageTrackingResult {
+    readonly imageSpace: XRSpace;
+    readonly index: number;
+    readonly trackingState: XRImageTrackingState;
+    readonly measuredWidthInMeters: number;
+}
 
 // This file contains native only extensions for WebXR. These APIs are not supported in the browser yet.
 // They are intended for use with either Babylon Native https://github.com/BabylonJS/BabylonNative or
@@ -82565,6 +82763,16 @@ declare module BABYLON.GUI {
         private _attachToOnPointerOut;
         private _attachToOnBlur;
         /**
+         * Serializes the entire GUI system
+         * @returns an object with the JSON serialized data
+         */
+        serializeContent(): any;
+        /**
+         * Recreate the content of the ADT from a JSON object
+         * @param serializedObject define the JSON serialized object to restore from
+         */
+        parseContent(serializedObject: any): void;
+        /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
          * @param width defines the texture width (1024 by default)
@@ -83033,13 +83241,13 @@ declare module BABYLON.GUI {
         get centerX(): number;
         /** Gets the center coordinate on Y axis */
         get centerY(): number;
-        /** Gets or sets if control is Enabled*/
+        /** Gets or sets if control is Enabled */
         get isEnabled(): boolean;
         set isEnabled(value: boolean);
-        /** Gets or sets background color of control if it's disabled*/
+        /** Gets or sets background color of control if it's disabled */
         get disabledColor(): string;
         set disabledColor(value: string);
-        /** Gets or sets front color of control if it's disabled*/
+        /** Gets or sets front color of control if it's disabled */
         get disabledColorItem(): string;
         set disabledColorItem(value: string);
         /**
@@ -83110,6 +83318,24 @@ declare module BABYLON.GUI {
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
         linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
+        /**
+        * Shorthand funtion to set the top, right, bottom, and left padding values on the control.
+        * @param { string | number} paddingTop - The value of the top padding.
+        * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
+        * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
+        * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
+        * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+        */
+        setPadding(paddingTop: string | number, paddingRight?: string | number, paddingBottom?: string | number, paddingLeft?: string | number): void;
+        /**
+         * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
+         * @param { number} paddingTop - The value in pixels of the top padding.
+         * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
+         * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
+         * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
+         * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+         */
+        setPaddingInPixels(paddingTop: number, paddingRight?: number, paddingBottom?: number, paddingLeft?: number): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */
@@ -83188,6 +83414,13 @@ declare module BABYLON.GUI {
         /** @hidden */
         _processObservables(type: number, x: number, y: number, pi: BABYLON.PointerInfoBase, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
         /** Releases associated resources */
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -83216,6 +83449,13 @@ declare module BABYLON.GUI {
             descent: number;
         };
         /**
+         * Creates a Control from parsed data
+         * @param serializedObject defines parsed data
+         * @param host defines the hosting AdvancedDynamicTexture
+         * @returns a new Control
+         */
+        static Parse(serializedObject: any, host: AdvancedDynamicTexture): Control;
+        /**
          * Creates a stack panel that can be used to render headers
          * @param control defines the control to associate with the header
          * @param text defines the text of the header
@@ -83338,8 +83578,15 @@ declare module BABYLON.GUI {
         _processPicking(x: number, y: number, pi: BABYLON.PointerInfoBase, type: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         /** @hidden */
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        /**
+        * Serializes the current control
+        * @param serializationObject defined the JSON serialized object
+        */
+        serialize(serializationObject: any): void;
         /** Releases associated resources */
         dispose(): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {
@@ -83834,6 +84081,13 @@ declare module BABYLON.GUI {
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _postMeasure(): void;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {

+ 59 - 3
dist/preview release/gui/babylon.gui.d.ts

@@ -635,6 +635,16 @@ declare module BABYLON.GUI {
         private _attachToOnPointerOut;
         private _attachToOnBlur;
         /**
+         * Serializes the entire GUI system
+         * @returns an object with the JSON serialized data
+         */
+        serializeContent(): any;
+        /**
+         * Recreate the content of the ADT from a JSON object
+         * @param serializedObject define the JSON serialized object to restore from
+         */
+        parseContent(serializedObject: any): void;
+        /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
          * @param width defines the texture width (1024 by default)
@@ -1103,13 +1113,13 @@ declare module BABYLON.GUI {
         get centerX(): number;
         /** Gets the center coordinate on Y axis */
         get centerY(): number;
-        /** Gets or sets if control is Enabled*/
+        /** Gets or sets if control is Enabled */
         get isEnabled(): boolean;
         set isEnabled(value: boolean);
-        /** Gets or sets background color of control if it's disabled*/
+        /** Gets or sets background color of control if it's disabled */
         get disabledColor(): string;
         set disabledColor(value: string);
-        /** Gets or sets front color of control if it's disabled*/
+        /** Gets or sets front color of control if it's disabled */
         get disabledColorItem(): string;
         set disabledColorItem(value: string);
         /**
@@ -1180,6 +1190,24 @@ declare module BABYLON.GUI {
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
         linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
+        /**
+        * Shorthand funtion to set the top, right, bottom, and left padding values on the control.
+        * @param { string | number} paddingTop - The value of the top padding.
+        * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
+        * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
+        * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
+        * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+        */
+        setPadding(paddingTop: string | number, paddingRight?: string | number, paddingBottom?: string | number, paddingLeft?: string | number): void;
+        /**
+         * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
+         * @param { number} paddingTop - The value in pixels of the top padding.
+         * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
+         * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
+         * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
+         * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+         */
+        setPaddingInPixels(paddingTop: number, paddingRight?: number, paddingBottom?: number, paddingLeft?: number): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */
@@ -1258,6 +1286,13 @@ declare module BABYLON.GUI {
         /** @hidden */
         _processObservables(type: number, x: number, y: number, pi: BABYLON.PointerInfoBase, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
         /** Releases associated resources */
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -1286,6 +1321,13 @@ declare module BABYLON.GUI {
             descent: number;
         };
         /**
+         * Creates a Control from parsed data
+         * @param serializedObject defines parsed data
+         * @param host defines the hosting AdvancedDynamicTexture
+         * @returns a new Control
+         */
+        static Parse(serializedObject: any, host: AdvancedDynamicTexture): Control;
+        /**
          * Creates a stack panel that can be used to render headers
          * @param control defines the control to associate with the header
          * @param text defines the text of the header
@@ -1408,8 +1450,15 @@ declare module BABYLON.GUI {
         _processPicking(x: number, y: number, pi: BABYLON.PointerInfoBase, type: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         /** @hidden */
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        /**
+        * Serializes the current control
+        * @param serializationObject defined the JSON serialized object
+        */
+        serialize(serializationObject: any): void;
         /** Releases associated resources */
         dispose(): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {
@@ -1904,6 +1953,13 @@ declare module BABYLON.GUI {
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _postMeasure(): void;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {

File diff ditekan karena terlalu besar
+ 701 - 115
dist/preview release/gui/babylon.gui.js


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


File diff ditekan karena terlalu besar
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


+ 119 - 6
dist/preview release/gui/babylon.gui.module.d.ts

@@ -658,6 +658,16 @@ declare module "babylonjs-gui/2D/advancedDynamicTexture" {
         private _attachToOnPointerOut;
         private _attachToOnBlur;
         /**
+         * Serializes the entire GUI system
+         * @returns an object with the JSON serialized data
+         */
+        serializeContent(): any;
+        /**
+         * Recreate the content of the ADT from a JSON object
+         * @param serializedObject define the JSON serialized object to restore from
+         */
+        parseContent(serializedObject: any): void;
+        /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
          * @param width defines the texture width (1024 by default)
@@ -1138,13 +1148,13 @@ declare module "babylonjs-gui/2D/controls/control" {
         get centerX(): number;
         /** Gets the center coordinate on Y axis */
         get centerY(): number;
-        /** Gets or sets if control is Enabled*/
+        /** Gets or sets if control is Enabled */
         get isEnabled(): boolean;
         set isEnabled(value: boolean);
-        /** Gets or sets background color of control if it's disabled*/
+        /** Gets or sets background color of control if it's disabled */
         get disabledColor(): string;
         set disabledColor(value: string);
-        /** Gets or sets front color of control if it's disabled*/
+        /** Gets or sets front color of control if it's disabled */
         get disabledColorItem(): string;
         set disabledColorItem(value: string);
         /**
@@ -1215,6 +1225,24 @@ declare module "babylonjs-gui/2D/controls/control" {
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
         linkWithMesh(mesh: Nullable<TransformNode>): void;
+        /**
+        * Shorthand funtion to set the top, right, bottom, and left padding values on the control.
+        * @param { string | number} paddingTop - The value of the top padding.
+        * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
+        * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
+        * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
+        * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+        */
+        setPadding(paddingTop: string | number, paddingRight?: string | number, paddingBottom?: string | number, paddingLeft?: string | number): void;
+        /**
+         * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
+         * @param { number} paddingTop - The value in pixels of the top padding.
+         * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
+         * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
+         * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
+         * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+         */
+        setPaddingInPixels(paddingTop: number, paddingRight?: number, paddingBottom?: number, paddingLeft?: number): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: Vector3): void;
         /** @hidden */
@@ -1293,6 +1321,13 @@ declare module "babylonjs-gui/2D/controls/control" {
         /** @hidden */
         _processObservables(type: number, x: number, y: number, pi: PointerInfoBase, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
         /** Releases associated resources */
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -1321,6 +1356,13 @@ declare module "babylonjs-gui/2D/controls/control" {
             descent: number;
         };
         /**
+         * Creates a Control from parsed data
+         * @param serializedObject defines parsed data
+         * @param host defines the hosting AdvancedDynamicTexture
+         * @returns a new Control
+         */
+        static Parse(serializedObject: any, host: AdvancedDynamicTexture): Control;
+        /**
          * Creates a stack panel that can be used to render headers
          * @param control defines the control to associate with the header
          * @param text defines the text of the header
@@ -1448,8 +1490,15 @@ declare module "babylonjs-gui/2D/controls/container" {
         _processPicking(x: number, y: number, pi: PointerInfoBase, type: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         /** @hidden */
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        /**
+        * Serializes the current control
+        * @param serializationObject defined the JSON serialized object
+        */
+        serialize(serializationObject: any): void;
         /** Releases associated resources */
         dispose(): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module "babylonjs-gui/2D/controls/rectangle" {
@@ -1925,6 +1974,7 @@ declare module "babylonjs-gui/2D/controls/button" {
 declare module "babylonjs-gui/2D/controls/stackPanel" {
     import { Container } from "babylonjs-gui/2D/controls/container";
     import { Measure } from "babylonjs-gui/2D/measure";
+    import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
     /**
      * Class used to create a 2D stack panel container
      */
@@ -1963,6 +2013,13 @@ declare module "babylonjs-gui/2D/controls/stackPanel" {
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _postMeasure(): void;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module "babylonjs-gui/2D/controls/checkbox" {
@@ -5283,6 +5340,16 @@ declare module BABYLON.GUI {
         private _attachToOnPointerOut;
         private _attachToOnBlur;
         /**
+         * Serializes the entire GUI system
+         * @returns an object with the JSON serialized data
+         */
+        serializeContent(): any;
+        /**
+         * Recreate the content of the ADT from a JSON object
+         * @param serializedObject define the JSON serialized object to restore from
+         */
+        parseContent(serializedObject: any): void;
+        /**
          * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)
          * @param mesh defines the mesh which will receive the texture
          * @param width defines the texture width (1024 by default)
@@ -5751,13 +5818,13 @@ declare module BABYLON.GUI {
         get centerX(): number;
         /** Gets the center coordinate on Y axis */
         get centerY(): number;
-        /** Gets or sets if control is Enabled*/
+        /** Gets or sets if control is Enabled */
         get isEnabled(): boolean;
         set isEnabled(value: boolean);
-        /** Gets or sets background color of control if it's disabled*/
+        /** Gets or sets background color of control if it's disabled */
         get disabledColor(): string;
         set disabledColor(value: string);
-        /** Gets or sets front color of control if it's disabled*/
+        /** Gets or sets front color of control if it's disabled */
         get disabledColorItem(): string;
         set disabledColorItem(value: string);
         /**
@@ -5828,6 +5895,24 @@ declare module BABYLON.GUI {
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
         linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
+        /**
+        * Shorthand funtion to set the top, right, bottom, and left padding values on the control.
+        * @param { string | number} paddingTop - The value of the top padding.
+        * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
+        * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
+        * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
+        * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+        */
+        setPadding(paddingTop: string | number, paddingRight?: string | number, paddingBottom?: string | number, paddingLeft?: string | number): void;
+        /**
+         * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
+         * @param { number} paddingTop - The value in pixels of the top padding.
+         * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
+         * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
+         * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
+         * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+         */
+        setPaddingInPixels(paddingTop: number, paddingRight?: number, paddingBottom?: number, paddingLeft?: number): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */
@@ -5906,6 +5991,13 @@ declare module BABYLON.GUI {
         /** @hidden */
         _processObservables(type: number, x: number, y: number, pi: BABYLON.PointerInfoBase, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         private _prepareFont;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
         /** Releases associated resources */
         dispose(): void;
         private static _HORIZONTAL_ALIGNMENT_LEFT;
@@ -5934,6 +6026,13 @@ declare module BABYLON.GUI {
             descent: number;
         };
         /**
+         * Creates a Control from parsed data
+         * @param serializedObject defines parsed data
+         * @param host defines the hosting AdvancedDynamicTexture
+         * @returns a new Control
+         */
+        static Parse(serializedObject: any, host: AdvancedDynamicTexture): Control;
+        /**
          * Creates a stack panel that can be used to render headers
          * @param control defines the control to associate with the header
          * @param text defines the text of the header
@@ -6056,8 +6155,15 @@ declare module BABYLON.GUI {
         _processPicking(x: number, y: number, pi: BABYLON.PointerInfoBase, type: number, pointerId: number, buttonIndex: number, deltaX?: number, deltaY?: number): boolean;
         /** @hidden */
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
+        /**
+        * Serializes the current control
+        * @param serializationObject defined the JSON serialized object
+        */
+        serialize(serializationObject: any): void;
         /** Releases associated resources */
         dispose(): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {
@@ -6552,6 +6658,13 @@ declare module BABYLON.GUI {
         protected _preMeasure(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _postMeasure(): void;
+        /**
+         * Serializes the current control
+         * @param serializationObject defined the JSON serialized object
+         */
+        serialize(serializationObject: any): void;
+        /** @hidden */
+        _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture): void;
     }
 }
 declare module BABYLON.GUI {

+ 2 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1571,7 +1571,7 @@ var TransmissionHelper = /** @class */ (function () {
      */
     TransmissionHelper._getDefaultOptions = function () {
         return {
-            renderSize: 512
+            renderSize: 1024
         };
     };
     /**
@@ -1694,6 +1694,7 @@ var TransmissionHelper = /** @class */ (function () {
         this._opaqueRenderTarget.gammaSpace = true;
         this._opaqueRenderTarget.lodGenerationScale = 1;
         this._opaqueRenderTarget.lodGenerationOffset = -4;
+        this._opaqueRenderTarget.samples = 4;
         if (opaqueRTIndex >= 0) {
             this._scene.customRenderTargets.splice(opaqueRTIndex, 0, this._opaqueRenderTarget);
         }

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 2 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3923,7 +3923,7 @@ var TransmissionHelper = /** @class */ (function () {
      */
     TransmissionHelper._getDefaultOptions = function () {
         return {
-            renderSize: 512
+            renderSize: 1024
         };
     };
     /**
@@ -4046,6 +4046,7 @@ var TransmissionHelper = /** @class */ (function () {
         this._opaqueRenderTarget.gammaSpace = true;
         this._opaqueRenderTarget.lodGenerationScale = 1;
         this._opaqueRenderTarget.lodGenerationOffset = -4;
+        this._opaqueRenderTarget.samples = 4;
         if (opaqueRTIndex >= 0) {
             this._scene.customRenderTargets.splice(opaqueRTIndex, 0, this._opaqueRenderTarget);
         }

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -5306,7 +5306,7 @@ var TransmissionHelper = /** @class */ (function () {
      */
     TransmissionHelper._getDefaultOptions = function () {
         return {
-            renderSize: 512
+            renderSize: 1024
         };
     };
     /**
@@ -5429,6 +5429,7 @@ var TransmissionHelper = /** @class */ (function () {
         this._opaqueRenderTarget.gammaSpace = true;
         this._opaqueRenderTarget.lodGenerationScale = 1;
         this._opaqueRenderTarget.lodGenerationOffset = -4;
+        this._opaqueRenderTarget.samples = 4;
         if (opaqueRTIndex >= 0) {
             this._scene.customRenderTargets.splice(opaqueRTIndex, 0, this._opaqueRenderTarget);
         }

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -1 +1 @@
-{"thinEngineOnly":129721,"engineOnly":166797,"sceneOnly":519975,"minGridMaterial":693943,"minStandardMaterial":854658}
+{"thinEngineOnly":129797,"engineOnly":166873,"sceneOnly":520051,"minGridMaterial":694019,"minStandardMaterial":854734}

+ 387 - 4
dist/preview release/viewer/babylon.module.d.ts

@@ -41406,6 +41406,10 @@ declare module "babylonjs/Engines/thinEngine" {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -46396,6 +46400,10 @@ declare module "babylonjs/Engines/webgpuEngine" {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -46461,6 +46469,11 @@ declare module "babylonjs/Engines/webgpuEngine" {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -46481,6 +46494,13 @@ declare module "babylonjs/Engines/webgpuEngine" {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -55600,6 +55620,10 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -55645,6 +55669,10 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -55760,14 +55788,14 @@ declare module "babylonjs/XR/webXRFeaturesManager" {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module "babylonjs/XR/webXRExperienceHelper" {
@@ -62464,6 +62492,21 @@ declare module "babylonjs/Engines/nativeEngine" {
         private _getNativeAttribType;
     }
 }
+declare module "babylonjs/Engines/engineFactory" {
+    import { ThinEngine } from "babylonjs/Engines/thinEngine";
+    /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
 declare module "babylonjs/Engines/index" {
     export * from "babylonjs/Engines/constants";
     export * from "babylonjs/Engines/engineCapabilities";
@@ -62482,6 +62525,7 @@ declare module "babylonjs/Engines/index" {
     export * from "babylonjs/Engines/Processors/shaderCodeInliner";
     export * from "babylonjs/Engines/performanceConfigurator";
     export * from "babylonjs/Engines/engineFeatures";
+    export * from "babylonjs/Engines/engineFactory";
 }
 declare module "babylonjs/Events/clipboardEvents" {
     /**
@@ -84140,6 +84184,146 @@ declare module "babylonjs/XR/features/WebXRMeshDetector" {
         private _updateVertexDataWithXRMesh;
     }
 }
+declare module "babylonjs/XR/features/WebXRImageTracking" {
+    import { WebXRSessionManager } from "babylonjs/XR/webXRSessionManager";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { WebXRAbstractFeature } from "babylonjs/XR/features/WebXRAbstractFeature";
+    import { Matrix } from "babylonjs/Maths/math.vector";
+    import { Nullable } from "babylonjs/types";
+    /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
 declare module "babylonjs/XR/features/index" {
     export * from "babylonjs/XR/features/WebXRAbstractFeature";
     export * from "babylonjs/XR/features/WebXRHitTestLegacy";
@@ -84153,6 +84337,7 @@ declare module "babylonjs/XR/features/index" {
     export * from "babylonjs/XR/features/WebXRFeaturePointSystem";
     export * from "babylonjs/XR/features/WebXRHandTracking";
     export * from "babylonjs/XR/features/WebXRMeshDetector";
+    export * from "babylonjs/XR/features/WebXRImageTracking";
 }
 declare module "babylonjs/XR/motionController/webXRMicrosoftMixedRealityController" {
     import { WebXRAbstractMotionController, IMinimalMotionControllerObject, MotionControllerHandedness } from "babylonjs/XR/motionController/webXRAbstractMotionController";
@@ -124381,6 +124566,10 @@ declare module BABYLON {
          * Will prevent the system from falling back to software implementation if a hardware device cannot be created
          */
         failIfMajorPerformanceCaveat?: boolean;
+        /**
+         * Defines whether to adapt to the device's viewport characteristics (default: false)
+         */
+        adaptToDeviceRatio?: boolean;
     }
     /**
      * The base engine class (root of all engines)
@@ -129257,6 +129446,10 @@ declare module BABYLON {
          * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
          */
         enableGPUDebugMarkers?: boolean;
+        /**
+         * Options to load the associated Glslang library
+         */
+        glslangOptions?: GlslangOptions;
     }
     /**
      * The web GPU engine class provides support for WebGPU version of babylon.js.
@@ -129322,6 +129515,11 @@ declare module BABYLON {
         /** @hidden */
         dbgShowWarningsNotImplemented: boolean;
         /**
+         * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+         * @returns true if the engine can be created
+         */
+        static get IsSupported(): boolean;
+        /**
          * Gets a boolean indicating that the engine supports uniform buffers
          */
         get supportsUniformBuffers(): boolean;
@@ -129342,6 +129540,13 @@ declare module BABYLON {
          */
         get version(): number;
         /**
+         * Create a new instance of the gpu engine asynchronously
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the GPU context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options?: WebGPUEngineOptions): Promise<WebGPUEngine>;
+        /**
          * Create a new instance of the gpu engine.
          * @param canvas Defines the canvas to use to display the result
          * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -138014,6 +138219,10 @@ declare module BABYLON {
          * A list of (Babylon WebXR) features this feature depends on
          */
         dependsOn?: string[];
+        /**
+         * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+         */
+        getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
     }
     /**
      * A list of the currently available features without referencing them
@@ -138059,6 +138268,10 @@ declare module BABYLON {
          * The name of the hand tracking feature.
          */
         static readonly HAND_TRACKING: string;
+        /**
+         * The name of the image tracking feature
+         */
+        static readonly IMAGE_TRACKING: string;
     }
     /**
      * Defining the constructor of a feature. Used to register the modules.
@@ -138174,14 +138387,14 @@ declare module BABYLON {
          */
         getEnabledFeatures(): string[];
         /**
-         * This function will exten the session creation configuration object with enabled features.
+         * This function will extend the session creation configuration object with enabled features.
          * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
          * according to the defined "required" variable, provided during enableFeature call
          * @param xrSessionInit the xr Session init object to extend
          *
          * @returns an extended XRSessionInit object
          */
-        extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit;
+        _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit>;
     }
 }
 declare module BABYLON {
@@ -144425,6 +144638,20 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Helper class to create the best engine depending on the current hardware
+     */
+    export class EngineFactory {
+        /**
+         * Creates an engine based on the capabilities of the underlying hardware
+         * @param canvas Defines the canvas to use to display the result
+         * @param options Defines the options passed to the engine to create the context dependencies
+         * @returns a promise that resolves with the created engine
+         */
+        static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine>;
+    }
+}
+declare module BABYLON {
+    /**
      * Gather the list of clipboard event types as constants.
      */
     export class ClipboardEventTypes {
@@ -164281,6 +164508,141 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Options interface for the background remover plugin
+     */
+    export interface IWebXRImageTrackingOptions {
+        /**
+         * A required array with images to track
+         */
+        images: {
+            /**
+             * The source of the image. can be a URL or an image bitmap
+             */
+            src: string | ImageBitmap;
+            /**
+             * The estimated width in the real world (in meters)
+             */
+            estimatedRealWorldWidth: number;
+        }[];
+    }
+    /**
+     * An object representing an image tracked by the system
+     */
+    export interface IWebXRTrackedImage {
+        /**
+         * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+         */
+        id: number;
+        /**
+         * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+         */
+        emulated?: boolean;
+        /**
+         * Just in case it is needed - the image bitmap that is being tracked
+         */
+        originalBitmap: ImageBitmap;
+        /**
+         * The native XR result image tracking result, untouched
+         */
+        xrTrackingResult?: XRImageTrackingResult;
+        /**
+         * Width in real world (meters)
+         */
+        realWorldWidth?: number;
+        /**
+         * A transformation matrix of this current image in the current reference space.
+         */
+        transformationMatrix: Matrix;
+        /**
+         * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+         */
+        ratio?: number;
+    }
+    /**
+     * Image tracking for immersive AR sessions.
+     * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+     */
+    export class WebXRImageTracking extends WebXRAbstractFeature {
+        /**
+         * read-only options to be used in this module
+         */
+        readonly options: IWebXRImageTrackingOptions;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
+        /**
+         * The (Babylon) version of this module.
+         * This is an integer representing the implementation version.
+         * This number does not correspond to the WebXR specs version
+         */
+        static readonly Version: number;
+        /**
+         * This will be triggered if the underlying system deems an image untrackable.
+         * The index is the index of the image from the array used to initialize the feature.
+         */
+        onUntrackableImageFoundObservable: Observable<number>;
+        /**
+         * An image was deemed trackable, and the system will start tracking it.
+         */
+        onTrackableImageFoundObservable: Observable<IWebXRTrackedImage>;
+        /**
+         * The image was found and its state was updated.
+         */
+        onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage>;
+        private _trackedImages;
+        private _originalTrackingRequest;
+        /**
+         * constructs the image tracking feature
+         * @param _xrSessionManager the session manager for this module
+         * @param options read-only options to be used in this module
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * read-only options to be used in this module
+         */
+        options: IWebXRImageTrackingOptions);
+        /**
+         * attach this feature
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        attach(): boolean;
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
+         */
+        detach(): boolean;
+        /**
+         * Check if the needed objects are defined.
+         * This does not mean that the feature is enabled, but that the objects needed are well defined.
+         */
+        isCompatible(): boolean;
+        /**
+         * Get a tracked image by its ID.
+         *
+         * @param id the id of the image to load (position in the init array)
+         * @returns a trackable image, if exists in this location
+         */
+        getTrackedImageById(id: number): Nullable<IWebXRTrackedImage>;
+        /**
+         * Dispose this feature and all of the resources attached
+         */
+        dispose(): void;
+        /**
+         * Extends the session init object if needed
+         * @returns augmentation object fo the xr session init object.
+         */
+        getXRSessionInitExtension(): Promise<Partial<XRSessionInit>>;
+        protected _onXRFrame(_xrFrame: XRFrame): void;
+        private _init;
+    }
+}
+declare module BABYLON {
+    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -166036,6 +166398,7 @@ interface XRLayer extends EventTarget {}
 interface XRSessionInit {
     optionalFeatures?: string[];
     requiredFeatures?: string[];
+    trackedImages?: XRTrackedImageInit[];
 }
 
 interface XRSessionEvent extends Event {
@@ -166135,6 +166498,8 @@ interface XRFrame {
     worldInformation?: XRWorldInformation;
     // Hand tracking
     getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose;
+    // Image tracking
+    getImageTrackingResults?(): Array<XRImageTrackingResult>;
 }
 
 interface XRInputSourceEvent extends Event {
@@ -166206,6 +166571,9 @@ interface XRSession {
 
     // legacy plane detection
     updateWorldTrackingState?(options: { planeDetectionState?: { enabled: boolean } }): void;
+
+    // image tracking
+    getTrackedImageScores?(): XRImageTrackingScore[];
 }
 
 interface XRViewerPose extends XRPose {
@@ -166337,6 +166705,21 @@ interface XRHand extends Iterable<XRJointSpace> {
     readonly LITTLE_PHALANX_DISTAL: number;
     readonly LITTLE_PHALANX_TIP: number;
 }
+
+type XRImageTrackingState = "tracked" | "emulated";
+type XRImageTrackingScore = "untrackable" | "trackable";
+
+interface XRTrackedImageInit {
+    image: ImageBitmap;
+    widthInMeters: number;
+}
+
+interface XRImageTrackingResult {
+    readonly imageSpace: XRSpace;
+    readonly index: number;
+    readonly trackingState: XRImageTrackingState;
+    readonly measuredWidthInMeters: number;
+}
 
 // This file contains native only extensions for WebXR. These APIs are not supported in the browser yet.
 // They are intended for use with either Babylon Native https://github.com/BabylonJS/BabylonNative or

File diff ditekan karena terlalu besar
+ 21 - 13
dist/preview release/viewer/babylon.viewer.js


File diff ditekan karena terlalu besar
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -12,6 +12,7 @@
 ### Loaders
 
 - Added support for EXT_meshopt_compression for glTF loader. ([zeux](https://github.com/zeux))
+- Increased KHR_materials_transmission render target texture default size. ([Drigax](https://github.com/drigax))
 
 ### Navigation
 
@@ -34,10 +35,13 @@
 - Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
 - Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
 - Added `ToggleButton` GUI control ([kintz09](https://github.com/kintz09))
+- Added shorthand methods which set all padding values at once, named `setPadding` and `setPaddingInPixels`, to the control class  ([kintz09](https://github.com/kintz09))
 
 ### WebXR
 
 - A browser error preventing the emulator to render scene is now correctly dealt with ([RaananW](https://github.com/RaananW))
+- Added a way to extend the XRSessionInit Object from inside of a feature ([RaananW](https://github.com/RaananW))
+- Added image tracking feature ([RaananW](https://github.com/RaananW))
 
 ## Bugs
 

+ 23 - 0
gui/src/2D/advancedDynamicTexture.ts

@@ -890,6 +890,29 @@ export class AdvancedDynamicTexture extends DynamicTexture {
             this._lastControlDown = {};
         });
     }
+
+    /**
+     * Serializes the entire GUI system
+     * @returns an object with the JSON serialized data
+     */
+    public serializeContent(): any {
+        let serializationObject = {
+            root: {}
+        };
+
+        this._rootContainer.serialize(serializationObject.root);
+
+        return serializationObject;
+    }
+
+    /**
+     * Recreate the content of the ADT from a JSON object
+     * @param serializedObject define the JSON serialized object to restore from
+     */
+    public parseContent(serializedObject: any) {
+        this._rootContainer = Control.Parse(serializedObject.root, this) as Container;
+    }
+
     // Statics
     /**
      * Creates a new AdvancedDynamicTexture in projected mode (ie. attached to a mesh)

+ 5 - 0
gui/src/2D/controls/checkbox.ts

@@ -8,6 +8,7 @@ import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Nullable } from 'babylonjs/types';
 import { Measure } from '../measure';
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Class used to represent a 2D checkbox
@@ -19,6 +20,7 @@ export class Checkbox extends Control {
     private _thickness = 1;
 
     /** Gets or sets border thickness  */
+    @serialize()
     public get thickness(): number {
         return this._thickness;
     }
@@ -38,6 +40,7 @@ export class Checkbox extends Control {
     public onIsCheckedChangedObservable = new Observable<boolean>();
 
     /** Gets or sets a value indicating the ratio between overall size and check size */
+    @serialize()
     public get checkSizeRatio(): number {
         return this._checkSizeRatio;
     }
@@ -54,6 +57,7 @@ export class Checkbox extends Control {
     }
 
     /** Gets or sets background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -68,6 +72,7 @@ export class Checkbox extends Control {
     }
 
     /** Gets or sets a boolean indicating if the checkbox is checked or not */
+    @serialize()
     public get isChecked(): boolean {
         return this._isChecked;
     }

+ 5 - 0
gui/src/2D/controls/colorpicker.ts

@@ -12,6 +12,7 @@ import { TextBlock } from "../controls/textBlock";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /** Class used to create color pickers */
 export class ColorPicker extends Control {
@@ -40,6 +41,7 @@ export class ColorPicker extends Control {
     public onValueChangedObservable = new Observable<Color3>();
 
     /** Gets or sets the color of the color picker */
+    @serialize()
     public get value(): Color3 {
         return this._value;
     }
@@ -90,6 +92,7 @@ export class ColorPicker extends Control {
      * Gets or sets control width
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get width(): string | number {
         return this._width.toString(this._host);
     }
@@ -109,6 +112,7 @@ export class ColorPicker extends Control {
      * Gets or sets control height
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get height(): string | number {
         return this._height.toString(this._host);
     }
@@ -126,6 +130,7 @@ export class ColorPicker extends Control {
     }
 
     /** Gets or sets control size */
+    @serialize()
     public get size(): string | number {
         return this.width;
     }

+ 38 - 0
gui/src/2D/controls/container.ts

@@ -6,6 +6,7 @@ import { Measure } from "../measure";
 import { AdvancedDynamicTexture } from "../advancedDynamicTexture";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Root class for 2D containers
@@ -31,9 +32,11 @@ export class Container extends Control {
     /**
      * Gets or sets the number of layout cycles (a change involved by a control while evaluating the layout) allowed
      */
+    @serialize()
     public maxLayoutCycle = 3;
 
     /** Gets or sets a boolean indicating if the container should try to adapt to its children height */
+    @serialize()
     public get adaptHeightToChildren(): boolean {
         return this._adaptHeightToChildren;
     }
@@ -53,6 +56,7 @@ export class Container extends Control {
     }
 
     /** Gets or sets a boolean indicating if the container should try to adapt to its children width */
+    @serialize()
     public get adaptWidthToChildren(): boolean {
         return this._adaptWidthToChildren;
     }
@@ -72,6 +76,7 @@ export class Container extends Control {
     }
 
     /** Gets or sets background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -453,6 +458,25 @@ export class Container extends Control {
         this._measureForChildren.copyFrom(this._currentMeasure);
     }
 
+     /**
+     * Serializes the current control
+     * @param serializationObject defined the JSON serialized object
+     */
+    public serialize(serializationObject: any) {
+        super.serialize(serializationObject);
+        if (!this.children.length) {
+            return;
+        }
+
+        serializationObject.children = [];
+
+        for (var child of this.children) {
+            let childSerializationObject = {};
+            child.serialize(childSerializationObject);
+            serializationObject.children.push(childSerializationObject);
+        }
+    }
+
     /** Releases associated resources */
     public dispose() {
         super.dispose();
@@ -461,5 +485,19 @@ export class Container extends Control {
             this.children[index].dispose();
         }
     }
+
+    /** @hidden */
+    public _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture) {
+        super._parseFromContent(serializedObject, host);
+        this._link(host);
+
+        if (!serializedObject.children) {
+            return;
+        }
+
+        for (var childData of serializedObject.children) {
+            this.addControl(Control.Parse(childData, host));
+        }
+    }
 }
 _TypeStore.RegisteredTypes["BABYLON.GUI.Container"] = Container;

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

@@ -14,6 +14,7 @@ import { Measure } from "../measure";
 import { Style } from "../style";
 import { Matrix2D, Vector2WithInfo } from "../math2D";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { SerializationHelper, serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Root class used for all 2D controls
@@ -120,36 +121,44 @@ export class Control {
     /**
      * Gets or sets an object used to store user defined information for the node
      */
+    @serialize()
     public metadata: any = null;
 
     /** Gets or sets a boolean indicating if the control can be hit with pointer events */
+    @serialize()
     public isHitTestVisible = true;
     /** Gets or sets a boolean indicating if the control can block pointer events */
+    @serialize()
     public isPointerBlocker = false;
     /** Gets or sets a boolean indicating if the control can be focusable */
+    @serialize()
     public isFocusInvisible = false;
 
     /**
      * Gets or sets a boolean indicating if the children are clipped to the current control bounds.
      * Please note that not clipping children may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
      */
+    @serialize()
     public clipChildren = true;
 
     /**
      * Gets or sets a boolean indicating that control content must be clipped
      * Please note that not clipping children may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
      */
+    @serialize()
     public clipContent = true;
 
     /**
      * Gets or sets a boolean indicating that the current control should cache its rendering (useful when the control does not change often)
      */
+    @serialize()
     public useBitmapCache = false;
 
     private _cacheData: Nullable<ImageData>;
 
     private _shadowOffsetX = 0;
     /** Gets or sets a value indicating the offset to apply on X axis to render the shadow */
+    @serialize()
     public get shadowOffsetX() {
         return this._shadowOffsetX;
     }
@@ -165,6 +174,7 @@ export class Control {
 
     private _shadowOffsetY = 0;
     /** Gets or sets a value indicating the offset to apply on Y axis to render the shadow */
+    @serialize()
     public get shadowOffsetY() {
         return this._shadowOffsetY;
     }
@@ -180,6 +190,7 @@ export class Control {
 
     private _shadowBlur = 0;
     /** Gets or sets a value indicating the amount of blur to use to render the shadow */
+    @serialize()
     public get shadowBlur() {
         return this._shadowBlur;
     }
@@ -195,6 +206,7 @@ export class Control {
 
     private _shadowColor = 'black';
     /** Gets or sets a value indicating the color of the shadow (black by default ie. "#000") */
+    @serialize()
     public get shadowColor() {
         return this._shadowColor;
     }
@@ -209,6 +221,7 @@ export class Control {
     }
 
     /** Gets or sets the cursor to use when the control is hovered */
+    @serialize()
     public hoverCursor = "";
 
     /** @hidden */
@@ -293,6 +306,7 @@ export class Control {
     }
 
     /** Gets or set information about font offsets (used to render and align text) */
+    @serialize()
     public get fontOffset(): { ascent: number, height: number, descent: number } {
         return this._fontOffset;
     }
@@ -302,6 +316,7 @@ export class Control {
     }
 
     /** Gets or sets alpha value for the control (1 means opaque and 0 means entirely transparent) */
+    @serialize()
     public get alpha(): number {
         return this._alpha;
     }
@@ -334,6 +349,7 @@ export class Control {
     /** Gets or sets a value indicating the scale factor on X axis (1 by default)
      * @see https://doc.babylonjs.com/how_to/gui#rotation-and-scaling
     */
+   @serialize()
     public get scaleX(): number {
         return this._scaleX;
     }
@@ -351,6 +367,7 @@ export class Control {
     /** Gets or sets a value indicating the scale factor on Y axis (1 by default)
      * @see https://doc.babylonjs.com/how_to/gui#rotation-and-scaling
     */
+   @serialize()
     public get scaleY(): number {
         return this._scaleY;
     }
@@ -368,6 +385,7 @@ export class Control {
     /** Gets or sets the rotation angle (0 by default)
      * @see https://doc.babylonjs.com/how_to/gui#rotation-and-scaling
     */
+   @serialize()
     public get rotation(): number {
         return this._rotation;
     }
@@ -385,6 +403,7 @@ export class Control {
     /** Gets or sets the transformation center on Y axis (0 by default)
      * @see https://doc.babylonjs.com/how_to/gui#rotation-and-scaling
     */
+   @serialize()
     public get transformCenterY(): number {
         return this._transformCenterY;
     }
@@ -402,6 +421,7 @@ export class Control {
     /** Gets or sets the transformation center on X axis (0 by default)
      * @see https://doc.babylonjs.com/how_to/gui#rotation-and-scaling
     */
+   @serialize()
     public get transformCenterX(): number {
         return this._transformCenterX;
     }
@@ -420,6 +440,7 @@ export class Control {
      * Gets or sets the horizontal alignment
      * @see https://doc.babylonjs.com/how_to/gui#alignments
      */
+    @serialize()
     public get horizontalAlignment(): number {
         return this._horizontalAlignment;
     }
@@ -437,6 +458,7 @@ export class Control {
      * Gets or sets the vertical alignment
      * @see https://doc.babylonjs.com/how_to/gui#alignments
      */
+    @serialize()
     public get verticalAlignment(): number {
         return this._verticalAlignment;
     }
@@ -456,6 +478,7 @@ export class Control {
      * The first dimension used in the computation is the last one set (by setting width / widthInPixels or height / heightInPixels), and the
      * second dimension is computed as first dimension * fixedRatio
      */
+    @serialize()
     public fixedRatio = 0;
 
     private _fixedRatioMasterIsWidth = true;
@@ -464,6 +487,7 @@ export class Control {
      * Gets or sets control width
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get width(): string | number {
         return this._width.toString(this._host);
     }
@@ -500,6 +524,7 @@ export class Control {
      * Gets or sets control height
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get height(): string | number {
         return this._height.toString(this._host);
     }
@@ -581,6 +606,7 @@ export class Control {
      * Gets or sets style
      * @see https://doc.babylonjs.com/how_to/gui#styles
      */
+    @serialize()
     public get style(): Nullable<Style> {
         return this._style;
     }
@@ -644,6 +670,7 @@ export class Control {
     }
 
     /** Gets or sets foreground color */
+    @serialize()
     public get color(): string {
         return this._color;
     }
@@ -658,6 +685,7 @@ export class Control {
     }
 
     /** Gets or sets z index which is used to reorder controls on the z axis */
+    @serialize()
     public get zIndex(): number {
         return this._zIndex;
     }
@@ -675,6 +703,7 @@ export class Control {
     }
 
     /** Gets or sets a boolean indicating if the control can be rendered */
+    @serialize()
     public get notRenderable(): boolean {
         return this._doNotRender;
     }
@@ -689,6 +718,7 @@ export class Control {
     }
 
     /** Gets or sets a boolean indicating if the control is visible */
+    @serialize()
     public get isVisible(): boolean {
         return this._isVisible;
     }
@@ -718,6 +748,7 @@ export class Control {
      * Gets or sets a value indicating the padding to use on the left of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get paddingLeft(): string | number {
         return this._paddingLeft.toString(this._host);
     }
@@ -747,6 +778,7 @@ export class Control {
      * Gets or sets a value indicating the padding to use on the right of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get paddingRight(): string | number {
         return this._paddingRight.toString(this._host);
     }
@@ -776,6 +808,7 @@ export class Control {
      * Gets or sets a value indicating the padding to use on the top of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get paddingTop(): string | number {
         return this._paddingTop.toString(this._host);
     }
@@ -805,6 +838,7 @@ export class Control {
      * Gets or sets a value indicating the padding to use on the bottom of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get paddingBottom(): string | number {
         return this._paddingBottom.toString(this._host);
     }
@@ -834,6 +868,7 @@ export class Control {
      * Gets or sets a value indicating the left coordinate of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get left(): string | number {
         return this._left.toString(this._host);
     }
@@ -863,6 +898,7 @@ export class Control {
      * Gets or sets a value indicating the top coordinate of the control
      * @see https://doc.babylonjs.com/how_to/gui#position-and-size
      */
+    @serialize()
     public get top(): string | number {
         return this._top.toString(this._host);
     }
@@ -892,6 +928,7 @@ export class Control {
      * Gets or sets a value indicating the offset on X axis to the linked mesh
      * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
      */
+    @serialize()
     public get linkOffsetX(): string | number {
         return this._linkOffsetX.toString(this._host);
     }
@@ -921,6 +958,7 @@ export class Control {
      * Gets or sets a value indicating the offset on Y axis to the linked mesh
      * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
      */
+    @serialize()
     public get linkOffsetY(): string | number {
         return this._linkOffsetY.toString(this._host);
     }
@@ -956,7 +994,8 @@ export class Control {
         return this._currentMeasure.top + this._currentMeasure.height / 2;
     }
 
-    /** Gets or sets if control is Enabled*/
+    /** Gets or sets if control is Enabled */
+    @serialize()
     public get isEnabled(): boolean {
         return this._isEnabled;
     }
@@ -969,7 +1008,8 @@ export class Control {
         this._isEnabled = value;
         this._markAsDirty();
     }
-    /** Gets or sets background color of control if it's disabled*/
+    /** Gets or sets background color of control if it's disabled */
+    @serialize()
     public get disabledColor(): string {
         return this._disabledColor;
     }
@@ -982,7 +1022,8 @@ export class Control {
         this._disabledColor = value;
         this._markAsDirty();
     }
-    /** Gets or sets front color of control if it's disabled*/
+    /** Gets or sets front color of control if it's disabled */
+    @serialize()
     public get disabledColorItem(): string {
         return this._disabledColorItem;
     }
@@ -1170,6 +1211,56 @@ export class Control {
         this._host._linkedControls.push(this);
     }
 
+     /**
+     * Shorthand funtion to set the top, right, bottom, and left padding values on the control.
+     * @param { string | number} paddingTop - The value of the top padding.
+     * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
+     * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
+     * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
+     * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public setPadding(
+        paddingTop: string | number,
+        paddingRight?: string | number,
+        paddingBottom?: string | number,
+        paddingLeft?: string | number
+    ) {
+        const top = paddingTop;
+        const right = paddingRight ?? top;
+        const bottom = paddingBottom ?? top;
+        const left = paddingLeft ?? right;
+
+        this.paddingTop = top;
+        this.paddingRight = right;
+        this.paddingBottom = bottom;
+        this.paddingLeft = left;
+    }
+
+    /**
+     * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
+     * @param { number} paddingTop - The value in pixels of the top padding.
+     * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
+     * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
+     * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
+     * @see https://doc.babylonjs.com/how_to/gui#position-and-size
+     */
+    public setPaddingInPixels(
+        paddingTop: number,
+        paddingRight?: number,
+        paddingBottom?: number,
+        paddingLeft?: number
+    ) {
+        const top = paddingTop;
+        const right = paddingRight ?? top;
+        const bottom = paddingBottom ?? top;
+        const left = paddingLeft ?? right;
+
+        this.paddingTopInPixels = top;
+        this.paddingRightInPixels = right;
+        this.paddingBottomInPixels = bottom;
+        this.paddingLeftInPixels = left;
+    }
+
     /** @hidden */
     public _moveToProjectedPosition(projectedPosition: Vector3): void {
         let oldLeft = this._left.getValue(this._host);
@@ -1922,6 +2013,42 @@ export class Control {
         this._fontOffset = Control._GetFontOffset(this._font);
     }
 
+    /**
+     * Serializes the current control
+     * @param serializationObject defined the JSON serialized object
+     */
+    public serialize(serializationObject: any) {
+        SerializationHelper.Serialize(this, serializationObject);
+        serializationObject.name = this.name;
+        serializationObject.className = this.getClassName();
+
+        if (this._font) {
+            serializationObject.fontFamily = this.fontFamily;
+            serializationObject.fontSize = this.fontSize;
+            serializationObject.fontWeight = this.fontWeight;
+            serializationObject.fontStyle = this.fontStyle;
+        }
+    }
+
+    /** @hidden */
+    public _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture) {
+        if (serializedObject.fontFamily) {
+            this.fontFamily = serializedObject.fontFamily;
+        }
+
+        if (serializedObject.fontSize) {
+            this.fontSize = serializedObject.fontSize;
+        }
+
+        if (serializedObject.fontWeight) {
+            this.fontWeight = serializedObject.fontWeight;
+        }
+
+        if (serializedObject.fontStyle) {
+            this.fontStyle = serializedObject.fontStyle;
+        }
+    }
+
     /** Releases associated resources */
     public dispose() {
         this.onDirtyObservable.clear();
@@ -2038,6 +2165,23 @@ export class Control {
     }
 
     /**
+     * Creates a Control from parsed data
+     * @param serializedObject defines parsed data
+     * @param host defines the hosting AdvancedDynamicTexture
+     * @returns a new Control
+     */
+    public static Parse(serializedObject: any, host: AdvancedDynamicTexture): Control {
+        let controlType = Tools.Instantiate("BABYLON.GUI." + serializedObject.className);
+        let control = SerializationHelper.Parse(() => new controlType(), serializedObject, null);
+
+        control.name = serializedObject.name;
+
+        control._parseFromContent(serializedObject, host);
+
+        return control;
+    }
+
+    /**
      * Creates a stack panel that can be used to render headers
      * @param control defines the control to associate with the header
      * @param text defines the text of the header

+ 11 - 0
gui/src/2D/controls/displayGrid.ts

@@ -2,6 +2,7 @@ import { Control } from "./control";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Nullable } from 'babylonjs/types';
 import { Measure } from '../measure';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /** Class used to render a grid  */
 export class DisplayGrid extends Control {
@@ -22,6 +23,7 @@ export class DisplayGrid extends Control {
     private _displayMinorLines = true;
 
     /** Gets or sets a boolean indicating if minor lines must be rendered (true by default)) */
+    @serialize()
     public get displayMinorLines(): boolean {
         return this._displayMinorLines;
     }
@@ -36,6 +38,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets a boolean indicating if major lines must be rendered (true by default)) */
+    @serialize()
     public get displayMajorLines(): boolean {
         return this._displayMajorLines;
     }
@@ -50,6 +53,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets background color (Black by default) */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -64,6 +68,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the width of each cell (20 by default) */
+    @serialize()
     public get cellWidth(): number {
         return this._cellWidth;
     }
@@ -75,6 +80,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the height of each cell (20 by default) */
+    @serialize()
     public get cellHeight(): number {
         return this._cellHeight;
     }
@@ -86,6 +92,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the tickness of minor lines (1 by default) */
+    @serialize()
     public get minorLineTickness(): number {
         return this._minorLineTickness;
     }
@@ -97,6 +104,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the color of minor lines (DarkGray by default) */
+    @serialize()
     public get minorLineColor(): string {
         return this._minorLineColor;
     }
@@ -108,6 +116,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the tickness of major lines (2 by default) */
+    @serialize()
     public get majorLineTickness(): number {
         return this._majorLineTickness;
     }
@@ -119,6 +128,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the color of major lines (White by default) */
+    @serialize()
     public get majorLineColor(): string {
         return this._majorLineColor;
     }
@@ -130,6 +140,7 @@ export class DisplayGrid extends Control {
     }
 
     /** Gets or sets the frequency of major lines (default is 1 every 5 minor lines)*/
+    @serialize()
     public get majorLineFrequency(): number {
         return this._majorLineFrequency;
     }

+ 2 - 0
gui/src/2D/controls/ellipse.ts

@@ -2,12 +2,14 @@ import { Container } from "./container";
 import { Control } from "./control";
 import { Measure } from "../measure";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /** Class used to create 2D ellipse containers */
 export class Ellipse extends Container {
     private _thickness = 1;
 
     /** Gets or sets border thickness */
+    @serialize()
     public get thickness(): number {
         return this._thickness;
     }

+ 15 - 0
gui/src/2D/controls/image.ts

@@ -5,6 +5,7 @@ import { Tools } from "babylonjs/Misc/tools";
 import { Control } from "./control";
 import { Measure } from "../measure";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { expandToProperty, serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Class used to create 2D images
@@ -17,6 +18,8 @@ export class Image extends Control {
     private _imageHeight: number;
     private _loaded = false;
     private _stretch = Image.STRETCH_FILL;
+    @serialize()
+    @expandToProperty("source")
     private _source: Nullable<string>;
     private _autoScale = false;
 
@@ -64,6 +67,7 @@ export class Image extends Control {
     /**
      * Gets or sets a boolean indicating if nine patch slices (left, top, right, bottom) should be read from image data
      */
+    @serialize()
     public get populateNinePatchSlicesFromImage(): boolean {
         return this._populateNinePatchSlicesFromImage;
     }
@@ -84,6 +88,7 @@ export class Image extends Control {
      * Gets or sets a boolean indicating if pointers should only be validated on pixels with alpha > 0.
      * Beware using this as this will comsume more memory as the image has to be stored twice
      */
+    @serialize()
     public get detectPointerOnOpaqueOnly(): boolean {
         return this._detectPointerOnOpaqueOnly;
     }
@@ -99,6 +104,7 @@ export class Image extends Control {
     /**
      * Gets or sets the left value for slicing (9-patch)
      */
+    @serialize()
     public get sliceLeft(): number {
         return this._sliceLeft;
     }
@@ -116,6 +122,7 @@ export class Image extends Control {
     /**
      * Gets or sets the right value for slicing (9-patch)
      */
+    @serialize()
     public get sliceRight(): number {
         return this._sliceRight;
     }
@@ -133,6 +140,7 @@ export class Image extends Control {
     /**
      * Gets or sets the top value for slicing (9-patch)
      */
+    @serialize()
     public get sliceTop(): number {
         return this._sliceTop;
     }
@@ -150,6 +158,7 @@ export class Image extends Control {
     /**
      * Gets or sets the bottom value for slicing (9-patch)
      */
+    @serialize()
     public get sliceBottom(): number {
         return this._sliceBottom;
     }
@@ -167,6 +176,7 @@ export class Image extends Control {
     /**
      * Gets or sets the left coordinate in the source image
      */
+    @serialize()
     public get sourceLeft(): number {
         return this._sourceLeft;
     }
@@ -184,6 +194,7 @@ export class Image extends Control {
     /**
      * Gets or sets the top coordinate in the source image
      */
+    @serialize()
     public get sourceTop(): number {
         return this._sourceTop;
     }
@@ -201,6 +212,7 @@ export class Image extends Control {
     /**
      * Gets or sets the width to capture in the source image
      */
+    @serialize()
     public get sourceWidth(): number {
         return this._sourceWidth;
     }
@@ -218,6 +230,7 @@ export class Image extends Control {
     /**
      * Gets or sets the height to capture in the source image
      */
+    @serialize()
     public get sourceHeight(): number {
         return this._sourceHeight;
     }
@@ -246,6 +259,7 @@ export class Image extends Control {
      * Gets or sets a boolean indicating if the image can force its container to adapt its size
      * @see https://doc.babylonjs.com/how_to/gui#image
      */
+    @serialize()
     public get autoScale(): boolean {
         return this._autoScale;
     }
@@ -263,6 +277,7 @@ export class Image extends Control {
     }
 
     /** Gets or sets the streching mode used by the image */
+    @serialize()
     public get stretch(): number {
         return this._stretch;
     }

+ 18 - 0
gui/src/2D/controls/inputText.ts

@@ -11,6 +11,7 @@ import { VirtualKeyboard } from "./virtualKeyboard";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Measure } from '../measure';
 import { TextWrapper } from './textWrapper';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Class used to create input text control
@@ -52,8 +53,10 @@ export class InputText extends Control implements IFocusableControl {
     public _connectedVirtualKeyboard: Nullable<VirtualKeyboard>;
 
     /** Gets or sets a string representing the message displayed on mobile when the control gets the focus */
+    @serialize()
     public promptMessage = "Please enter text:";
     /** Force disable prompt on mobile device */
+    @serialize()
     public disableMobilePrompt = false;
 
     /** Observable raised when the text changes */
@@ -76,6 +79,7 @@ export class InputText extends Control implements IFocusableControl {
     public onKeyboardEventProcessedObservable = new Observable<KeyboardEvent>();
 
     /** Gets or sets the maximum width allowed by the control */
+    @serialize()
     public get maxWidth(): string | number {
         return this._maxWidth.toString(this._host);
     }
@@ -96,6 +100,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the text highlighter transparency; default: 0.4 */
+    @serialize()
     public get highligherOpacity(): number {
         return this._highligherOpacity;
     }
@@ -108,6 +113,7 @@ export class InputText extends Control implements IFocusableControl {
         this._markAsDirty();
     }
     /** Gets or sets a boolean indicating whether to select complete text by default on input focus */
+    @serialize()
     public get onFocusSelectAll(): boolean {
         return this._onFocusSelectAll;
     }
@@ -122,6 +128,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the text hightlight color */
+    @serialize()
     public get textHighlightColor(): string {
         return this._textHighlightColor;
     }
@@ -135,6 +142,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets control margin */
+    @serialize()
     public get margin(): string {
         return this._margin.toString(this._host);
     }
@@ -155,6 +163,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets a boolean indicating if the control can auto stretch its width to adapt to the text */
+    @serialize()
     public get autoStretchWidth(): boolean {
         return this._autoStretchWidth;
     }
@@ -169,6 +178,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets border thickness */
+    @serialize()
     public get thickness(): number {
         return this._thickness;
     }
@@ -183,6 +193,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the background color when focused */
+    @serialize()
     public get focusedBackground(): string {
         return this._focusedBackground;
     }
@@ -197,6 +208,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the background color when focused */
+    @serialize()
     public get focusedColor(): string {
         return this._focusedColor;
     }
@@ -211,6 +223,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -225,6 +238,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the placeholder color */
+    @serialize()
     public get placeholderColor(): string {
         return this._placeholderColor;
     }
@@ -239,6 +253,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the text displayed when the control is empty */
+    @serialize()
     public get placeholderText(): string {
         return this._placeholderText;
     }
@@ -252,6 +267,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the dead key flag */
+    @serialize()
     public get deadKey(): boolean {
         return this._deadKey;
     }
@@ -291,6 +307,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets the text displayed in the control */
+    @serialize()
     public get text(): string {
         return this._textWrapper.text;
     }
@@ -315,6 +332,7 @@ export class InputText extends Control implements IFocusableControl {
     }
 
     /** Gets or sets control width */
+    @serialize()
     public get width(): string | number {
         return this._width.toString(this._host);
     }

+ 7 - 0
gui/src/2D/controls/line.ts

@@ -8,6 +8,7 @@ import { Control } from "./control";
 import { ValueAndUnit } from "../valueAndUnit";
 import { Measure } from "../measure";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /** Class used to render 2D lines */
 export class Line extends Control {
@@ -21,6 +22,7 @@ export class Line extends Control {
     private _connectedControlDirtyObserver: Nullable<Observer<Control>>;
 
     /** Gets or sets the dash pattern */
+    @serialize()
     public get dash(): Array<number> {
         return this._dash;
     }
@@ -58,6 +60,7 @@ export class Line extends Control {
     }
 
     /** Gets or sets start coordinates on X axis */
+    @serialize()
     public get x1(): string | number {
         return this._x1.toString(this._host);
     }
@@ -73,6 +76,7 @@ export class Line extends Control {
     }
 
     /** Gets or sets start coordinates on Y axis */
+    @serialize()
     public get y1(): string | number {
         return this._y1.toString(this._host);
     }
@@ -88,6 +92,7 @@ export class Line extends Control {
     }
 
     /** Gets or sets end coordinates on X axis */
+    @serialize()
     public get x2(): string | number {
         return this._x2.toString(this._host);
     }
@@ -103,6 +108,7 @@ export class Line extends Control {
     }
 
     /** Gets or sets end coordinates on Y axis */
+    @serialize()
     public get y2(): string | number {
         return this._y2.toString(this._host);
     }
@@ -118,6 +124,7 @@ export class Line extends Control {
     }
 
     /** Gets or sets line width */
+    @serialize()
     public get lineWidth(): number {
         return this._lineWidth;
     }

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

@@ -6,6 +6,7 @@ import { MultiLinePoint } from "../multiLinePoint";
 import { Measure } from "../measure";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Vector3 } from "babylonjs/Maths/math.vector";
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Class used to create multi line control
@@ -38,6 +39,7 @@ export class MultiLine extends Control {
     }
 
     /** Gets or sets dash pattern */
+    @serialize()
     public get dash(): Array<number> {
         return this._dash;
     }

+ 6 - 0
gui/src/2D/controls/radioButton.ts

@@ -6,6 +6,7 @@ import { StackPanel } from "./stackPanel";
 import { TextBlock } from "./textBlock";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Class used to create radio button controls
@@ -17,6 +18,7 @@ export class RadioButton extends Control {
     private _thickness = 1;
 
     /** Gets or sets border thickness */
+    @serialize()
     public get thickness(): number {
         return this._thickness;
     }
@@ -31,12 +33,14 @@ export class RadioButton extends Control {
     }
 
     /** Gets or sets group name */
+    @serialize()
     public group = "";
 
     /** Observable raised when isChecked is changed */
     public onIsCheckedChangedObservable = new Observable<boolean>();
 
     /** Gets or sets a value indicating the ratio between overall size and check size */
+    @serialize()
     public get checkSizeRatio(): number {
         return this._checkSizeRatio;
     }
@@ -53,6 +57,7 @@ export class RadioButton extends Control {
     }
 
     /** Gets or sets background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -67,6 +72,7 @@ export class RadioButton extends Control {
     }
 
     /** Gets or sets a boolean indicating if the checkbox is checked or not */
+    @serialize()
     public get isChecked(): boolean {
         return this._isChecked;
     }

+ 3 - 0
gui/src/2D/controls/rectangle.ts

@@ -1,6 +1,7 @@
 import { Container } from "./container";
 import { Measure } from "../measure";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /** Class used to create rectangle container */
 export class Rectangle extends Container {
@@ -8,6 +9,7 @@ export class Rectangle extends Container {
     private _cornerRadius = 0;
 
     /** Gets or sets border thickness */
+    @serialize()
     public get thickness(): number {
         return this._thickness;
     }
@@ -22,6 +24,7 @@ export class Rectangle extends Container {
     }
 
     /** Gets or sets the corner radius angle */
+    @serialize()
     public get cornerRadius(): number {
         return this._cornerRadius;
     }

+ 10 - 0
gui/src/2D/controls/sliders/baseSlider.ts

@@ -4,6 +4,7 @@ import { Vector2 } from "babylonjs/Maths/math.vector";
 import { Control } from "../control";
 import { ValueAndUnit } from "../../valueAndUnit";
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from "babylonjs/Misc/decorators";
 
 /**
  * Class used to create slider controls
@@ -35,6 +36,7 @@ export class BaseSlider extends Control {
     public onValueChangedObservable = new Observable<number>();
 
     /** Gets or sets a boolean indicating if the thumb must be rendered */
+    @serialize()
     public get displayThumb(): boolean {
         return this._displayThumb;
     }
@@ -49,6 +51,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets a step to apply to values (0 by default) */
+    @serialize()
     public get step(): number {
         return this._step;
     }
@@ -63,6 +66,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets main bar offset (ie. the margin applied to the value bar) */
+    @serialize()
     public get barOffset(): string | number {
         return this._barOffset.toString(this._host);
     }
@@ -83,6 +87,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets thumb width */
+    @serialize()
     public get thumbWidth(): string | number {
         return this._thumbWidth.toString(this._host);
     }
@@ -103,6 +108,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets minimum value */
+    @serialize()
     public get minimum(): number {
         return this._minimum;
     }
@@ -119,6 +125,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets maximum value */
+    @serialize()
     public get maximum(): number {
         return this._maximum;
     }
@@ -135,6 +142,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets current value */
+    @serialize()
     public get value(): number {
         return this._value;
     }
@@ -152,6 +160,7 @@ export class BaseSlider extends Control {
     }
 
     /**Gets or sets a boolean indicating if the slider should be vertical or horizontal */
+    @serialize()
     public get isVertical(): boolean {
         return this._isVertical;
     }
@@ -166,6 +175,7 @@ export class BaseSlider extends Control {
     }
 
     /** Gets or sets a value indicating if the thumb can go over main bar extends */
+    @serialize()
     public get isThumbClamped(): boolean {
         return this._isThumbClamped;
     }

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

@@ -3,6 +3,7 @@ import { Measure } from "../../measure";
 import { Image } from "../image";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Nullable } from 'babylonjs/types';
+import { serialize } from "babylonjs/Misc/decorators";
 
 /**
  * Class used to create slider controls based on images
@@ -14,6 +15,7 @@ export class ImageBasedSlider extends BaseSlider {
 
     private _tempMeasure = new Measure(0, 0, 0, 0);
 
+    @serialize()
     public get displayThumb(): boolean {
         return this._displayThumb && this.thumbImage != null;
     }

+ 2 - 0
gui/src/2D/controls/sliders/imageScrollBar.ts

@@ -4,6 +4,7 @@ import { Control } from "../control";
 import { Image } from "../image";
 import { Measure } from "../../measure";
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from "babylonjs/Misc/decorators";
 
 /**
  * Class used to create slider controls
@@ -19,6 +20,7 @@ export class ImageScrollBar extends BaseSlider {
     private _tempMeasure = new Measure(0, 0, 0, 0);
 
     /** Number of 90° rotation to apply on the images when in vertical mode */
+    @serialize()
     public num90RotationInVerticalMode = 1;
 
     /**

+ 3 - 0
gui/src/2D/controls/sliders/scrollBar.ts

@@ -3,6 +3,7 @@ import { BaseSlider } from "./baseSlider";
 import { Control } from "../control";
 import { Measure } from "../../measure";
 import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
+import { serialize } from "babylonjs/Misc/decorators";
 
 /**
  * Class used to create slider controls
@@ -13,6 +14,7 @@ export class ScrollBar extends BaseSlider {
     private _tempMeasure = new Measure(0, 0, 0, 0);
 
     /** Gets or sets border color */
+    @serialize()
     public get borderColor(): string {
         return this._borderColor;
     }
@@ -27,6 +29,7 @@ export class ScrollBar extends BaseSlider {
     }
 
     /** Gets or sets background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }

+ 6 - 0
gui/src/2D/controls/sliders/slider.ts

@@ -2,6 +2,7 @@ import { BaseSlider } from "./baseSlider";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 import { Nullable } from 'babylonjs/types';
 import { Measure } from '../../measure';
+import { serialize } from "babylonjs/Misc/decorators";
 
 /**
  * Class used to create slider controls
@@ -14,6 +15,7 @@ export class Slider extends BaseSlider {
     protected _displayValueBar = true;
 
     /** Gets or sets a boolean indicating if the value bar must be rendered */
+    @serialize()
     public get displayValueBar(): boolean {
         return this._displayValueBar;
     }
@@ -28,6 +30,7 @@ export class Slider extends BaseSlider {
     }
 
     /** Gets or sets border color */
+    @serialize()
     public get borderColor(): string {
         return this._borderColor;
     }
@@ -42,6 +45,7 @@ export class Slider extends BaseSlider {
     }
 
     /** Gets or sets background color */
+    @serialize()
     public get background(): string {
         return this._background;
     }
@@ -56,6 +60,7 @@ export class Slider extends BaseSlider {
     }
 
     /** Gets or sets thumb's color */
+    @serialize()
     public get thumbColor(): string {
         return this._thumbColor;
     }
@@ -70,6 +75,7 @@ export class Slider extends BaseSlider {
     }
 
     /** Gets or sets a boolean indicating if the thumb should be round or square */
+    @serialize()
     public get isThumbCircle(): boolean {
         return this._isThumbCircle;
     }

+ 25 - 0
gui/src/2D/controls/stackPanel.ts

@@ -4,6 +4,8 @@ import { Container } from "./container";
 import { Measure } from "../measure";
 import { Control } from "./control";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
+import { serialize } from 'babylonjs/Misc/decorators';
+import { AdvancedDynamicTexture } from "../advancedDynamicTexture";
 
 /**
  * Class used to create a 2D stack panel container
@@ -17,9 +19,11 @@ export class StackPanel extends Container {
     /**
      * Gets or sets a boolean indicating that layou warnings should be ignored
      */
+    @serialize()
     public ignoreLayoutWarnings = false;
 
     /** Gets or sets a boolean indicating if the stack panel is vertical or horizontal*/
+    @serialize()
     public get isVertical(): boolean {
         return this._isVertical;
     }
@@ -37,6 +41,7 @@ export class StackPanel extends Container {
      * Gets or sets panel width.
      * This value should not be set when in horizontal mode as it will be computed automatically
      */
+    @serialize()
     public set width(value: string | number) {
         if (!this._doNotTrackManualChanges) {
             this._manualWidth = true;
@@ -59,6 +64,7 @@ export class StackPanel extends Container {
      * Gets or sets panel height.
      * This value should not be set when in vertical mode as it will be computed automatically
      */
+    @serialize()
     public set height(value: string | number) {
         if (!this._doNotTrackManualChanges) {
             this._manualHeight = true;
@@ -196,5 +202,24 @@ export class StackPanel extends Container {
 
         super._postMeasure();
     }
+
+    /**
+     * Serializes the current control
+     * @param serializationObject defined the JSON serialized object
+     */
+    public serialize(serializationObject: any) {
+        super.serialize(serializationObject);
+        serializationObject.manualWidth = this._manualWidth;
+        serializationObject.manualHeight = this._manualHeight;
+    }
+
+    /** @hidden */
+    public _parseFromContent(serializedObject: any, host: AdvancedDynamicTexture) {
+        this._manualWidth = serializedObject.manualWidth;
+        this._manualHeight = serializedObject.manualHeight;
+
+        super._parseFromContent(serializedObject, host);
+    }
+
 }
 _TypeStore.RegisteredTypes["BABYLON.GUI.StackPanel"] = StackPanel;

+ 12 - 0
gui/src/2D/controls/textBlock.ts

@@ -4,6 +4,7 @@ import { ValueAndUnit } from "../valueAndUnit";
 import { Control } from "./control";
 import { _TypeStore } from "babylonjs/Misc/typeStore";
 import { Nullable } from "babylonjs/types";
+import { serialize } from 'babylonjs/Misc/decorators';
 
 /**
  * Enum that determines the text-wrapping mode to use.
@@ -66,6 +67,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
      */
+    @serialize()
     public get resizeToFit(): boolean {
         return this._resizeToFit;
     }
@@ -90,6 +92,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets a boolean indicating if text must be wrapped
      */
+    @serialize()
     public get textWrapping(): TextWrapping | boolean {
         return this._textWrapping;
     }
@@ -108,6 +111,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets text to display
      */
+    @serialize()
     public get text(): string {
         return this._text;
     }
@@ -128,6 +132,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
      */
+    @serialize()
     public get textHorizontalAlignment(): number {
         return this._textHorizontalAlignment;
     }
@@ -147,6 +152,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
      */
+    @serialize()
     public get textVerticalAlignment(): number {
         return this._textVerticalAlignment;
     }
@@ -166,6 +172,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets line spacing value
      */
+    @serialize()
     public set lineSpacing(value: string | number) {
         if (this._lineSpacing.fromString(value)) {
             this._markAsDirty();
@@ -182,6 +189,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets outlineWidth of the text to display
      */
+    @serialize()
     public get outlineWidth(): number {
         return this._outlineWidth;
     }
@@ -200,6 +208,8 @@ export class TextBlock extends Control {
     /**
      * Gets or sets a boolean indicating that text must have underline
      */
+    @serialize()
+
     public get underline(): boolean {
         return this._underline;
     }
@@ -218,6 +228,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets an boolean indicating that text must be crossed out
      */
+    @serialize()
     public get lineThrough(): boolean {
         return this._lineThrough;
     }
@@ -236,6 +247,7 @@ export class TextBlock extends Control {
     /**
      * Gets or sets outlineColor of the text to display
      */
+    @serialize()
     public get outlineColor(): string {
         return this._outlineColor;
     }

+ 2 - 1
loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts

@@ -37,7 +37,7 @@ class TransmissionHelper {
      */
     private static _getDefaultOptions(): ITransmissionHelperOptions {
         return {
-            renderSize: 512
+            renderSize: 1024
         };
     }
 
@@ -211,6 +211,7 @@ class TransmissionHelper {
         this._opaqueRenderTarget.gammaSpace = true;
         this._opaqueRenderTarget.lodGenerationScale = 1;
         this._opaqueRenderTarget.lodGenerationOffset = -4;
+        this._opaqueRenderTarget.samples = 4;
 
         if (opaqueRTIndex >= 0) {
             this._scene.customRenderTargets.splice(opaqueRTIndex, 0, this._opaqueRenderTarget);

+ 24 - 19
sandbox/src/components/renderingZone.tsx

@@ -35,6 +35,7 @@ function isTextureAsset(name: string): boolean {
 interface IRenderingZoneProps {
     globalState: GlobalState;
     assetUrl?: string;
+    autoRotate?: boolean;
     cameraPosition?: Vector3;
     expanded: boolean;
 }
@@ -149,29 +150,33 @@ export class RenderingZone extends React.Component<IRenderingZoneProps> {
 
             camera = this._scene.activeCamera! as ArcRotateCamera;
 
-            if (this.props.cameraPosition) {
-                camera.setPosition(this.props.cameraPosition);
-            } else {
-                if (this._currentPluginName === "gltf") {
-                    // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
-                    camera.alpha += Math.PI;
-                }
+            if (this._currentPluginName === "gltf") {
+                // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
+                camera.alpha += Math.PI;
+            }
 
-                // Enable camera's behaviors
-                camera.useFramingBehavior = true;
+            // Enable camera's behaviors
+            camera.useFramingBehavior = true;
 
-                var framingBehavior = camera.getBehaviorByName("Framing") as FramingBehavior;
-                framingBehavior.framingTime = 0;
-                framingBehavior.elevationReturnTime = -1;
+            var framingBehavior = camera.getBehaviorByName("Framing") as FramingBehavior;
+            framingBehavior.framingTime = 0;
+            framingBehavior.elevationReturnTime = -1;
 
-                if (this._scene.meshes.length) {
-                    camera.lowerRadiusLimit = null;
+            if (this._scene.meshes.length) {
+                camera.lowerRadiusLimit = null;
 
-                    var worldExtends = this._scene.getWorldExtends(function (mesh) {
-                        return mesh.isVisible && mesh.isEnabled();
-                    });
-                    framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
-                }
+                var worldExtends = this._scene.getWorldExtends(function (mesh) {
+                    return mesh.isVisible && mesh.isEnabled();
+                });
+                framingBehavior.zoomOnBoundingInfo(worldExtends.min, worldExtends.max);
+            }
+
+            if (this.props.autoRotate) {
+                camera.useAutoRotationBehavior = true;
+            }
+
+            if (this.props.cameraPosition) {
+                camera.setPosition(this.props.cameraPosition);
             }
 
             camera.pinchPrecision = 200 / camera.radius;

+ 6 - 0
sandbox/src/sandbox.tsx

@@ -15,6 +15,7 @@ interface ISandboxProps {
 export class Sandbox extends React.Component<ISandboxProps, { isFooterVisible: boolean, errorMessage: string }> {
     private _globalState: GlobalState;
     private _assetUrl?: string;
+    private _autoRotate?: boolean;
     private _cameraPosition?: Vector3;
     private _logoRef: React.RefObject<HTMLImageElement>;
     private _dropTextRef: React.RefObject<HTMLDivElement>;
@@ -90,6 +91,10 @@ export class Sandbox extends React.Component<ISandboxProps, { isFooterVisible: b
                         this._assetUrl = value;
                         break;
                     }
+                    case "autoRotate": {
+                        this._autoRotate = !!value;
+                        break;
+                    }
                     case "cameraPosition": {
                         this._cameraPosition = Vector3.FromArray(value.split(",").map(function (component) { return +component; }));
                         break;
@@ -115,6 +120,7 @@ export class Sandbox extends React.Component<ISandboxProps, { isFooterVisible: b
                 <p id="droptext" ref={this._dropTextRef}>Drag and drop gltf, glb, obj or babylon files to view them</p>
                 <RenderingZone globalState={this._globalState}
                     assetUrl={this._assetUrl}
+                    autoRotate={this._autoRotate}
                     cameraPosition={this._cameraPosition}
                     expanded={!this.state.isFooterVisible} />
                 <div ref={this._clickInterceptorRef}

+ 8 - 5
src/Engines/Processors/shaderProcessor.ts

@@ -301,8 +301,8 @@ export class ShaderProcessor {
     }
 
     private static _ProcessIncludes(sourceCode: string, options: ProcessingOptions, callback: (data: any) => void): void {
-        var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
-        var match = regex.exec(sourceCode);
+        const regexShaderInclude = /#include\s?<(.+)>(\((.*)\))*(\[(.*)\])*/g;
+        var match = regexShaderInclude.exec(sourceCode);
 
         var returnValue = new String(sourceCode);
         var keepProcessing = false;
@@ -371,7 +371,10 @@ export class ShaderProcessor {
                 // Replace
                 returnValue = returnValue.replace(match[0], includeContent);
 
-                keepProcessing = keepProcessing || includeContent.indexOf("#include<") >= 0;
+                keepProcessing =
+                    keepProcessing ||
+                    includeContent.indexOf("#include<") >= 0 ||
+                    includeContent.indexOf("#include <") >= 0;
             } else {
                 var includeShaderUrl = options.shadersRepository + "ShadersInclude/" + includeFile + ".fx";
 
@@ -382,7 +385,7 @@ export class ShaderProcessor {
                 return;
             }
 
-            match = regex.exec(sourceCode);
+            match = regexShaderInclude.exec(sourceCode);
         }
 
         if (keepProcessing) {
@@ -406,4 +409,4 @@ export class ShaderProcessor {
     public static _FileToolsLoadFile(url: string, onSuccess: (data: string | ArrayBuffer, responseURL?: string) => void, onProgress?: (ev: ProgressEvent) => void, offlineProvider?: IOfflineProvider, useArrayBuffer?: boolean, onError?: (request?: WebRequest, exception?: LoadFileError) => void): IFileRequest {
         throw  _DevTools.WarnImport("FileTools");
     }
-}
+}

+ 29 - 0
src/Engines/engineFactory.ts

@@ -0,0 +1,29 @@
+import { Engine } from "./engine";
+import { NullEngine } from "./nullEngine";
+import { ThinEngine } from "./thinEngine";
+import { WebGPUEngine } from "./webgpuEngine";
+
+/**
+ * Helper class to create the best engine depending on the current hardware
+ */
+export class EngineFactory {
+
+    /**
+     * Creates an engine based on the capabilities of the underlying hardware
+     * @param canvas Defines the canvas to use to display the result
+     * @param options Defines the options passed to the engine to create the context dependencies
+     * @returns a promise that resolves with the created engine
+     */
+    public static CreateAsync(canvas: HTMLCanvasElement, options: any): Promise<ThinEngine> {
+        if (WebGPUEngine.IsSupported) {
+            return WebGPUEngine.CreateAsync(canvas, options);
+        } else if (Engine.IsSupported) {
+            return new Promise((resolve) => {
+                resolve(new Engine(canvas, undefined, options));
+            });
+        }
+        return new Promise((resolve) => {
+            resolve(new NullEngine(options));
+        });
+    }
+}

+ 1 - 0
src/Engines/index.ts

@@ -15,3 +15,4 @@ export * from "./nativeEngine";
 export * from "./Processors/shaderCodeInliner";
 export * from "./performanceConfigurator";
 export * from "./engineFeatures";
+export * from "./engineFactory";

+ 9 - 2
src/Engines/thinEngine.ts

@@ -136,6 +136,11 @@ export interface EngineOptions extends WebGLContextAttributes {
      * Will prevent the system from falling back to software implementation if a hardware device cannot be created
      */
     failIfMajorPerformanceCaveat?: boolean;
+
+    /**
+     * Defines whether to adapt to the device's viewport characteristics (default: false)
+     */
+    adaptToDeviceRatio?: boolean;
 }
 
 /**
@@ -549,7 +554,7 @@ export class ThinEngine {
      * @param options defines further options to be sent to the getContext() function
      * @param adaptToDeviceRatio defines whether to adapt to the device's viewport characteristics (default: false)
      */
-    constructor(canvasOrContext: Nullable<HTMLCanvasElement | OffscreenCanvas | WebGLRenderingContext | WebGL2RenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio: boolean = false) {
+    constructor(canvasOrContext: Nullable<HTMLCanvasElement | OffscreenCanvas | WebGLRenderingContext | WebGL2RenderingContext>, antialias?: boolean, options?: EngineOptions, adaptToDeviceRatio?: boolean) {
 
         let canvas: Nullable<HTMLCanvasElement> = null;
 
@@ -561,11 +566,13 @@ export class ThinEngine {
             return;
         }
 
+        adaptToDeviceRatio = adaptToDeviceRatio ?? options.adaptToDeviceRatio ?? false;
+
         if ((canvasOrContext as any).getContext) {
             canvas = <HTMLCanvasElement>canvasOrContext;
             this._renderingCanvas = canvas;
 
-            if (antialias != null) {
+            if (antialias !== undefined) {
                 options.antialias = antialias;
             }
 

+ 32 - 4
src/Engines/webgpuEngine.ts

@@ -131,6 +131,11 @@ export interface WebGPUEngineOptions extends GPURequestAdapterOptions {
      * Defines wether we should generate debug markers in the gpu command lists (can be seen with PIX for eg)
      */
     enableGPUDebugMarkers?: boolean;
+
+    /**
+     * Options to load the associated Glslang library
+     */
+    glslangOptions?: GlslangOptions;
 }
 
 /**
@@ -229,6 +234,14 @@ export class WebGPUEngine extends Engine {
     public dbgShowWarningsNotImplemented = false;
 
     /**
+     * Gets a boolean indicating if the engine can be instanciated (ie. if a WebGPU context can be found)
+     * @returns true if the engine can be created
+     */
+    public static get IsSupported(): boolean {
+        return !!navigator.gpu;
+    }
+
+    /**
      * Gets a boolean indicating that the engine supports uniform buffers
      */
     public get supportsUniformBuffers(): boolean {
@@ -269,6 +282,20 @@ export class WebGPUEngine extends Engine {
     }
 
     /**
+     * Create a new instance of the gpu engine asynchronously
+     * @param canvas Defines the canvas to use to display the result
+     * @param options Defines the options passed to the engine to create the GPU context dependencies
+     * @returns a promise that resolves with the created engine
+     */
+    public static CreateAsync(canvas: HTMLCanvasElement, options: WebGPUEngineOptions = {}): Promise<WebGPUEngine> {
+        const engine = new WebGPUEngine(canvas, options);
+
+        return new Promise((resolve) => {
+            engine.initAsync(options.glslangOptions).then(() => resolve(engine));
+        });
+    }
+
+    /**
      * Create a new instance of the gpu engine.
      * @param canvas Defines the canvas to use to display the result
      * @param options Defines the options passed to the engine to create the GPU context dependencies
@@ -337,7 +364,7 @@ export class WebGPUEngine extends Engine {
      * @returns a promise notifying the readiness of the engine.
      */
     public initAsync(glslangOptions?: GlslangOptions): Promise<void> {
-        return this._initGlslang(glslangOptions)
+        return this._initGlslang(glslangOptions ?? this._options?.glslangOptions)
             .then((glslang: any) => {
                 this._glslang = glslang;
                 return navigator.gpu!.requestAdapter(this._options);
@@ -484,7 +511,7 @@ export class WebGPUEngine extends Engine {
             supportRenderAndCopyToLodForFloatTextures: true,
             supportDepthStencilTexture: true,
             supportShadowSamplers: true,
-            uniformBufferHardCheckMatrix: true,
+            uniformBufferHardCheckMatrix: false,
             allowTexturePrefiltering: true,
             trackUbosInFrame: true,
             supportCSM: true,
@@ -2950,7 +2977,7 @@ export class WebGPUEngine extends Engine {
      * Restores the WebGPU state to only draw on the main color attachment
      */
     public restoreSingleAttachment(): void {
-        this.bindAttachments([]);
+        // nothing to do, this is done automatically in the unBindFramebuffer function
     }
 
     /**
@@ -2977,7 +3004,7 @@ export class WebGPUEngine extends Engine {
      * @param attachments index of attachments
      */
     public bindAttachments(attachments: number[]): void {
-        this._mrtAttachments = attachments;
+        // nothing to do, this is done automatically in the _startRenderTargetRenderPass function
     }
 
     /**
@@ -3087,6 +3114,7 @@ export class WebGPUEngine extends Engine {
 
         this._currentRenderTarget = null;
 
+        this._mrtAttachments = [];
         this._currentRenderPass = this._mainRenderPassWrapper.renderPass;
         this._setDepthTextureFormat(this._mainRenderPassWrapper);
         this._setColorFormat(this._mainRenderPassWrapper);

+ 21 - 0
src/LibDeclarations/webxr.d.ts

@@ -44,6 +44,7 @@ interface XRLayer extends EventTarget {}
 interface XRSessionInit {
     optionalFeatures?: string[];
     requiredFeatures?: string[];
+    trackedImages?: XRTrackedImageInit[];
 }
 
 interface XRSessionEvent extends Event {
@@ -143,6 +144,8 @@ interface XRFrame {
     worldInformation?: XRWorldInformation;
     // Hand tracking
     getJointPose?(joint: XRJointSpace, baseSpace: XRSpace): XRJointPose;
+    // Image tracking
+    getImageTrackingResults?(): Array<XRImageTrackingResult>;
 }
 
 interface XRInputSourceEvent extends Event {
@@ -214,6 +217,9 @@ interface XRSession {
 
     // legacy plane detection
     updateWorldTrackingState?(options: { planeDetectionState?: { enabled: boolean } }): void;
+
+    // image tracking
+    getTrackedImageScores?(): XRImageTrackingScore[];
 }
 
 interface XRViewerPose extends XRPose {
@@ -345,3 +351,18 @@ interface XRHand extends Iterable<XRJointSpace> {
     readonly LITTLE_PHALANX_DISTAL: number;
     readonly LITTLE_PHALANX_TIP: number;
 }
+
+type XRImageTrackingState = "tracked" | "emulated";
+type XRImageTrackingScore = "untrackable" | "trackable";
+
+interface XRTrackedImageInit {
+    image: ImageBitmap;
+    widthInMeters: number;
+}
+
+interface XRImageTrackingResult {
+    readonly imageSpace: XRSpace;
+    readonly index: number;
+    readonly trackingState: XRImageTrackingState;
+    readonly measuredWidthInMeters: number;
+}

+ 303 - 0
src/XR/features/WebXRImageTracking.ts

@@ -0,0 +1,303 @@
+import { WebXRFeaturesManager, WebXRFeatureName } from "../webXRFeaturesManager";
+import { WebXRSessionManager } from "../webXRSessionManager";
+import { Observable } from "../../Misc/observable";
+import { WebXRAbstractFeature } from "./WebXRAbstractFeature";
+import { Matrix } from "../../Maths/math.vector";
+import { Tools } from "../../Misc/tools";
+import { Nullable } from "../../types";
+
+declare const XRImageTrackingResult: XRImageTrackingResult;
+
+/**
+ * Options interface for the background remover plugin
+ */
+export interface IWebXRImageTrackingOptions {
+    /**
+     * A required array with images to track
+     */
+    images: {
+        /**
+         * The source of the image. can be a URL or an image bitmap
+         */
+        src: string | ImageBitmap;
+        /**
+         * The estimated width in the real world (in meters)
+         */
+        estimatedRealWorldWidth: number; // In meters!
+    }[];
+}
+
+/**
+ * An object representing an image tracked by the system
+ */
+export interface IWebXRTrackedImage {
+    /**
+     * The ID of this image (which is the same as the position in the array that was used to initialize the feature)
+     */
+    id: number;
+    /**
+     * Is the transformation provided emulated. If it is, the system "guesses" its real position. Otherwise it can be considered as exact position.
+     */
+    emulated?: boolean;
+    /**
+     * Just in case it is needed - the image bitmap that is being tracked
+     */
+    originalBitmap: ImageBitmap;
+    /**
+     * The native XR result image tracking result, untouched
+     */
+    xrTrackingResult?: XRImageTrackingResult;
+    /**
+     * Width in real world (meters)
+     */
+    realWorldWidth?: number;
+    /**
+     * A transformation matrix of this current image in the current reference space.
+     */
+    transformationMatrix: Matrix;
+    /**
+     * The width/height ratio of this image. can be used to calculate the size of the detected object/image
+     */
+    ratio?: number;
+}
+
+/**
+ * Image tracking for immersive AR sessions.
+ * Providing a list of images and their estimated widths will enable tracking those images in the real world.
+ */
+export class WebXRImageTracking extends WebXRAbstractFeature {
+    /**
+     * The module's name
+     */
+    public static readonly Name = WebXRFeatureName.IMAGE_TRACKING;
+    /**
+     * The (Babylon) version of this module.
+     * This is an integer representing the implementation version.
+     * This number does not correspond to the WebXR specs version
+     */
+    public static readonly Version = 1;
+
+    /**
+     * This will be triggered if the underlying system deems an image untrackable.
+     * The index is the index of the image from the array used to initialize the feature.
+     */
+    public onUntrackableImageFoundObservable: Observable<number> = new Observable();
+    /**
+     * An image was deemed trackable, and the system will start tracking it.
+     */
+    public onTrackableImageFoundObservable: Observable<IWebXRTrackedImage> = new Observable();
+    /**
+     * The image was found and its state was updated.
+     */
+    public onTrackedImageUpdatedObservable: Observable<IWebXRTrackedImage> = new Observable();
+
+    private _trackedImages: IWebXRTrackedImage[] = [];
+
+    private _originalTrackingRequest: XRTrackedImageInit[];
+
+    /**
+     * constructs the image tracking feature
+     * @param _xrSessionManager the session manager for this module
+     * @param options read-only options to be used in this module
+     */
+    constructor(
+        _xrSessionManager: WebXRSessionManager,
+        /**
+         * read-only options to be used in this module
+         */
+        public readonly options: IWebXRImageTrackingOptions
+    ) {
+        super(_xrSessionManager);
+        this.xrNativeFeatureName = "image-tracking";
+        if (this.options.images.length === 0) {
+            // no images provided?... return.
+            return;
+        }
+        if (this._xrSessionManager.session) {
+            this._init();
+        } else {
+            this._xrSessionManager.onXRSessionInit.addOnce(() => {
+                this._init();
+            });
+        }
+    }
+
+    /**
+     * attach this feature
+     * Will usually be called by the features manager
+     *
+     * @returns true if successful.
+     */
+    public attach(): boolean {
+        return super.attach();
+    }
+
+    /**
+     * detach this feature.
+     * Will usually be called by the features manager
+     *
+     * @returns true if successful.
+     */
+    public detach(): boolean {
+        return super.detach();
+    }
+
+    /**
+     * Check if the needed objects are defined.
+     * This does not mean that the feature is enabled, but that the objects needed are well defined.
+     */
+    public isCompatible(): boolean {
+        return typeof XRImageTrackingResult !== "undefined";
+    }
+
+    /**
+     * Get a tracked image by its ID.
+     *
+     * @param id the id of the image to load (position in the init array)
+     * @returns a trackable image, if exists in this location
+     */
+    public getTrackedImageById(id: number): Nullable<IWebXRTrackedImage> {
+        return this._trackedImages[id] || null;
+    }
+
+    /**
+     * Dispose this feature and all of the resources attached
+     */
+    public dispose(): void {
+        super.dispose();
+        this._trackedImages.forEach((trackedImage) => {
+            trackedImage.originalBitmap.close();
+        });
+        this._trackedImages.length = 0;
+        this.onTrackableImageFoundObservable.clear();
+        this.onUntrackableImageFoundObservable.clear();
+        this.onTrackedImageUpdatedObservable.clear();
+    }
+
+    /**
+     * Extends the session init object if needed
+     * @returns augmentation object fo the xr session init object.
+     */
+    public async getXRSessionInitExtension(): Promise<Partial<XRSessionInit>> {
+        if (!this.options.images || !this.options.images.length) {
+            return {};
+        }
+        const promises = this.options.images.map((image) => {
+            if (typeof image.src === "string") {
+                const p = new Promise<ImageBitmap>((resolve, reject) => {
+                    if (typeof image.src === "string") {
+                        const img = new Image();
+                        img.src = image.src;
+                        img.onload = () => {
+                            img.decode().then(() => {
+                                createImageBitmap(img).then((imageBitmap) => {
+                                    resolve(imageBitmap);
+                                });
+                            });
+                        };
+                        img.onerror = () => {
+                            Tools.Error(`Error loading image ${image.src}`);
+                            reject(`Error loading image ${image.src}`);
+                        };
+                    }
+                });
+                return p;
+            } else {
+                return Promise.resolve(image.src); // resolve is probably unneeded
+            }
+        });
+
+        const images = await Promise.all(promises);
+
+        this._originalTrackingRequest = images.map((image, idx) => {
+            return {
+                image,
+                widthInMeters: this.options.images[idx].estimatedRealWorldWidth,
+            };
+        });
+
+        return {
+            trackedImages: this._originalTrackingRequest,
+        };
+    }
+
+    protected _onXRFrame(_xrFrame: XRFrame) {
+        if (!_xrFrame.getImageTrackingResults) {
+            return;
+        }
+        const imageTrackedResults = _xrFrame.getImageTrackingResults();
+        for (const result of imageTrackedResults) {
+            let changed = false;
+            const imageIndex = result.index;
+
+            const imageObject = this._trackedImages[imageIndex];
+            if (!imageObject) {
+                // something went wrong!
+                continue;
+            }
+
+            imageObject.xrTrackingResult = result;
+            if (imageObject.realWorldWidth !== result.measuredWidthInMeters) {
+                imageObject.realWorldWidth = result.measuredWidthInMeters;
+                changed = true;
+            }
+
+            // Get the pose of the image relative to a reference space.
+            const pose = _xrFrame.getPose(result.imageSpace, this._xrSessionManager.referenceSpace);
+
+            if (pose) {
+                const mat = imageObject.transformationMatrix;
+                Matrix.FromArrayToRef(pose.transform.matrix, 0, mat);
+                if (!this._xrSessionManager.scene.useRightHandedSystem) {
+                    mat.toggleModelMatrixHandInPlace();
+                }
+                changed = true;
+            }
+
+            const state = result.trackingState;
+            const emulated = state === "emulated";
+
+            if (imageObject.emulated !== emulated) {
+                imageObject.emulated = emulated;
+                changed = true;
+            }
+            if (changed) {
+                this.onTrackedImageUpdatedObservable.notifyObservers(imageObject);
+            }
+        }
+    }
+
+    private async _init() {
+        if (!this._xrSessionManager.session.getTrackedImageScores) {
+            return;
+        }
+        //
+        const imageScores = await this._xrSessionManager.session.getTrackedImageScores();
+        // check the scores for all
+        for (let idx = 0; idx < imageScores.length; ++idx) {
+            if (imageScores[idx] == "untrackable") {
+                this.onUntrackableImageFoundObservable.notifyObservers(idx);
+            } else {
+                const originalBitmap = this._originalTrackingRequest[idx].image;
+                const imageObject: IWebXRTrackedImage = {
+                    id: idx,
+                    originalBitmap,
+                    transformationMatrix: new Matrix(),
+                    ratio: originalBitmap.width / originalBitmap.height,
+                };
+                this._trackedImages[idx] = imageObject;
+                this.onTrackableImageFoundObservable.notifyObservers(imageObject);
+            }
+        }
+    }
+}
+
+//register the plugin
+WebXRFeaturesManager.AddWebXRFeature(
+    WebXRImageTracking.Name,
+    (xrSessionManager, options) => {
+        return () => new WebXRImageTracking(xrSessionManager, options);
+    },
+    WebXRImageTracking.Version,
+    false
+);

+ 1 - 0
src/XR/features/index.ts

@@ -10,3 +10,4 @@ export * from "./WebXRHitTest";
 export * from "./WebXRFeaturePointSystem";
 export * from "./WebXRHandTracking";
 export * from "./WebXRMeshDetector";
+export * from "./WebXRImageTracking";

+ 52 - 61
src/XR/webXRExperienceHelper.ts

@@ -97,7 +97,7 @@ export class WebXRExperienceHelper implements IDisposable {
      * @param sessionCreationOptions optional XRSessionInit object to init the session with
      * @returns promise that resolves after xr mode has entered
      */
-    public enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget = this.sessionManager.getWebXRRenderTarget(), sessionCreationOptions: XRSessionInit = {}): Promise<WebXRSessionManager> {
+    public async enterXRAsync(sessionMode: XRSessionMode, referenceSpaceType: XRReferenceSpaceType, renderTarget: WebXRRenderTarget = this.sessionManager.getWebXRRenderTarget(), sessionCreationOptions: XRSessionInit = {}): Promise<WebXRSessionManager> {
         if (!this._supported) {
             throw "WebXR not supported in this browser or environment";
         }
@@ -106,77 +106,68 @@ export class WebXRExperienceHelper implements IDisposable {
             sessionCreationOptions.optionalFeatures = sessionCreationOptions.optionalFeatures || [];
             sessionCreationOptions.optionalFeatures.push(referenceSpaceType);
         }
-        this.featuresManager.extendXRSessionInitObject(sessionCreationOptions);
+        sessionCreationOptions = await this.featuresManager._extendXRSessionInitObject(sessionCreationOptions);
         // we currently recommend "unbounded" space in AR (#7959)
         if (sessionMode === "immersive-ar" && referenceSpaceType !== "unbounded") {
             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
-            .initializeSessionAsync(sessionMode, sessionCreationOptions)
-            .then(() => {
-                return this.sessionManager.setReferenceSpaceTypeAsync(referenceSpaceType);
-            })
-            .then(() => {
-                return renderTarget.initializeXRLayerAsync(this.sessionManager.session);
-            })
-            .then(() => {
-                return this.sessionManager.updateRenderStateAsync({
-                    depthFar: this.camera.maxZ,
-                    depthNear: this.camera.minZ,
-                    baseLayer: renderTarget.xrLayer!,
+        try {
+            await this.sessionManager.initializeSessionAsync(sessionMode, sessionCreationOptions);
+            await this.sessionManager.setReferenceSpaceTypeAsync(referenceSpaceType);
+            await renderTarget.initializeXRLayerAsync(this.sessionManager.session);
+            await this.sessionManager.updateRenderStateAsync({
+                depthFar: this.camera.maxZ,
+                depthNear: this.camera.minZ,
+                baseLayer: renderTarget.xrLayer!,
+            });
+            // run the render loop
+            this.sessionManager.runXRRenderLoop();
+            // Cache pre xr scene settings
+            this._originalSceneAutoClear = this.scene.autoClear;
+            this._nonVRCamera = this.scene.activeCamera;
+
+            this.scene.activeCamera = this.camera;
+            // do not compensate when AR session is used
+            if (sessionMode !== "immersive-ar") {
+                this._nonXRToXRCamera();
+            } else {
+                // Kept here, TODO - check if needed
+                this.scene.autoClear = false;
+                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
+                this.camera.rigCameras.forEach((c) => {
+                    c.outputRenderTarget = null;
                 });
-            })
-            .then(() => {
-                // run the render loop
-                this.sessionManager.runXRRenderLoop();
-                // Cache pre xr scene settings
-                this._originalSceneAutoClear = this.scene.autoClear;
-                this._nonVRCamera = this.scene.activeCamera;
-
-                this.scene.activeCamera = this.camera;
-                // do not compensate when AR session is used
-                if (sessionMode !== "immersive-ar") {
-                    this._nonXRToXRCamera();
-                } else {
-                    // Kept here, TODO - check if needed
-                    this.scene.autoClear = false;
-                    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
-                    this.camera.rigCameras.forEach((c) => {
-                        c.outputRenderTarget = null;
-                    });
 
-                    // Restore scene settings
-                    this.scene.autoClear = this._originalSceneAutoClear;
-                    this.scene.activeCamera = this._nonVRCamera;
-                    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);
-                        }
+                // Restore scene settings
+                this.scene.autoClear = this._originalSceneAutoClear;
+                this.scene.activeCamera = this._nonVRCamera;
+                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);
-                });
-
-                // Wait until the first frame arrives before setting state to in xr
-                this.sessionManager.onXRFrameObservable.addOnce(() => {
-                    this._setState(WebXRState.IN_XR);
-                });
-
-                return this.sessionManager;
-            })
-            .catch((e: any) => {
-                console.log(e);
-                console.log(e.message);
                 this._setState(WebXRState.NOT_IN_XR);
-                throw e;
             });
+
+            // Wait until the first frame arrives before setting state to in xr
+            this.sessionManager.onXRFrameObservable.addOnce(() => {
+                this._setState(WebXRState.IN_XR);
+            });
+            return this.sessionManager;
+        } catch (e) {
+            console.log(e);
+            console.log(e.message);
+            this._setState(WebXRState.NOT_IN_XR);
+            throw e;
+        }
     }
 
     /**

+ 20 - 4
src/XR/webXRFeaturesManager.ts

@@ -53,6 +53,11 @@ export interface IWebXRFeature extends IDisposable {
      * A list of (Babylon WebXR) features this feature depends on
      */
     dependsOn?: string[];
+
+    /**
+     * If this feature requires to extend the XRSessionInit object, this function will return the partial XR session init object
+     */
+    getXRSessionInitExtension?: () => Promise<Partial<XRSessionInit>>;
 }
 
 /**
@@ -99,6 +104,10 @@ export class WebXRFeatureName {
      * The name of the hand tracking feature.
      */
     public static readonly HAND_TRACKING = "xr-hand-tracking";
+    /**
+     * The name of the image tracking feature
+     */
+    public static readonly IMAGE_TRACKING = "xr-image-tracking";
 }
 
 /**
@@ -384,16 +393,16 @@ export class WebXRFeaturesManager implements IDisposable {
     }
 
     /**
-     * This function will exten the session creation configuration object with enabled features.
+     * This function will extend the session creation configuration object with enabled features.
      * If, for example, the anchors feature is enabled, it will be automatically added to the optional or required features list,
      * according to the defined "required" variable, provided during enableFeature call
      * @param xrSessionInit the xr Session init object to extend
      *
      * @returns an extended XRSessionInit object
      */
-    public extendXRSessionInitObject(xrSessionInit: XRSessionInit): XRSessionInit {
+    public async _extendXRSessionInitObject(xrSessionInit: XRSessionInit): Promise<XRSessionInit> {
         const enabledFeatures = this.getEnabledFeatures();
-        enabledFeatures.forEach((featureName) => {
+        for (const featureName of enabledFeatures) {
             const feature = this._features[featureName];
             const nativeName = feature.featureImplementation.xrNativeFeatureName;
             if (nativeName) {
@@ -409,7 +418,14 @@ export class WebXRFeaturesManager implements IDisposable {
                     }
                 }
             }
-        });
+            if (feature.featureImplementation.getXRSessionInitExtension) {
+                const extended = await feature.featureImplementation.getXRSessionInitExtension();
+                xrSessionInit = {
+                    ...xrSessionInit,
+                    ...extended,
+                };
+            }
+        }
         return xrSessionInit;
     }
 }