浏览代码

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

Michael Bond 5 年之前
父节点
当前提交
22da556daa
共有 100 个文件被更改,包括 4797 次插入2485 次删除
  1. 376 248
      dist/preview release/babylon.d.ts
  2. 2 2
      dist/preview release/babylon.js
  3. 818 338
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 812 542
      dist/preview release/babylon.module.d.ts
  6. 377 245
      dist/preview release/documentation.d.ts
  7. 1 1
      dist/preview release/glTF2Interface/package.json
  8. 4 0
      dist/preview release/gui/babylon.gui.d.ts
  9. 50 50
      dist/preview release/gui/babylon.gui.js
  10. 1 1
      dist/preview release/gui/babylon.gui.js.map
  11. 2 2
      dist/preview release/gui/babylon.gui.min.js
  12. 8 0
      dist/preview release/gui/babylon.gui.module.d.ts
  13. 2 2
      dist/preview release/gui/package.json
  14. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  15. 230 46
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  16. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  17. 11 0
      dist/preview release/inspector/babylon.inspector.d.ts
  18. 22 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  19. 7 7
      dist/preview release/inspector/package.json
  20. 17 26
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  21. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  22. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  23. 17 26
      dist/preview release/loaders/babylon.glTFFileLoader.js
  24. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  25. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  26. 2 0
      dist/preview release/loaders/babylonjs.loaders.d.ts
  27. 17 26
      dist/preview release/loaders/babylonjs.loaders.js
  28. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  29. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  30. 4 0
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  31. 3 3
      dist/preview release/loaders/package.json
  32. 2 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.js
  33. 1 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.js.map
  34. 1 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.min.js
  35. 2 1
      dist/preview release/materialsLibrary/babylonjs.materials.js
  36. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js.map
  37. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  38. 2 2
      dist/preview release/materialsLibrary/package.json
  39. 2 2
      dist/preview release/nodeEditor/package.json
  40. 1 1
      dist/preview release/package.json
  41. 1 1
      dist/preview release/packagesSizeBaseLine.json
  42. 2 2
      dist/preview release/postProcessesLibrary/package.json
  43. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  44. 8 1
      dist/preview release/serializers/babylon.objSerializer.js
  45. 1 1
      dist/preview release/serializers/babylon.objSerializer.js.map
  46. 1 1
      dist/preview release/serializers/babylon.objSerializer.min.js
  47. 8 1
      dist/preview release/serializers/babylonjs.serializers.js
  48. 1 1
      dist/preview release/serializers/babylonjs.serializers.js.map
  49. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  50. 3 3
      dist/preview release/serializers/package.json
  51. 812 542
      dist/preview release/viewer/babylon.module.d.ts
  52. 138 134
      dist/preview release/viewer/babylon.viewer.js
  53. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  54. 4 0
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  55. 9 0
      dist/preview release/what's new.md
  56. 6 1
      gui/src/2D/controls/textBlock.ts
  57. 1 1
      gui/src/3D/controls/control3D.ts
  58. 3 2
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/anchorSvgPoint.tsx
  59. 210 23
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx
  60. 21 1
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/curveEditor.scss
  61. 9 1
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx
  62. 2 2
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/keyframeSvgPoint.tsx
  63. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/commonPropertyGridComponent.tsx
  64. 23 30
      loaders/src/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.ts
  65. 4 1
      loaders/src/glTF/2.0/glTFLoader.ts
  66. 2 1
      materialsLibrary/src/grid/gridMaterial.ts
  67. 1 1
      package.json
  68. 7 1
      serializers/src/OBJ/objSerializer.ts
  69. 1 1
      src/DeviceInput/InputDevices/deviceSourceManager.ts
  70. 18 5
      src/DeviceInput/deviceInputSystem.ts
  71. 2 2
      src/Engines/thinEngine.ts
  72. 6 3
      src/Layers/effectLayer.ts
  73. 6 11
      src/LibDeclarations/webxr.d.ts
  74. 12 5
      src/Lights/Shadows/shadowGenerator.ts
  75. 1 1
      src/Materials/Background/backgroundMaterial.ts
  76. 11 2
      src/Materials/Node/Blocks/Vertex/instancesBlock.ts
  77. 57 11
      src/Materials/Node/Blocks/transformBlock.ts
  78. 3 3
      src/Materials/Node/nodeMaterial.ts
  79. 2 1
      src/Materials/Node/nodeMaterialBlock.ts
  80. 9 7
      src/Materials/PBR/pbrBaseMaterial.ts
  81. 35 15
      src/Materials/material.ts
  82. 9 2
      src/Materials/materialHelper.ts
  83. 2 2
      src/Materials/multiMaterial.ts
  84. 5 2
      src/Materials/shaderMaterial.ts
  85. 1 0
      src/Materials/shadowDepthWrapper.ts
  86. 3 2
      src/Materials/standardMaterial.ts
  87. 7 0
      src/Meshes/abstractMesh.ts
  88. 3 1
      src/Meshes/index.ts
  89. 107 4
      src/Meshes/mesh.ts
  90. 20 8
      src/Meshes/subMesh.ts
  91. 345 0
      src/Meshes/thinInstanceMesh.ts
  92. 12 25
      src/Particles/EmitterTypes/coneParticleEmitter.ts
  93. 2 0
      src/Particles/index.ts
  94. 0 5
      src/Particles/particleSystemComponent.ts
  95. 1 1
      src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts
  96. 6 5
      src/PostProcesses/volumetricLightScatteringPostProcess.ts
  97. 6 5
      src/Rendering/depthRenderer.ts
  98. 6 5
      src/Rendering/geometryBufferRenderer.ts
  99. 4 1
      src/Rendering/outlineRenderer.ts
  100. 0 0
      src/Shaders/ShadersInclude/hdrFilteringFunctions.fx

+ 376 - 248
dist/preview release/babylon.d.ts

@@ -16583,7 +16583,7 @@ declare module BABYLON {
          * @param useInstances specifies that instances should be used
          * @returns a boolean indicating that the submesh is ready or not
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Checks if the material is ready to render the requested mesh
          * @param mesh Define the mesh to render
@@ -20006,8 +20006,10 @@ declare module BABYLON {
          * @param defines specifies the list of active defines
          * @param useInstances defines if instances have to be turned on
          * @param useClipPlane defines if clip plane have to be turned on
+         * @param useInstances defines if instances have to be turned on
+         * @param useThinInstances defines if thin instances have to be turned on
          */
-        static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane?: Nullable<boolean>): void;
+        static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane?: Nullable<boolean>, useThinInstances?: boolean): void;
         /**
          * Prepares the defines for bones
          * @param mesh The mesh containing the geometry data we will draw
@@ -21464,8 +21466,9 @@ declare module BABYLON {
          * @param nodeMaterial defines the node material requesting the update
          * @param defines defines the material defines to update
          * @param useInstances specifies that instances should be used
+         * @param subMesh defines which submesh to render
          */
-        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean, subMesh?: SubMesh): void;
         /**
          * Lets the block try to connect some inputs automatically
          * @param material defines the hosting NodeMaterial
@@ -24054,7 +24057,7 @@ declare module BABYLON {
          * @param useInstances specifies that instances should be used
          * @returns a boolean indicating that the submesh is ready or not
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Returns the material effect
          * @returns the effect associated with the material
@@ -24339,7 +24342,7 @@ declare module BABYLON {
          * @param useInstances Define whether or not the material is used with instances
          * @returns true if ready, otherwise false
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Clones the current material and its related sub materials
          * @param name Define the name of the newly cloned material
@@ -24370,9 +24373,19 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Base class for submeshes
+     * Defines a subdivision inside a mesh
      */
