浏览代码

Merge remote-tracking branch 'remotes/origin/master' into home-diagram

# Conflicts:
#	dist/preview release/babylon.js
#	dist/preview release/babylon.max.js.map
David Catuhe 5 年之前
父节点
当前提交
59a9d0ed92

文件差异内容过多而无法显示
+ 1375 - 383
Playground/js/babylonWebGpu.max.js


文件差异内容过多而无法显示
+ 1 - 1
Playground/js/babylonWebGpu.max.js.map


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

@@ -21044,6 +21044,13 @@ declare module BABYLON {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -26516,6 +26523,7 @@ declare module BABYLON {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -26867,6 +26875,10 @@ declare module BABYLON {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -41943,7 +41955,6 @@ declare module BABYLON {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -49062,7 +49073,7 @@ declare module BABYLON {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.js


+ 46 - 9
dist/preview release/babylon.max.js

@@ -20315,7 +20315,6 @@ var WebXRController = /** @class */ (function () {
          * Event that fires when the controller is removed/disposed
          */
         this.onDisposeObservable = new _Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
-        this._tmpMatrix = new _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Matrix"]();
         this._tmpQuaternion = new _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Quaternion"]();
         this._tmpVector = new _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Vector3"]();
         this.pointer = new _Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["AbstractMesh"]("controllerPointer", scene);
@@ -20325,6 +20324,7 @@ var WebXRController = /** @class */ (function () {
         }
         if (this.inputSource.gripSpace) {
             this.grip = new _Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["AbstractMesh"]("controllerGrip", this.scene);
+            this.grip.rotationQuaternion = new _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Quaternion"]();
             if (this.parentContainer) {
                 this.parentContainer.addChild(this.grip);
             }
@@ -20354,14 +20354,13 @@ var WebXRController = /** @class */ (function () {
         if (this.inputSource.gripSpace && this.grip) {
             var pose_1 = xrFrame.getPose(this.inputSource.gripSpace, referenceSpace);
             if (pose_1) {
-                _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Matrix"].FromFloat32ArrayToRefScaled(pose_1.transform.matrix, 0, 1, this._tmpMatrix);
+                this.grip.position.copyFrom((pose_1.transform.position));
+                this.grip.rotationQuaternion.copyFrom((pose_1.transform.orientation));
                 if (!this.scene.useRightHandedSystem) {
-                    this._tmpMatrix.toggleModelMatrixHandInPlace();
+                    this.grip.position.z *= -1;
+                    this.grip.rotationQuaternion.z *= -1;
+                    this.grip.rotationQuaternion.w *= -1;
                 }
-                if (!this.grip.rotationQuaternion) {
-                    this.grip.rotationQuaternion = new _Maths_math_vector__WEBPACK_IMPORTED_MODULE_2__["Quaternion"]();
-                }
-                this._tmpMatrix.decompose(this.grip.scaling, this.grip.rotationQuaternion, this.grip.position);
             }
         }
         if (this.gamepadController) {
@@ -92425,6 +92424,11 @@ var ShaderMaterial = /** @class */ (function (_super) {
      * @returns true if ready, otherwise false
      */
     ShaderMaterial.prototype.isReady = function (mesh, useInstances) {
+        if (this._effect && this.isFrozen) {
+            if (this._wasPreviouslyReady) {
+                return true;
+            }
+        }
         var scene = this.getScene();
         var engine = scene.getEngine();
         if (!this.checkReadyOnEveryCall) {
@@ -92523,6 +92527,7 @@ var ShaderMaterial = /** @class */ (function (_super) {
             scene.resetCachedMaterial();
         }
         this._renderId = scene.getRenderId();
+        this._wasPreviouslyReady = true;
         return true;
     };
     /**
@@ -120918,6 +120923,22 @@ var BaseSubMesh = /** @class */ (function () {
         /** @hidden */
         this._materialEffect = null;
     }
+    Object.defineProperty(BaseSubMesh.prototype, "materialDefines", {
+        /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        get: function () {
+            return this._materialDefines;
+        },
+        /**
+         * Sets material defines used by the effect associated to the sub mesh
+         */
+        set: function (defines) {
+            this._materialDefines = defines;
+        },
+        enumerable: true,
+        configurable: true
+    });
     Object.defineProperty(BaseSubMesh.prototype, "effect", {
         /**
          * Gets associated effect
@@ -144049,6 +144070,7 @@ var SolidParticleSystem = /** @class */ (function () {
         this._useModelMaterial = false;
         this._depthSortFunction = function (p1, p2) { return p2.sqDistance - p1.sqDistance; };
         this._materialSortFunction = function (p1, p2) { return p1.materialIndex - p2.materialIndex; };
+        this._autoUpdateSubMeshes = false;
         this.name = name;
         this._scene = scene || _Engines_engineStore__WEBPACK_IMPORTED_MODULE_6__["EngineStore"].LastCreatedScene;
         this._camera = scene.activeCamera;
@@ -144516,9 +144538,8 @@ var SolidParticleSystem = /** @class */ (function () {
         }
         var modelShape = new _solidParticle__WEBPACK_IMPORTED_MODULE_7__["ModelShape"](this._shapeCounter, shape, indices, shapeNormals, shapeColors, shapeUV, posfunc, vtxfunc, material);
         // particles
-        var idx = this.nbParticles;
         for (var i = 0; i < nb; i++) {
-            this._insertNewParticle(idx, i, modelShape, shape, meshInd, meshUV, meshCol, meshNor, bbInfo, storage, options);
+            this._insertNewParticle(this.nbParticles, i, modelShape, shape, meshInd, meshUV, meshCol, meshNor, bbInfo, storage, options);
         }
         this._shapeCounter++;
         this._isNotBuilt = true; // buildMesh() call is now expected for setParticles() to work
@@ -145074,6 +145095,9 @@ var SolidParticleSystem = /** @class */ (function () {
                 mesh._boundingInfo = new _Culling_boundingInfo__WEBPACK_IMPORTED_MODULE_8__["BoundingInfo"](minimum, maximum, mesh._worldMatrix);
             }
         }
+        if (this._autoUpdateSubMeshes) {
+            this.computeSubMeshes();
+        }
         this.afterUpdateParticles(start, end, update);
         return this;
     };
@@ -145501,6 +145525,19 @@ var SolidParticleSystem = /** @class */ (function () {
         enumerable: true,
         configurable: true
     });
+    Object.defineProperty(SolidParticleSystem.prototype, "autoUpdateSubMeshes", {
+        /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        get: function () {
+            return this._autoUpdateSubMeshes;
+        },
+        set: function (val) {
+            this._autoUpdateSubMeshes = val;
+        },
+        enumerable: true,
+        configurable: true
+    });
     // =======================================================================
     // Particle behavior logic
     // these following methods may be overwritten by the user to fit his needs

文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/babylon.max.js.map


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

@@ -21693,6 +21693,13 @@ declare module "babylonjs/Meshes/subMesh" {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -27337,6 +27344,7 @@ declare module "babylonjs/Particles/solidParticleSystem" {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -27688,6 +27696,10 @@ declare module "babylonjs/Particles/solidParticleSystem" {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -43422,7 +43434,6 @@ declare module "babylonjs/Cameras/XR/webXRController" {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -51223,7 +51234,7 @@ declare module "babylonjs/Materials/PBR/pbrMaterial" {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**
@@ -89775,6 +89786,13 @@ declare module BABYLON {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -95247,6 +95265,7 @@ declare module BABYLON {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -95598,6 +95617,10 @@ declare module BABYLON {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -110674,7 +110697,6 @@ declare module BABYLON {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -117793,7 +117815,7 @@ declare module BABYLON {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**

+ 85 - 6
dist/preview release/documentation.d.ts

@@ -21044,6 +21044,13 @@ declare module BABYLON {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -26516,6 +26523,7 @@ declare module BABYLON {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -26867,6 +26875,10 @@ declare module BABYLON {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -41943,7 +41955,6 @@ declare module BABYLON {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -49062,7 +49073,7 @@ declare module BABYLON {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**
@@ -68384,7 +68395,7 @@ declare module BABYLON.GUI {
         name?: string | undefined;
         private _background;
         private _borderColor;
-        private _thumbMeasure;
+        private _tempMeasure;
         /** Gets or sets border color */
         borderColor: string;
         /** Gets or sets background color */
@@ -68407,6 +68418,54 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+     * Class used to create slider controls
+     */
+    export class ImageScrollBar extends BaseSlider {
+        name?: string | undefined;
+        private _backgroundImage;
+        private _thumbImage;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
+        private _tempMeasure;
+        /**
+         * Gets or sets the image used to render the background
+         */
+        backgroundImage: Image;
+        /**
+         * Gets or sets the image used to render the thumb
+         */
+        thumbImage: Image;
+        /**
+         * Gets or sets the length of the thumb
+         */
+        thumbLength: number;
+        /**
+         * Gets or sets the height of the thumb
+         */
+        thumbHeight: number;
+        /**
+         * Gets or sets the height of the bar image
+         */
+        barImageHeight: number;
+        /**
+         * Creates a new ImageScrollBar
+         * @param name defines the control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _getThumbThickness(): number;
+        _draw(context: CanvasRenderingContext2D): void;
+        private _first;
+        private _originX;
+        private _originY;
+        /** @hidden */
+        protected _updateValueFromPointer(x: number, y: number): void;
+        _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+    }
+}
+declare module BABYLON.GUI {
+    /**
      * Class used to hold a viewer window and sliders in a grid
     */
     export class ScrollViewer extends Rectangle {
@@ -68418,6 +68477,8 @@ declare module BABYLON.GUI {
         private _verticalBar;
         private _barColor;
         private _barBackground;
+        private _barImage;
+        private _barBackgroundImage;
         private _barSize;
         private _endLeft;
         private _endTop;
@@ -68427,14 +68488,18 @@ declare module BABYLON.GUI {
         private _onPointerObserver;
         private _clientWidth;
         private _clientHeight;
+        private _useImageBar;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
         /**
          * Gets the horizontal scrollbar
          */
-        readonly horizontalBar: ScrollBar;
+        readonly horizontalBar: ScrollBar | ImageScrollBar;
         /**
          * Gets the vertical scrollbar
          */
-        readonly verticalBar: ScrollBar;
+        readonly verticalBar: ScrollBar | ImageScrollBar;
         /**
          * Adds a new control to the current container
          * @param control defines the control to add
@@ -68454,7 +68519,7 @@ declare module BABYLON.GUI {
         * Creates a new ScrollViewer
         * @param name of ScrollViewer
         */
-        constructor(name?: string);
+        constructor(name?: string, isImageBased?: boolean);
         /** Reset the scroll viewer window to initial size */
         resetWindow(): void;
         protected _getTypeName(): string;
@@ -68466,16 +68531,30 @@ declare module BABYLON.GUI {
          * from 0 to 1 with a default value of 0.05
          * */
         wheelPrecision: number;
+        /** Gets or sets the scroll bar container background color */
+        scrollBackground: string;
         /** Gets or sets the bar color */
         barColor: string;
+        /** Gets or sets the bar image */
+        thumbImage: Image;
         /** Gets or sets the size of the bar */
         barSize: number;
+        /** Gets or sets the length of the thumb */
+        thumbLength: number;
+        /** Gets or sets the height of the thumb */
+        thumbHeight: number;
+        /** Gets or sets the height of the bar image */
+        barImageHeight: number;
         /** Gets or sets the bar background */
         barBackground: string;
+        /** Gets or sets the bar background image */
+        barImage: Image;
         /** @hidden */
         private _updateScroller;
         _link(host: AdvancedDynamicTexture): void;
         /** @hidden */
+        private _addBar;
+        /** @hidden */
         private _attachWheel;
         _renderHighlightSpecific(context: CanvasRenderingContext2D): void;
         /** Releases associated resources */

+ 72 - 4
dist/preview release/gui/babylon.gui.d.ts

@@ -2723,7 +2723,7 @@ declare module BABYLON.GUI {
         name?: string | undefined;
         private _background;
         private _borderColor;
-        private _thumbMeasure;
+        private _tempMeasure;
         /** Gets or sets border color */
         borderColor: string;
         /** Gets or sets background color */
@@ -2746,6 +2746,54 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+     * Class used to create slider controls
+     */
+    export class ImageScrollBar extends BaseSlider {
+        name?: string | undefined;
+        private _backgroundImage;
+        private _thumbImage;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
+        private _tempMeasure;
+        /**
+         * Gets or sets the image used to render the background
+         */
+        backgroundImage: Image;
+        /**
+         * Gets or sets the image used to render the thumb
+         */
+        thumbImage: Image;
+        /**
+         * Gets or sets the length of the thumb
+         */
+        thumbLength: number;
+        /**
+         * Gets or sets the height of the thumb
+         */
+        thumbHeight: number;
+        /**
+         * Gets or sets the height of the bar image
+         */
+        barImageHeight: number;
+        /**
+         * Creates a new ImageScrollBar
+         * @param name defines the control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _getThumbThickness(): number;
+        _draw(context: CanvasRenderingContext2D): void;
+        private _first;
+        private _originX;
+        private _originY;
+        /** @hidden */
+        protected _updateValueFromPointer(x: number, y: number): void;
+        _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+    }
+}
+declare module BABYLON.GUI {
+    /**
      * Class used to hold a viewer window and sliders in a grid
     */
     export class ScrollViewer extends Rectangle {
@@ -2757,6 +2805,8 @@ declare module BABYLON.GUI {
         private _verticalBar;
         private _barColor;
         private _barBackground;
+        private _barImage;
+        private _barBackgroundImage;
         private _barSize;
         private _endLeft;
         private _endTop;
@@ -2766,14 +2816,18 @@ declare module BABYLON.GUI {
         private _onPointerObserver;
         private _clientWidth;
         private _clientHeight;
+        private _useImageBar;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
         /**
          * Gets the horizontal scrollbar
          */
-        readonly horizontalBar: ScrollBar;
+        readonly horizontalBar: ScrollBar | ImageScrollBar;
         /**
          * Gets the vertical scrollbar
          */
-        readonly verticalBar: ScrollBar;
+        readonly verticalBar: ScrollBar | ImageScrollBar;
         /**
          * Adds a new control to the current container
          * @param control defines the control to add
@@ -2793,7 +2847,7 @@ declare module BABYLON.GUI {
         * Creates a new ScrollViewer
         * @param name of ScrollViewer
         */
-        constructor(name?: string);
+        constructor(name?: string, isImageBased?: boolean);
         /** Reset the scroll viewer window to initial size */
         resetWindow(): void;
         protected _getTypeName(): string;
@@ -2805,16 +2859,30 @@ declare module BABYLON.GUI {
          * from 0 to 1 with a default value of 0.05
          * */
         wheelPrecision: number;
+        /** Gets or sets the scroll bar container background color */
+        scrollBackground: string;
         /** Gets or sets the bar color */
         barColor: string;
+        /** Gets or sets the bar image */
+        thumbImage: Image;
         /** Gets or sets the size of the bar */
         barSize: number;
+        /** Gets or sets the length of the thumb */
+        thumbLength: number;
+        /** Gets or sets the height of the thumb */
+        thumbHeight: number;
+        /** Gets or sets the height of the bar image */
+        barImageHeight: number;
         /** Gets or sets the bar background */
         barBackground: string;
+        /** Gets or sets the bar background image */
+        barImage: Image;
         /** @hidden */
         private _updateScroller;
         _link(host: AdvancedDynamicTexture): void;
         /** @hidden */
+        private _addBar;
+        /** @hidden */
         private _attachWheel;
         _renderHighlightSpecific(context: CanvasRenderingContext2D): void;
         /** Releases associated resources */

文件差异内容过多而无法显示
+ 422 - 56
dist/preview release/gui/babylon.gui.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


+ 151 - 8
dist/preview release/gui/babylon.gui.module.d.ts

@@ -2837,7 +2837,7 @@ declare module "babylonjs-gui/2D/controls/sliders/scrollBar" {
         name?: string | undefined;
         private _background;
         private _borderColor;
-        private _thumbMeasure;
+        private _tempMeasure;
         /** Gets or sets border color */
         borderColor: string;
         /** Gets or sets background color */
@@ -2858,14 +2858,68 @@ declare module "babylonjs-gui/2D/controls/sliders/scrollBar" {
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
     }
 }
+declare module "babylonjs-gui/2D/controls/sliders/imageScrollBar" {
+    import { Vector2 } from "babylonjs/Maths/math";
+    import { BaseSlider } from "babylonjs-gui/2D/controls/sliders/baseSlider";
+    import { Control } from "babylonjs-gui/2D/controls/control";
+    import { Image } from "babylonjs-gui/2D/controls/image";
+    /**
+     * Class used to create slider controls
+     */
+    export class ImageScrollBar extends BaseSlider {
+        name?: string | undefined;
+        private _backgroundImage;
+        private _thumbImage;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
+        private _tempMeasure;
+        /**
+         * Gets or sets the image used to render the background
+         */
+        backgroundImage: Image;
+        /**
+         * Gets or sets the image used to render the thumb
+         */
+        thumbImage: Image;
+        /**
+         * Gets or sets the length of the thumb
+         */
+        thumbLength: number;
+        /**
+         * Gets or sets the height of the thumb
+         */
+        thumbHeight: number;
+        /**
+         * Gets or sets the height of the bar image
+         */
+        barImageHeight: number;
+        /**
+         * Creates a new ImageScrollBar
+         * @param name defines the control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _getThumbThickness(): number;
+        _draw(context: CanvasRenderingContext2D): void;
+        private _first;
+        private _originX;
+        private _originY;
+        /** @hidden */
+        protected _updateValueFromPointer(x: number, y: number): void;
+        _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
+    }
+}
 declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
     import { Nullable } from "babylonjs/types";
     import { Rectangle } from "babylonjs-gui/2D/controls/rectangle";
+    import { Image } from "babylonjs-gui/2D/controls/image";
     import { Control } from "babylonjs-gui/2D/controls/control";
     import { Container } from "babylonjs-gui/2D/controls/container";
     import { Measure } from "babylonjs-gui/2D/measure";
     import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
     import { ScrollBar } from "babylonjs-gui/2D/controls/sliders/scrollBar";
+    import { ImageScrollBar } from "babylonjs-gui/2D/controls/sliders/imageScrollBar";
     /**
      * Class used to hold a viewer window and sliders in a grid
     */
@@ -2878,6 +2932,8 @@ declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
         private _verticalBar;
         private _barColor;
         private _barBackground;
+        private _barImage;
+        private _barBackgroundImage;
         private _barSize;
         private _endLeft;
         private _endTop;
@@ -2887,14 +2943,18 @@ declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
         private _onPointerObserver;
         private _clientWidth;
         private _clientHeight;
+        private _useImageBar;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
         /**
          * Gets the horizontal scrollbar
          */
-        readonly horizontalBar: ScrollBar;
+        readonly horizontalBar: ScrollBar | ImageScrollBar;
         /**
          * Gets the vertical scrollbar
          */
-        readonly verticalBar: ScrollBar;
+        readonly verticalBar: ScrollBar | ImageScrollBar;
         /**
          * Adds a new control to the current container
          * @param control defines the control to add
@@ -2914,7 +2974,7 @@ declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
         * Creates a new ScrollViewer
         * @param name of ScrollViewer
         */
-        constructor(name?: string);
+        constructor(name?: string, isImageBased?: boolean);
         /** Reset the scroll viewer window to initial size */
         resetWindow(): void;
         protected _getTypeName(): string;
@@ -2926,16 +2986,30 @@ declare module "babylonjs-gui/2D/controls/scrollViewers/scrollViewer" {
          * from 0 to 1 with a default value of 0.05
          * */
         wheelPrecision: number;
+        /** Gets or sets the scroll bar container background color */
+        scrollBackground: string;
         /** Gets or sets the bar color */
         barColor: string;
+        /** Gets or sets the bar image */
+        thumbImage: Image;
         /** Gets or sets the size of the bar */
         barSize: number;
+        /** Gets or sets the length of the thumb */
+        thumbLength: number;
+        /** Gets or sets the height of the thumb */
+        thumbHeight: number;
+        /** Gets or sets the height of the bar image */
+        barImageHeight: number;
         /** Gets or sets the bar background */
         barBackground: string;
+        /** Gets or sets the bar background image */
+        barImage: Image;
         /** @hidden */
         private _updateScroller;
         _link(host: AdvancedDynamicTexture): void;
         /** @hidden */
+        private _addBar;
+        /** @hidden */
         private _attachWheel;
         _renderHighlightSpecific(context: CanvasRenderingContext2D): void;
         /** Releases associated resources */
@@ -3057,6 +3131,7 @@ declare module "babylonjs-gui/2D/controls/index" {
     export * from "babylonjs-gui/2D/controls/sliders/slider";
     export * from "babylonjs-gui/2D/controls/sliders/imageBasedSlider";
     export * from "babylonjs-gui/2D/controls/sliders/scrollBar";
+    export * from "babylonjs-gui/2D/controls/sliders/imageScrollBar";
     export * from "babylonjs-gui/2D/controls/statics";
 }
 declare module "babylonjs-gui/2D/adtInstrumentation" {
@@ -6675,7 +6750,7 @@ declare module BABYLON.GUI {
         name?: string | undefined;
         private _background;
         private _borderColor;
-        private _thumbMeasure;
+        private _tempMeasure;
         /** Gets or sets border color */
         borderColor: string;
         /** Gets or sets background color */
@@ -6698,6 +6773,54 @@ declare module BABYLON.GUI {
 }
 declare module BABYLON.GUI {
     /**
+     * Class used to create slider controls
+     */
+    export class ImageScrollBar extends BaseSlider {
+        name?: string | undefined;
+        private _backgroundImage;
+        private _thumbImage;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
+        private _tempMeasure;
+        /**
+         * Gets or sets the image used to render the background
+         */
+        backgroundImage: Image;
+        /**
+         * Gets or sets the image used to render the thumb
+         */
+        thumbImage: Image;
+        /**
+         * Gets or sets the length of the thumb
+         */
+        thumbLength: number;
+        /**
+         * Gets or sets the height of the thumb
+         */
+        thumbHeight: number;
+        /**
+         * Gets or sets the height of the bar image
+         */
+        barImageHeight: number;
+        /**
+         * Creates a new ImageScrollBar
+         * @param name defines the control name
+         */
+        constructor(name?: string | undefined);
+        protected _getTypeName(): string;
+        protected _getThumbThickness(): number;
+        _draw(context: CanvasRenderingContext2D): void;
+        private _first;
+        private _originX;
+        private _originY;
+        /** @hidden */
+        protected _updateValueFromPointer(x: number, y: number): void;
+        _onPointerDown(target: Control, coordinates: BABYLON.Vector2, pointerId: number, buttonIndex: number): boolean;
+    }
+}
+declare module BABYLON.GUI {
+    /**
      * Class used to hold a viewer window and sliders in a grid
     */
     export class ScrollViewer extends Rectangle {
@@ -6709,6 +6832,8 @@ declare module BABYLON.GUI {
         private _verticalBar;
         private _barColor;
         private _barBackground;
+        private _barImage;
+        private _barBackgroundImage;
         private _barSize;
         private _endLeft;
         private _endTop;
@@ -6718,14 +6843,18 @@ declare module BABYLON.GUI {
         private _onPointerObserver;
         private _clientWidth;
         private _clientHeight;
+        private _useImageBar;
+        private _thumbLength;
+        private _thumbHeight;
+        private _barImageHeight;
         /**
          * Gets the horizontal scrollbar
          */
-        readonly horizontalBar: ScrollBar;
+        readonly horizontalBar: ScrollBar | ImageScrollBar;
         /**
          * Gets the vertical scrollbar
          */
-        readonly verticalBar: ScrollBar;
+        readonly verticalBar: ScrollBar | ImageScrollBar;
         /**
          * Adds a new control to the current container
          * @param control defines the control to add
@@ -6745,7 +6874,7 @@ declare module BABYLON.GUI {
         * Creates a new ScrollViewer
         * @param name of ScrollViewer
         */
-        constructor(name?: string);
+        constructor(name?: string, isImageBased?: boolean);
         /** Reset the scroll viewer window to initial size */
         resetWindow(): void;
         protected _getTypeName(): string;
@@ -6757,16 +6886,30 @@ declare module BABYLON.GUI {
          * from 0 to 1 with a default value of 0.05
          * */
         wheelPrecision: number;
+        /** Gets or sets the scroll bar container background color */
+        scrollBackground: string;
         /** Gets or sets the bar color */
         barColor: string;
+        /** Gets or sets the bar image */
+        thumbImage: Image;
         /** Gets or sets the size of the bar */
         barSize: number;
+        /** Gets or sets the length of the thumb */
+        thumbLength: number;
+        /** Gets or sets the height of the thumb */
+        thumbHeight: number;
+        /** Gets or sets the height of the bar image */
+        barImageHeight: number;
         /** Gets or sets the bar background */
         barBackground: string;
+        /** Gets or sets the bar background image */
+        barImage: Image;
         /** @hidden */
         private _updateScroller;
         _link(host: AdvancedDynamicTexture): void;
         /** @hidden */
+        private _addBar;
+        /** @hidden */
         private _attachWheel;
         _renderHighlightSpecific(context: CanvasRenderingContext2D): void;
         /** Releases associated resources */

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

@@ -1 +1 @@
-{"thinEngineOnly":116435,"engineOnly":153253,"sceneOnly":497651,"minGridMaterial":628216,"minStandardMaterial":752148}
+{"thinEngineOnly":116435,"engineOnly":153253,"sceneOnly":497822,"minGridMaterial":628387,"minStandardMaterial":752319}

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

@@ -21693,6 +21693,13 @@ declare module "babylonjs/Meshes/subMesh" {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -27337,6 +27344,7 @@ declare module "babylonjs/Particles/solidParticleSystem" {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -27688,6 +27696,10 @@ declare module "babylonjs/Particles/solidParticleSystem" {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -43422,7 +43434,6 @@ declare module "babylonjs/Cameras/XR/webXRController" {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -51223,7 +51234,7 @@ declare module "babylonjs/Materials/PBR/pbrMaterial" {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**
@@ -89757,6 +89768,13 @@ declare module BABYLON {
         /** @hidden */
         _materialEffect: Nullable<Effect>;
         /**
+         * Gets material defines used by the effect associated to the sub mesh
+         */
+        /**
+        * Sets material defines used by the effect associated to the sub mesh
+        */
+        materialDefines: Nullable<MaterialDefines>;
+        /**
          * Gets associated effect
          */
         readonly effect: Nullable<Effect>;
@@ -95229,6 +95247,7 @@ declare module BABYLON {
         private _multimaterial;
         private _materialIndexesById;
         private _defaultMaterial;
+        private _autoUpdateSubMeshes;
         /**
          * Creates a SPS (Solid Particle System) object.
          * @param name (String) is the SPS name, this will be the underlying mesh name.
@@ -95580,6 +95599,10 @@ declare module BABYLON {
          */
         multimaterial: MultiMaterial;
         /**
+         * If the subMeshes must be updated on the next call to setParticles()
+         */
+        autoUpdateSubMeshes: boolean;
+        /**
          * This function does nothing. It may be overwritten to set all the particle first values.
          * The SPS doesn't call this function, you may have to call it by your own.
          * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#particle-management
@@ -110656,7 +110679,6 @@ declare module BABYLON {
          * Event that fires when the controller is removed/disposed
          */
         onDisposeObservable: Observable<{}>;
-        private _tmpMatrix;
         private _tmpQuaternion;
         private _tmpVector;
         /**
@@ -117775,7 +117797,7 @@ declare module BABYLON {
          */
         ambientTextureImpactOnAnalyticalLights: number;
         /**
-         * Stores the alpha values in a texture.
+         * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
          */
         opacityTexture: BaseTexture;
         /**

文件差异内容过多而无法显示
+ 4 - 4
dist/preview release/viewer/babylon.viewer.js


文件差异内容过多而无法显示
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -95,6 +95,7 @@
 - Added new CreateTiledPlane and CreateTiledBox ([JohnK](https://github.com/BabylonJSGuide/))
 - Added absolute scaling and rotation getters ([haroldma](https://github.com/haroldma))
 - Added `BILLBOARDMODE_USE_POSITION` flag to billboards allowing use of camera positioning instead of orientation for mesh rotation ([delaneyj](https://github.com/delaneyj))
+- Added accessor functions for `SubMesh._materialDefines` ([Popov72](https://github.com/Popov72))
 
 ### Physics
 
@@ -126,6 +127,7 @@
 - Added `scene.environmentIntensity` to control the IBL strength overall in a scene ([Sebavan](https://github.com/sebavan/))
 - Added support of image processing for `WaterMaterial` ([julien-moreau](https://github.com/julien-moreau))
 - Added `pbrBRDFConfiguration.useSpecularGlossinessInputEnergyConservation` to allow Specular-Workflow energy conservation to be turned off ([ColorDigital-PS](https://github.com/ColorDigital-PS)).
+- Added support for the `freeze` / `unfreeze` functions in `ShaderMaterial` ([Popov72](https://github.com/Popov72))
 - Added `depthFunction` new property to `Material` base class ([Popov72](https://github.com/Popov72))
 
 ### ScreenshotTools
@@ -158,6 +160,7 @@
 - Added option to change the teleportation duration in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 - Added support to teleport the camera at constant speed in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 - VRExperienceHelper has now an XR fallback to force XR usage (Beta) ([RaananW](https://github.com/RaananW/))
+- Added option to change the teleportation easing function in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 
 ### Ray
 
@@ -171,13 +174,14 @@
 - Added `Container.maxLayoutCycle` and `Container.logLayoutCycleErrors` to get more control over layout cycles ([Deltakosh](https://github.com/deltakosh/))
 - Added `StackPanel.ignoreLayoutWarnings` to disable console warnings when controls with percentage size are added to a StackPanel ([Deltakosh](https://github.com/deltakosh/))
 - Added `_getSVGAttribs` functionality for loading multiple svg icons from an external svg file via icon id. Fixed bug for Chrome. Strip icon id from image url for firefox.([lockphase](https://github.com/lockphase/))
+- Scroll Viewer extended to include the use of images in the scroll bars([JohnK](https://github.com/BabylonJSGuide/))
 
 ### Particles
 
 - Added the feature `expandable` to the Solid Particle System ([jerome](https://github.com/jbousquie/))
 - Added the feature `removeParticles()` to the Solid Particle System ([jerome](https://github.com/jbousquie/))
 - Added the feature "storable particles" and `insertParticlesFromArray()` to the Solid Particle System ([jerome](https://github.com/jbousquie/))
-- Added the support for MultiMaterials to the Solid Particle System ([jerome](https://github.com/jbousquie/))
+- Added the support for MultiMaterials to the Solid Particle System ([jerome](https://github.com/jbousquie/))  
 
 ### Navigation Mesh
 
@@ -235,6 +239,7 @@
 - Fixed Path3D (bi)normals computation for specific edge cases ([Poolminer](https://github.com/Poolminer/))
 - WebXR UI BUtton will only change to "In XR" after XR Session started ([RaananW](https://github.com/RaananW/))
 - Fix bug when we call `Mesh.render` twice and the material is still not ready on the second call ([barroij](https://github.com/barroij/))
+- Fixed an issue with pose input in webxr ([RaananW](https://github.com/RaananW/))
 
 ## Breaking changes
 

+ 1 - 0
gui/src/2D/controls/index.ts

@@ -22,5 +22,6 @@ export * from "./sliders/baseSlider";
 export * from "./sliders/slider";
 export * from "./sliders/imageBasedSlider";
 export * from "./sliders/scrollBar";
+export * from "./sliders/imageScrollBar";
 
 export * from "./statics";

+ 176 - 48
gui/src/2D/controls/scrollViewers/scrollViewer.ts

@@ -4,12 +4,14 @@ import { PointerInfo, PointerEventTypes } from "babylonjs/Events/pointerEvents";
 
 import { Rectangle } from "../rectangle";
 import { Grid } from "../grid";
+import { Image } from "../image";
 import { Control } from "../control";
 import { Container } from "../container";
 import { Measure } from "../../measure";
 import { AdvancedDynamicTexture } from "../../advancedDynamicTexture";
 import { _ScrollViewerWindow } from "./scrollViewerWindow";
 import { ScrollBar } from "../sliders/scrollBar";
+import { ImageScrollBar } from "../sliders/imageScrollBar";
 import { _TypeStore } from 'babylonjs/Misc/typeStore';
 
 /**
@@ -20,10 +22,12 @@ export class ScrollViewer extends Rectangle {
     private _horizontalBarSpace: Rectangle;
     private _verticalBarSpace: Rectangle;
     private _dragSpace: Rectangle;
-    private _horizontalBar: ScrollBar;
-    private _verticalBar: ScrollBar;
+    private _horizontalBar: ScrollBar | ImageScrollBar;
+    private _verticalBar: ScrollBar | ImageScrollBar;
     private _barColor: string;
     private _barBackground: string;
+    private _barImage: Image;
+    private _barBackgroundImage: Image;
     private _barSize: number = 20;
     private _endLeft: number;
     private _endTop: number;
@@ -33,18 +37,22 @@ export class ScrollViewer extends Rectangle {
     private _onPointerObserver: Nullable<Observer<PointerInfo>>;
     private _clientWidth: number;
     private _clientHeight: number;
+    private _useImageBar: Boolean;
+    private _thumbLength: number = 0.5;
+    private _thumbHeight: number = 1;
+    private _barImageHeight: number = 1;
 
     /**
      * Gets the horizontal scrollbar
      */
-    public get horizontalBar(): ScrollBar {
+    public get horizontalBar(): ScrollBar | ImageScrollBar {
         return this._horizontalBar;
     }
 
     /**
      * Gets the vertical scrollbar
      */
-    public get verticalBar(): ScrollBar {
+    public get verticalBar(): ScrollBar | ImageScrollBar {
         return this._verticalBar;
     }
 
@@ -88,9 +96,11 @@ export class ScrollViewer extends Rectangle {
     * Creates a new ScrollViewer
     * @param name of ScrollViewer
     */
-    constructor(name?: string) {
+    constructor(name?: string, isImageBased?: boolean) {
         super(name);
 
+        this._useImageBar = isImageBased ? isImageBased : false;
+
         this.onDirtyObservable.add(() => {
             this._horizontalBarSpace.color = this.color;
             this._verticalBarSpace.color = this.color;
@@ -106,8 +116,14 @@ export class ScrollViewer extends Rectangle {
         });
 
         this._grid = new Grid();
-        this._horizontalBar = new ScrollBar();
-        this._verticalBar = new ScrollBar();
+        if (this._useImageBar) {
+            this._horizontalBar = new ImageScrollBar();
+            this._verticalBar = new ImageScrollBar();
+        }
+        else {
+            this._horizontalBar = new ScrollBar();
+            this._verticalBar = new ScrollBar();
+        }
 
         this._window = new _ScrollViewerWindow();
         this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
@@ -121,57 +137,29 @@ export class ScrollViewer extends Rectangle {
         super.addControl(this._grid);
         this._grid.addControl(this._window, 0, 0);
 
-        this._verticalBar.paddingLeft = 0;
-        this._verticalBar.width = "100%";
-        this._verticalBar.height = "100%";
-        this._verticalBar.barOffset = 0;
-        this._verticalBar.value = 0;
-        this._verticalBar.maximum = 1;
-        this._verticalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
-        this._verticalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
-        this._verticalBar.isVertical = true;
-        this._verticalBar.rotation = Math.PI;
-        this._verticalBar.isVisible = false;
-
         this._verticalBarSpace = new Rectangle();
         this._verticalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._verticalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
         this._verticalBarSpace.thickness = 1;
         this._grid.addControl(this._verticalBarSpace, 0, 1);
-        this._verticalBarSpace.addControl(this._verticalBar);
-
-        this._verticalBar.onValueChangedObservable.add((value) => {
-            this._window.top = value * this._endTop + "px";
-        });
-
-        this._horizontalBar.paddingLeft = 0;
-        this._horizontalBar.width = "100%";
-        this._horizontalBar.height = "100%";
-        this._horizontalBar.barOffset = 0;
-        this._horizontalBar.value = 0;
-        this._horizontalBar.maximum = 1;
-        this._horizontalBar.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
-        this._horizontalBar.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
-        this._horizontalBar.isVisible = false;
+        this._addBar(this._verticalBar, this._verticalBarSpace, true, Math.PI);
 
         this._horizontalBarSpace = new Rectangle();
         this._horizontalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
         this._horizontalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
         this._horizontalBarSpace.thickness = 1;
         this._grid.addControl(this._horizontalBarSpace, 1, 0);
-        this._horizontalBarSpace.addControl(this._horizontalBar);
-
-        this._horizontalBar.onValueChangedObservable.add((value) => {
-            this._window.left = value * this._endLeft + "px";
-        });
+        this._addBar(this._horizontalBar, this._horizontalBarSpace, false, 0);
 
         this._dragSpace = new Rectangle();
         this._dragSpace.thickness = 1;
         this._grid.addControl(this._dragSpace, 1, 1);
 
         // Colors
-        this.barColor = "grey";
-        this.barBackground = "transparent";
+        if (!this._useImageBar) {
+            this.barColor = "grey";
+            this.barBackground = "transparent";
+        }
     }
 
     /** Reset the scroll viewer window to initial size */
@@ -228,6 +216,19 @@ export class ScrollViewer extends Rectangle {
         this._wheelPrecision = value;
     }
 
+    /** Gets or sets the scroll bar container background color */
+    public get scrollBackground(): string {
+        return this._horizontalBarSpace.background;
+    }
+
+    public set scrollBackground(color: string) {
+        if (this._horizontalBarSpace.background === color) {
+            return;
+        }
+        this._horizontalBarSpace.background = color;
+        this._verticalBarSpace.background = color;
+    }
+
     /** Gets or sets the bar color */
     public get barColor(): string {
         return this._barColor;
@@ -243,6 +244,23 @@ export class ScrollViewer extends Rectangle {
         this._verticalBar.color = color;
     }
 
+    /** Gets or sets the bar image */
+    public get thumbImage(): Image {
+        return this._barImage;
+    }
+
+    public set thumbImage(value: Image) {
+        if (this._barImage === value) {
+            return;
+        }
+
+        this._barImage = value;
+        let hb = <ImageScrollBar>this._horizontalBar;
+        let vb = <ImageScrollBar>this._verticalBar;
+        hb.thumbImage = value;
+        vb.thumbImage = value;
+    }
+
     /** Gets or sets the size of the bar */
     public get barSize(): number {
         return this._barSize;
@@ -264,6 +282,75 @@ export class ScrollViewer extends Rectangle {
         }
     }
 
+    /** Gets or sets the length of the thumb */
+    public get thumbLength(): number {
+        return this._thumbLength;
+    }
+
+    public set thumbLength(value: number) {
+        if (this._thumbLength === value) {
+            return;
+        }
+        if (value <= 0) {
+            value = 0.1;
+        }
+        if (value > 1) {
+            value = 1;
+        }
+        this._thumbLength = value;
+        var hb = <ImageScrollBar>this._horizontalBar;
+        var vb = <ImageScrollBar>this._verticalBar;
+        hb.thumbLength = value;
+        vb.thumbLength = value;
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the height of the thumb */
+    public get thumbHeight(): number {
+        return this._thumbHeight;
+    }
+
+    public set thumbHeight(value: number) {
+        if (this._thumbHeight === value) {
+            return;
+        }
+        if (value <= 0) {
+            value = 0.1;
+        }
+        if (value > 1) {
+            value = 1;
+        }
+        this._thumbHeight = value;
+        var hb = <ImageScrollBar>this._horizontalBar;
+        var vb = <ImageScrollBar>this._verticalBar;
+        hb.thumbHeight = value;
+        vb.thumbHeight = value;
+        this._markAsDirty();
+    }
+
+    /** Gets or sets the height of the bar image */
+    public get barImageHeight(): number {
+        return this._barImageHeight;
+    }
+
+    public set barImageHeight(value: number) {
+        if (this._barImageHeight === value) {
+            return;
+        }
+        if (value <= 0) {
+            value = 0.1;
+        }
+        if (value > 1) {
+            value = 1;
+        }
+        this._barImageHeight = value;
+        var hb = <ImageScrollBar>this._horizontalBar;
+        var vb = <ImageScrollBar>this._verticalBar;
+        hb.barImageHeight = value;
+        vb.barImageHeight = value;
+        this._markAsDirty();
+    }
+
     /** Gets or sets the bar background */
     public get barBackground(): string {
         return this._barBackground;
@@ -275,11 +362,29 @@ export class ScrollViewer extends Rectangle {
         }
 
         this._barBackground = color;
-        this._horizontalBar.background = color;
-        this._verticalBar.background = color;
+        let hb = <ScrollBar>this._horizontalBar;
+        let vb = <ScrollBar>this._verticalBar;
+        hb.background = color;
+        vb.background = color;
         this._dragSpace.background = color;
     }
 
+    /** Gets or sets the bar background image */
+    public get barImage(): Image {
+        return this._barBackgroundImage;
+    }
+
+    public set barImage(value: Image) {
+        if (this._barBackgroundImage === value) {
+        }
+
+        this._barBackgroundImage = value;
+        let hb = <ImageScrollBar>this._horizontalBar;
+        let vb = <ImageScrollBar>this._verticalBar;
+        hb.backgroundImage = value;
+        vb.backgroundImage = value;
+    }
+
     /** @hidden */
     private _updateScroller(): void {
         let windowContentsWidth = this._window._currentMeasure.width;
@@ -326,11 +431,8 @@ export class ScrollViewer extends Rectangle {
             this._rebuildLayout = true;
         }
 
-        let horizontalMultiplicator = this._clientWidth / windowContentsWidth;
-        let verticalMultiplicator = this._clientHeight / windowContentsHeight;
-
-        this._horizontalBar.thumbWidth = (this._clientWidth * horizontalMultiplicator) + "px";
-        this._verticalBar.thumbWidth = (this._clientHeight * verticalMultiplicator) + "px";
+        this._horizontalBar.thumbWidth = this._thumbLength * 0.9 * this._clientWidth + "px";
+        this._verticalBar.thumbWidth = this._thumbLength *  0.9 * this._clientHeight + "px";
     }
 
     public _link(host: AdvancedDynamicTexture): void {
@@ -340,6 +442,32 @@ export class ScrollViewer extends Rectangle {
     }
 
     /** @hidden */
+    private _addBar(barControl: ScrollBar | ImageScrollBar, barContainer: Rectangle, isVertical: boolean, rotation: number) {
+        barControl.paddingLeft = 0;
+        barControl.width = "100%";
+        barControl.height = "100%";
+        barControl.barOffset = 0;
+        barControl.value = 0;
+        barControl.maximum = 1;
+        barControl.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
+        barControl.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
+        barControl.isVertical = isVertical;
+        barControl.rotation = rotation;
+        barControl.isVisible = false;
+
+        barContainer.addControl(barControl);
+
+        barControl.onValueChangedObservable.add((value) => {
+            if (rotation > 0) {
+                this._window.top = value * this._endTop + "px";
+            }
+            else {
+                this._window.left = value * this._endLeft + "px";
+            }
+        });
+    }
+
+    /** @hidden */
     private _attachWheel() {
         if (!this._host || this._onPointerObserver) {
             return;

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

@@ -0,0 +1,224 @@
+import { Vector2 } from "babylonjs/Maths/math";
+import { BaseSlider } from "./baseSlider";
+import { Control } from "../control";
+import { Image } from "../image";
+import { Measure } from "../../measure";
+
+/**
+ * Class used to create slider controls
+ */
+export class ImageScrollBar extends BaseSlider {
+    private _backgroundImage: Image;
+    private _thumbImage: Image;
+    private _thumbLength: number = 0.5;
+    private _thumbHeight: number = 1;
+    private _barImageHeight: number = 1;
+    private _tempMeasure = new Measure(0, 0, 0, 0);
+
+    /**
+     * Gets or sets the image used to render the background
+     */
+    public get backgroundImage(): Image {
+        return this._backgroundImage;
+    }
+
+    public set backgroundImage(value: Image) {
+        if (this._backgroundImage === value) {
+            return;
+        }
+
+        this._backgroundImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the image used to render the thumb
+     */
+    public get thumbImage(): Image {
+        return this._thumbImage;
+    }
+
+    public set thumbImage(value: Image) {
+        if (this._thumbImage === value) {
+            return;
+        }
+
+        this._thumbImage = value;
+
+        if (value && !value.isLoaded) {
+            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        }
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the length of the thumb
+     */
+    public get thumbLength(): number {
+        return this._thumbLength;
+    }
+
+    public set thumbLength(value: number) {
+        if (this._thumbLength === value) {
+            return;
+        }
+
+        this._thumbLength = value;
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the height of the thumb
+     */
+    public get thumbHeight(): number {
+        return this._thumbHeight;
+    }
+
+    public set thumbHeight(value: number) {
+        if (this._thumbLength === value) {
+            return;
+        }
+
+        this._thumbHeight = value;
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Gets or sets the height of the bar image
+     */
+    public get barImageHeight(): number {
+        return this._barImageHeight;
+    }
+
+    public set barImageHeight(value: number) {
+        if (this._barImageHeight === value) {
+            return;
+        }
+
+        this._barImageHeight = value;
+
+        this._markAsDirty();
+    }
+
+    /**
+     * Creates a new ImageScrollBar
+     * @param name defines the control name
+     */
+    constructor(public name?: string) {
+        super(name);
+    }
+
+    protected _getTypeName(): string {
+        return "ImageScrollBar";
+    }
+
+    protected _getThumbThickness(): number {
+        var thumbThickness = 0;
+        if (this._thumbWidth.isPixel) {
+            thumbThickness = this._thumbWidth.getValue(this._host);
+        }
+        else {
+            thumbThickness = this._backgroundBoxThickness * this._thumbWidth.getValue(this._host);
+        }
+        return thumbThickness;
+    }
+
+    public _draw(context: CanvasRenderingContext2D): void {
+        context.save();
+
+        this._applyStates(context);
+
+        this._prepareRenderingData("rectangle");
+        const thumbPosition = this._getThumbPosition();
+        var left = this._renderLeft;
+        var top = this._renderTop;
+        var width = this._renderWidth;
+        var height = this._renderHeight;
+
+       // Background
+       if (this._backgroundImage) {
+        this._tempMeasure.copyFromFloats(left, top, width, height);
+        if (this.isVertical) {
+            this._tempMeasure.copyFromFloats(left + width * (1 - this._barImageHeight) * 0.5, this._currentMeasure.top, width * this._barImageHeight, height);
+            this._tempMeasure.height += this._effectiveThumbThickness;
+            this._backgroundImage._currentMeasure.copyFrom(this._tempMeasure);
+        }
+        else {
+            this._tempMeasure.copyFromFloats(this._currentMeasure.left, top + height * (1 - this._barImageHeight) * 0.5, width, height * this._barImageHeight);
+            this._tempMeasure.width += this._effectiveThumbThickness;
+            this._backgroundImage._currentMeasure.copyFrom(this._tempMeasure);
+        }
+        this._backgroundImage._draw(context);
+    }
+
+        // Thumb
+        if (this.isVertical) {
+            this._tempMeasure.copyFromFloats(left - this._effectiveBarOffset + this._currentMeasure.width * (1 - this._thumbHeight) * 0.5, this._currentMeasure.top + thumbPosition, this._currentMeasure.width * this._thumbHeight, this._effectiveThumbThickness);
+        }
+        else {
+            this._tempMeasure.copyFromFloats(this._currentMeasure.left + thumbPosition, this._currentMeasure.top + this._currentMeasure.height * (1 - this._thumbHeight) * 0.5, this._effectiveThumbThickness, this._currentMeasure.height * this._thumbHeight);
+        }
+
+        this._thumbImage._currentMeasure.copyFrom(this._tempMeasure);
+        this._thumbImage._draw(context);
+
+        context.restore();
+    }
+
+    private _first: boolean;
+    private _originX: number;
+    private _originY: number;
+
+    /** @hidden */
+    protected _updateValueFromPointer(x: number, y: number): void {
+        if (this.rotation != 0) {
+            this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
+            x = this._transformedPosition.x;
+            y = this._transformedPosition.y;
+        }
+
+        if (this._first) {
+            this._first = false;
+            this._originX = x;
+            this._originY = y;
+
+            // Check if move is required
+            if (x < this._tempMeasure.left || x > this._tempMeasure.left + this._tempMeasure.width || y < this._tempMeasure.top || y > this._tempMeasure.top + this._tempMeasure.height) {
+                if (this.isVertical) {
+                    this.value = this.minimum + (1 - ((y - this._currentMeasure.top) / this._currentMeasure.height)) * (this.maximum - this.minimum);
+                }
+                else {
+                    this.value = this.minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this.maximum - this.minimum);
+                }
+            }
+        }
+
+        // Delta mode
+        let delta = 0;
+        if (this.isVertical) {
+            delta = -((y - this._originY) / (this._currentMeasure.height - this._effectiveThumbThickness));
+        }
+        else {
+            delta = (x - this._originX) / (this._currentMeasure.width - this._effectiveThumbThickness);
+        }
+
+        this.value += delta * (this.maximum - this.minimum);
+
+        this._originX = x;
+        this._originY = y;
+    }
+
+    public _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean {
+        this._first = true;
+
+        return super._onPointerDown(target, coordinates, pointerId, buttonIndex);
+    }
+}

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

@@ -9,7 +9,7 @@ import { Measure } from "../../measure";
 export class ScrollBar extends BaseSlider {
     private _background = "black";
     private _borderColor = "white";
-    private _thumbMeasure = new Measure(0, 0, 0, 0);
+    private _tempMeasure = new Measure(0, 0, 0, 0);
 
     /** Gets or sets border color */
     public get borderColor(): string {
@@ -79,19 +79,19 @@ export class ScrollBar extends BaseSlider {
 
         // Thumb
         if (this.isVertical) {
-            this._thumbMeasure.left = left - this._effectiveBarOffset;
-            this._thumbMeasure.top = this._currentMeasure.top + thumbPosition;
-            this._thumbMeasure.width = this._currentMeasure.width;
-            this._thumbMeasure.height = this._effectiveThumbThickness;
+            this._tempMeasure.left = left - this._effectiveBarOffset;
+            this._tempMeasure.top = this._currentMeasure.top + thumbPosition;
+            this._tempMeasure.width = this._currentMeasure.width;
+            this._tempMeasure.height = this._effectiveThumbThickness;
         }
         else {
-            this._thumbMeasure.left = this._currentMeasure.left + thumbPosition;
-            this._thumbMeasure.top = this._currentMeasure.top;
-            this._thumbMeasure.width = this._effectiveThumbThickness;
-            this._thumbMeasure.height = this._currentMeasure.height;
+            this._tempMeasure.left = this._currentMeasure.left + thumbPosition;
+            this._tempMeasure.top = this._currentMeasure.top;
+            this._tempMeasure.width = this._effectiveThumbThickness;
+            this._tempMeasure.height = this._currentMeasure.height;
         }
 
-        context.fillRect(this._thumbMeasure.left, this._thumbMeasure.top, this._thumbMeasure.width, this._thumbMeasure.height);
+        context.fillRect(this._tempMeasure.left, this._tempMeasure.top, this._tempMeasure.width, this._tempMeasure.height);
 
         context.restore();
     }
@@ -114,7 +114,7 @@ export class ScrollBar extends BaseSlider {
             this._originY = y;
 
             // Check if move is required
-            if (x < this._thumbMeasure.left || x > this._thumbMeasure.left + this._thumbMeasure.width || y < this._thumbMeasure.top || y > this._thumbMeasure.top + this._thumbMeasure.height) {
+            if (x < this._tempMeasure.left || x > this._tempMeasure.left + this._tempMeasure.width || y < this._tempMeasure.top || y > this._tempMeasure.top + this._tempMeasure.height) {
                 if (this.isVertical) {
                     this.value = this.minimum + (1 - ((y - this._currentMeasure.top) / this._currentMeasure.height)) * (this.maximum - this.minimum);
                 }

+ 10 - 1
src/Cameras/VR/vrExperienceHelper.ts

@@ -65,6 +65,10 @@ export interface VRTeleportationOptions {
      * The speed of the animation in distance/sec, apply when animationMode is TELEPORTATIONMODE_CONSTANTSPEED. (default 20 units / sec)
      */
     teleportationSpeed?: number;
+    /**
+     * The easing function used in the animation or null for Linear. (default CircleEase)
+     */
+    easingFunction?: EasingFunction;
 }
 
 /**
@@ -408,6 +412,7 @@ export class VRExperienceHelper {
     private _teleportationMode: number = VRExperienceHelper.TELEPORTATIONMODE_CONSTANTTIME;
     private _teleportationTime: number = 122;
     private _teleportationSpeed: number = 20;
+    private _teleportationEasing: EasingFunction;
     private _rotationAllowed: boolean = true;
     private _teleportBackwardsVector = new Vector3(0, -1, -1);
     private _teleportationTarget: Mesh;
@@ -983,6 +988,7 @@ export class VRExperienceHelper {
         //create easing functions
         this._circleEase = new CircleEase();
         this._circleEase.setEasingMode(EasingFunction.EASINGMODE_EASEINOUT);
+        this._teleportationEasing = this._circleEase;
 
         // Allow clicking in the vrDeviceOrientationCamera
         scene.onPointerObservable.add((e) => {
@@ -1492,6 +1498,9 @@ export class VRExperienceHelper {
             if (vrTeleportationOptions.teleportationSpeed && vrTeleportationOptions.teleportationSpeed > 0) {
                 this._teleportationSpeed = vrTeleportationOptions.teleportationSpeed;
             }
+            if (vrTeleportationOptions.easingFunction !== undefined) {
+                this._teleportationEasing = vrTeleportationOptions.easingFunction;
+            }
 
             if (this._leftController != null) {
                 this._enableTeleportationOnController(this._leftController);
@@ -2017,7 +2026,7 @@ export class VRExperienceHelper {
         ];
 
         animationCameraTeleportation.setKeys(animationCameraTeleportationKeys);
-        animationCameraTeleportation.setEasingFunction(this._circleEase);
+        animationCameraTeleportation.setEasingFunction(this._teleportationEasing);
         this.currentVRCamera.animations.push(animationCameraTeleportation);
 
         this._postProcessMove.animations = [];

+ 7 - 8
src/Cameras/XR/webXRController.ts

@@ -1,7 +1,7 @@
 import { Nullable } from "../../types";
 import { Observable } from "../../Misc/observable";
 import { AbstractMesh } from "../../Meshes/abstractMesh";
-import { Matrix, Quaternion, Vector3 } from '../../Maths/math.vector';
+import { Quaternion, Vector3 } from '../../Maths/math.vector';
 import { Ray } from '../../Culling/ray';
 import { Scene } from '../../scene';
 import { WebVRController } from '../../Gamepads/Controllers/webVRController';
@@ -31,7 +31,6 @@ export class WebXRController {
      */
     public onDisposeObservable = new Observable<{}>();
 
-    private _tmpMatrix = new Matrix();
     private _tmpQuaternion = new Quaternion();
     private _tmpVector = new Vector3();
 
@@ -55,6 +54,7 @@ export class WebXRController {
 
         if (this.inputSource.gripSpace) {
             this.grip = new AbstractMesh("controllerGrip", this.scene);
+            this.grip.rotationQuaternion = new Quaternion();
             if (this.parentContainer) {
                 this.parentContainer.addChild(this.grip);
             }
@@ -86,14 +86,13 @@ export class WebXRController {
         if (this.inputSource.gripSpace && this.grip) {
             let pose = xrFrame.getPose(this.inputSource.gripSpace, referenceSpace);
             if (pose) {
-                Matrix.FromFloat32ArrayToRefScaled(pose.transform.matrix, 0, 1, this._tmpMatrix);
+                this.grip.position.copyFrom(<any>(pose.transform.position));
+                this.grip.rotationQuaternion!.copyFrom(<any>(pose.transform.orientation));
                 if (!this.scene.useRightHandedSystem) {
-                    this._tmpMatrix.toggleModelMatrixHandInPlace();
+                    this.grip.position.z *= -1;
+                    this.grip.rotationQuaternion!.z *= -1;
+                    this.grip.rotationQuaternion!.w *= -1;
                 }
-                if (!this.grip.rotationQuaternion) {
-                    this.grip.rotationQuaternion = new Quaternion();
-                }
-                this._tmpMatrix.decompose(this.grip.scaling, this.grip.rotationQuaternion!, this.grip.position);
             }
         }
         if (this.gamepadController) {

+ 1 - 1
src/Materials/PBR/pbrMaterial.ts

@@ -115,7 +115,7 @@ export class PBRMaterial extends PBRBaseMaterial {
     public ambientTextureImpactOnAnalyticalLights: number = PBRMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS;
 
     /**
-     * Stores the alpha values in a texture.
+     * Stores the alpha values in a texture. Use luminance if texture.getAlphaFromRGB is true.
      */
     @serializeAsTexture()
     @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")

+ 7 - 0
src/Materials/shaderMaterial.ts

@@ -470,6 +470,12 @@ export class ShaderMaterial extends Material {
      * @returns true if ready, otherwise false
      */
     public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+        if (this._effect && this.isFrozen) {
+            if (this._wasPreviouslyReady) {
+                return true;
+            }
+        }
+
         var scene = this.getScene();
         var engine = scene.getEngine();
 
@@ -588,6 +594,7 @@ export class ShaderMaterial extends Material {
         }
 
         this._renderId = scene.getRenderId();
+        this._wasPreviouslyReady = true;
 
         return true;
     }

+ 14 - 0
src/Meshes/subMesh.ts

@@ -29,6 +29,20 @@ export class BaseSubMesh {
     public _materialEffect: Nullable<Effect> = null;
 
     /**
+     * Gets material defines used by the effect associated to the sub mesh
+     */
+    public get materialDefines(): Nullable<MaterialDefines> {
+        return this._materialDefines;
+    }
+
+    /**
+     * Sets material defines used by the effect associated to the sub mesh
+     */
+    public set materialDefines(defines: Nullable<MaterialDefines>) {
+        this._materialDefines = defines;
+    }
+
+    /**
      * Gets associated effect
      */
     public get effect(): Nullable<Effect> {

+ 14 - 3
src/Particles/solidParticleSystem.ts

@@ -131,6 +131,7 @@ export class SolidParticleSystem implements IDisposable {
     private _multimaterial: MultiMaterial;
     private _materialIndexesById: any;
     private _defaultMaterial: Material;
+    private _autoUpdateSubMeshes: boolean = false;
 
     /**
      * Creates a SPS (Solid Particle System) object.
@@ -656,9 +657,8 @@ export class SolidParticleSystem implements IDisposable {
         var modelShape = new ModelShape(this._shapeCounter, shape, indices, shapeNormals, shapeColors, shapeUV, posfunc, vtxfunc, material);
 
         // particles
-        var idx = this.nbParticles;
         for (var i = 0; i < nb; i++) {
-            this._insertNewParticle(idx, i, modelShape, shape, meshInd, meshUV, meshCol, meshNor, bbInfo, storage, options);
+            this._insertNewParticle(this.nbParticles, i, modelShape, shape, meshInd, meshUV, meshCol, meshNor, bbInfo, storage, options);
         }
         this._shapeCounter++;
         this._isNotBuilt = true;        // buildMesh() call is now expected for setParticles() to work
@@ -1265,6 +1265,9 @@ export class SolidParticleSystem implements IDisposable {
                 mesh._boundingInfo = new BoundingInfo(minimum, maximum, mesh._worldMatrix);
             }
         }
+        if (this._autoUpdateSubMeshes) {
+            this.computeSubMeshes();
+        }
         this.afterUpdateParticles(start, end, update);
         return this;
     }
@@ -1661,7 +1664,15 @@ export class SolidParticleSystem implements IDisposable {
     public set multimaterial(mm) {
         this._multimaterial = mm;
     }
-
+    /**
+     * If the subMeshes must be updated on the next call to setParticles()
+     */
+    public get autoUpdateSubMeshes(): boolean {
+        return this._autoUpdateSubMeshes;
+    }
+    public set autoUpdateSubMeshes(val: boolean) {
+        this._autoUpdateSubMeshes = val;
+    }
     // =======================================================================
     // Particle behavior logic
     // these following methods may be overwritten by the user to fit his needs