-    export class BaseSubMesh {
+    export class SubMesh implements ICullable {
+        /** the material index to use */
+        materialIndex: number;
+        /** vertex index start */
+        verticesStart: number;
+        /** vertices count */
+        verticesCount: number;
+        /** index start */
+        indexStart: number;
+        /** indices count */
+        indexCount: number;
         /** @hidden */
         _materialDefines: Nullable<MaterialDefines>;
         /** @hidden */
@@ -24397,21 +24410,6 @@ declare module BABYLON {
          * @param defines defines the set of defines used to compile this effect
          */
         setEffect(effect: Nullable<Effect>, defines?: Nullable<MaterialDefines>): void;
-    }
-    /**
-     * Defines a subdivision inside a mesh
-     */
-    export class SubMesh extends BaseSubMesh implements ICullable {
-        /** the material index to use */
-        materialIndex: number;
-        /** vertex index start */
-        verticesStart: number;
-        /** vertices count */
-        verticesCount: number;
-        /** index start */
-        indexStart: number;
-        /** indices count */
-        indexCount: number;
         /** @hidden */
         _linesIndexCount: number;
         private _mesh;
@@ -24495,6 +24493,16 @@ declare module BABYLON {
          */
         getRenderingMesh(): Mesh;
         /**
+         * Returns the replacement mesh of the submesh
+         * @returns the replacement mesh (could be different from parent mesh)
+         */
+        getReplacementMesh(): Nullable<AbstractMesh>;
+        /**
+         * Returns the effective mesh of the submesh
+         * @returns the effective mesh (could be different from parent mesh)
+         */
+        getEffectiveMesh(): AbstractMesh;
+        /**
          * Returns the submesh material
          * @returns null or the current material
          */
@@ -27162,6 +27170,16 @@ declare module BABYLON {
         hardwareInstancedRendering: boolean[];
     }
     /**
+     * @hidden
+     **/
+    class _ThinInstanceDataStorage {
+        instancesCount: number;
+        matrixBuffer: Nullable<Buffer>;
+        matrixBufferSize: number;
+        matrixData: Nullable<Float32Array>;
+        boundingVectors: Array<Vector3>;
+    }
+    /**
      * Class used to represent renderable models
      */
     export class Mesh extends AbstractMesh implements IGetSetVerticesData {
@@ -27275,6 +27293,7 @@ declare module BABYLON {
          */
         set onBeforeDraw(callback: () => void);
         get hasInstances(): boolean;
+        get hasThinInstances(): boolean;
         /**
          * Gets the delay loading state of the mesh (when delay loading is turned on)
          * @see http://doc.babylonjs.com/how_to/using_the_incremental_loading_system
@@ -27314,6 +27333,8 @@ declare module BABYLON {
         _delayLoadingFunction: (any: any, mesh: Mesh) => void;
         /** @hidden */
         _instanceDataStorage: _InstanceDataStorage;
+        /** @hidden */
+        _thinInstanceDataStorage: _ThinInstanceDataStorage;
         private _effectiveMaterial;
         /** @hidden */
         _shouldGenerateFlatShading: boolean;
@@ -27555,6 +27576,7 @@ declare module BABYLON {
         _preActivateForIntermediateRendering(renderId: number): Mesh;
         /** @hidden */
         _registerInstanceForRenderId(instance: InstancedMesh, renderId: number): Mesh;
+        protected _afterComputeWorldMatrix(): void;
         /**
          * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
          * This means the mesh underlying bounding box and sphere are recomputed.
@@ -27719,6 +27741,8 @@ declare module BABYLON {
         /** @hidden */
         _renderWithInstances(subMesh: SubMesh, fillMode: number, batch: _InstancesBatch, effect: Effect, engine: Engine): Mesh;
         /** @hidden */
+        _renderWithThinInstances(subMesh: SubMesh, fillMode: number, effect: Effect, engine: Engine): void;
+        /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
         _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
@@ -27822,6 +27846,8 @@ declare module BABYLON {
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
         /** @hidden */
         _disposeInstanceSpecificData(): void;
+        /** @hidden */
+        _disposeThinInstanceSpecificData(): void;
         /**
          * Modifies the mesh geometry according to a displacement map.
          * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.
@@ -29314,6 +29340,7 @@ declare module BABYLON {
         BonesPerMesh: number;
         BONETEXTURE: boolean;
         INSTANCES: boolean;
+        THIN_INSTANCES: boolean;
         GLOSSINESS: boolean;
         ROUGHNESS: boolean;
         EMISSIVEASILLUMINATION: boolean;
@@ -31320,6 +31347,10 @@ declare module BABYLON {
          */
         get hasInstances(): boolean;
         /**
+         * Gets a boolean indicating if this mesh has thin instances
+         */
+        get hasThinInstances(): boolean;
+        /**
          * Perform relative position change from the point of view of behind the front of the mesh.
          * This is performed taking into account the meshes current rotation, so you do not have to care.
          * Supports definition of mesh facing forward or backward
@@ -49750,11 +49781,13 @@ declare module BABYLON {
         private _gamepadDisconnectedEvent;
         private static _MAX_KEYCODES;
         private static _MAX_POINTER_INPUTS;
+        private constructor();
         /**
-         * Default Constructor
-         * @param engine - engine to pull input element from
+         * Creates a new DeviceInputSystem instance
+         * @param engine Engine to pull input element from
+         * @returns The new instance
          */
-        constructor(engine: Engine);
+        static Create(engine: Engine): DeviceInputSystem;
         /**
          * Checks for current device input value, given an id and input index
          * @param deviceName Id of connected device
@@ -54568,6 +54601,7 @@ declare module BABYLON {
         RADIANCEOCCLUSION: boolean;
         HORIZONOCCLUSION: boolean;
         INSTANCES: boolean;
+        THIN_INSTANCES: boolean;
         NUM_BONE_INFLUENCERS: number;
         BonesPerMesh: number;
         BONETEXTURE: boolean;
@@ -60688,7 +60722,7 @@ declare module BABYLON {
          */
         get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
-        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean, subMesh?: SubMesh): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
 }
@@ -64895,6 +64929,85 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+        interface Mesh {
+            /**
+             * Creates a new thin instance
+             * @param matrix the matrix or array of matrices (position, rotation, scale) of the thin instance(s) to create
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             * @returns the thin instance index number. If you pass an array of matrices, other instance indexes are index+1, index+2, etc
+             */
+            thinInstanceAdd(matrix: DeepImmutableObject<Matrix> | Array<DeepImmutableObject<Matrix>>, refresh: boolean): number;
+            /**
+             * Adds the transformation (matrix) of the current mesh as a thin instance
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             * @returns the thin instance index number
+             */
+            thinInstanceAddSelf(refresh: boolean): number;
+            /**
+             * Registers a custom attribute to be used with thin instances
+             * @param kind name of the attribute
+             * @param stride size in floats of the attribute
+             */
+            thinInstanceRegisterAttribute(kind: string, stride: number): void;
+            /**
+             * Sets the matrix of a thin instance
+             * @param index index of the thin instance
+             * @param matrix matrix to set
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             */
+            thinInstanceSetMatrixAt(index: number, matrix: DeepImmutableObject<Matrix>, refresh: boolean): void;
+            /**
+             * Sets the value of a custom attribute for a thin instance
+             * @param kind name of the attribute
+             * @param index index of the thin instance
+             * @param value value to set
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             */
+            thinInstanceSetAttributeAt(kind: string, index: number, value: Array<number>, refresh: boolean): void;
+            /**
+             * Gets / sets the number of thin instances to display. Note that you can't set a number higher than what the underlying buffer can handle.
+             */
+            thinInstanceCount: number;
+            /**
+             * Sets a buffer to be used with thin instances. This method is a faster way to setup multiple instances than calling thinInstanceAdd repeatedly
+             * @param kind name of the attribute. Use "matrix" to setup the buffer of matrices
+             * @param buffer buffer to set
+             * @param stride size in floats of each value of the buffer
+             * @param staticBuffer indicates that the buffer is static, so that you won't change it after it is set (better performances - false by default)
+             */
+            thinInstanceSetBuffer(kind: string, buffer: Nullable<Float32Array>, stride: number, staticBuffer: boolean): void;
+            /**
+             * Synchronize the gpu buffers with a thin instance buffer. Call this method if you update later on the buffers passed to thinInstanceSetBuffer
+             * @param kind name of the attribute to update. Use "matrix" to update the buffer of matrices
+             */
+            thinInstanceBufferUpdated(kind: string): void;
+            /**
+             * Refreshes the bounding info, taking into account all the thin instances defined
+             * @param forceRefreshParentInfo true to force recomputing the mesh bounding info and use it to compute the aggregated bounding info
+             */
+            thinInstanceRefreshBoundingInfo(forceRefreshParentInfo: boolean): void;
+            /** @hidden */
+            _thinInstanceInitializeUserStorage(): void;
+            /** @hidden */
+            _thinInstanceUpdateBufferSize(kind: string, numInstances: number): void;
+            /** @hidden */
+            _userThinInstanceBuffersStorage: {
+                data: {
+                    [key: string]: Float32Array;
+                };
+                sizes: {
+                    [key: string]: number;
+                };
+                vertexBuffers: {
+                    [key: string]: Nullable<VertexBuffer>;
+                };
+                strides: {
+                    [key: string]: number;
+                };
+            };
+        }
+}
+declare module BABYLON {
     /**
      * Navigation plugin interface to add navigation constrained by a navigation mesh
      */
@@ -66114,10 +66227,6 @@ declare module BABYLON {
              */
             getHierarchyEmittedParticleSystems(): IParticleSystem[];
         }
-    /**
-     * @hidden
-     */
-    export var _IDoNeedToBeInTheBuild: number;
 }
 declare module BABYLON {
     /** Defines the 4 color options */
@@ -71982,6 +72091,15 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * An interface for all Hit test features
+     */
+    export interface IWebXRHitTestFeature<T extends IWebXRLegacyHitResult> extends IWebXRFeature {
+        /**
+         * Triggered when new babylon (transformed) hit test results are available
+         */
+        onHitTestResultObservable: Observable<T[]>;
+    }
+    /**
      * Options used for hit testing
      */
     export interface IWebXRLegacyHitTestOptions {
@@ -72012,7 +72130,7 @@ declare module BABYLON {
      * Hit test (or Ray-casting) is used to interact with the real world.
      * For further information read here - https://github.com/immersive-web/hit-test
      */
-    export class WebXRHitTestLegacy extends WebXRAbstractFeature {
+    export class WebXRHitTestLegacy extends WebXRAbstractFeature implements IWebXRHitTestFeature<IWebXRLegacyHitResult> {
         /**
          * options to use when constructing this feature
          */
@@ -72091,48 +72209,74 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Options used in the plane detector module
+     * Options used for hit testing (version 2)
      */
-    export interface IWebXRPlaneDetectorOptions {
+    export interface IWebXRHitTestOptions extends IWebXRLegacyHitTestOptions {
         /**
-         * The node to use to transform the local results to world coordinates
+         * Do not create a permanent hit test. Will usually be used when only
+         * transient inputs are needed.
          */
-        worldParentNode?: TransformNode;
+        disablePermanentHitTest?: boolean;
+        /**
+         * Enable transient (for example touch-based) hit test inspections
+         */
+        enableTransientHitTest?: boolean;
+        /**
+         * Offset ray for the permanent hit test
+         */
+        offsetRay?: Vector3;
+        /**
+         * Offset ray for the transient hit test
+         */
+        transientOffsetRay?: Vector3;
+        /**
+         * Instead of using viewer space for hit tests, use the reference space defined in the session manager
+         */
+        useReferenceSpace?: boolean;
     }
     /**
-     * A babylon interface for a WebXR plane.
-     * A Plane is actually a polygon, built from N points in space
-     *
-     * Supported in chrome 79, not supported in canary 81 ATM
+     * Interface defining the babylon result of hit-test
      */
-    export interface IWebXRPlane {
+    export interface IWebXRHitResult extends IWebXRLegacyHitResult {
         /**
-         * a babylon-assigned ID for this polygon
+         * The input source that generated this hit test (if transient)
          */
-        id: number;
+        inputSource?: XRInputSource;
         /**
-         * an array of vector3 points in babylon space. right/left hand system is taken into account.
+         * Is this a transient hit test
          */
-        polygonDefinition: Array<Vector3>;
+        isTransient?: boolean;
         /**
-         * A transformation matrix to apply on the mesh that will be built using the polygonDefinition
-         * Local vs. World are decided if worldParentNode was provided or not in the options when constructing the module
+         * Position of the hit test result
          */
-        transformationMatrix: Matrix;
+        position: Vector3;
         /**
-         * the native xr-plane object
+         * Rotation of the hit test result
          */
-        xrPlane: XRPlane;
+        rotationQuaternion: Quaternion;
+        /**
+         * The native hit test result
+         */
+        xrHitResult: XRHitTestResult;
     }
     /**
-     * The plane detector is used to detect planes in the real world when in AR
-     * For more information see https://github.com/immersive-web/real-world-geometry/
+     * The currently-working hit-test module.
+     * Hit test (or Ray-casting) is used to interact with the real world.
+     * For further information read here - https://github.com/immersive-web/hit-test
+     *
+     * Tested on chrome (mobile) 80.
      */
-    export class WebXRPlaneDetector extends WebXRAbstractFeature {
-        private _options;
-        private _detectedPlanes;
-        private _enabled;
-        private _lastFrameDetected;
+    export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestFeature<IWebXRHitResult> {
+        /**
+         * options to use when constructing this feature
+         */
+        readonly options: IWebXRHitTestOptions;
+        private _tmpMat;
+        private _tmpPos;
+        private _tmpQuat;
+        private _transientXrHitTestSource;
+        private _xrHitTestSource;
+        private initHitTestSource;
         /**
          * The module's name
          */
@@ -72144,36 +72288,49 @@ declare module BABYLON {
          */
         static readonly Version: number;
         /**
-         * Observers registered here will be executed when a new plane was added to the session
+         * When set to true, each hit test will have its own position/rotation objects
+         * When set to false, position and rotation objects will be reused for each hit test. It is expected that
+         * the developers will clone them or copy them as they see fit.
          */
-        onPlaneAddedObservable: Observable<IWebXRPlane>;
+        autoCloneTransformation: boolean;
         /**
-         * Observers registered here will be executed when a plane is no longer detected in the session
+         * Triggered when new babylon (transformed) hit test results are available
          */
-        onPlaneRemovedObservable: Observable<IWebXRPlane>;
+        onHitTestResultObservable: Observable<IWebXRHitResult[]>;
         /**
-         * Observers registered here will be executed when an existing plane updates (for example - expanded)
-         * This can execute N times every frame
+         * Use this to temporarily pause hit test checks.
          */
-        onPlaneUpdatedObservable: Observable<IWebXRPlane>;
+        paused: boolean;
         /**
-         * construct a new Plane Detector
-         * @param _xrSessionManager an instance of xr Session manager
-         * @param _options configuration to use when constructing this feature
+         * Creates a new instance of the hit test feature
+         * @param _xrSessionManager an instance of WebXRSessionManager
+         * @param options options to use when constructing this feature
          */
-        constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * options to use when constructing this feature
+         */
+        options?: IWebXRHitTestOptions);
+        /**
+         * 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;
         /**
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
         protected _onXRFrame(frame: XRFrame): void;
-        private _init;
-        private _updatePlaneWithXRPlane;
-        /**
-         * avoiding using Array.find for global support.
-         * @param xrPlane the plane to find in the array
-         */
-        private findIndexInPlaneArray;
+        private _processWebXRHitTestResult;
     }
 }
 declare module BABYLON {
@@ -72182,18 +72339,14 @@ declare module BABYLON {
      */
     export interface IWebXRAnchorSystemOptions {
         /**
-         * Should a new anchor be added every time a select event is triggered
-         */
-        addAnchorOnSelect?: boolean;
-        /**
-         * should the anchor system use plane detection.
-         * If set to true, the plane-detection feature should be set using setPlaneDetector
-         */
-        usePlaneDetection?: boolean;
-        /**
          * a node that will be used to convert local to world coordinates
          */
         worldParentNode?: TransformNode;
+        /**
+         * If set to true a reference of the created anchors will be kept until the next session starts
+         * If not defined, anchors will be removed from the array when the feature is detached or the session ended.
+         */
+        doNotRemoveAnchorsOnSessionEnded?: boolean;
     }
     /**
      * A babylon container for an XR Anchor
@@ -72211,21 +72364,21 @@ declare module BABYLON {
          * The native anchor object
          */
         xrAnchor: XRAnchor;
+        /**
+         * if defined, this object will be constantly updated by the anchor's position and rotation
+         */
+        attachedNode?: TransformNode;
     }
     /**
-     * An implementation of the anchor system of WebXR.
-     * Note that the current documented implementation is not available in any browser. Future implementations
-     * will use the frame to create an anchor and not the session or a detected plane
+     * An implementation of the anchor system for WebXR.
      * For further information see https://github.com/immersive-web/anchors/
      */
     export class WebXRAnchorSystem extends WebXRAbstractFeature {
         private _options;
-        private _enabled;
-        private _hitTestModule;
         private _lastFrameDetected;
-        private _onSelect;
-        private _planeDetector;
         private _trackedAnchors;
+        private _referenceSpaceForFrameAnchors;
+        private _futureAnchors;
         /**
          * The module's name
          */
@@ -72250,26 +72403,43 @@ declare module BABYLON {
          */
         onAnchorUpdatedObservable: Observable<IWebXRAnchor>;
         /**
+         * Set the reference space to use for anchor creation, when not using a hit test.
+         * Will default to the session's reference space if not defined
+         */
+        set referenceSpaceForFrameAnchors(referenceSpace: XRReferenceSpace);
+        /**
          * constructs a new anchor system
          * @param _xrSessionManager an instance of WebXRSessionManager
          * @param _options configuration object for this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRAnchorSystemOptions);
+        private _tmpVector;
+        private _tmpQuaternion;
+        private _populateTmpTransformation;
         /**
-         * Add anchor at a specific XR point.
+         * Create a new anchor point using a hit test result at a specific point in the scene
+         * An anchor is tracked only after it is added to the trackerAnchors in xrFrame. The promise returned here does not yet guaranty that.
+         * Use onAnchorAddedObservable to get newly added anchors if you require tracking guaranty.
          *
-         * @param xrRigidTransformation xr-coordinates where a new anchor should be added
-         * @param anchorCreator the object o use to create an anchor with. either a session or a plane
-         * @returns a promise the fulfills when the anchor was created
-         */
-        addAnchorAtRigidTransformation(xrRigidTransformation: XRRigidTransform, anchorCreator?: XRAnchorCreator): Promise<XRAnchor>;
-        /**
-         * attach this feature
-         * Will usually be called by the features manager
+         * @param hitTestResult The hit test result to use for this anchor creation
+         * @param position an optional position offset for this anchor
+         * @param rotationQuaternion an optional rotation offset for this anchor
+         * @returns A promise that fulfills when the XR anchor was registered in the system (but not necessarily added to the tracked anchors)
+         */
+        addAnchorPointUsingHitTestResultAsync(hitTestResult: IWebXRHitResult, position?: Vector3, rotationQuaternion?: Quaternion): Promise<XRAnchor>;
+        /**
+         * Add a new anchor at a specific position and rotation
+         * This function will add a new anchor per default in the next available frame. Unless forced, the createAnchor function
+         * will be called in the next xrFrame loop to make sure that the anchor can be created correctly.
+         * An anchor is tracked only after it is added to the trackerAnchors in xrFrame. The promise returned here does not yet guaranty that.
+         * Use onAnchorAddedObservable to get newly added anchors if you require tracking guaranty.
          *
-         * @returns true if successful.
+         * @param position the position in which to add an anchor
+         * @param rotationQuaternion an optional rotation for the anchor transformation
+         * @param forceCreateInCurrentFrame force the creation of this anchor in the current frame. Must be called inside xrFrame loop!
+         * @returns A promise that fulfills when the XR anchor was registered in the system (but not necessarily added to the tracked anchors)
          */
-        attach(): boolean;
+        addAnchorAtPositionAndRotationAsync(position: Vector3, rotationQuaternion?: Quaternion, forceCreateInCurrentFrame?: boolean): Promise<XRAnchor>;
         /**
          * detach this feature.
          * Will usually be called by the features manager
@@ -72281,24 +72451,113 @@ declare module BABYLON {
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
+        protected _onXRFrame(frame: XRFrame): void;
+        /**
+         * avoiding using Array.find for global support.
+         * @param xrAnchor the plane to find in the array
+         */
+        private _findIndexInAnchorArray;
+        private _updateAnchorWithXRFrame;
+        private _createAnchorAtTransformation;
+    }
+}
+declare module BABYLON {
+    /**
+     * Options used in the plane detector module
+     */
+    export interface IWebXRPlaneDetectorOptions {
+        /**
+         * The node to use to transform the local results to world coordinates
+         */
+        worldParentNode?: TransformNode;
+        /**
+         * If set to true a reference of the created planes will be kept until the next session starts
+         * If not defined, planes will be removed from the array when the feature is detached or the session ended.
+         */
+        doNotRemovePlanesOnSessionEnded?: boolean;
+    }
+    /**
+     * A babylon interface for a WebXR plane.
+     * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
+     */
+    export interface IWebXRPlane {
+        /**
+         * a babylon-assigned ID for this polygon
+         */
+        id: number;
+        /**
+         * an array of vector3 points in babylon space. right/left hand system is taken into account.
+         */
+        polygonDefinition: Array<Vector3>;
+        /**
+         * A transformation matrix to apply on the mesh that will be built using the polygonDefinition
+         * Local vs. World are decided if worldParentNode was provided or not in the options when constructing the module
+         */
+        transformationMatrix: Matrix;
+        /**
+         * the native xr-plane object
+         */
+        xrPlane: XRPlane;
+    }
+    /**
+     * The plane detector is used to detect planes in the real world when in AR
+     * For more information see https://github.com/immersive-web/real-world-geometry/
+     */
+    export class WebXRPlaneDetector extends WebXRAbstractFeature {
+        private _options;
+        private _detectedPlanes;
+        private _enabled;
+        private _lastFrameDetected;
+        /**
+         * 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;
+        /**
+         * Observers registered here will be executed when a new plane was added to the session
+         */
+        onPlaneAddedObservable: Observable<IWebXRPlane>;
+        /**
+         * Observers registered here will be executed when a plane is no longer detected in the session
+         */
+        onPlaneRemovedObservable: Observable<IWebXRPlane>;
+        /**
+         * Observers registered here will be executed when an existing plane updates (for example - expanded)
+         * This can execute N times every frame
+         */
+        onPlaneUpdatedObservable: Observable<IWebXRPlane>;
+        /**
+         * construct a new Plane Detector
+         * @param _xrSessionManager an instance of xr Session manager
+         * @param _options configuration to use when constructing this feature
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
         /**
-         * If set, it will improve performance by using the current hit-test results instead of executing a new hit-test
-         * @param hitTestModule the hit-test module to use.
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
          */
-        setHitTestModule(hitTestModule: WebXRHitTestLegacy): void;
+        detach(): boolean;
         /**
-         * set the plane detector to use in order to create anchors from frames
-         * @param planeDetector the plane-detector module to use
-         * @param enable enable plane-anchors. default is true
+         * Dispose this feature and all of the resources attached
          */
-        setPlaneDetector(planeDetector: WebXRPlaneDetector, enable?: boolean): void;
+        dispose(): void;
         protected _onXRFrame(frame: XRFrame): void;
+        private _init;
+        private _updatePlaneWithXRPlane;
         /**
          * avoiding using Array.find for global support.
-         * @param xrAnchor the plane to find in the array
+         * @param xrPlane the plane to find in the array
          */
-        private _findIndexInAnchorArray;
-        private _updateAnchorWithXRFrame;
+        private findIndexInPlaneArray;
     }
 }
 declare module BABYLON {
@@ -72539,132 +72798,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Options used for hit testing (version 2)
-     */
-    export interface IWebXRHitTestOptions extends IWebXRLegacyHitTestOptions {
-        /**
-         * Do not create a permanent hit test. Will usually be used when only
-         * transient inputs are needed.
-         */
-        disablePermanentHitTest?: boolean;
-        /**
-         * Enable transient (for example touch-based) hit test inspections
-         */
-        enableTransientHitTest?: boolean;
-        /**
-         * Offset ray for the permanent hit test
-         */
-        offsetRay?: Vector3;
-        /**
-         * Offset ray for the transient hit test
-         */
-        transientOffsetRay?: Vector3;
-        /**
-         * Instead of using viewer space for hit tests, use the reference space defined in the session manager
-         */
-        useReferenceSpace?: boolean;
-    }
-    /**
-     * Interface defining the babylon result of hit-test
-     */
-    export interface IWebXRHitResult extends IWebXRLegacyHitResult {
-        /**
-         * The input source that generated this hit test (if transient)
-         */
-        inputSource?: XRInputSource;
-        /**
-         * Is this a transient hit test
-         */
-        isTransient?: boolean;
-        /**
-         * Position of the hit test result
-         */
-        position: Vector3;
-        /**
-         * Rotation of the hit test result
-         */
-        rotationQuaternion: Quaternion;
-    }
-    /**
-     * The currently-working hit-test module.
-     * Hit test (or Ray-casting) is used to interact with the real world.
-     * For further information read here - https://github.com/immersive-web/hit-test
-     *
-     * Tested on chrome (mobile) 80.
-     */
-    export class WebXRHitTest extends WebXRAbstractFeature {
-        /**
-         * options to use when constructing this feature
-         */
-        readonly options: IWebXRHitTestOptions;
-        private _tmpMat;
-        private _tmpPos;
-        private _tmpQuat;
-        private _transientXrHitTestSource;
-        private _xrHitTestSource;
-        private initHitTestSource;
-        /**
-         * 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;
-        /**
-         * When set to true, each hit test will have its own position/rotation objects
-         * When set to false, position and rotation objects will be reused for each hit test. It is expected that
-         * the developers will clone them or copy them as they see fit.
-         */
-        autoCloneTransformation: boolean;
-        /**
-         * Populated with the last native XR Hit Results
-         */
-        lastNativeXRHitResults: XRHitResult[];
-        /**
-         * Triggered when new babylon (transformed) hit test results are available
-         */
-        onHitTestResultObservable: Observable<IWebXRHitResult[]>;
-        /**
-         * Use this to temporarily pause hit test checks.
-         */
-        paused: boolean;
-        /**
-         * Creates a new instance of the hit test feature
-         * @param _xrSessionManager an instance of WebXRSessionManager
-         * @param options options to use when constructing this feature
-         */
-        constructor(_xrSessionManager: WebXRSessionManager, 
-        /**
-         * options to use when constructing this feature
-         */
-        options?: IWebXRHitTestOptions);
-        /**
-         * 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;
-        /**
-         * Dispose this feature and all of the resources attached
-         */
-        dispose(): void;
-        protected _onXRFrame(frame: XRFrame): void;
-        private _processWebXRHitTestResult;
-    }
-}
-declare module BABYLON {
-    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -73468,7 +73601,7 @@ interface XRSessionInit {
     requiredFeatures?: string[];
 }
 
-interface XRSession extends XRAnchorCreator {
+interface XRSession {
     addEventListener: Function;
     removeEventListener: Function;
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<XRReferenceSpace>;
@@ -73509,6 +73642,7 @@ interface XRFrame {
     getHitTestResultsForTransientInput(hitTestSource: XRTransientInputHitTestSource): Array<XRTransientInputHitTestResult>;
     // Anchors
     trackedAnchors?: XRAnchorSet;
+    createAnchor(pose: XRRigidTransform, space: XRSpace): Promise<XRAnchor>;
     // Planes
     worldInformation: {
         detectedPlanes?: XRPlaneSet;
@@ -73593,6 +73727,8 @@ interface XRTransientInputHitTestResult {
 
 interface XRHitTestResult {
     getPose(baseSpace: XRSpace): XRPose | undefined;
+    // When anchor system is enabled
+    createAnchor?(pose: XRRigidTransform): Promise<XRAnchor>;
 }
 
 interface XRHitTestSource {
@@ -73616,21 +73752,13 @@ interface XRTransientInputHitTestOptionsInit {
 }
 
 interface XRAnchor {
-    // remove?
-    id?: string;
     anchorSpace: XRSpace;
-    lastChangedTime: number;
-    detach(): void;
+    delete(): void;
 }
 
-interface XRPlane extends XRAnchorCreator {
+interface XRPlane {
     orientation: "Horizontal" | "Vertical";
     planeSpace: XRSpace;
     polygon: Array<DOMPointReadOnly>;
     lastChangedTime: number;
-}
-
-interface XRAnchorCreator {
-    // AR Anchors
-    createAnchor(pose: XRPose | XRRigidTransform, referenceSpace: XRReferenceSpace): Promise<XRAnchor>;
 }

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


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


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


文件差异内容过多而无法显示
+ 812 - 542
dist/preview release/babylon.module.d.ts


+ 377 - 245
dist/preview release/documentation.d.ts

@@ -16583,7 +16583,7 @@ declare module BABYLON {
          * @param useInstances specifies that instances should be used
          * @returns a boolean indicating that the submesh is ready or not
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Checks if the material is ready to render the requested mesh
          * @param mesh Define the mesh to render
@@ -20006,8 +20006,10 @@ declare module BABYLON {
          * @param defines specifies the list of active defines
          * @param useInstances defines if instances have to be turned on
          * @param useClipPlane defines if clip plane have to be turned on
+         * @param useInstances defines if instances have to be turned on
+         * @param useThinInstances defines if thin instances have to be turned on
          */
-        static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane?: Nullable<boolean>): void;
+        static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane?: Nullable<boolean>, useThinInstances?: boolean): void;
         /**
          * Prepares the defines for bones
          * @param mesh The mesh containing the geometry data we will draw
@@ -21464,8 +21466,9 @@ declare module BABYLON {
          * @param nodeMaterial defines the node material requesting the update
          * @param defines defines the material defines to update
          * @param useInstances specifies that instances should be used
+         * @param subMesh defines which submesh to render
          */
-        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean, subMesh?: SubMesh): void;
         /**
          * Lets the block try to connect some inputs automatically
          * @param material defines the hosting NodeMaterial
@@ -24054,7 +24057,7 @@ declare module BABYLON {
          * @param useInstances specifies that instances should be used
          * @returns a boolean indicating that the submesh is ready or not
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Returns the material effect
          * @returns the effect associated with the material
@@ -24339,7 +24342,7 @@ declare module BABYLON {
          * @param useInstances Define whether or not the material is used with instances
          * @returns true if ready, otherwise false
          */
-        isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean;
+        isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean;
         /**
          * Clones the current material and its related sub materials
          * @param name Define the name of the newly cloned material
@@ -24370,9 +24373,19 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Base class for submeshes
+     * Defines a subdivision inside a mesh
      */
-    export class BaseSubMesh {
+    export class SubMesh implements ICullable {
+        /** the material index to use */
+        materialIndex: number;
+        /** vertex index start */
+        verticesStart: number;
+        /** vertices count */
+        verticesCount: number;
+        /** index start */
+        indexStart: number;
+        /** indices count */
+        indexCount: number;
         /** @hidden */
         _materialDefines: Nullable<MaterialDefines>;
         /** @hidden */
@@ -24397,21 +24410,6 @@ declare module BABYLON {
          * @param defines defines the set of defines used to compile this effect
          */
         setEffect(effect: Nullable<Effect>, defines?: Nullable<MaterialDefines>): void;
-    }
-    /**
-     * Defines a subdivision inside a mesh
-     */
-    export class SubMesh extends BaseSubMesh implements ICullable {
-        /** the material index to use */
-        materialIndex: number;
-        /** vertex index start */
-        verticesStart: number;
-        /** vertices count */
-        verticesCount: number;
-        /** index start */
-        indexStart: number;
-        /** indices count */
-        indexCount: number;
         /** @hidden */
         _linesIndexCount: number;
         private _mesh;
@@ -24495,6 +24493,16 @@ declare module BABYLON {
          */
         getRenderingMesh(): Mesh;
         /**
+         * Returns the replacement mesh of the submesh
+         * @returns the replacement mesh (could be different from parent mesh)
+         */
+        getReplacementMesh(): Nullable<AbstractMesh>;
+        /**
+         * Returns the effective mesh of the submesh
+         * @returns the effective mesh (could be different from parent mesh)
+         */
+        getEffectiveMesh(): AbstractMesh;
+        /**
          * Returns the submesh material
          * @returns null or the current material
          */
@@ -27162,6 +27170,16 @@ declare module BABYLON {
         hardwareInstancedRendering: boolean[];
     }
     /**
+     * @hidden
+     **/
+    class _ThinInstanceDataStorage {
+        instancesCount: number;
+        matrixBuffer: Nullable<Buffer>;
+        matrixBufferSize: number;
+        matrixData: Nullable<Float32Array>;
+        boundingVectors: Array<Vector3>;
+    }
+    /**
      * Class used to represent renderable models
      */
     export class Mesh extends AbstractMesh implements IGetSetVerticesData {
@@ -27275,6 +27293,7 @@ declare module BABYLON {
          */
         set onBeforeDraw(callback: () => void);
         get hasInstances(): boolean;
+        get hasThinInstances(): boolean;
         /**
          * Gets the delay loading state of the mesh (when delay loading is turned on)
          * @see http://doc.babylonjs.com/how_to/using_the_incremental_loading_system
@@ -27314,6 +27333,8 @@ declare module BABYLON {
         _delayLoadingFunction: (any: any, mesh: Mesh) => void;
         /** @hidden */
         _instanceDataStorage: _InstanceDataStorage;
+        /** @hidden */
+        _thinInstanceDataStorage: _ThinInstanceDataStorage;
         private _effectiveMaterial;
         /** @hidden */
         _shouldGenerateFlatShading: boolean;
@@ -27555,6 +27576,7 @@ declare module BABYLON {
         _preActivateForIntermediateRendering(renderId: number): Mesh;
         /** @hidden */
         _registerInstanceForRenderId(instance: InstancedMesh, renderId: number): Mesh;
+        protected _afterComputeWorldMatrix(): void;
         /**
          * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
          * This means the mesh underlying bounding box and sphere are recomputed.
@@ -27719,6 +27741,8 @@ declare module BABYLON {
         /** @hidden */
         _renderWithInstances(subMesh: SubMesh, fillMode: number, batch: _InstancesBatch, effect: Effect, engine: Engine): Mesh;
         /** @hidden */
+        _renderWithThinInstances(subMesh: SubMesh, fillMode: number, effect: Effect, engine: Engine): void;
+        /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
         _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
@@ -27822,6 +27846,8 @@ declare module BABYLON {
         dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
         /** @hidden */
         _disposeInstanceSpecificData(): void;
+        /** @hidden */
+        _disposeThinInstanceSpecificData(): void;
         /**
          * Modifies the mesh geometry according to a displacement map.
          * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.
@@ -29314,6 +29340,7 @@ declare module BABYLON {
         BonesPerMesh: number;
         BONETEXTURE: boolean;
         INSTANCES: boolean;
+        THIN_INSTANCES: boolean;
         GLOSSINESS: boolean;
         ROUGHNESS: boolean;
         EMISSIVEASILLUMINATION: boolean;
@@ -31320,6 +31347,10 @@ declare module BABYLON {
          */
         get hasInstances(): boolean;
         /**
+         * Gets a boolean indicating if this mesh has thin instances
+         */
+        get hasThinInstances(): boolean;
+        /**
          * Perform relative position change from the point of view of behind the front of the mesh.
          * This is performed taking into account the meshes current rotation, so you do not have to care.
          * Supports definition of mesh facing forward or backward
@@ -54568,6 +54599,7 @@ declare module BABYLON {
         RADIANCEOCCLUSION: boolean;
         HORIZONOCCLUSION: boolean;
         INSTANCES: boolean;
+        THIN_INSTANCES: boolean;
         NUM_BONE_INFLUENCERS: number;
         BonesPerMesh: number;
         BONETEXTURE: boolean;
@@ -60688,7 +60720,7 @@ declare module BABYLON {
          */
         get instanceID(): NodeMaterialConnectionPoint;
         autoConfigure(material: NodeMaterial): void;
-        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean): void;
+        prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances?: boolean, subMesh?: SubMesh): void;
         protected _buildBlock(state: NodeMaterialBuildState): this;
     }
 }
@@ -64895,6 +64927,85 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+        interface Mesh {
+            /**
+             * Creates a new thin instance
+             * @param matrix the matrix or array of matrices (position, rotation, scale) of the thin instance(s) to create
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             * @returns the thin instance index number. If you pass an array of matrices, other instance indexes are index+1, index+2, etc
+             */
+            thinInstanceAdd(matrix: DeepImmutableObject<Matrix> | Array<DeepImmutableObject<Matrix>>, refresh: boolean): number;
+            /**
+             * Adds the transformation (matrix) of the current mesh as a thin instance
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             * @returns the thin instance index number
+             */
+            thinInstanceAddSelf(refresh: boolean): number;
+            /**
+             * Registers a custom attribute to be used with thin instances
+             * @param kind name of the attribute
+             * @param stride size in floats of the attribute
+             */
+            thinInstanceRegisterAttribute(kind: string, stride: number): void;
+            /**
+             * Sets the matrix of a thin instance
+             * @param index index of the thin instance
+             * @param matrix matrix to set
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             */
+            thinInstanceSetMatrixAt(index: number, matrix: DeepImmutableObject<Matrix>, refresh: boolean): void;
+            /**
+             * Sets the value of a custom attribute for a thin instance
+             * @param kind name of the attribute
+             * @param index index of the thin instance
+             * @param value value to set
+             * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+             */
+            thinInstanceSetAttributeAt(kind: string, index: number, value: Array<number>, refresh: boolean): void;
+            /**
+             * Gets / sets the number of thin instances to display. Note that you can't set a number higher than what the underlying buffer can handle.
+             */
+            thinInstanceCount: number;
+            /**
+             * Sets a buffer to be used with thin instances. This method is a faster way to setup multiple instances than calling thinInstanceAdd repeatedly
+             * @param kind name of the attribute. Use "matrix" to setup the buffer of matrices
+             * @param buffer buffer to set
+             * @param stride size in floats of each value of the buffer
+             * @param staticBuffer indicates that the buffer is static, so that you won't change it after it is set (better performances - false by default)
+             */
+            thinInstanceSetBuffer(kind: string, buffer: Nullable<Float32Array>, stride: number, staticBuffer: boolean): void;
+            /**
+             * Synchronize the gpu buffers with a thin instance buffer. Call this method if you update later on the buffers passed to thinInstanceSetBuffer
+             * @param kind name of the attribute to update. Use "matrix" to update the buffer of matrices
+             */
+            thinInstanceBufferUpdated(kind: string): void;
+            /**
+             * Refreshes the bounding info, taking into account all the thin instances defined
+             * @param forceRefreshParentInfo true to force recomputing the mesh bounding info and use it to compute the aggregated bounding info
+             */
+            thinInstanceRefreshBoundingInfo(forceRefreshParentInfo: boolean): void;
+            /** @hidden */
+            _thinInstanceInitializeUserStorage(): void;
+            /** @hidden */
+            _thinInstanceUpdateBufferSize(kind: string, numInstances: number): void;
+            /** @hidden */
+            _userThinInstanceBuffersStorage: {
+                data: {
+                    [key: string]: Float32Array;
+                };
+                sizes: {
+                    [key: string]: number;
+                };
+                vertexBuffers: {
+                    [key: string]: Nullable<VertexBuffer>;
+                };
+                strides: {
+                    [key: string]: number;
+                };
+            };
+        }
+}
+declare module BABYLON {
     /**
      * Navigation plugin interface to add navigation constrained by a navigation mesh
      */
@@ -66114,10 +66225,6 @@ declare module BABYLON {
              */
             getHierarchyEmittedParticleSystems(): IParticleSystem[];
         }
-    /**
-     * @hidden
-     */
-    export var _IDoNeedToBeInTheBuild: number;
 }
 declare module BABYLON {
     /** Defines the 4 color options */
@@ -71982,6 +72089,15 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * An interface for all Hit test features
+     */
+    export interface IWebXRHitTestFeature<T extends IWebXRLegacyHitResult> extends IWebXRFeature {
+        /**
+         * Triggered when new babylon (transformed) hit test results are available
+         */
+        onHitTestResultObservable: Observable<T[]>;
+    }
+    /**
      * Options used for hit testing
      */
     export interface IWebXRLegacyHitTestOptions {
@@ -72012,7 +72128,7 @@ declare module BABYLON {
      * Hit test (or Ray-casting) is used to interact with the real world.
      * For further information read here - https://github.com/immersive-web/hit-test
      */
-    export class WebXRHitTestLegacy extends WebXRAbstractFeature {
+    export class WebXRHitTestLegacy extends WebXRAbstractFeature implements IWebXRHitTestFeature<IWebXRLegacyHitResult> {
         /**
          * options to use when constructing this feature
          */
@@ -72091,48 +72207,74 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Options used in the plane detector module
+     * Options used for hit testing (version 2)
      */
-    export interface IWebXRPlaneDetectorOptions {
+    export interface IWebXRHitTestOptions extends IWebXRLegacyHitTestOptions {
         /**
-         * The node to use to transform the local results to world coordinates
+         * Do not create a permanent hit test. Will usually be used when only
+         * transient inputs are needed.
          */
-        worldParentNode?: TransformNode;
+        disablePermanentHitTest?: boolean;
+        /**
+         * Enable transient (for example touch-based) hit test inspections
+         */
+        enableTransientHitTest?: boolean;
+        /**
+         * Offset ray for the permanent hit test
+         */
+        offsetRay?: Vector3;
+        /**
+         * Offset ray for the transient hit test
+         */
+        transientOffsetRay?: Vector3;
+        /**
+         * Instead of using viewer space for hit tests, use the reference space defined in the session manager
+         */
+        useReferenceSpace?: boolean;
     }
     /**
-     * A babylon interface for a WebXR plane.
-     * A Plane is actually a polygon, built from N points in space
-     *
-     * Supported in chrome 79, not supported in canary 81 ATM
+     * Interface defining the babylon result of hit-test
      */
-    export interface IWebXRPlane {
+    export interface IWebXRHitResult extends IWebXRLegacyHitResult {
         /**
-         * a babylon-assigned ID for this polygon
+         * The input source that generated this hit test (if transient)
          */
-        id: number;
+        inputSource?: XRInputSource;
         /**
-         * an array of vector3 points in babylon space. right/left hand system is taken into account.
+         * Is this a transient hit test
          */
-        polygonDefinition: Array<Vector3>;
+        isTransient?: boolean;
         /**
-         * A transformation matrix to apply on the mesh that will be built using the polygonDefinition
-         * Local vs. World are decided if worldParentNode was provided or not in the options when constructing the module
+         * Position of the hit test result
          */
-        transformationMatrix: Matrix;
+        position: Vector3;
         /**
-         * the native xr-plane object
+         * Rotation of the hit test result
          */
-        xrPlane: XRPlane;
+        rotationQuaternion: Quaternion;
+        /**
+         * The native hit test result
+         */
+        xrHitResult: XRHitTestResult;
     }
     /**
-     * The plane detector is used to detect planes in the real world when in AR
-     * For more information see https://github.com/immersive-web/real-world-geometry/
+     * The currently-working hit-test module.
+     * Hit test (or Ray-casting) is used to interact with the real world.
+     * For further information read here - https://github.com/immersive-web/hit-test
+     *
+     * Tested on chrome (mobile) 80.
      */
-    export class WebXRPlaneDetector extends WebXRAbstractFeature {
-        private _options;
-        private _detectedPlanes;
-        private _enabled;
-        private _lastFrameDetected;
+    export class WebXRHitTest extends WebXRAbstractFeature implements IWebXRHitTestFeature<IWebXRHitResult> {
+        /**
+         * options to use when constructing this feature
+         */
+        readonly options: IWebXRHitTestOptions;
+        private _tmpMat;
+        private _tmpPos;
+        private _tmpQuat;
+        private _transientXrHitTestSource;
+        private _xrHitTestSource;
+        private initHitTestSource;
         /**
          * The module's name
          */
@@ -72144,36 +72286,49 @@ declare module BABYLON {
          */
         static readonly Version: number;
         /**
-         * Observers registered here will be executed when a new plane was added to the session
+         * When set to true, each hit test will have its own position/rotation objects
+         * When set to false, position and rotation objects will be reused for each hit test. It is expected that
+         * the developers will clone them or copy them as they see fit.
          */
-        onPlaneAddedObservable: Observable<IWebXRPlane>;
+        autoCloneTransformation: boolean;
         /**
-         * Observers registered here will be executed when a plane is no longer detected in the session
+         * Triggered when new babylon (transformed) hit test results are available
          */
-        onPlaneRemovedObservable: Observable<IWebXRPlane>;
+        onHitTestResultObservable: Observable<IWebXRHitResult[]>;
         /**
-         * Observers registered here will be executed when an existing plane updates (for example - expanded)
-         * This can execute N times every frame
+         * Use this to temporarily pause hit test checks.
          */
-        onPlaneUpdatedObservable: Observable<IWebXRPlane>;
+        paused: boolean;
         /**
-         * construct a new Plane Detector
-         * @param _xrSessionManager an instance of xr Session manager
-         * @param _options configuration to use when constructing this feature
+         * Creates a new instance of the hit test feature
+         * @param _xrSessionManager an instance of WebXRSessionManager
+         * @param options options to use when constructing this feature
          */
-        constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        constructor(_xrSessionManager: WebXRSessionManager, 
+        /**
+         * options to use when constructing this feature
+         */
+        options?: IWebXRHitTestOptions);
+        /**
+         * 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;
         /**
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
         protected _onXRFrame(frame: XRFrame): void;
-        private _init;
-        private _updatePlaneWithXRPlane;
-        /**
-         * avoiding using Array.find for global support.
-         * @param xrPlane the plane to find in the array
-         */
-        private findIndexInPlaneArray;
+        private _processWebXRHitTestResult;
     }
 }
 declare module BABYLON {
@@ -72182,18 +72337,14 @@ declare module BABYLON {
      */
     export interface IWebXRAnchorSystemOptions {
         /**
-         * Should a new anchor be added every time a select event is triggered
-         */
-        addAnchorOnSelect?: boolean;
-        /**
-         * should the anchor system use plane detection.
-         * If set to true, the plane-detection feature should be set using setPlaneDetector
-         */
-        usePlaneDetection?: boolean;
-        /**
          * a node that will be used to convert local to world coordinates
          */
         worldParentNode?: TransformNode;
+        /**
+         * If set to true a reference of the created anchors will be kept until the next session starts
+         * If not defined, anchors will be removed from the array when the feature is detached or the session ended.
+         */
+        doNotRemoveAnchorsOnSessionEnded?: boolean;
     }
     /**
      * A babylon container for an XR Anchor
@@ -72211,21 +72362,21 @@ declare module BABYLON {
          * The native anchor object
          */
         xrAnchor: XRAnchor;
+        /**
+         * if defined, this object will be constantly updated by the anchor's position and rotation
+         */
+        attachedNode?: TransformNode;
     }
     /**
-     * An implementation of the anchor system of WebXR.
-     * Note that the current documented implementation is not available in any browser. Future implementations
-     * will use the frame to create an anchor and not the session or a detected plane
+     * An implementation of the anchor system for WebXR.
      * For further information see https://github.com/immersive-web/anchors/
      */
     export class WebXRAnchorSystem extends WebXRAbstractFeature {
         private _options;
-        private _enabled;
-        private _hitTestModule;
         private _lastFrameDetected;
-        private _onSelect;
-        private _planeDetector;
         private _trackedAnchors;
+        private _referenceSpaceForFrameAnchors;
+        private _futureAnchors;
         /**
          * The module's name
          */
@@ -72250,26 +72401,43 @@ declare module BABYLON {
          */
         onAnchorUpdatedObservable: Observable<IWebXRAnchor>;
         /**
+         * Set the reference space to use for anchor creation, when not using a hit test.
+         * Will default to the session's reference space if not defined
+         */
+        set referenceSpaceForFrameAnchors(referenceSpace: XRReferenceSpace);
+        /**
          * constructs a new anchor system
          * @param _xrSessionManager an instance of WebXRSessionManager
          * @param _options configuration object for this feature
          */
         constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRAnchorSystemOptions);
+        private _tmpVector;
+        private _tmpQuaternion;
+        private _populateTmpTransformation;
         /**
-         * Add anchor at a specific XR point.
+         * Create a new anchor point using a hit test result at a specific point in the scene
+         * An anchor is tracked only after it is added to the trackerAnchors in xrFrame. The promise returned here does not yet guaranty that.
+         * Use onAnchorAddedObservable to get newly added anchors if you require tracking guaranty.
          *
-         * @param xrRigidTransformation xr-coordinates where a new anchor should be added
-         * @param anchorCreator the object o use to create an anchor with. either a session or a plane
-         * @returns a promise the fulfills when the anchor was created
-         */
-        addAnchorAtRigidTransformation(xrRigidTransformation: XRRigidTransform, anchorCreator?: XRAnchorCreator): Promise<XRAnchor>;
-        /**
-         * attach this feature
-         * Will usually be called by the features manager
+         * @param hitTestResult The hit test result to use for this anchor creation
+         * @param position an optional position offset for this anchor
+         * @param rotationQuaternion an optional rotation offset for this anchor
+         * @returns A promise that fulfills when the XR anchor was registered in the system (but not necessarily added to the tracked anchors)
+         */
+        addAnchorPointUsingHitTestResultAsync(hitTestResult: IWebXRHitResult, position?: Vector3, rotationQuaternion?: Quaternion): Promise<XRAnchor>;
+        /**
+         * Add a new anchor at a specific position and rotation
+         * This function will add a new anchor per default in the next available frame. Unless forced, the createAnchor function
+         * will be called in the next xrFrame loop to make sure that the anchor can be created correctly.
+         * An anchor is tracked only after it is added to the trackerAnchors in xrFrame. The promise returned here does not yet guaranty that.
+         * Use onAnchorAddedObservable to get newly added anchors if you require tracking guaranty.
          *
-         * @returns true if successful.
+         * @param position the position in which to add an anchor
+         * @param rotationQuaternion an optional rotation for the anchor transformation
+         * @param forceCreateInCurrentFrame force the creation of this anchor in the current frame. Must be called inside xrFrame loop!
+         * @returns A promise that fulfills when the XR anchor was registered in the system (but not necessarily added to the tracked anchors)
          */
-        attach(): boolean;
+        addAnchorAtPositionAndRotationAsync(position: Vector3, rotationQuaternion?: Quaternion, forceCreateInCurrentFrame?: boolean): Promise<XRAnchor>;
         /**
          * detach this feature.
          * Will usually be called by the features manager
@@ -72281,24 +72449,113 @@ declare module BABYLON {
          * Dispose this feature and all of the resources attached
          */
         dispose(): void;
+        protected _onXRFrame(frame: XRFrame): void;
+        /**
+         * avoiding using Array.find for global support.
+         * @param xrAnchor the plane to find in the array
+         */
+        private _findIndexInAnchorArray;
+        private _updateAnchorWithXRFrame;
+        private _createAnchorAtTransformation;
+    }
+}
+declare module BABYLON {
+    /**
+     * Options used in the plane detector module
+     */
+    export interface IWebXRPlaneDetectorOptions {
+        /**
+         * The node to use to transform the local results to world coordinates
+         */
+        worldParentNode?: TransformNode;
+        /**
+         * If set to true a reference of the created planes will be kept until the next session starts
+         * If not defined, planes will be removed from the array when the feature is detached or the session ended.
+         */
+        doNotRemovePlanesOnSessionEnded?: boolean;
+    }
+    /**
+     * A babylon interface for a WebXR plane.
+     * A Plane is actually a polygon, built from N points in space
+     *
+     * Supported in chrome 79, not supported in canary 81 ATM
+     */
+    export interface IWebXRPlane {
+        /**
+         * a babylon-assigned ID for this polygon
+         */
+        id: number;
+        /**
+         * an array of vector3 points in babylon space. right/left hand system is taken into account.
+         */
+        polygonDefinition: Array<Vector3>;
+        /**
+         * A transformation matrix to apply on the mesh that will be built using the polygonDefinition
+         * Local vs. World are decided if worldParentNode was provided or not in the options when constructing the module
+         */
+        transformationMatrix: Matrix;
+        /**
+         * the native xr-plane object
+         */
+        xrPlane: XRPlane;
+    }
+    /**
+     * The plane detector is used to detect planes in the real world when in AR
+     * For more information see https://github.com/immersive-web/real-world-geometry/
+     */
+    export class WebXRPlaneDetector extends WebXRAbstractFeature {
+        private _options;
+        private _detectedPlanes;
+        private _enabled;
+        private _lastFrameDetected;
+        /**
+         * The module's name
+         */
+        static readonly Name: string;
         /**
-         * If set, it will improve performance by using the current hit-test results instead of executing a new hit-test
-         * @param hitTestModule the hit-test module to use.
+         * 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;
+        /**
+         * Observers registered here will be executed when a new plane was added to the session
+         */
+        onPlaneAddedObservable: Observable<IWebXRPlane>;
+        /**
+         * Observers registered here will be executed when a plane is no longer detected in the session
+         */
+        onPlaneRemovedObservable: Observable<IWebXRPlane>;
+        /**
+         * Observers registered here will be executed when an existing plane updates (for example - expanded)
+         * This can execute N times every frame
+         */
+        onPlaneUpdatedObservable: Observable<IWebXRPlane>;
+        /**
+         * construct a new Plane Detector
+         * @param _xrSessionManager an instance of xr Session manager
+         * @param _options configuration to use when constructing this feature
+         */
+        constructor(_xrSessionManager: WebXRSessionManager, _options?: IWebXRPlaneDetectorOptions);
+        /**
+         * detach this feature.
+         * Will usually be called by the features manager
+         *
+         * @returns true if successful.
          */
-        setHitTestModule(hitTestModule: WebXRHitTestLegacy): void;
+        detach(): boolean;
         /**
-         * set the plane detector to use in order to create anchors from frames
-         * @param planeDetector the plane-detector module to use
-         * @param enable enable plane-anchors. default is true
+         * Dispose this feature and all of the resources attached
          */
-        setPlaneDetector(planeDetector: WebXRPlaneDetector, enable?: boolean): void;
+        dispose(): void;
         protected _onXRFrame(frame: XRFrame): void;
+        private _init;
+        private _updatePlaneWithXRPlane;
         /**
          * avoiding using Array.find for global support.
-         * @param xrAnchor the plane to find in the array
+         * @param xrPlane the plane to find in the array
          */
-        private _findIndexInAnchorArray;
-        private _updateAnchorWithXRFrame;
+        private findIndexInPlaneArray;
     }
 }
 declare module BABYLON {
@@ -72539,132 +72796,6 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
-     * Options used for hit testing (version 2)
-     */
-    export interface IWebXRHitTestOptions extends IWebXRLegacyHitTestOptions {
-        /**
-         * Do not create a permanent hit test. Will usually be used when only
-         * transient inputs are needed.
-         */
-        disablePermanentHitTest?: boolean;
-        /**
-         * Enable transient (for example touch-based) hit test inspections
-         */
-        enableTransientHitTest?: boolean;
-        /**
-         * Offset ray for the permanent hit test
-         */
-        offsetRay?: Vector3;
-        /**
-         * Offset ray for the transient hit test
-         */
-        transientOffsetRay?: Vector3;
-        /**
-         * Instead of using viewer space for hit tests, use the reference space defined in the session manager
-         */
-        useReferenceSpace?: boolean;
-    }
-    /**
-     * Interface defining the babylon result of hit-test
-     */
-    export interface IWebXRHitResult extends IWebXRLegacyHitResult {
-        /**
-         * The input source that generated this hit test (if transient)
-         */
-        inputSource?: XRInputSource;
-        /**
-         * Is this a transient hit test
-         */
-        isTransient?: boolean;
-        /**
-         * Position of the hit test result
-         */
-        position: Vector3;
-        /**
-         * Rotation of the hit test result
-         */
-        rotationQuaternion: Quaternion;
-    }
-    /**
-     * The currently-working hit-test module.
-     * Hit test (or Ray-casting) is used to interact with the real world.
-     * For further information read here - https://github.com/immersive-web/hit-test
-     *
-     * Tested on chrome (mobile) 80.
-     */
-    export class WebXRHitTest extends WebXRAbstractFeature {
-        /**
-         * options to use when constructing this feature
-         */
-        readonly options: IWebXRHitTestOptions;
-        private _tmpMat;
-        private _tmpPos;
-        private _tmpQuat;
-        private _transientXrHitTestSource;
-        private _xrHitTestSource;
-        private initHitTestSource;
-        /**
-         * 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;
-        /**
-         * When set to true, each hit test will have its own position/rotation objects
-         * When set to false, position and rotation objects will be reused for each hit test. It is expected that
-         * the developers will clone them or copy them as they see fit.
-         */
-        autoCloneTransformation: boolean;
-        /**
-         * Populated with the last native XR Hit Results
-         */
-        lastNativeXRHitResults: XRHitResult[];
-        /**
-         * Triggered when new babylon (transformed) hit test results are available
-         */
-        onHitTestResultObservable: Observable<IWebXRHitResult[]>;
-        /**
-         * Use this to temporarily pause hit test checks.
-         */
-        paused: boolean;
-        /**
-         * Creates a new instance of the hit test feature
-         * @param _xrSessionManager an instance of WebXRSessionManager
-         * @param options options to use when constructing this feature
-         */
-        constructor(_xrSessionManager: WebXRSessionManager, 
-        /**
-         * options to use when constructing this feature
-         */
-        options?: IWebXRHitTestOptions);
-        /**
-         * 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;
-        /**
-         * Dispose this feature and all of the resources attached
-         */
-        dispose(): void;
-        protected _onXRFrame(frame: XRFrame): void;
-        private _processWebXRHitTestResult;
-    }
-}
-declare module BABYLON {
-    /**
      * The motion controller class for all microsoft mixed reality controllers
      */
     export class WebXRMicrosoftMixedRealityController extends WebXRAbstractMotionController {
@@ -73468,7 +73599,7 @@ interface XRSessionInit {
     requiredFeatures?: string[];
 }
 
-interface XRSession extends XRAnchorCreator {
+interface XRSession {
     addEventListener: Function;
     removeEventListener: Function;
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<XRReferenceSpace>;
@@ -73509,6 +73640,7 @@ interface XRFrame {
     getHitTestResultsForTransientInput(hitTestSource: XRTransientInputHitTestSource): Array<XRTransientInputHitTestResult>;
     // Anchors
     trackedAnchors?: XRAnchorSet;
+    createAnchor(pose: XRRigidTransform, space: XRSpace): Promise<XRAnchor>;
     // Planes
     worldInformation: {
         detectedPlanes?: XRPlaneSet;
@@ -73593,6 +73725,8 @@ interface XRTransientInputHitTestResult {
 
 interface XRHitTestResult {
     getPose(baseSpace: XRSpace): XRPose | undefined;
+    // When anchor system is enabled
+    createAnchor?(pose: XRRigidTransform): Promise<XRAnchor>;
 }
 
 interface XRHitTestSource {
@@ -73616,23 +73750,15 @@ interface XRTransientInputHitTestOptionsInit {
 }
 
 interface XRAnchor {
-    // remove?
-    id?: string;
     anchorSpace: XRSpace;
-    lastChangedTime: number;
-    detach(): void;
+    delete(): void;
 }
 
-interface XRPlane extends XRAnchorCreator {
+interface XRPlane {
     orientation: "Horizontal" | "Vertical";
     planeSpace: XRSpace;
     polygon: Array<DOMPointReadOnly>;
     lastChangedTime: number;
-}
-
-interface XRAnchorCreator {
-    // AR Anchors
-    createAnchor(pose: XRPose | XRRigidTransform, referenceSpace: XRReferenceSpace): Promise<XRAnchor>;
 }
 
 /**
@@ -75073,6 +75199,10 @@ declare module BABYLON.GUI {
         */
         onLinesReadyObservable: BABYLON.Observable<TextBlock>;
         /**
+         * Function used to split a string into words. By default, a string is split at each space character found
+         */
+        wordSplittingFunction: BABYLON.Nullable<(line: string) => string[]>;
+        /**
          * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
          */
         get lines(): any[];
@@ -79060,6 +79190,8 @@ declare module BABYLON.GLTF2 {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;

+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1425,6 +1425,10 @@ declare module BABYLON.GUI {
         */
         onLinesReadyObservable: BABYLON.Observable<TextBlock>;
         /**
+         * Function used to split a string into words. By default, a string is split at each space character found
+         */
+        wordSplittingFunction: BABYLON.Nullable<(line: string) => string[]>;
+        /**
          * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
          */
         get lines(): any[];

+ 50 - 50
dist/preview release/gui/babylon.gui.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-gui"] = factory(require("babylonjs"));
 	else
 		root["BABYLON"] = root["BABYLON"] || {}, root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -366,7 +366,7 @@ module.exports = g;
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTextureInstrumentation", function() { return AdvancedDynamicTextureInstrumentation; });
-/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/perfCounter */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_perfCounter__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -509,7 +509,7 @@ var AdvancedDynamicTextureInstrumentation = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AdvancedDynamicTexture", function() { return AdvancedDynamicTexture; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _controls_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./controls/container */ "./2D/controls/container.ts");
 /* harmony import */ var _style__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./style */ "./2D/style.ts");
@@ -1481,7 +1481,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./textBlock */ "./2D/controls/textBlock.ts");
 /* harmony import */ var _image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./image */ "./2D/controls/image.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__);
 
 
@@ -1713,7 +1713,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_5__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Checkbox", function() { return Checkbox; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -1896,7 +1896,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ColorPicker", function() { return ColorPicker; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
@@ -3285,7 +3285,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/logger */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -3700,7 +3700,7 @@ babylonjs_Misc_logger__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredTypes
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control", function() { return Control; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../measure */ "./2D/measure.ts");
@@ -5626,7 +5626,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DisplayGrid", function() { return DisplayGrid; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -5859,7 +5859,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -5956,7 +5956,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__);
 
 
@@ -6414,7 +6414,7 @@ babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_4__["_TypeStore"].RegisteredTypes[
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Image", function() { return Image; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 
@@ -7341,7 +7341,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputPassword", function() { return InputPassword; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _inputText__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./inputText */ "./2D/controls/inputText.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -7380,7 +7380,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "InputText", function() { return InputText; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8393,7 +8393,7 @@ babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].RegisteredT
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Line", function() { return Line; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -8664,7 +8664,7 @@ babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registere
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLine", function() { return MultiLine; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/abstractMesh */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _multiLinePoint__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../multiLinePoint */ "./2D/multiLinePoint.ts");
@@ -8934,7 +8934,7 @@ babylonjs_Meshes_abstractMesh__WEBPACK_IMPORTED_MODULE_1__["_TypeStore"].Registe
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RadioButton", function() { return RadioButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
@@ -9141,7 +9141,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Rectangle", function() { return Rectangle; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -9291,7 +9291,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _scrollViewerWindow__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./scrollViewerWindow */ "./2D/controls/scrollViewers/scrollViewerWindow.ts");
 /* harmony import */ var _sliders_scrollBar__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../sliders/scrollBar */ "./2D/controls/sliders/scrollBar.ts");
 /* harmony import */ var _sliders_imageScrollBar__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../sliders/imageScrollBar */ "./2D/controls/sliders/imageScrollBar.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_7__);
 
 
@@ -10914,7 +10914,7 @@ var SelectionPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BaseSlider", function() { return BaseSlider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../control */ "./2D/controls/control.ts");
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../valueAndUnit */ "./2D/valueAndUnit.ts");
@@ -11244,7 +11244,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
 /* harmony import */ var _measure__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../measure */ "./2D/measure.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_3__);
 
 
@@ -11837,7 +11837,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Slider", function() { return Slider; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _baseSlider__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./baseSlider */ "./2D/controls/sliders/baseSlider.ts");
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__);
 
 
@@ -12092,7 +12092,7 @@ babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_2__["_TypeStore"].RegisteredTy
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel", function() { return StackPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container */ "./2D/controls/container.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -12360,7 +12360,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextWrapping", function() { return TextWrapping; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TextBlock", function() { return TextBlock; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../valueAndUnit */ "./2D/valueAndUnit.ts");
 /* harmony import */ var _control__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./control */ "./2D/controls/control.ts");
@@ -12722,7 +12722,7 @@ var TextBlock = /** @class */ (function (_super) {
     TextBlock.prototype._parseLineWordWrap = function (line, width, context) {
         if (line === void 0) { line = ''; }
         var lines = [];
-        var words = line.split(' ');
+        var words = this.wordSplittingFunction ? this.wordSplittingFunction(line) : line.split(' ');
         var lineWidth = 0;
         for (var n = 0; n < words.length; n++) {
             var testLine = n > 0 ? line + " " + words[n] : words[0];
@@ -12823,7 +12823,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KeyPropertySet", function() { return KeyPropertySet; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VirtualKeyboard", function() { return VirtualKeyboard; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _stackPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stackPanel */ "./2D/controls/stackPanel.ts");
 /* harmony import */ var _button__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./button */ "./2D/controls/button.ts");
@@ -13212,7 +13212,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector2WithInfo", function() { return Vector2WithInfo; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Matrix2D", function() { return Matrix2D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -13437,7 +13437,7 @@ var Matrix2D = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Measure", function() { return Measure; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 
 var tmpRect = [
@@ -13586,7 +13586,7 @@ var Measure = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MultiLinePoint", function() { return MultiLinePoint; });
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -13729,7 +13729,7 @@ var MultiLinePoint = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Style", function() { return Style; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _valueAndUnit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./valueAndUnit */ "./2D/valueAndUnit.ts");
 
@@ -14035,7 +14035,7 @@ var ValueAndUnit = /** @class */ (function () {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "XmlLoader", function() { return XmlLoader; });
-/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/typeStore */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_typeStore__WEBPACK_IMPORTED_MODULE_0__);
 
 /**
@@ -14354,7 +14354,7 @@ var XmlLoader = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "AbstractButton3D", function() { return AbstractButton3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14397,7 +14397,7 @@ var AbstractButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Button3D", function() { return Button3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _abstractButton3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./abstractButton3D */ "./3D/controls/abstractButton3D.ts");
 /* harmony import */ var _2D_advancedDynamicTexture__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../2D/advancedDynamicTexture */ "./2D/advancedDynamicTexture.ts");
@@ -14578,7 +14578,7 @@ var Button3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container3D", function() { return Container3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Meshes/transformNode */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Meshes_transformNode__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _control3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./control3D */ "./3D/controls/control3D.ts");
 
@@ -14735,7 +14735,7 @@ var Container3D = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Control3D", function() { return Control3D; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _vector3WithInfo__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../vector3WithInfo */ "./3D/vector3WithInfo.ts");
 
@@ -15090,7 +15090,7 @@ var Control3D = /** @class */ (function () {
             this._host._lastPickedControl = this;
             return true;
         }
-        if (type === babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERUP) {
+        if (type === babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERUP || type === babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["PointerEventTypes"].POINTERDOUBLETAP) {
             if (this._host._lastControlDown[pointerId]) {
                 this._host._lastControlDown[pointerId]._onPointerUp(this, pickedPoint, pointerId, buttonIndex, true);
             }
@@ -15141,7 +15141,7 @@ var Control3D = /** @class */ (function () {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderPanel", function() { return CylinderPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15227,7 +15227,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HolographicButton", function() { return HolographicButton; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
 /* harmony import */ var _button3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./button3D */ "./3D/controls/button3D.ts");
-/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! babylonjs/Materials/standardMaterial */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_standardMaterial__WEBPACK_IMPORTED_MODULE_2__);
 /* harmony import */ var _materials_fluentMaterial__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../materials/fluentMaterial */ "./3D/materials/fluentMaterial.ts");
 /* harmony import */ var _2D_controls_stackPanel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../2D/controls/stackPanel */ "./2D/controls/stackPanel.ts");
@@ -15721,7 +15721,7 @@ var MeshButton3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PlanePanel", function() { return PlanePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
@@ -15776,7 +15776,7 @@ var PlanePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ScatterPanel", function() { return ScatterPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15903,7 +15903,7 @@ var ScatterPanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SpherePanel", function() { return SpherePanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _volumeBasedPanel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./volumeBasedPanel */ "./3D/controls/volumeBasedPanel.ts");
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
@@ -15989,7 +15989,7 @@ var SpherePanel = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "StackPanel3D", function() { return StackPanel3D; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16114,7 +16114,7 @@ var StackPanel3D = /** @class */ (function (_super) {
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "VolumeBasedPanel", function() { return VolumeBasedPanel; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/tools */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _container3D__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./container3D */ "./3D/controls/container3D.ts");
 
@@ -16305,7 +16305,7 @@ var VolumeBasedPanel = /** @class */ (function (_super) {
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "GUI3DManager", function() { return GUI3DManager; });
-/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Misc/observable */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__);
 /* harmony import */ var _controls_container3D__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./controls/container3D */ "./3D/controls/container3D.ts");
 
@@ -16572,7 +16572,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterialDefines", function() { return FluentMaterialDefines; });
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FluentMaterial", function() { return FluentMaterial; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Misc/decorators */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Misc_decorators__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _shaders_fluent_vertex__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./shaders/fluent.vertex */ "./3D/materials/shaders/fluent.vertex.ts");
 /* harmony import */ var _shaders_fluent_fragment__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./shaders/fluent.fragment */ "./3D/materials/shaders/fluent.fragment.ts");
@@ -16895,7 +16895,7 @@ __webpack_require__.r(__webpack_exports__);
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentPixelShader", function() { return fluentPixelShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentPixelShader';
@@ -16917,7 +16917,7 @@ var fluentPixelShader = { name: name, shader: shader };
 "use strict";
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fluentVertexShader", function() { return fluentVertexShader; });
-/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! babylonjs/Materials/effect */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_0__);
 
 var name = 'fluentVertexShader';
@@ -16940,7 +16940,7 @@ var fluentVertexShader = { name: name, shader: shader };
 __webpack_require__.r(__webpack_exports__);
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Vector3WithInfo", function() { return Vector3WithInfo; });
 /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
-/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Misc/perfCounter");
+/* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Maths/math.vector */ "babylonjs/Maths/math.vector");
 /* harmony import */ var babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_1__);
 
 
@@ -17242,14 +17242,14 @@ if (typeof globalObject !== "undefined") {
 
 /***/ }),
 
-/***/ "babylonjs/Misc/perfCounter":
+/***/ "babylonjs/Maths/math.vector":
 /*!****************************************************************************************************!*\
   !*** external {"root":"BABYLON","commonjs":"babylonjs","commonjs2":"babylonjs","amd":"babylonjs"} ***!
   \****************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_perfCounter__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_Maths_math_vector__;
 
 /***/ })
 

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


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


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

@@ -1466,6 +1466,10 @@ declare module "babylonjs-gui/2D/controls/textBlock" {
         */
         onLinesReadyObservable: Observable<TextBlock>;
         /**
+         * Function used to split a string into words. By default, a string is split at each space character found
+         */
+        wordSplittingFunction: Nullable<(line: string) => string[]>;
+        /**
          * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
          */
         get lines(): any[];
@@ -5800,6 +5804,10 @@ declare module BABYLON.GUI {
         */
         onLinesReadyObservable: BABYLON.Observable<TextBlock>;
         /**
+         * Function used to split a string into words. By default, a string is split at each space character found
+         */
+        wordSplittingFunction: BABYLON.Nullable<(line: string) => string[]>;
+        /**
          * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
          */
         get lines(): any[];

+ 2 - 2
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

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


文件差异内容过多而无法显示
+ 230 - 46
dist/preview release/inspector/babylon.inspector.bundle.max.js


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


+ 11 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -518,6 +518,7 @@ declare module INSPECTOR {
         active: boolean;
         type: string;
         index: string;
+        selected: boolean;
     }
     export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps> {
         constructor(props: IAnchorSvgPointProps);
@@ -620,9 +621,12 @@ declare module INSPECTOR {
 declare module INSPECTOR {
     interface IGraphActionsBarProps {
         addKeyframe: () => void;
+        removeKeyframe: () => void;
         handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+        handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
         flatTangent: () => void;
         currentValue: number;
+        currentFrame: number;
     }
     export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
         constructor(props: IGraphActionsBarProps);
@@ -660,6 +664,9 @@ declare module INSPECTOR {
         scale: number;
         playheadOffset: number;
         notification: string;
+        currentPoint: SVGPoint | undefined;
+        lastFrame: number;
+        playheadPos: number;
     }> {
         private _heightScale;
         readonly _canvasLength: number;
@@ -668,6 +675,8 @@ declare module INSPECTOR {
         private _frames;
         private _isPlaying;
         private _graphCanvas;
+        private _selectedCurve;
+        private _svgCanvas;
         constructor(props: IAnimationCurveEditorComponentProps);
         componentDidMount(): void;
         resetPlayheadOffset(): void;
@@ -675,11 +684,13 @@ declare module INSPECTOR {
         getValueLabel(i: number): number;
         handleNameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleValueChange(event: React.ChangeEvent<HTMLInputElement>): void;
+        handleFrameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleTypeChange(event: React.ChangeEvent<HTMLSelectElement>): void;
         handlePropertyChange(event: React.ChangeEvent<HTMLInputElement>): void;
         addAnimation(): void;
         clearNotification(): void;
         addKeyframeClick(): void;
+        removeKeyframeClick(): void;
         addKeyFrame(event: React.MouseEvent<SVGSVGElement>): void;
         updateKeyframe(keyframe: BABYLON.Vector2, index: number): void;
         getAnimationProperties(animation: BABYLON.Animation): {

+ 22 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -589,6 +589,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         active: boolean;
         type: string;
         index: string;
+        selected: boolean;
     }
     export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps> {
         constructor(props: IAnchorSvgPointProps);
@@ -701,9 +702,12 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
     import * as React from "react";
     interface IGraphActionsBarProps {
         addKeyframe: () => void;
+        removeKeyframe: () => void;
         handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+        handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
         flatTangent: () => void;
         currentValue: number;
+        currentFrame: number;
     }
     export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
         constructor(props: IGraphActionsBarProps);
@@ -749,6 +753,9 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         scale: number;
         playheadOffset: number;
         notification: string;
+        currentPoint: SVGPoint | undefined;
+        lastFrame: number;
+        playheadPos: number;
     }> {
         private _heightScale;
         readonly _canvasLength: number;
@@ -757,6 +764,8 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         private _frames;
         private _isPlaying;
         private _graphCanvas;
+        private _selectedCurve;
+        private _svgCanvas;
         constructor(props: IAnimationCurveEditorComponentProps);
         componentDidMount(): void;
         resetPlayheadOffset(): void;
@@ -764,11 +773,13 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         getValueLabel(i: number): number;
         handleNameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleValueChange(event: React.ChangeEvent<HTMLInputElement>): void;
+        handleFrameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleTypeChange(event: React.ChangeEvent<HTMLSelectElement>): void;
         handlePropertyChange(event: React.ChangeEvent<HTMLInputElement>): void;
         addAnimation(): void;
         clearNotification(): void;
         addKeyframeClick(): void;
+        removeKeyframeClick(): void;
         addKeyFrame(event: React.MouseEvent<SVGSVGElement>): void;
         updateKeyframe(keyframe: Vector2, index: number): void;
         getAnimationProperties(animation: Animation): {
@@ -3681,6 +3692,7 @@ declare module INSPECTOR {
         active: boolean;
         type: string;
         index: string;
+        selected: boolean;
     }
     export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps> {
         constructor(props: IAnchorSvgPointProps);
@@ -3783,9 +3795,12 @@ declare module INSPECTOR {
 declare module INSPECTOR {
     interface IGraphActionsBarProps {
         addKeyframe: () => void;
+        removeKeyframe: () => void;
         handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+        handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
         flatTangent: () => void;
         currentValue: number;
+        currentFrame: number;
     }
     export class GraphActionsBar extends React.Component<IGraphActionsBarProps> {
         constructor(props: IGraphActionsBarProps);
@@ -3823,6 +3838,9 @@ declare module INSPECTOR {
         scale: number;
         playheadOffset: number;
         notification: string;
+        currentPoint: SVGPoint | undefined;
+        lastFrame: number;
+        playheadPos: number;
     }> {
         private _heightScale;
         readonly _canvasLength: number;
@@ -3831,6 +3849,8 @@ declare module INSPECTOR {
         private _frames;
         private _isPlaying;
         private _graphCanvas;
+        private _selectedCurve;
+        private _svgCanvas;
         constructor(props: IAnimationCurveEditorComponentProps);
         componentDidMount(): void;
         resetPlayheadOffset(): void;
@@ -3838,11 +3858,13 @@ declare module INSPECTOR {
         getValueLabel(i: number): number;
         handleNameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleValueChange(event: React.ChangeEvent<HTMLInputElement>): void;
+        handleFrameChange(event: React.ChangeEvent<HTMLInputElement>): void;
         handleTypeChange(event: React.ChangeEvent<HTMLSelectElement>): void;
         handlePropertyChange(event: React.ChangeEvent<HTMLInputElement>): void;
         addAnimation(): void;
         clearNotification(): void;
         addKeyframeClick(): void;
+        removeKeyframeClick(): void;
         addKeyFrame(event: React.MouseEvent<SVGSVGElement>): void;
         updateKeyframe(keyframe: BABYLON.Vector2, index: number): void;
         getAnimationProperties(animation: BABYLON.Animation): {

+ 7 - 7
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,12 +29,12 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16",
-        "babylonjs-gui": "4.2.0-alpha.16",
-        "babylonjs-loaders": "4.2.0-alpha.16",
-        "babylonjs-materials": "4.2.0-alpha.16",
-        "babylonjs-serializers": "4.2.0-alpha.16",
-        "babylonjs-gltf2interface": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17",
+        "babylonjs-gui": "4.2.0-alpha.17",
+        "babylonjs-loaders": "4.2.0-alpha.17",
+        "babylonjs-materials": "4.2.0-alpha.17",
+        "babylonjs-serializers": "4.2.0-alpha.17",
+        "babylonjs-gltf2interface": "4.2.0-alpha.17"
     },
     "devDependencies": {
         "@types/react": "~16.7.3",

+ 17 - 26
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -290,15 +290,12 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
+            _this._loader._disableInstancedMesh++;
             var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            _this._loader._disableInstancedMesh--;
             if (!node._primitiveBabylonMeshes) {
                 return promise;
             }
-            // Hide the source meshes.
-            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
-                var babylonMesh = _a[_i];
-                babylonMesh.isVisible = false;
-            }
             var promises = new Array();
             var instanceCount = 0;
             var loadAttribute = function (attribute) {
@@ -318,31 +315,23 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
             loadAttribute("TRANSLATION");
             loadAttribute("ROTATION");
             loadAttribute("SCALE");
-            if (instanceCount == 0) {
-                return promise;
-            }
-            var digitLength = instanceCount.toString().length;
-            for (var i = 0; i < instanceCount; ++i) {
-                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
-                    var babylonMesh = _c[_b];
-                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
-                    babylonInstancedMesh.setParent(babylonMesh);
-                }
-            }
             return promise.then(function (babylonTransformNode) {
                 return Promise.all(promises).then(function (_a) {
                     var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    var matrices = new Float32Array(instanceCount * 16);
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0].copyFromFloats(0, 0, 0); // translation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0].copyFromFloats(0, 0, 0, 1); // rotation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1].copyFromFloats(1, 1, 1); // scale
+                    for (var i = 0; i < instanceCount; ++i) {
+                        translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0]);
+                        rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0]);
+                        scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Matrix"].ComposeToRef(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0].copyToArray(matrices, i * 16);
+                    }
                     for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
                         var babylonMesh = _b[_i];
-                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
-                        for (var i = 0; i < instanceCount; ++i) {
-                            var babylonInstancedMesh = babylonInstancedMeshes[i];
-                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
-                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
-                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
-                            babylonInstancedMesh.refreshBoundingInfo();
-                        }
+                        babylonMesh.thinInstanceSetBuffer("matrix", matrices, 16, true);
                     }
                     return babylonTransformNode;
                 });
@@ -2196,6 +2185,8 @@ var GLTFLoader = /** @class */ (function () {
         this._forAssetContainer = false;
         /** Storage */
         this._babylonLights = [];
+        /** @hidden */
+        this._disableInstancedMesh = 0;
         this._disposed = false;
         this._state = null;
         this._extensions = new Array();
@@ -2788,7 +2779,7 @@ var GLTFLoader = /** @class */ (function () {
             return extensionPromise;
         }
         this.logOpen("" + context);
-        var shouldInstance = this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
+        var shouldInstance = (this._disableInstancedMesh === 0) && this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
         var babylonAbstractMesh;
         var promise;
         if (shouldInstance && primitive._instanceData) {

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


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


+ 17 - 26
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2870,15 +2870,12 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
+            _this._loader._disableInstancedMesh++;
             var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            _this._loader._disableInstancedMesh--;
             if (!node._primitiveBabylonMeshes) {
                 return promise;
             }
-            // Hide the source meshes.
-            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
-                var babylonMesh = _a[_i];
-                babylonMesh.isVisible = false;
-            }
             var promises = new Array();
             var instanceCount = 0;
             var loadAttribute = function (attribute) {
@@ -2898,31 +2895,23 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
             loadAttribute("TRANSLATION");
             loadAttribute("ROTATION");
             loadAttribute("SCALE");
-            if (instanceCount == 0) {
-                return promise;
-            }
-            var digitLength = instanceCount.toString().length;
-            for (var i = 0; i < instanceCount; ++i) {
-                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
-                    var babylonMesh = _c[_b];
-                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
-                    babylonInstancedMesh.setParent(babylonMesh);
-                }
-            }
             return promise.then(function (babylonTransformNode) {
                 return Promise.all(promises).then(function (_a) {
                     var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    var matrices = new Float32Array(instanceCount * 16);
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0].copyFromFloats(0, 0, 0); // translation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0].copyFromFloats(0, 0, 0, 1); // rotation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1].copyFromFloats(1, 1, 1); // scale
+                    for (var i = 0; i < instanceCount; ++i) {
+                        translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0]);
+                        rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0]);
+                        scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Matrix"].ComposeToRef(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0].copyToArray(matrices, i * 16);
+                    }
                     for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
                         var babylonMesh = _b[_i];
-                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
-                        for (var i = 0; i < instanceCount; ++i) {
-                            var babylonInstancedMesh = babylonInstancedMeshes[i];
-                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
-                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
-                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
-                            babylonInstancedMesh.refreshBoundingInfo();
-                        }
+                        babylonMesh.thinInstanceSetBuffer("matrix", matrices, 16, true);
                     }
                     return babylonTransformNode;
                 });
@@ -4776,6 +4765,8 @@ var GLTFLoader = /** @class */ (function () {
         this._forAssetContainer = false;
         /** Storage */
         this._babylonLights = [];
+        /** @hidden */
+        this._disableInstancedMesh = 0;
         this._disposed = false;
         this._state = null;
         this._extensions = new Array();
@@ -5368,7 +5359,7 @@ var GLTFLoader = /** @class */ (function () {
             return extensionPromise;
         }
         this.logOpen("" + context);
-        var shouldInstance = this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
+        var shouldInstance = (this._disableInstancedMesh === 0) && this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
         var babylonAbstractMesh;
         var promise;
         if (shouldInstance && primitive._instanceData) {

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


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


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

@@ -1328,6 +1328,8 @@ declare module BABYLON.GLTF2 {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;

+ 17 - 26
dist/preview release/loaders/babylonjs.loaders.js

@@ -4250,15 +4250,12 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
+            _this._loader._disableInstancedMesh++;
             var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            _this._loader._disableInstancedMesh--;
             if (!node._primitiveBabylonMeshes) {
                 return promise;
             }
-            // Hide the source meshes.
-            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
-                var babylonMesh = _a[_i];
-                babylonMesh.isVisible = false;
-            }
             var promises = new Array();
             var instanceCount = 0;
             var loadAttribute = function (attribute) {
@@ -4278,31 +4275,23 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
             loadAttribute("TRANSLATION");
             loadAttribute("ROTATION");
             loadAttribute("SCALE");
-            if (instanceCount == 0) {
-                return promise;
-            }
-            var digitLength = instanceCount.toString().length;
-            for (var i = 0; i < instanceCount; ++i) {
-                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
-                    var babylonMesh = _c[_b];
-                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
-                    babylonInstancedMesh.setParent(babylonMesh);
-                }
-            }
             return promise.then(function (babylonTransformNode) {
                 return Promise.all(promises).then(function (_a) {
                     var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    var matrices = new Float32Array(instanceCount * 16);
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0].copyFromFloats(0, 0, 0); // translation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0].copyFromFloats(0, 0, 0, 1); // rotation
+                    babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1].copyFromFloats(1, 1, 1); // scale
+                    for (var i = 0; i < instanceCount; ++i) {
+                        translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0]);
+                        rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0]);
+                        scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Matrix"].ComposeToRef(babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[1], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Quaternion[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Vector3[0], babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0]);
+                        babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["TmpVectors"].Matrix[0].copyToArray(matrices, i * 16);
+                    }
                     for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
                         var babylonMesh = _b[_i];
-                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
-                        for (var i = 0; i < instanceCount; ++i) {
-                            var babylonInstancedMesh = babylonInstancedMeshes[i];
-                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
-                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
-                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
-                            babylonInstancedMesh.refreshBoundingInfo();
-                        }
+                        babylonMesh.thinInstanceSetBuffer("matrix", matrices, 16, true);
                     }
                     return babylonTransformNode;
                 });
@@ -6156,6 +6145,8 @@ var GLTFLoader = /** @class */ (function () {
         this._forAssetContainer = false;
         /** Storage */
         this._babylonLights = [];
+        /** @hidden */
+        this._disableInstancedMesh = 0;
         this._disposed = false;
         this._state = null;
         this._extensions = new Array();
@@ -6748,7 +6739,7 @@ var GLTFLoader = /** @class */ (function () {
             return extensionPromise;
         }
         this.logOpen("" + context);
-        var shouldInstance = this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
+        var shouldInstance = (this._disableInstancedMesh === 0) && this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
         var babylonAbstractMesh;
         var promise;
         if (shouldInstance && primitive._instanceData) {

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


文件差异内容过多而无法显示
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 4 - 0
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -1417,6 +1417,8 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;
@@ -4062,6 +4064,8 @@ declare module BABYLON.GLTF2 {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;

+ 3 - 3
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.2.0-alpha.16",
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs-gltf2interface": "4.2.0-alpha.17",
+        "babylonjs": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

+ 2 - 1
dist/preview release/materialsLibrary/babylon.gridMaterial.js

@@ -444,6 +444,7 @@ var GridMaterialDefines = /** @class */ (function (_super) {
         _this.UV1 = false;
         _this.UV2 = false;
         _this.INSTANCES = false;
+        _this.THIN_INSTANCES = false;
         _this.rebuild();
         return _this;
     }
@@ -584,7 +585,7 @@ var GridMaterial = /** @class */ (function (_super) {
         }
         this._activeEffect = effect;
         // Matrices
-        if (!defines.INSTANCES) {
+        if (!defines.INSTANCES || defines.THIN_INSTANCE) {
             this.bindOnlyWorldMatrix(world);
         }
         this._activeEffect.setMatrix("view", scene.getViewMatrix());

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


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


+ 2 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -2680,6 +2680,7 @@ var GridMaterialDefines = /** @class */ (function (_super) {
         _this.UV1 = false;
         _this.UV2 = false;
         _this.INSTANCES = false;
+        _this.THIN_INSTANCES = false;
         _this.rebuild();
         return _this;
     }
@@ -2820,7 +2821,7 @@ var GridMaterial = /** @class */ (function (_super) {
         }
         this._activeEffect = effect;
         // Matrices
-        if (!defines.INSTANCES) {
+        if (!defines.INSTANCES || defines.THIN_INSTANCE) {
             this.bindOnlyWorldMatrix(world);
         }
         this._activeEffect.setMatrix("view", scene.getViewMatrix());

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


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


+ 2 - 2
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/nodeEditor/package.json

@@ -4,14 +4,14 @@
     },
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17"
     },
     "files": [
         "babylon.nodeEditor.max.js.map",

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

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1 +1 @@
-{"thinEngineOnly":115966,"engineOnly":152369,"sceneOnly":511571,"minGridMaterial":644906,"minStandardMaterial":788730}
+{"thinEngineOnly":115966,"engineOnly":152369,"sceneOnly":505311,"minGridMaterial":647903,"minStandardMaterial":792016}

+ 2 - 2
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

+ 2 - 2
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

+ 8 - 1
dist/preview release/serializers/babylon.objSerializer.js

@@ -214,7 +214,14 @@ var OBJExport = /** @class */ (function () {
                 continue;
             }
             for (var i = 0; i < trunkVerts.length; i += 3) {
-                output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                // Babylon.js default is left handed, while OBJ default is right handed
+                // Need to invert Z vertices unless Babylon is set to use a right handed system
+                if (mesh[0].getScene().useRightHandedSystem) {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                }
+                else {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + -trunkVerts[i + 2]);
+                }
                 curV++;
             }
             if (trunkNormals != null) {

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


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


+ 8 - 1
dist/preview release/serializers/babylonjs.serializers.js

@@ -443,7 +443,14 @@ var OBJExport = /** @class */ (function () {
                 continue;
             }
             for (var i = 0; i < trunkVerts.length; i += 3) {
-                output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                // Babylon.js default is left handed, while OBJ default is right handed
+                // Need to invert Z vertices unless Babylon is set to use a right handed system
+                if (mesh[0].getScene().useRightHandedSystem) {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                }
+                else {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + -trunkVerts[i + 2]);
+                }
                 curV++;
             }
             if (trunkNormals != null) {

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


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


+ 3 - 3
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.16",
-        "babylonjs-gltf2interface": "4.2.0-alpha.16"
+        "babylonjs": "4.2.0-alpha.17",
+        "babylonjs-gltf2interface": "4.2.0-alpha.17"
     },
     "engines": {
         "node": "*"

文件差异内容过多而无法显示
+ 812 - 542
dist/preview release/viewer/babylon.module.d.ts


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


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


+ 4 - 0
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -1417,6 +1417,8 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;
@@ -4062,6 +4064,8 @@ declare module BABYLON.GLTF2 {
         _forAssetContainer: boolean;
         /** Storage */
         _babylonLights: Light[];
+        /** @hidden */
+        _disableInstancedMesh: number;
         private _disposed;
         private _parent;
         private _state;

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

@@ -10,6 +10,7 @@
 - Added editing of PBR materials, Post processes and Particle fragment shaders in the node material editor ([Popov72](https://github.com/Popov72))
 - Added Curve editor to create and view selected entity's animations in the Inspector ([pixelspace](https://github.com/devpixelspace))
 - Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
+- Added support for **thin instances** for faster mesh instances. [Doc](https://doc.babylonjs.com/how_to/how_to_use_thininstances) ([Popov72](https://github.com/Popov72))
 
 ## Updates
 
@@ -116,6 +117,7 @@
 - Added support for (experimental) haptic actuators ([#8068](https://github.com/BabylonJS/Babylon.js/issues/8068)) ([RaananW](https://github.com/RaananW))
 - It is now possible to enable experimental (AR) features using the options of the default xr helper ([RaananW](https://github.com/RaananW))
 - Full support for right handed systems ([#8132](https://github.com/BabylonJS/Babylon.js/issues/8132)) ([RaananW](https://github.com/RaananW))
+- WebXR anchors feature ([#7917](https://github.com/BabylonJS/Babylon.js/issues/7917)) ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 
@@ -152,6 +154,10 @@
 - Added support for code templates in the playground ([sailro](http://www.github.com/sailro))
 - If createEngine fails, a default engine will be created ([#8084](https://github.com/BabylonJS/Babylon.js/issues/8084)) ([RaananW](https://github.com/RaananW))
 
+### GUI
+
+- Added support for custom word splitting function for `TextBlock` ([Popov72](https://github.com/Popov72))
+
 ## Bugs
 
 - Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72))
@@ -202,6 +208,9 @@
 - Fixed `Sound` not accepting a `TransformNode` as a source for spatial sound ([Poolminer](https://github.com/Poolminer))
 - Fixed an issue with transformation set after physics body was created using cannon.js ([#7928](https://github.com/BabylonJS/Babylon.js/issues/7928)) ([RaananW](https://github.com/RaananW))
 - Fix bug when using `ShadowOnlyMaterial` with Cascaded Shadow Map and `autoCalcDepthBounds` is `true` ([Popov72](https://github.com/Popov72))
+- Fix OBJ serializer default scene scene handedness causing [OBJ Mirror export](https://forum.babylonjs.com/t/obj-export-mirrored/10835/10)
+- Fix bug when using shadows + instances + transparent meshes + `transparencyShadow = false` ([Popov72](https://github.com/Popov72))
+- Incorrect initialization when reattaching XR pointer selection  ([#8227](https://github.com/BabylonJS/Babylon.js/issues/8227)) ([RaananW](https://github.com/RaananW))
 
 ## Breaking changes
 

+ 6 - 1
gui/src/2D/controls/textBlock.ts

@@ -50,6 +50,11 @@ export class TextBlock extends Control {
     public onLinesReadyObservable = new Observable<TextBlock>();
 
     /**
+     * Function used to split a string into words. By default, a string is split at each space character found
+     */
+    public wordSplittingFunction: Nullable<(line: string) => string[]>;
+
+    /**
      * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
      */
     public get lines(): any[] {
@@ -368,7 +373,7 @@ export class TextBlock extends Control {
     protected _parseLineWordWrap(line: string = '', width: number,
         context: CanvasRenderingContext2D): object[] {
         var lines = [];
-        var words = line.split(' ');
+        var words = this.wordSplittingFunction ? this.wordSplittingFunction(line) : line.split(' ');
         var lineWidth = 0;
 
         for (var n = 0; n < words.length; n++) {

+ 1 - 1
gui/src/3D/controls/control3D.ts

@@ -414,7 +414,7 @@ export class Control3D implements IDisposable, IBehaviorAware<Control3D> {
             return true;
         }
 
-        if (type === PointerEventTypes.POINTERUP) {
+        if (type === PointerEventTypes.POINTERUP || type === PointerEventTypes.POINTERDOUBLETAP) {
             if (this._host._lastControlDown[pointerId]) {
                 this._host._lastControlDown[pointerId]._onPointerUp(this, pickedPoint, pointerId, buttonIndex, true);
             }

+ 3 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/anchorSvgPoint.tsx

@@ -8,6 +8,7 @@ interface IAnchorSvgPointProps {
    active: boolean;
    type: string;
    index: string;
+   selected: boolean;
 }
 
 
@@ -20,9 +21,9 @@ export class AnchorSvgPoint extends React.Component<IAnchorSvgPointProps>{
         return (
         <>
             <svg x={this.props.control.x} y={this.props.control.y} style={{overflow:'visible'}}>
-                <circle type={this.props.type} data-id={this.props.index} className="draggable control-point" cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill={this.props.active ? "blue" : "black"}   />
+                <circle type={this.props.type} data-id={this.props.index} className={`draggable control-point ${this.props.active ? 'active' : ''}`} cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill={this.props.active ? "blue" : "black"}   />
             </svg>
-            <line x1={this.props.anchor.x} y1={this.props.anchor.y} x2={this.props.control.x} y2={this.props.control.y} stroke="green" strokeWidth="0.75" />
+            <line className={`control-point ${this.props.active ? 'active' : ''}`} x1={this.props.anchor.x} y1={this.props.anchor.y} x2={this.props.control.x} y2={this.props.control.y} stroke="green" strokeWidth="0.75" />
         </>
         )
     }

文件差异内容过多而无法显示
+ 210 - 23
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx


+ 21 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/curveEditor.scss

@@ -142,7 +142,17 @@
             ul {
                 list-style:none;
                 padding-left: 0px;
+                li.property {
+                    &:before {
+                        content: '';
+                        background: none;
+                    }
+                }
                 li {
+                    p {
+                        font-weight: bolder;
+                        font-variant: all-small-caps;
+                    }
                     cursor: pointer;
                     &:before {
                         content: '';
@@ -170,7 +180,9 @@
                 background-color: rgba(0, 0, 0, 0.3);
                 padding: 10px;
                 margin-top: 19px;
-                height: 15em;
+                height: 11em;
+                overflow: scroll;
+                overflow-x: hidden;
             }
 
             .label-input{
@@ -218,6 +230,14 @@
                 text {
                     fill: #cecece;
                 }
+
+                .control-point {
+                    display: none;
+                }
+
+                .control-point.active {
+                    display: inline;
+                }
             }
 
             .playhead-wrapper {

+ 9 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/animations/graphActionsBar.tsx

@@ -4,9 +4,12 @@ import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 
 interface IGraphActionsBarProps {
    addKeyframe: () => void;
+   removeKeyframe: () => void;
    handleValueChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
+   handleFrameChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
    flatTangent: () => void;
    currentValue: number;
+   currentFrame: number;
 }
 
 export class GraphActionsBar extends React.Component<IGraphActionsBarProps>{ 
@@ -18,10 +21,15 @@ export class GraphActionsBar extends React.Component<IGraphActionsBarProps>{
        return (
            <div className="actions-wrapper">
                <div className="action-input">
+               <label>Frame</label>
+               <input type="number" value={this.props.currentFrame} onChange={this.props.handleFrameChange} step="1"/>
+               </div>
+               <div className="action-input">
                <label>Value</label>
-               <input type="number" value={this.props.currentValue} onChange={this.props.handleValueChange}/>
+               <input type="number" value={this.props.currentValue.toFixed(3)} onChange={this.props.handleValueChange} step="0.001"/>
                </div>
               <ButtonLineComponent label={"Add Keyframe"} onClick={this.props.addKeyframe} />
+              <ButtonLineComponent label={"Remove Keyframe"} onClick={this.props.removeKeyframe} />
               <ButtonLineComponent label={"Flat Tangent"} onClick={this.props.flatTangent} />
            </div>
         )

+ 2 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/animations/keyframeSvgPoint.tsx

@@ -28,8 +28,8 @@ export class KeyframeSvgPoint extends React.Component<IKeyframeSvgPointProps>{
                 <svg className="draggable" x={this.props.keyframePoint.x} y={this.props.keyframePoint.y} style={{overflow:'visible'}}>
                     <circle data-id={this.props.id} className="draggable" cx="0" cy="0"  r="2" stroke="none" strokeWidth="0" fill="red" />
                 </svg>
-               { this.props.leftControlPoint && <AnchorSvgPoint type="left" index={this.props.id} control={this.props.leftControlPoint} anchor={this.props.keyframePoint} active={false}/>} 
-               { this.props.rightControlPoint &&  <AnchorSvgPoint type="right" index={this.props.id} control={this.props.rightControlPoint} anchor={this.props.keyframePoint} active={false}/>}
+               { this.props.leftControlPoint && <AnchorSvgPoint type="left" index={this.props.id} control={this.props.leftControlPoint} anchor={this.props.keyframePoint} active={false} selected={false}/>} 
+               { this.props.rightControlPoint &&  <AnchorSvgPoint type="right" index={this.props.id} control={this.props.rightControlPoint} anchor={this.props.keyframePoint} active={false} selected={false}/>}
             </>
         )
     }

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/commonPropertyGridComponent.tsx

@@ -74,7 +74,7 @@ export class CommonPropertyGridComponent extends React.Component<ICommonProperty
 
         return (
             <div>
-                <LineContainerComponent globalState={this.props.globalState} title="XMP METADA">
+                <LineContainerComponent globalState={this.props.globalState} title="XMP METADATA">
                     {
                         this.renderLevel(this.props.host.metadata.xmp)                        
                     }

+ 23 - 30
loaders/src/glTF/2.0/Extensions/EXT_mesh_gpu_instancing.ts

@@ -1,13 +1,11 @@
-import { Vector3, Quaternion } from 'babylonjs/Maths/math.vector';
-import { InstancedMesh } from 'babylonjs/Meshes/instancedMesh';
+import { Vector3, Quaternion, Matrix } from 'babylonjs/Maths/math.vector';
 import { Mesh } from 'babylonjs/Meshes/mesh';
 import { TransformNode } from "babylonjs/Meshes/transformNode";
-import { StringTools } from 'babylonjs/Misc/stringTools';
 import { Nullable } from "babylonjs/types";
 import { GLTFLoader, ArrayItem } from "../glTFLoader";
 import { IGLTFLoaderExtension } from "../glTFLoaderExtension";
 import { INode } from "../glTFLoaderInterfaces";
-import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { TmpVectors } from 'babylonjs/Maths/math.vector';
 
 const NAME = "EXT_mesh_gpu_instancing";
 
@@ -48,17 +46,16 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
     /** @hidden */
     public loadNodeAsync(context: string, node: INode, assign: (babylonTransformNode: TransformNode) => void): Nullable<Promise<TransformNode>> {
         return GLTFLoader.LoadExtensionAsync<IEXTMeshGpuInstancing, TransformNode>(context, node, this.name, (extensionContext, extension) => {
+            this._loader._disableInstancedMesh++;
+
             const promise = this._loader.loadNodeAsync(`#/nodes/${node.index}`, node, assign);
 
+            this._loader._disableInstancedMesh--;
+
             if (!node._primitiveBabylonMeshes) {
                 return promise;
             }
 
-            // Hide the source meshes.
-            for (const babylonMesh of node._primitiveBabylonMeshes) {
-                babylonMesh.isVisible = false;
-            }
-
             const promises = new Array<Promise<Nullable<Float32Array>>>();
             let instanceCount = 0;
 
@@ -82,30 +79,26 @@ export class EXT_mesh_gpu_instancing implements IGLTFLoaderExtension {
             loadAttribute("ROTATION");
             loadAttribute("SCALE");
 
-            if (instanceCount == 0) {
-                return promise;
-            }
-
-            const digitLength = instanceCount.toString().length;
-            for (let i = 0; i < instanceCount; ++i) {
-                for (const babylonMesh of node._primitiveBabylonMeshes!) {
-                    const instanceName = `${babylonMesh.name || babylonMesh.id}_${StringTools.PadNumber(i, digitLength)}`;
-                    const babylonInstancedMesh = (babylonMesh as (InstancedMesh | Mesh)).createInstance(instanceName);
-                    babylonInstancedMesh.setParent(babylonMesh);
-                }
-            }
-
             return promise.then((babylonTransformNode) => {
                 return Promise.all(promises).then(([translationBuffer, rotationBuffer, scaleBuffer]) => {
+                    const matrices = new Float32Array(instanceCount * 16);
+
+                    TmpVectors.Vector3[0].copyFromFloats(0, 0, 0); // translation
+                    TmpVectors.Quaternion[0].copyFromFloats(0, 0, 0, 1); // rotation
+                    TmpVectors.Vector3[1].copyFromFloats(1, 1, 1); // scale
+
+                    for (let i = 0; i < instanceCount; ++i) {
+                        translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, TmpVectors.Vector3[0]);
+                        rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, TmpVectors.Quaternion[0]);
+                        scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, TmpVectors.Vector3[1]);
+
+                        Matrix.ComposeToRef(TmpVectors.Vector3[1], TmpVectors.Quaternion[0], TmpVectors.Vector3[0], TmpVectors.Matrix[0]);
+
+                        TmpVectors.Matrix[0].copyToArray(matrices, i * 16);
+                    }
+
                     for (const babylonMesh of node._primitiveBabylonMeshes!) {
-                        const babylonInstancedMeshes = babylonMesh.getChildMeshes(true, (node) => (node as AbstractMesh).isAnInstance);
-                        for (let i = 0; i < instanceCount; ++i) {
-                            const babylonInstancedMesh = babylonInstancedMeshes[i];
-                            translationBuffer && Vector3.FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
-                            rotationBuffer && Quaternion.FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion!);
-                            scaleBuffer && Vector3.FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
-                            babylonInstancedMesh.refreshBoundingInfo();
-                        }
+                            (babylonMesh as Mesh).thinInstanceSetBuffer("matrix", matrices, 16, true);
                     }
 
                     return babylonTransformNode;

+ 4 - 1
loaders/src/glTF/2.0/glTFLoader.ts

@@ -106,6 +106,9 @@ export class GLTFLoader implements IGLTFLoader {
     /** Storage */
     public _babylonLights: Light[] = [];
 
+    /** @hidden */
+    public _disableInstancedMesh = 0;
+
     private _disposed = false;
     private _parent: GLTFFileLoader;
     private _state: Nullable<GLTFLoaderState> = null;
@@ -777,7 +780,7 @@ export class GLTFLoader implements IGLTFLoader {
 
         this.logOpen(`${context}`);
 
-        const shouldInstance = this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
+        const shouldInstance = (this._disableInstancedMesh === 0) && this._parent.createInstances && (node.skin == undefined && !mesh.primitives[0].targets);
 
         let babylonAbstractMesh: AbstractMesh;
         let promise: Promise<any>;

+ 2 - 1
materialsLibrary/src/grid/gridMaterial.ts

@@ -24,6 +24,7 @@ class GridMaterialDefines extends MaterialDefines {
     public UV1 = false;
     public UV2 = false;
     public INSTANCES = false;
+    public THIN_INSTANCES = false;
 
     constructor() {
         super();
@@ -216,7 +217,7 @@ export class GridMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        if (!defines.INSTANCES) {
+        if (!defines.INSTANCES || defines.THIN_INSTANCE) {
             this.bindOnlyWorldMatrix(world);
         }
         this._activeEffect.setMatrix("view", scene.getViewMatrix());

+ 1 - 1
package.json

@@ -7,7 +7,7 @@
     ],
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.16",
+    "version": "4.2.0-alpha.17",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 7 - 1
serializers/src/OBJ/objSerializer.ts

@@ -67,7 +67,13 @@ export class OBJExport {
             }
 
             for (var i = 0; i < trunkVerts.length; i += 3) {
-                output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                // Babylon.js default is left handed, while OBJ default is right handed
+                // Need to invert Z vertices unless Babylon is set to use a right handed system
+                if (mesh[0].getScene().useRightHandedSystem) {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + trunkVerts[i + 2]);
+                } else {
+                    output.push("v " + trunkVerts[i] + " " + trunkVerts[i + 1] + " " + -trunkVerts[i + 2]);
+                }
                 curV++;
             }
 

+ 1 - 1
src/DeviceInput/InputDevices/deviceSourceManager.ts

@@ -81,7 +81,7 @@ export class DeviceSourceManager implements IDisposable {
         const numberOfDeviceTypes = Object.keys(DeviceType).length / 2;
         this._devices = new Array<Array<DeviceSource<DeviceType>>>(numberOfDeviceTypes);
         this._firstDevice = new Array<number>(numberOfDeviceTypes);
-        this._deviceInputSystem = new DeviceInputSystem(engine);
+        this._deviceInputSystem = DeviceInputSystem.Create(engine);
 
         this._deviceInputSystem.onDeviceConnected = (deviceType, deviceSlot) => {
             this.onBeforeDeviceConnectedObservable.notifyObservers({ deviceType, deviceSlot });

+ 18 - 5
src/DeviceInput/deviceInputSystem.ts

@@ -3,6 +3,9 @@ import { IDisposable } from '../scene';
 import { Nullable } from '../types';
 import { DeviceType } from './InputDevices/deviceEnums';
 
+/** @hidden */
+declare const _native: any;
+
 /**
  * This class will take all inputs from Keyboard, Pointer, and
  * any Gamepads and provide a polling system that all devices
@@ -45,11 +48,7 @@ export class DeviceInputSystem implements IDisposable {
     private static _MAX_KEYCODES: number = 255;
     private static _MAX_POINTER_INPUTS: number = 7;
 
-    /**
-     * Default Constructor
-     * @param engine - engine to pull input element from
-     */
-    constructor(engine: Engine) {
+    private constructor(engine: Engine) {
         const inputElement = engine.getInputElement();
         if (inputElement) {
             this._elementToAttachTo = inputElement;
@@ -59,6 +58,20 @@ export class DeviceInputSystem implements IDisposable {
         }
     }
 
+    /**
+     * Creates a new DeviceInputSystem instance
+     * @param engine Engine to pull input element from
+     * @returns The new instance
+     */
+    public static Create(engine: Engine): DeviceInputSystem {
+        // If running in Babylon Native, then defer to the native input system, which has the same public contract
+        if (typeof _native.DeviceInputSystem !== 'undefined') {
+            return new _native.DeviceInputSystem(engine);
+        }
+
+        return new DeviceInputSystem(engine);
+    }
+
     // Public functions
     /**
      * Checks for current device input value, given an id and input index

+ 2 - 2
src/Engines/thinEngine.ts

@@ -132,14 +132,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.2.0-alpha.16";
+        return "babylonjs@4.2.0-alpha.17";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.2.0-alpha.16";
+        return "4.2.0-alpha.17";
     }
 
     /**

+ 6 - 3
src/Layers/effectLayer.ts

@@ -522,6 +522,9 @@ export abstract class EffectLayer {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (subMesh.getRenderingMesh().hasThinInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         this._addCustomEffectDefines(defines);
@@ -654,9 +657,9 @@ export abstract class EffectLayer {
 
         var material = subMesh.getMaterial();
         var ownerMesh = subMesh.getMesh();
-        var replacementMesh = ownerMesh._internalAbstractMeshDataInfo._actAsRegularMesh ? ownerMesh : null;
+        var replacementMesh = subMesh.getReplacementMesh();
         var renderingMesh = subMesh.getRenderingMesh();
-        var effectiveMesh = replacementMesh ? replacementMesh : renderingMesh;
+        var effectiveMesh = subMesh.getEffectiveMesh();
         var scene = this._scene;
         var engine = scene.getEngine();
 
@@ -685,7 +688,7 @@ export abstract class EffectLayer {
             return;
         }
 
-        var hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id];
+        var hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id] || renderingMesh.hasThinInstances;
 
         this._setEmissiveTextureAndColor(renderingMesh, subMesh, material);
 

+ 6 - 11
src/LibDeclarations/webxr.d.ts

@@ -73,7 +73,7 @@ interface XRSessionInit {
     requiredFeatures?: string[];
 }
 
-interface XRSession extends XRAnchorCreator {
+interface XRSession {
     addEventListener: Function;
     removeEventListener: Function;
     requestReferenceSpace(type: XRReferenceSpaceType): Promise<XRReferenceSpace>;
@@ -114,6 +114,7 @@ interface XRFrame {
     getHitTestResultsForTransientInput(hitTestSource: XRTransientInputHitTestSource): Array<XRTransientInputHitTestResult>;
     // Anchors
     trackedAnchors?: XRAnchorSet;
+    createAnchor(pose: XRRigidTransform, space: XRSpace): Promise<XRAnchor>;
     // Planes
     worldInformation: {
         detectedPlanes?: XRPlaneSet;
@@ -198,6 +199,8 @@ interface XRTransientInputHitTestResult {
 
 interface XRHitTestResult {
     getPose(baseSpace: XRSpace): XRPose | undefined;
+    // When anchor system is enabled
+    createAnchor?(pose: XRRigidTransform): Promise<XRAnchor>;
 }
 
 interface XRHitTestSource {
@@ -221,21 +224,13 @@ interface XRTransientInputHitTestOptionsInit {
 }
 
 interface XRAnchor {
-    // remove?
-    id?: string;
     anchorSpace: XRSpace;
-    lastChangedTime: number;
-    detach(): void;
+    delete(): void;
 }
 
-interface XRPlane extends XRAnchorCreator {
+interface XRPlane {
     orientation: "Horizontal" | "Vertical";
     planeSpace: XRSpace;
     polygon: Array<DOMPointReadOnly>;
     lastChangedTime: number;
-}
-
-interface XRAnchorCreator {
-    // AR Anchors
-    createAnchor(pose: XRPose | XRRigidTransform, referenceSpace: XRReferenceSpace): Promise<XRAnchor>;
 }

+ 12 - 5
src/Lights/Shadows/shadowGenerator.ts

@@ -1030,6 +1030,10 @@ export class ShadowGenerator implements IShadowGenerator {
             for (index = 0; index < transparentSubMeshes.length; index++) {
                 this._renderSubMeshForShadowMap(transparentSubMeshes.data[index], true);
             }
+        } else {
+            for (index = 0; index < transparentSubMeshes.length; index++) {
+                transparentSubMeshes.data[index].getEffectiveMesh()._internalAbstractMeshDataInfo._isActiveIntermediate = false;
+            }
         }
     }
 
@@ -1042,6 +1046,8 @@ export class ShadowGenerator implements IShadowGenerator {
 
         const world = mesh.getWorldMatrix();
 
+        effect.setMatrix(matriceNames?.world ?? "world", world);
+
         world.multiplyToRef(this.getTransformMatrix(), tmpMatrix);
 
         effect.setMatrix(matriceNames?.worldViewProjection ?? "worldViewProjection", tmpMatrix);
@@ -1052,10 +1058,8 @@ export class ShadowGenerator implements IShadowGenerator {
     }
 
     protected _renderSubMeshForShadowMap(subMesh: SubMesh, isTransparent: boolean = false): void {
-        var ownerMesh = subMesh.getMesh();
-        var replacementMesh = ownerMesh._internalAbstractMeshDataInfo._actAsRegularMesh ? ownerMesh : null;
         var renderingMesh = subMesh.getRenderingMesh();
-        var effectiveMesh = replacementMesh ? replacementMesh : renderingMesh;
+        var effectiveMesh = subMesh.getEffectiveMesh();
         var scene = this._scene;
         var engine = scene.getEngine();
         let material = subMesh.getMaterial();
@@ -1070,12 +1074,12 @@ export class ShadowGenerator implements IShadowGenerator {
         engine.setState(material.backFaceCulling);
 
         // Managing instances
-        var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!replacementMesh);
+        var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
         if (batch.mustReturn) {
             return;
         }
 
-        var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
+        var hardwareInstancedRendering = engine.getCaps().instancedArrays && (batch.visibleInstances[subMesh._id] !== null && batch.visibleInstances[subMesh._id] !== undefined || renderingMesh.hasThinInstances);
         if (this.isReady(subMesh, hardwareInstancedRendering, isTransparent)) {
             const shadowDepthWrapper = renderingMesh.material?.shadowDepthWrapper;
 
@@ -1402,6 +1406,9 @@ export class ShadowGenerator implements IShadowGenerator {
             if (useInstances) {
                 defines.push("#define INSTANCES");
                 MaterialHelper.PushAttributesForInstances(attribs);
+                if (subMesh.getRenderingMesh().hasThinInstances) {
+                    defines.push("#define THIN_INSTANCES");
+                }
             }
 
             if (this.customShaderOptions) {

+ 1 - 1
src/Materials/Background/backgroundMaterial.ts

@@ -813,7 +813,7 @@ export class BackgroundMaterial extends PushMaterial {
         MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
         // Values that need to be evaluated on every frame
-        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances, null, subMesh.getRenderingMesh().hasThinInstances);
 
         // Attribs
         if (MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false)) {

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

@@ -8,6 +8,7 @@ import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
 import { NodeMaterialSystemValues } from '../../Enums/nodeMaterialSystemValues';
 import { InputBlock } from '../Input/inputBlock';
 import { _TypeStore } from '../../../../Misc/typeStore';
+import { SubMesh } from '../../../../Meshes/subMesh';
 
 /**
  * Block used to add support for instances
@@ -135,16 +136,21 @@ export class InstancesBlock extends NodeMaterialBlock {
             worldInput.output.connectTo(this.world);
         }
 
-        this.world.define = "!INSTANCES";
+        this.world.define = "!INSTANCES || THIN_INSTANCES";
     }
 
-    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false) {
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false, subMesh?: SubMesh) {
         let changed = false;
         if (defines["INSTANCES"] !== useInstances) {
             defines.setValue("INSTANCES", useInstances);
             changed = true;
         }
 
+        if (subMesh && defines["THIN_INSTANCES"] !== subMesh?.getRenderingMesh().hasInstances) {
+            defines.setValue("THIN_INSTANCES", subMesh?.getRenderingMesh().hasInstances);
+            changed = true;
+        }
+
         if (changed) {
             defines.markAsUnprocessed();
         }
@@ -166,6 +172,9 @@ export class InstancesBlock extends NodeMaterialBlock {
 
         state.compilationString += `#ifdef INSTANCES\r\n`;
         state.compilationString += this._declareOutput(output, state) + ` = mat4(${world0.associatedVariableName}, ${world1.associatedVariableName}, ${world2.associatedVariableName}, ${world3.associatedVariableName});\r\n`;
+        state.compilationString += `#ifdef THIN_INSTANCES\r\n`;
+        state.compilationString += `${output.associatedVariableName} = ${this.world.associatedVariableName} * ${output.associatedVariableName};\r\n`;
+        state.compilationString += `#endif\r\n`;
         state.compilationString += this._declareOutput(instanceID, state) + ` = float(gl_InstanceID);\r\n`;
         state.compilationString += `#else\r\n`;
         state.compilationString += this._declareOutput(output, state) + ` = ${this.world.associatedVariableName};\r\n`;

+ 57 - 11
src/Materials/Node/Blocks/transformBlock.ts

@@ -6,6 +6,9 @@ import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint
 import { _TypeStore } from '../../../Misc/typeStore';
 import { Scene } from '../../../scene';
 import { InputBlock } from './Input/inputBlock';
+import { AbstractMesh } from '../../../Meshes/abstractMesh';
+import { NodeMaterial, NodeMaterialDefines } from '../nodeMaterial';
+import { SubMesh } from '../../../Meshes/subMesh';
 
 /**
  * Block used to transform a vector (2, 3 or 4) with a matrix. It will generate a Vector4
@@ -87,17 +90,45 @@ export class TransformBlock extends NodeMaterialBlock {
         let transform = this.transform;
 
         if (vector.connectedPoint) {
-            switch (vector.connectedPoint.type) {
-                case NodeMaterialBlockConnectionPointTypes.Vector2:
-                    state.compilationString += this._declareOutput(this.output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementZ)}, ${this._writeFloat(this.complementW)});\r\n`;
-                    break;
-                case NodeMaterialBlockConnectionPointTypes.Vector3:
-                case NodeMaterialBlockConnectionPointTypes.Color3:
-                    state.compilationString += this._declareOutput(this.output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
-                    break;
-                default:
-                    state.compilationString += this._declareOutput(this.output, state) + ` = ${transform.associatedVariableName} * ${vector.associatedVariableName};\r\n`;
-                    break;
+
+            // None uniform scaling case.
+            if (this.complementW === 0) {
+                let comments = `//${this.name}`;
+                state._emitFunctionFromInclude("helperFunctions", comments);
+                state.sharedData.blocksWithDefines.push(this);
+
+                const transformName = state._getFreeVariableName(`${transform.associatedVariableName}_NUS`);
+                state.compilationString += `mat3 ${transformName} = mat3(${transform.associatedVariableName});\r\n`;
+                state.compilationString += `#ifdef NONUNIFORMSCALING\r\n`;
+                state.compilationString += `${transformName} = transposeMat3(inverseMat3(${transformName}));\r\n`;
+                state.compilationString += `#endif\r\n`;
+                switch (vector.connectedPoint.type) {
+                    case NodeMaterialBlockConnectionPointTypes.Vector2:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = vec4(${transformName} * vec3(${vector.associatedVariableName}, ${this._writeFloat(this.complementZ)}), ${this._writeFloat(this.complementW)});\r\n`;
+                        break;
+                    case NodeMaterialBlockConnectionPointTypes.Vector3:
+                    case NodeMaterialBlockConnectionPointTypes.Color3:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = vec4(${transformName} * ${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
+                        break;
+                    default:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = vec4(${transformName} * ${vector.associatedVariableName}.xyz, ${this._writeFloat(this.complementW)});\r\n`;
+                        break;
+                }
+            }
+            else {
+                const transformName = transform.associatedVariableName;
+                switch (vector.connectedPoint.type) {
+                    case NodeMaterialBlockConnectionPointTypes.Vector2:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = ${transformName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementZ)}, ${this._writeFloat(this.complementW)});\r\n`;
+                        break;
+                    case NodeMaterialBlockConnectionPointTypes.Vector3:
+                    case NodeMaterialBlockConnectionPointTypes.Color3:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = ${transformName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
+                        break;
+                    default:
+                        state.compilationString += this._declareOutput(this.output, state) + ` = ${transformName} * ${vector.associatedVariableName};\r\n`;
+                        break;
+                }
             }
 
             if (this.xyz.hasEndpoints) {
@@ -108,6 +139,21 @@ export class TransformBlock extends NodeMaterialBlock {
         return this;
     }
 
+    /**
+     * Update defines for shader compilation
+     * @param mesh defines the mesh to be rendered
+     * @param nodeMaterial defines the node material requesting the update
+     * @param defines defines the material defines to update
+     * @param useInstances specifies that instances should be used
+     * @param subMesh defines which submesh to render
+     */
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false, subMesh?: SubMesh) {
+        // Do nothing
+        if (mesh.nonUniformScaling) {
+            defines.setValue("NONUNIFORMSCALING", true);
+        }
+    }
+
     public serialize(): any {
         let serializationObject = super.serialize();
 

+ 3 - 3
src/Materials/Node/nodeMaterial.ts

@@ -940,7 +940,7 @@ export class NodeMaterial extends PushMaterial {
         this._createEffectForParticles(particleSystem, BaseParticleSystem.BLENDMODE_MULTIPLY, onCompiled, onError);
     }
 
-    private _processDefines(mesh: AbstractMesh, defines: NodeMaterialDefines, useInstances = false): Nullable<{
+    private _processDefines(mesh: AbstractMesh, defines: NodeMaterialDefines, useInstances = false, subMesh?: SubMesh): Nullable<{
         lightDisposed: boolean,
         uniformBuffers: string[],
         mergedUniforms: string[],
@@ -955,7 +955,7 @@ export class NodeMaterial extends PushMaterial {
         });
 
         this._sharedData.blocksWithDefines.forEach((b) => {
-            b.prepareDefines(mesh, this, defines, useInstances);
+            b.prepareDefines(mesh, this, defines, useInstances, subMesh);
         });
 
         // Need to recompile?
@@ -1066,7 +1066,7 @@ export class NodeMaterial extends PushMaterial {
             return false;
         }
 
-        const result = this._processDefines(mesh, defines, useInstances);
+        const result = this._processDefines(mesh, defines, useInstances, subMesh);
 
         if (result) {
             let previousEffect = subMesh.effect;

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

@@ -372,8 +372,9 @@ export class NodeMaterialBlock {
      * @param nodeMaterial defines the node material requesting the update
      * @param defines defines the material defines to update
      * @param useInstances specifies that instances should be used
+     * @param subMesh defines which submesh to render
      */
-    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false) {
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false, subMesh?: SubMesh) {
         // Do nothing
     }
 

+ 9 - 7
src/Materials/PBR/pbrBaseMaterial.ts

@@ -153,6 +153,7 @@ export class PBRMaterialDefines extends MaterialDefines
     public HORIZONOCCLUSION = false;
 
     public INSTANCES = false;
+    public THIN_INSTANCES = false;
 
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
@@ -1030,7 +1031,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
 
         const previousEffect = subMesh.effect;
         const lightDisposed = defines._areLightsDisposed;
-        let effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances);
+        let effect = this._prepareEffect(mesh, defines, this.onCompiled, this.onError, useInstances, null, subMesh.getRenderingMesh().hasThinInstances);
 
         if (effect) {
             if (this._onEffectCreatedObservable) {
@@ -1080,8 +1081,9 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         return false;
     }
 
-    private _prepareEffect(mesh: AbstractMesh, defines: PBRMaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null): Nullable<Effect> {
-        this._prepareDefines(mesh, defines, useInstances, useClipPlane);
+    private _prepareEffect(mesh: AbstractMesh, defines: PBRMaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null,
+                useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null, useThinInstances: boolean): Nullable<Effect> {
+        this._prepareDefines(mesh, defines, useInstances, useClipPlane, useThinInstances);
 
         if (!defines.isDirty) {
             return null;
@@ -1278,7 +1280,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         }, engine);
     }
 
-    private _prepareDefines(mesh: AbstractMesh, defines: PBRMaterialDefines, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null): void {
+    private _prepareDefines(mesh: AbstractMesh, defines: PBRMaterialDefines, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null, useThinInstances: boolean = false): void {
         const scene = this.getScene();
         const engine = scene.getEngine();
 
@@ -1567,7 +1569,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         this.sheen.prepareDefines(defines, scene);
 
         // Values that need to be evaluated on every frame
-        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, useClipPlane);
+        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, useClipPlane, useThinInstances);
 
         // Attribs
         MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true, this._transparencyMode !== PBRBaseMaterial.PBRMATERIAL_OPAQUE);
@@ -1584,7 +1586,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         };
 
         const defines = new PBRMaterialDefines();
-        const effect = this._prepareEffect(mesh, defines, undefined, undefined, localOptions.useInstances, localOptions.clipPlane)!;
+        const effect = this._prepareEffect(mesh, defines, undefined, undefined, localOptions.useInstances, localOptions.clipPlane, mesh.hasThinInstances)!;
         if (this._onEffectCreatedObservable) {
             onCreatedEffectParameters.effect = effect;
             onCreatedEffectParameters.subMesh = null;
@@ -1700,7 +1702,7 @@ export abstract class PBRBaseMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        if (!defines.INSTANCES) {
+        if (!defines.INSTANCES || defines.THIN_INSTANCES) {
             this.bindOnlyWorldMatrix(world);
         }
 

+ 35 - 15
src/Materials/material.ts

@@ -7,7 +7,7 @@ import { Nullable } from "../types";
 import { Scene } from "../scene";
 import { Matrix } from "../Maths/math.vector";
 import { EngineStore } from "../Engines/engineStore";
-import { BaseSubMesh, SubMesh } from "../Meshes/subMesh";
+import { SubMesh } from "../Meshes/subMesh";
 import { Geometry } from "../Meshes/geometry";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { UniformBuffer } from "./uniformBuffer";
@@ -709,7 +709,7 @@ export class Material implements IAnimatable {
      * @param useInstances specifies that instances should be used
      * @returns a boolean indicating that the submesh is ready or not
      */
-    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
+    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
         return false;
     }
 
@@ -1044,7 +1044,6 @@ export class Material implements IAnimatable {
             ...options
         };
 
-        var subMesh = new BaseSubMesh();
         var scene = this.getScene();
 
         var checkReady = () => {
@@ -1052,10 +1051,6 @@ export class Material implements IAnimatable {
                 return;
             }
 
-            if (subMesh._materialDefines) {
-                subMesh._materialDefines._renderId = -1;
-            }
-
             var clipPlaneState = scene.clipPlane;
 
             if (localOptions.clipPlane) {
@@ -1063,18 +1058,43 @@ export class Material implements IAnimatable {
             }
 
             if (this._storeEffectOnSubMeshes) {
-                if (this.isReadyForSubMesh(mesh, subMesh, localOptions.useInstances)) {
-                    if (onCompiled) {
-                        onCompiled(this);
+                var allDone = true, lastError = null;
+                if (mesh.subMeshes) {
+                    for (var subMesh of mesh.subMeshes) {
+                        let effectiveMaterial = subMesh.getMaterial();
+                        if (effectiveMaterial) {
+                            if (effectiveMaterial._storeEffectOnSubMeshes) {
+                                if (!effectiveMaterial.isReadyForSubMesh(mesh, subMesh, localOptions.useInstances)) {
+                                    if (subMesh.effect && subMesh.effect.getCompilationError() && subMesh.effect.allFallbacksProcessed()) {
+                                        lastError = subMesh.effect.getCompilationError();
+                                    } else {
+                                        allDone = false;
+                                        setTimeout(checkReady, 16);
+                                        break;
+                                    }
+                                }
+                            } else {
+                                if (!effectiveMaterial.isReady(mesh, localOptions.useInstances)) {
+                                    if (effectiveMaterial.getEffect() && effectiveMaterial.getEffect()!.getCompilationError() && effectiveMaterial.getEffect()!.allFallbacksProcessed()) {
+                                        lastError = effectiveMaterial.getEffect()!.getCompilationError();
+                                    } else {
+                                        allDone = false;
+                                        setTimeout(checkReady, 16);
+                                        break;
+                                    }
+                                }
+                            }
+                        }
                     }
                 }
-                else {
-                    if (subMesh.effect && subMesh.effect.getCompilationError() && subMesh.effect.allFallbacksProcessed()) {
+                if (allDone) {
+                    if (lastError) {
                         if (onError) {
-                            onError(subMesh.effect.getCompilationError());
+                            onError(lastError);
                         }
-                    } else {
-                        setTimeout(checkReady, 16);
+                    }
+                    if (onCompiled) {
+                        onCompiled(this);
                     }
                 }
             } else {

+ 9 - 2
src/Materials/materialHelper.ts

@@ -117,8 +117,10 @@ export class MaterialHelper {
      * @param defines specifies the list of active defines
      * @param useInstances defines if instances have to be turned on
      * @param useClipPlane defines if clip plane have to be turned on
+     * @param useInstances defines if instances have to be turned on
+     * @param useThinInstances defines if thin instances have to be turned on
      */
-    public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane: Nullable<boolean> = null): void {
+    public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, useClipPlane: Nullable<boolean> = null, useThinInstances: boolean = false): void {
         var changed = false;
         let useClipPlane1 = false;
         let useClipPlane2 = false;
@@ -174,6 +176,11 @@ export class MaterialHelper {
             changed = true;
         }
 
+        if (defines["THIN_INSTANCES"] !== useThinInstances) {
+            defines["THIN_INSTANCES"] = useThinInstances;
+            changed = true;
+        }
+
         if (changed) {
             defines.markAsUnprocessed();
         }
@@ -664,7 +671,7 @@ export class MaterialHelper {
      * @param defines The current MaterialDefines of the effect
      */
     public static PrepareAttributesForInstances(attribs: string[], defines: MaterialDefines): void {
-        if (defines["INSTANCES"]) {
+        if (defines["INSTANCES"] || defines["THIN_INSTANCES"]) {
             this.PushAttributesForInstances(attribs);
         }
     }

+ 2 - 2
src/Materials/multiMaterial.ts

@@ -1,7 +1,7 @@
 import { Nullable } from "../types";
 import { Scene } from "../scene";
 import { AbstractMesh } from "../Meshes/abstractMesh";
-import { BaseSubMesh } from "../Meshes/subMesh";
+import { SubMesh } from "../Meshes/subMesh";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
 import { Material } from "../Materials/material";
 import { Tags } from "../Misc/tags";
@@ -117,7 +117,7 @@ export class MultiMaterial extends Material {
      * @param useInstances Define whether or not the material is used with instances
      * @returns true if ready, otherwise false
      */
-    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
+    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
         for (var index = 0; index < this.subMaterials.length; index++) {
             var subMaterial = this.subMaterials[index];
             if (subMaterial) {

+ 5 - 2
src/Materials/shaderMaterial.ts

@@ -4,7 +4,7 @@ import { Scene } from "../scene";
 import { Matrix, Vector3, Vector2, Vector4 } from "../Maths/math.vector";
 import { AbstractMesh } from "../Meshes/abstractMesh";
 import { Mesh } from "../Meshes/mesh";
-import { SubMesh, BaseSubMesh } from "../Meshes/subMesh";
+import { SubMesh } from "../Meshes/subMesh";
 import { VertexBuffer } from "../Meshes/buffer";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
 import { Texture } from "../Materials/Textures/texture";
@@ -463,7 +463,7 @@ export class ShaderMaterial extends Material {
      * @param useInstances specifies that instances should be used
      * @returns a boolean indicating that the submesh is ready or not
      */
-    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
+    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances?: boolean): boolean {
         return this.isReady(mesh, useInstances);
     }
 
@@ -525,6 +525,9 @@ export class ShaderMaterial extends Material {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (mesh?.hasThinInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         // Bones

+ 1 - 0
src/Materials/shadowDepthWrapper.ts

@@ -94,6 +94,7 @@ export class ShadowDepthWrapper {
         const prefix = baseMaterial.getClassName() === "NodeMaterial" ? "u_" : "";
 
         this._matriceNames = {
+            "world": prefix + "world",
             "view": prefix + "view",
             "projection": prefix + "projection",
             "viewProjection": prefix + "viewProjection",

+ 3 - 2
src/Materials/standardMaterial.ts

@@ -83,6 +83,7 @@ export class StandardMaterialDefines extends MaterialDefines implements IImagePr
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
     public INSTANCES = false;
+    public THIN_INSTANCES = false;
     public GLOSSINESS = false;
     public ROUGHNESS = false;
     public EMISSIVEASILLUMINATION = false;
@@ -1035,7 +1036,7 @@ export class StandardMaterial extends PushMaterial {
         MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
 
         // Values that need to be evaluated on every frame
-        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
+        MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances, null, subMesh.getRenderingMesh().hasThinInstances);
 
         // Get correct effect
         if (defines.isDirty) {
@@ -1316,7 +1317,7 @@ export class StandardMaterial extends PushMaterial {
         this._activeEffect = effect;
 
         // Matrices
-        if (!defines.INSTANCES) {
+        if (!defines.INSTANCES || defines.THIN_INSTANCES) {
             this.bindOnlyWorldMatrix(world);
         }
 

+ 7 - 0
src/Meshes/abstractMesh.ts

@@ -1089,6 +1089,13 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
         return false;
     }
 
+    /**
+     * Gets a boolean indicating if this mesh has thin instances
+     */
+    public get hasThinInstances(): boolean {
+        return false;
+    }
+
     // ================================== Point of View Movement =================================
 
     /**

+ 3 - 1
src/Meshes/index.ts

@@ -18,4 +18,6 @@ export * from "./meshLODLevel";
 export * from "./transformNode";
 export * from "./Builders/index";
 export * from "./dataBuffer";
-export * from "./WebGL/webGLDataBuffer";
+export * from "./WebGL/webGLDataBuffer";
+import "./thinInstanceMesh";
+export * from "./thinInstanceMesh";

+ 107 - 4
src/Meshes/mesh.ts

@@ -91,6 +91,17 @@ export class _InstancesBatch {
 /**
  * @hidden
  **/
+class _ThinInstanceDataStorage {
+    public instancesCount: number = 0;
+    public matrixBuffer: Nullable<Buffer> = null;
+    public matrixBufferSize = 32 * 16; // let's start with a maximum of 32 thin instances
+    public matrixData: Nullable<Float32Array>;
+    public boundingVectors: Array<Vector3> = [];
+}
+
+/**
+ * @hidden
+ **/
 class _InternalMeshDataInfo {
     // Events
     public _onBeforeRenderObservable: Nullable<Observable<Mesh>>;
@@ -275,6 +286,10 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         return this.instances.length > 0;
     }
 
+    public get hasThinInstances(): boolean {
+        return (this._thinInstanceDataStorage.instancesCount ?? 0) > 0;
+    }
+
     // Members
 
     /**
@@ -335,6 +350,9 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
     /** @hidden */
     public _instanceDataStorage = new _InstanceDataStorage();
 
+    /** @hidden */
+    public _thinInstanceDataStorage = new _ThinInstanceDataStorage();
+
     private _effectiveMaterial: Nullable<Material> = null;
 
     /** @hidden */
@@ -412,7 +430,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
                 "hasInstances", "source", "worldMatrixInstancedBuffer", "hasLODLevels", "geometry", "isBlocked", "areNormalsFrozen",
                 "facetNb", "isFacetDataEnabled", "lightSources", "useBones", "isAnInstance", "collider", "edgesRenderer", "forward",
                 "up", "right", "absolutePosition", "absoluteScaling", "absoluteRotationQuaternion", "isWorldMatrixFrozen",
-                "nonUniformScaling", "behaviors", "worldMatrixFromCache"
+                "nonUniformScaling", "behaviors", "worldMatrixFromCache", "hasThinInstances"
             ], ["_poseMatrix"]);
 
             // Source mesh
@@ -955,7 +973,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
         let engine = this.getEngine();
         let scene = this.getScene();
-        let hardwareInstancedRendering = forceInstanceSupport || engine.getCaps().instancedArrays && this.instances.length > 0;
+        let hardwareInstancedRendering = forceInstanceSupport || engine.getCaps().instancedArrays && (this.instances.length > 0 || this.hasThinInstances);
 
         this.computeWorldMatrix();
 
@@ -1078,6 +1096,18 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         return this;
     }
 
+    protected _afterComputeWorldMatrix(): void {
+        super._afterComputeWorldMatrix();
+
+        if (!this.hasThinInstances) {
+            return;
+        }
+
+        if (!this.doNotSyncBoundingInfo) {
+            this.thinInstanceRefreshBoundingInfo(false);
+        }
+    }
+
     /**
      * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
      * This means the mesh underlying bounding box and sphere are recomputed.
@@ -1614,6 +1644,20 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
     }
 
     /** @hidden */
+    public _renderWithThinInstances(subMesh: SubMesh, fillMode: number, effect: Effect, engine: Engine) {
+        // Stats
+        const instancesCount = this._thinInstanceDataStorage?.instancesCount ?? 0;
+
+        this.getScene()._activeIndices.addCount(subMesh.indexCount * instancesCount, false);
+
+        // Draw
+        this._bind(subMesh, effect, fillMode);
+        this._draw(subMesh, fillMode, instancesCount);
+
+        engine.unbindInstanceAttributes();
+    }
+
+    /** @hidden */
     public _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean) {
         // Do nothing
     }
@@ -1624,6 +1668,11 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         var scene = this.getScene();
         var engine = scene.getEngine();
 
+        if (hardwareInstancedRendering && subMesh.getRenderingMesh().hasThinInstances) {
+            this._renderWithThinInstances(subMesh, fillMode, effect, engine);
+            return this;
+        }
+
         if (hardwareInstancedRendering) {
             this._renderWithInstances(subMesh, fillMode, batch, effect, engine);
         } else {
@@ -1732,7 +1781,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         }
 
         var engine = scene.getEngine();
-        var hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id];
+        var hardwareInstancedRendering = batch.hardwareInstancedRendering[subMesh._id] || subMesh.getRenderingMesh().hasThinInstances;
         let instanceDataStorage = this._instanceDataStorage;
 
         let material = subMesh.getMaterial();
@@ -2273,6 +2322,9 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         // Instances
         this._disposeInstanceSpecificData();
 
+        // Thin instances
+        this._disposeThinInstanceSpecificData();
+
         super.dispose(doNotRecurse, disposeMaterialAndTextures);
     }
 
@@ -2281,6 +2333,11 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         // Do nothing
     }
 
+    /** @hidden */
+    public _disposeThinInstanceSpecificData() {
+        // Do nothing
+    }
+
     /**
      * Modifies the mesh geometry according to a displacement map.
      * A displacement map is a colored image. Each pixel color value (actually a gradient computed from red, green, blue values) will give the displacement to apply to each mesh vertex.
@@ -3057,7 +3114,30 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             serializationInstance.ranges = instance.serializeAnimationRanges();
         }
 
-        //
+        // Thin instances
+        if (this._thinInstanceDataStorage.instancesCount && this._thinInstanceDataStorage.matrixData) {
+            serializationObject.thinInstances = {
+                instancesCount: this._thinInstanceDataStorage.instancesCount,
+                matrixData: Array.from(this._thinInstanceDataStorage.matrixData),
+                matrixBufferSize: this._thinInstanceDataStorage.matrixBufferSize,
+            };
+
+            if (this._userThinInstanceBuffersStorage) {
+                const userThinInstance: any = {
+                    data: {},
+                    sizes: {},
+                    strides: {},
+                };
+
+                for (const kind in this._userThinInstanceBuffersStorage.data) {
+                    userThinInstance.data[kind] = Array.from(this._userThinInstanceBuffersStorage.data[kind]);
+                    userThinInstance.sizes[kind] = this._userThinInstanceBuffersStorage.sizes[kind];
+                    userThinInstance.strides[kind] = this._userThinInstanceBuffersStorage.strides[kind];
+                }
+
+                serializationObject.thinInstances.userThinInstance = userThinInstance;
+            }
+        }
 
         // Animations
         SerializationHelper.AppendSerializedAnimations(this, serializationObject);
@@ -3454,6 +3534,29 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             }
         }
 
+        // Thin instances
+        if (parsedMesh.thinInstances) {
+            const thinInstances = parsedMesh.thinInstances;
+
+            if (thinInstances.matrixData) {
+                mesh.thinInstanceSetBuffer("matrix", new Float32Array(thinInstances.matrixData), 16, false);
+
+                mesh._thinInstanceDataStorage.matrixBufferSize = thinInstances.matrixBufferSize;
+                mesh._thinInstanceDataStorage.instancesCount = thinInstances.instancesCount;
+            } else {
+                mesh._thinInstanceDataStorage.matrixBufferSize = thinInstances.matrixBufferSize;
+            }
+
+            if (parsedMesh.thinInstances.userThinInstance) {
+                const userThinInstance = parsedMesh.thinInstances.userThinInstance;
+
+                for (const kind in userThinInstance.data) {
+                    mesh.thinInstanceSetBuffer(kind, new Float32Array(userThinInstance.data[kind]), userThinInstance.strides[kind], false);
+                    mesh._userThinInstanceBuffersStorage.sizes[kind] = userThinInstance.sizes[kind];
+                }
+            }
+        }
+
         return mesh;
     }
 

+ 20 - 8
src/Meshes/subMesh.ts

@@ -20,9 +20,9 @@ declare type Ray = import("../Culling/ray").Ray;
 declare type TrianglePickingPredicate = import("../Culling/ray").TrianglePickingPredicate;
 
 /**
- * Base class for submeshes
+ * Defines a subdivision inside a mesh
  */
-export class BaseSubMesh {
+export class SubMesh implements ICullable {
     /** @hidden */
     public _materialDefines: Nullable<MaterialDefines> = null;
     /** @hidden */
@@ -66,12 +66,7 @@ export class BaseSubMesh {
         this._materialDefines = defines;
         this._materialEffect = effect;
     }
-}
 
-/**
- * Defines a subdivision inside a mesh
- */
-export class SubMesh extends BaseSubMesh implements ICullable {
     /** @hidden */
     public _linesIndexCount: number = 0;
     private _mesh: AbstractMesh;
@@ -134,7 +129,6 @@ export class SubMesh extends BaseSubMesh implements ICullable {
         public indexStart: number,
         /** indices count */
         public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh, createBoundingBox: boolean = true) {
-        super();
         this._mesh = mesh;
         this._renderingMesh = renderingMesh || <Mesh>mesh;
         mesh.subMeshes.push(this);
@@ -196,6 +190,24 @@ export class SubMesh extends BaseSubMesh implements ICullable {
     }
 
     /**
+     * Returns the replacement mesh of the submesh
+     * @returns the replacement mesh (could be different from parent mesh)
+     */
+    public getReplacementMesh(): Nullable<AbstractMesh> {
+        return this._mesh._internalAbstractMeshDataInfo._actAsRegularMesh ? this._mesh : null;
+    }
+
+    /**
+     * Returns the effective mesh of the submesh
+     * @returns the effective mesh (could be different from parent mesh)
+     */
+    public getEffectiveMesh(): AbstractMesh {
+        const replacementMesh = this._mesh._internalAbstractMeshDataInfo._actAsRegularMesh ? this._mesh : null;
+
+        return replacementMesh ? replacementMesh : this._renderingMesh;
+    }
+
+    /**
      * Returns the submesh material
      * @returns null or the current material
      */

+ 345 - 0
src/Meshes/thinInstanceMesh.ts

@@ -0,0 +1,345 @@
+import { Nullable, DeepImmutableObject } from "../types";
+import { Mesh, _InstancesBatch } from "../Meshes/mesh";
+import { VertexBuffer, Buffer } from './buffer';
+import { Matrix, Vector3, TmpVectors } from '../Maths/math.vector';
+
+declare module "./mesh" {
+    export interface Mesh {
+        /**
+         * Creates a new thin instance
+         * @param matrix the matrix or array of matrices (position, rotation, scale) of the thin instance(s) to create
+         * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+         * @returns the thin instance index number. If you pass an array of matrices, other instance indexes are index+1, index+2, etc
+         */
+        thinInstanceAdd(matrix: DeepImmutableObject<Matrix> | Array<DeepImmutableObject<Matrix>>, refresh: boolean): number;
+
+        /**
+         * Adds the transformation (matrix) of the current mesh as a thin instance
+         * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+         * @returns the thin instance index number
+         */
+        thinInstanceAddSelf(refresh: boolean): number;
+
+        /**
+         * Registers a custom attribute to be used with thin instances
+         * @param kind name of the attribute
+         * @param stride size in floats of the attribute
+         */
+        thinInstanceRegisterAttribute(kind: string, stride: number): void;
+
+        /**
+         * Sets the matrix of a thin instance
+         * @param index index of the thin instance
+         * @param matrix matrix to set
+         * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+         */
+        thinInstanceSetMatrixAt(index: number, matrix: DeepImmutableObject<Matrix>, refresh: boolean): void;
+
+        /**
+         * Sets the value of a custom attribute for a thin instance
+         * @param kind name of the attribute
+         * @param index index of the thin instance
+         * @param value value to set
+         * @param refresh true to refresh the underlying gpu buffer (default: true). If you do multiple calls to this method in a row, set refresh to true only for the last call to save performance
+         */
+        thinInstanceSetAttributeAt(kind: string, index: number, value: Array<number>, refresh: boolean): void;
+
+        /**
+         * Gets / sets the number of thin instances to display. Note that you can't set a number higher than what the underlying buffer can handle.
+         */
+        thinInstanceCount: number;
+
+        /**
+         * Sets a buffer to be used with thin instances. This method is a faster way to setup multiple instances than calling thinInstanceAdd repeatedly
+         * @param kind name of the attribute. Use "matrix" to setup the buffer of matrices
+         * @param buffer buffer to set
+         * @param stride size in floats of each value of the buffer
+         * @param staticBuffer indicates that the buffer is static, so that you won't change it after it is set (better performances - false by default)
+         */
+        thinInstanceSetBuffer(kind: string, buffer: Nullable<Float32Array>,  stride: number, staticBuffer: boolean): void;
+
+        /**
+         * Synchronize the gpu buffers with a thin instance buffer. Call this method if you update later on the buffers passed to thinInstanceSetBuffer
+         * @param kind name of the attribute to update. Use "matrix" to update the buffer of matrices
+         */
+        thinInstanceBufferUpdated(kind: string): void;
+
+        /**
+         * Refreshes the bounding info, taking into account all the thin instances defined
+         * @param forceRefreshParentInfo true to force recomputing the mesh bounding info and use it to compute the aggregated bounding info
+         */
+        thinInstanceRefreshBoundingInfo(forceRefreshParentInfo: boolean): void;
+
+        /** @hidden */
+        _thinInstanceInitializeUserStorage(): void;
+
+        /** @hidden */
+        _thinInstanceUpdateBufferSize(kind: string, numInstances: number): void;
+
+        /** @hidden */
+        _userThinInstanceBuffersStorage: {
+            data: {[key: string]: Float32Array},
+            sizes: {[key: string]: number},
+            vertexBuffers: {[key: string]: Nullable<VertexBuffer>},
+            strides: {[key: string]: number}
+        };
+
+    }
+}
+
+Mesh.prototype.thinInstanceAdd = function(matrix: DeepImmutableObject<Matrix> | Array<DeepImmutableObject<Matrix>>, refresh: boolean = true): number {
+    this._thinInstanceUpdateBufferSize("matrix", Array.isArray(matrix) ? matrix.length : 1);
+
+    const index = this._thinInstanceDataStorage.instancesCount;
+
+    if (Array.isArray(matrix)) {
+        for (let i = 0; i < matrix.length; ++i) {
+            this.thinInstanceSetMatrixAt(this._thinInstanceDataStorage.instancesCount++, matrix[i], (i === matrix.length - 1) && refresh);
+        }
+    } else {
+        this.thinInstanceSetMatrixAt(this._thinInstanceDataStorage.instancesCount++, matrix, refresh);
+    }
+
+    return index;
+};
+
+Mesh.prototype.thinInstanceAddSelf = function(refresh: boolean = true): number {
+    return this.thinInstanceAdd(Matrix.IdentityReadOnly, refresh);
+};
+
+Mesh.prototype.thinInstanceRegisterAttribute = function(kind: string, stride: number): void {
+    this.removeVerticesData(kind);
+
+    this._thinInstanceInitializeUserStorage();
+
+    this._userThinInstanceBuffersStorage.strides[kind] = stride;
+    this._userThinInstanceBuffersStorage.sizes[kind] = stride * Math.max(32, this._thinInstanceDataStorage.instancesCount); // Initial size
+    this._userThinInstanceBuffersStorage.data[kind] = new Float32Array(this._userThinInstanceBuffersStorage.sizes[kind]);
+    this._userThinInstanceBuffersStorage.vertexBuffers[kind] = new VertexBuffer(this.getEngine(), this._userThinInstanceBuffersStorage.data[kind], kind, true, false, stride, true);
+
+    this.setVerticesBuffer(this._userThinInstanceBuffersStorage.vertexBuffers[kind]!);
+};
+
+Mesh.prototype.thinInstanceSetMatrixAt = function(index: number, matrix: DeepImmutableObject<Matrix>, refresh: boolean = true): boolean {
+    if (!this._thinInstanceDataStorage.matrixData || index >= this._thinInstanceDataStorage.instancesCount) {
+        return false;
+    }
+
+    const matrixData = this._thinInstanceDataStorage.matrixData;
+
+    matrix.copyToArray(matrixData, index * 16);
+
+    if (refresh) {
+        this.thinInstanceBufferUpdated("matrix");
+
+        if (!this.doNotSyncBoundingInfo) {
+            this.thinInstanceRefreshBoundingInfo(false);
+        }
+    }
+
+    return true;
+};
+
+Mesh.prototype.thinInstanceSetAttributeAt = function(kind: string, index: number, value: Array<number>, refresh: boolean = true): boolean {
+    if (!this._userThinInstanceBuffersStorage || !this._userThinInstanceBuffersStorage.data[kind] || index >= this._thinInstanceDataStorage.instancesCount) {
+        return false;
+    }
+
+    this._thinInstanceUpdateBufferSize(kind, 0); // make sur the buffer for the kind attribute is big enough
+
+    this._userThinInstanceBuffersStorage.data[kind].set(value, index * this._userThinInstanceBuffersStorage.strides[kind]);
+
+    if (refresh) {
+        this.thinInstanceBufferUpdated(kind);
+    }
+
+    return true;
+};
+
+Object.defineProperty(Mesh.prototype, "thinInstanceCount", {
+    get: function(this: Mesh) {
+        return this._thinInstanceDataStorage.instancesCount;
+    },
+    set: function(this: Mesh, value: number) {
+        const numMaxInstances = (this._thinInstanceDataStorage.matrixData?.length ?? 0) / 16;
+
+        if (value <= numMaxInstances) {
+            this._thinInstanceDataStorage.instancesCount = value;
+        }
+    },
+    enumerable: true,
+    configurable: true
+});
+
+Mesh.prototype.thinInstanceSetBuffer = function(kind: string, buffer: Nullable<Float32Array>, stride: number = 0, staticBuffer: boolean = false): void {
+    stride = stride || 16;
+
+    if (kind === "matrix") {
+        this._thinInstanceDataStorage.matrixBuffer?.dispose();
+        this._thinInstanceDataStorage.matrixBuffer = null;
+        this._thinInstanceDataStorage.matrixBufferSize = buffer ? buffer.length : 32 * stride;
+        this._thinInstanceDataStorage.matrixData = buffer;
+
+        if (buffer !== null) {
+            this._thinInstanceDataStorage.instancesCount = buffer.length / stride;
+
+            const matrixBuffer = new Buffer(this.getEngine(), buffer, !staticBuffer, stride, false, true);
+
+            this._thinInstanceDataStorage.matrixBuffer = matrixBuffer;
+
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world0", 0, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world1", 4, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world2", 8, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world3", 12, 4));
+
+            if (!this.doNotSyncBoundingInfo) {
+                this.thinInstanceRefreshBoundingInfo(false);
+            }
+        } else {
+            this._thinInstanceDataStorage.instancesCount = 0;
+            if (!this.doNotSyncBoundingInfo) {
+                // mesh has no more thin instances, so need to recompute the bounding box because it's the regular mesh that will now be displayed
+                this.refreshBoundingInfo(true);
+            }
+        }
+    } else {
+        if (buffer === null) {
+            if (this._userThinInstanceBuffersStorage?.data[kind]) {
+                this.removeVerticesData(kind);
+                delete this._userThinInstanceBuffersStorage.data[kind];
+                delete this._userThinInstanceBuffersStorage.strides[kind];
+                delete this._userThinInstanceBuffersStorage.sizes[kind];
+                delete this._userThinInstanceBuffersStorage.vertexBuffers[kind];
+            }
+        } else {
+            this._thinInstanceInitializeUserStorage();
+
+            this._userThinInstanceBuffersStorage.data[kind] = buffer;
+            this._userThinInstanceBuffersStorage.strides[kind] = stride;
+            this._userThinInstanceBuffersStorage.sizes[kind] = buffer.length;
+            this._userThinInstanceBuffersStorage.vertexBuffers[kind] = new VertexBuffer(this.getEngine(), buffer, kind, !staticBuffer, false, stride, true);
+
+            this.setVerticesBuffer(this._userThinInstanceBuffersStorage.vertexBuffers[kind]!);
+        }
+    }
+};
+
+Mesh.prototype.thinInstanceBufferUpdated = function(kind: string): void {
+    if (kind === "matrix") {
+        if (this._thinInstanceDataStorage.matrixBuffer) {
+            this._thinInstanceDataStorage.matrixBuffer!.updateDirectly(this._thinInstanceDataStorage.matrixData!, 0, this._thinInstanceDataStorage.instancesCount);
+        }
+    } else if (this._userThinInstanceBuffersStorage?.vertexBuffers[kind]) {
+        this._userThinInstanceBuffersStorage.vertexBuffers[kind]!.updateDirectly(this._userThinInstanceBuffersStorage.data[kind], 0);
+    }
+};
+
+Mesh.prototype.thinInstanceRefreshBoundingInfo = function(forceRefreshParentInfo: boolean = false) {
+    if (!this._thinInstanceDataStorage.matrixData || !this._thinInstanceDataStorage.matrixBuffer) {
+        return;
+    }
+
+    const vectors = this._thinInstanceDataStorage.boundingVectors;
+
+    if (forceRefreshParentInfo) {
+        vectors.length = 0;
+        this.refreshBoundingInfo(true);
+    }
+
+    const boundingInfo = this.getBoundingInfo();
+    const matrixData = this._thinInstanceDataStorage.matrixData;
+
+    if (vectors.length === 0) {
+        const worldMatrix = this.getWorldMatrix();
+        for (let v = 0; v < boundingInfo.boundingBox.vectors.length; ++v) {
+            vectors.push(boundingInfo.boundingBox.vectors[v].clone());
+            Vector3.TransformCoordinatesToRef(vectors[v], worldMatrix, vectors[v]);
+        }
+    }
+
+    TmpVectors.Vector3[0].setAll(Number.MAX_VALUE); // min
+    TmpVectors.Vector3[1].setAll(Number.MIN_VALUE); // max
+
+    for (let i = 0; i < this._thinInstanceDataStorage.instancesCount; ++i) {
+        Matrix.FromArrayToRef(matrixData, i * 16, TmpVectors.Matrix[0]);
+
+        for (let v = 0; v < vectors.length; ++v) {
+            Vector3.TransformCoordinatesToRef(vectors[v], TmpVectors.Matrix[0], TmpVectors.Vector3[2]);
+            TmpVectors.Vector3[0].minimizeInPlace(TmpVectors.Vector3[2]);
+            TmpVectors.Vector3[1].maximizeInPlace(TmpVectors.Vector3[2]);
+        }
+    }
+
+    boundingInfo.reConstruct(TmpVectors.Vector3[0], TmpVectors.Vector3[1]);
+};
+
+Mesh.prototype._thinInstanceUpdateBufferSize = function(kind: string, numInstances: number = 1) {
+    const kindIsMatrix = kind === "matrix";
+
+    if (!kindIsMatrix && (!this._userThinInstanceBuffersStorage || !this._userThinInstanceBuffersStorage.strides[kind])) {
+        return;
+    }
+
+    const stride = kindIsMatrix ? 16 : this._userThinInstanceBuffersStorage.strides[kind];
+    const currentSize = kindIsMatrix ? this._thinInstanceDataStorage.matrixBufferSize : this._userThinInstanceBuffersStorage.sizes[kind];
+    let data = kindIsMatrix ? this._thinInstanceDataStorage.matrixData : this._userThinInstanceBuffersStorage.data[kind];
+
+    const bufferSize = (this._thinInstanceDataStorage.instancesCount + numInstances) * stride;
+
+    let newSize = currentSize;
+
+    while (newSize < bufferSize) {
+        newSize *= 2;
+    }
+
+    if (!data || currentSize != newSize) {
+        if (!data) {
+            data = new Float32Array(newSize);
+        } else {
+            const newData = new Float32Array(newSize);
+            newData.set(data, 0);
+            data = newData;
+        }
+
+        if (kindIsMatrix) {
+            this._thinInstanceDataStorage.matrixBuffer?.dispose();
+
+            const matrixBuffer = new Buffer(this.getEngine(), data, true, stride, false, true);
+
+            this._thinInstanceDataStorage.matrixBuffer = matrixBuffer;
+            this._thinInstanceDataStorage.matrixData = data;
+            this._thinInstanceDataStorage.matrixBufferSize = newSize;
+
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world0", 0, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world1", 4, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world2", 8, 4));
+            this.setVerticesBuffer(matrixBuffer.createVertexBuffer("world3", 12, 4));
+        } else {
+            this._userThinInstanceBuffersStorage.vertexBuffers[kind]?.dispose();
+
+            this._userThinInstanceBuffersStorage.data[kind] = data;
+            this._userThinInstanceBuffersStorage.sizes[kind] = newSize;
+            this._userThinInstanceBuffersStorage.vertexBuffers[kind] = new VertexBuffer(this.getEngine(), data, kind, true, false, stride, true);
+
+            this.setVerticesBuffer(this._userThinInstanceBuffersStorage.vertexBuffers[kind]!);
+        }
+    }
+};
+
+Mesh.prototype._thinInstanceInitializeUserStorage = function() {
+    if (!this._userThinInstanceBuffersStorage) {
+        this._userThinInstanceBuffersStorage = {
+            data: {},
+            sizes: {},
+            vertexBuffers: {},
+            strides: {},
+        };
+    }
+};
+
+Mesh.prototype._disposeThinInstanceSpecificData = function() {
+    if (this._thinInstanceDataStorage?.matrixBuffer) {
+        this._thinInstanceDataStorage.matrixBuffer.dispose();
+        this._thinInstanceDataStorage.matrixBuffer = null;
+    }
+};

+ 12 - 25
src/Particles/EmitterTypes/coneParticleEmitter.ts

@@ -1,5 +1,5 @@
 import { DeepCopier } from "../../Misc/deepCopier";
-import { Vector3, Matrix } from "../../Maths/math.vector";
+import { Vector3, Matrix, TmpVectors } from "../../Maths/math.vector";
 import { Scalar } from "../../Maths/math.scalar";
 import { Effect } from "../../Materials/effect";
 import { Particle } from "../../Particles/particle";
@@ -83,33 +83,20 @@ export class ConeParticleEmitter implements IParticleEmitterType {
      * @param isLocal defines if the direction should be set in local space
      */
     public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean): void {
-        if (Math.abs(Math.cos(this._angle)) === 1.0) {
-            if (isLocal) {
-                directionToUpdate.x = 0;
-                directionToUpdate.y = 1.0;
-                directionToUpdate.z = 0;
-                return;
-            }
-            Vector3.TransformNormalFromFloatsToRef(0, 1.0, 0, worldMatrix, directionToUpdate);
+        if (isLocal) {
+            TmpVectors.Vector3[0].copyFrom(particle._localPosition!).normalize();
         }
         else {
-            // measure the direction Vector from the emitter to the particle.
-            var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
-            var randX = Scalar.RandomRange(0, this.directionRandomizer);
-            var randY = Scalar.RandomRange(0, this.directionRandomizer);
-            var randZ = Scalar.RandomRange(0, this.directionRandomizer);
-            direction.x += randX;
-            direction.y += randY;
-            direction.z += randZ;
-            direction.normalize();
-
-            if (isLocal) {
-                directionToUpdate.copyFrom(direction);
-                return;
-            }
-
-            Vector3.TransformNormalFromFloatsToRef(direction.x, direction.y, direction.z, worldMatrix, directionToUpdate);
+            particle.position.subtractToRef(worldMatrix.getTranslation(), TmpVectors.Vector3[0]).normalize();
         }
+
+        var randX = Scalar.RandomRange(0, this.directionRandomizer);
+        var randY = Scalar.RandomRange(0, this.directionRandomizer);
+        var randZ = Scalar.RandomRange(0, this.directionRandomizer);
+        directionToUpdate.x = TmpVectors.Vector3[0].x + randX;
+        directionToUpdate.y = TmpVectors.Vector3[0].y + randY;
+        directionToUpdate.z = TmpVectors.Vector3[0].z + randZ;
+        directionToUpdate.normalize();
     }
 
     /**

+ 2 - 0
src/Particles/index.ts

@@ -5,6 +5,8 @@ export * from "./IParticleSystem";
 export * from "./particle";
 export * from "./particleHelper";
 export * from "./particleSystem";
+
+import "./particleSystemComponent";
 export * from "./particleSystemComponent";
 export * from "./particleSystemSet";
 export * from "./solidParticle";

+ 0 - 5
src/Particles/particleSystemComponent.ts

@@ -136,8 +136,3 @@ Mesh.prototype.getHierarchyEmittedParticleSystems = function(): IParticleSystem[
 
     return results;
 };
-
-/**
- * @hidden
- */
-export var _IDoNeedToBeInTheBuild = 42;

+ 1 - 1
src/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.ts

@@ -155,7 +155,7 @@ export class SSAO2RenderingPipeline extends PostProcessRenderPipeline {
         if (!engine) {
             return false;
         }
-        return engine.getCaps().drawBuffersExtension;
+        return engine.webGLVersion >= 2;
     }
 
     private _scene: Scene;

+ 6 - 5
src/PostProcesses/volumetricLightScatteringPostProcess.ts

@@ -206,6 +206,9 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (subMesh.getRenderingMesh().hasInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         // Get correct effect
@@ -291,10 +294,8 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {
 
         // Custom render function for submeshes
         var renderSubMesh = (subMesh: SubMesh): void => {
-            var ownerMesh = subMesh.getMesh();
-            var replacementMesh = ownerMesh._internalAbstractMeshDataInfo._actAsRegularMesh ? ownerMesh : null;
             var renderingMesh = subMesh.getRenderingMesh();
-            var effectiveMesh = replacementMesh ? replacementMesh : renderingMesh;
+            var effectiveMesh = subMesh.getEffectiveMesh();
             if (this._meshExcluded(renderingMesh)) {
                 return;
             }
@@ -314,13 +315,13 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {
             engine.setState(material.backFaceCulling);
 
             // Managing instances
-            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!replacementMesh);
+            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
 
             if (batch.mustReturn) {
                 return;
             }
 
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
 
             if (this._isReady(subMesh, hardwareInstancedRendering)) {
                 var effect: Effect = this._volumetricLightScatteringPass;

+ 6 - 5
src/Rendering/depthRenderer.ts

@@ -94,10 +94,8 @@ export class DepthRenderer {
 
         // Custom render function
         var renderSubMesh = (subMesh: SubMesh): void => {
-            var ownerMesh = subMesh.getMesh();
-            var replacementMesh = ownerMesh._internalAbstractMeshDataInfo._actAsRegularMesh ? ownerMesh : null;
             var renderingMesh = subMesh.getRenderingMesh();
-            var effectiveMesh = replacementMesh ? replacementMesh : renderingMesh;
+            var effectiveMesh = subMesh.getEffectiveMesh();
             var scene = this._scene;
             var engine = scene.getEngine();
             let material = subMesh.getMaterial();
@@ -112,13 +110,13 @@ export class DepthRenderer {
             engine.setState(material.backFaceCulling, 0, false, scene.useRightHandedSystem);
 
             // Managing instances
-            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!replacementMesh);
+            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
 
             if (batch.mustReturn) {
                 return;
             }
 
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
 
             var camera = this._camera || scene.activeCamera;
             if (this.isReady(subMesh, hardwareInstancedRendering) && camera) {
@@ -237,6 +235,9 @@ export class DepthRenderer {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (subMesh.getRenderingMesh().hasInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         // None linear depth

+ 6 - 5
src/Rendering/geometryBufferRenderer.ts

@@ -300,6 +300,9 @@ export class GeometryBufferRenderer {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (subMesh.getRenderingMesh().hasInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         // Setup textures count
@@ -390,10 +393,8 @@ export class GeometryBufferRenderer {
 
         // Custom render function
         var renderSubMesh = (subMesh: SubMesh): void => {
-            var ownerMesh = subMesh.getMesh();
-            var replacementMesh = ownerMesh._internalAbstractMeshDataInfo._actAsRegularMesh ? ownerMesh : null;
             var renderingMesh = subMesh.getRenderingMesh();
-            var effectiveMesh = replacementMesh ? replacementMesh : renderingMesh;
+            var effectiveMesh = subMesh.getEffectiveMesh();
             var scene = this._scene;
             var engine = scene.getEngine();
             let material = <any> subMesh.getMaterial();
@@ -421,13 +422,13 @@ export class GeometryBufferRenderer {
             engine.setState(material.backFaceCulling, 0, false, scene.useRightHandedSystem);
 
             // Managing instances
-            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!replacementMesh);
+            var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
 
             if (batch.mustReturn) {
                 return;
             }
 
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
             var world = effectiveMesh.getWorldMatrix();
 
             if (this.isReady(subMesh, hardwareInstancedRendering)) {

+ 4 - 1
src/Rendering/outlineRenderer.ts

@@ -157,7 +157,7 @@ export class OutlineRenderer implements ISceneComponent {
         var scene = this.scene;
         var engine = scene.getEngine();
 
-        var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
+        var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null && batch.visibleInstances[subMesh._id] !== undefined || subMesh.getRenderingMesh().hasThinInstances);
 
         if (!this.isReady(subMesh, hardwareInstancedRendering)) {
             return;
@@ -274,6 +274,9 @@ export class OutlineRenderer implements ISceneComponent {
         if (useInstances) {
             defines.push("#define INSTANCES");
             MaterialHelper.PushAttributesForInstances(attribs);
+            if (subMesh.getRenderingMesh().hasInstances) {
+                defines.push("#define THIN_INSTANCES");
+            }
         }
 
         // Get correct effect

+ 0 - 0
src/Shaders/ShadersInclude/hdrFilteringFunctions.fx


部分文件因为文件数量过多而无法显示