Bläddra i källkod

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

sebavan 4 år sedan
förälder
incheckning
078714c9e5
100 ändrade filer med 5054 tillägg och 1120 borttagningar
  1. 12 0
      Playground/templates.json
  2. 351 7
      dist/preview release/babylon.d.ts
  3. 2 2
      dist/preview release/babylon.js
  4. 1 1
      dist/preview release/babylon.ktx2Decoder.js
  5. 1017 173
      dist/preview release/babylon.max.js
  6. 1 1
      dist/preview release/babylon.max.js.map
  7. 717 15
      dist/preview release/babylon.module.d.ts
  8. 367 19
      dist/preview release/documentation.d.ts
  9. BIN
      dist/preview release/draco_decoder_gltf.wasm
  10. 104 119
      dist/preview release/draco_wasm_wrapper_gltf.js
  11. 1 1
      dist/preview release/glTF2Interface/package.json
  12. 3 3
      dist/preview release/gui/babylon.gui.d.ts
  13. 1 1
      dist/preview release/gui/babylon.gui.js
  14. 1 1
      dist/preview release/gui/babylon.gui.js.map
  15. 1 1
      dist/preview release/gui/babylon.gui.min.js
  16. 7 7
      dist/preview release/gui/babylon.gui.module.d.ts
  17. 2 2
      dist/preview release/gui/package.json
  18. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  19. 77 73
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  20. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  21. 3 2
      dist/preview release/inspector/babylon.inspector.d.ts
  22. 6 4
      dist/preview release/inspector/babylon.inspector.module.d.ts
  23. 7 7
      dist/preview release/inspector/package.json
  24. 3 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  25. 1 1
      dist/preview release/loaders/babylon.glTF1FileLoader.js.map
  26. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  27. 55 31
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  28. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  29. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  30. 57 32
      dist/preview release/loaders/babylon.glTFFileLoader.js
  31. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  32. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  33. 13 9
      dist/preview release/loaders/babylonjs.loaders.d.ts
  34. 57 32
      dist/preview release/loaders/babylonjs.loaders.js
  35. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  36. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  37. 27 18
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  38. 3 3
      dist/preview release/loaders/package.json
  39. 2 2
      dist/preview release/materialsLibrary/package.json
  40. 6 0
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  41. 6 6
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  42. 59 14
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  43. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  44. 12 0
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  45. 2 2
      dist/preview release/nodeEditor/package.json
  46. 1 1
      dist/preview release/package.json
  47. 1 1
      dist/preview release/packagesSizeBaseLine.json
  48. 2 2
      dist/preview release/postProcessesLibrary/package.json
  49. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  50. 8 8
      dist/preview release/recast.js
  51. 3 3
      dist/preview release/serializers/package.json
  52. 717 15
      dist/preview release/viewer/babylon.module.d.ts
  53. 62 50
      dist/preview release/viewer/babylon.viewer.js
  54. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  55. 27 18
      dist/preview release/viewer/babylonjs.loaders.module.d.ts
  56. 8 0
      dist/preview release/what's new.md
  57. 1 1
      gui/src/2D/advancedDynamicTexture.ts
  58. 5 5
      gui/src/2D/controls/control.ts
  59. 11 13
      inspector/src/components/actionTabs/lines/optionsLineComponent.tsx
  60. 155 165
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx
  61. 12 0
      inspector/src/components/actionTabs/tabs/propertyGrids/meshes/skeletonPropertyGridComponent.tsx
  62. 2 2
      ktx2Decoder/src/ktx2Decoder.ts
  63. 2 1
      loaders/src/glTF/1.0/glTFLoader.ts
  64. 3 4
      loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts
  65. 1 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts
  66. 1 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts
  67. 1 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts
  68. 1 1
      loaders/src/glTF/2.0/Extensions/KHR_materials_transmission.ts
  69. 2 2
      loaders/src/glTF/2.0/Extensions/KHR_texture_basisu.ts
  70. 2 2
      loaders/src/glTF/2.0/Extensions/KHR_texture_transform.ts
  71. 37 15
      loaders/src/glTF/2.0/glTFLoader.ts
  72. 4 2
      loaders/src/glTF/2.0/glTFLoaderExtension.ts
  73. 3 0
      loaders/src/glTF/glTFFileLoader.ts
  74. 50 2
      nodeEditor/src/components/propertyTab/propertyTab.scss
  75. 2 0
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  76. 11 1
      nodeEditor/src/diagram/properties/gradientStepComponent.tsx
  77. 145 115
      nodeEditor/src/sharedComponents/floatLineComponent.tsx
  78. 33 16
      nodeEditor/src/sharedComponents/textInputLineComponent.tsx
  79. 1 1
      package.json
  80. 8 0
      sandbox/public/index-local.html
  81. 6 9
      sandbox/public/index.html
  82. 189 0
      src/Cameras/Inputs/BaseCameraMouseWheelInput.ts
  83. 6 2
      src/Cameras/Inputs/freeCameraGamepadInput.ts
  84. 393 0
      src/Cameras/Inputs/freeCameraMouseWheelInput.ts
  85. 1 0
      src/Cameras/Inputs/index.ts
  86. 28 0
      src/Cameras/freeCameraInputsManager.ts
  87. 3 1
      src/Engines/Processors/iShaderProcessor.ts
  88. 5 4
      src/Engines/Processors/shaderProcessor.ts
  89. 18 0
      src/Engines/WebGL/webGLShaderProcessors.ts
  90. 5 2
      src/Engines/thinEngine.ts
  91. 16 0
      src/Layers/effectLayer.ts
  92. 8 0
      src/Loading/loadingScreen.ts
  93. 10 34
      src/Materials/Node/Blocks/Dual/currentScreenBlock.ts
  94. 11 0
      src/Materials/Node/Blocks/Dual/lightBlock.ts
  95. 11 0
      src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts
  96. 1 1
      src/Materials/Node/Blocks/Particle/particleTextureBlock.ts
  97. 3 2
      src/Materials/Node/Blocks/smoothStepBlock.ts
  98. 8 8
      src/Materials/Node/Blocks/vectorMergerBlock.ts
  99. 8 0
      src/Materials/Node/nodeMaterial.ts
  100. 0 0
      src/Materials/Node/nodeMaterialBuildState.ts

+ 12 - 0
Playground/templates.json

@@ -78,5 +78,17 @@
     "label" : "Setup a shadow generator",
     "documentation" : "https://doc.babylonjs.com/babylon101/shadows",
     "insertText" : "var shadowGenerator = new BABYLON.ShadowGenerator(${1:size}, ${2:the_light_source});\nshadowGenerator.getShadowMap().renderList.push(${3:the_mesh_that_casts_a_shadow});\n${4:mesh_that_receives_the_shadow}.receiveShadows = true;"    
+  },
+  {
+    "label" : "Export scene to GLB",
+    "documentation" : "https://doc.babylonjs.com/extensions/gltfexporter#exporting-a-scene-to-gltf",
+    "insertText" : "BABYLON.GLTF2Export.GLBAsync(scene, \"${1:fileName}\").then((glb) => {\n     glb.downloadFiles();\n});",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Export scene to GLTF",
+    "documentation" : "https://doc.babylonjs.com/extensions/gltfexporter#exporting-a-scene-to-gltf",
+    "insertText" : "BABYLON.GLTF2Export.GLTFAsync(scene, \"${1:fileName}\").then((gltf) => {\n     gltf.downloadFiles();\n});",
+    "language" : "javascript"
   }
 ]

+ 351 - 7
dist/preview release/babylon.d.ts

@@ -1184,7 +1184,7 @@ declare module BABYLON {
         endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean) => string;
         lineProcessor?: (line: string, isFragment: boolean) => string;
         preProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
-        postProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
+        postProcessor?: (code: string, defines: string[], isFragment: boolean, engine: ThinEngine) => string;
     }
 }
 declare module BABYLON {
@@ -1497,7 +1497,7 @@ declare module BABYLON {
 declare module BABYLON {
     /** @hidden */
     export class ShaderProcessor {
-        static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void): void;
+        static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void, engine: ThinEngine): void;
         private static _ProcessPrecision;
         private static _ExtractOperation;
         private static _BuildSubExpression;
@@ -8786,6 +8786,17 @@ declare module BABYLON {
         /** Z axis */
         static Z: Vector3;
     }
+    /**
+     * Defines cartesian components.
+     */
+    export enum Coordinate {
+        /** X axis */
+        X = 0,
+        /** Y axis */
+        Y = 1,
+        /** Z axis */
+        Z = 2
+    }
 }
 declare module BABYLON {
     /**
@@ -10710,7 +10721,7 @@ declare module BABYLON {
         static readonly STEP_ISREADYFORMESH_EFFECTLAYER: number;
         static readonly STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER: number;
         static readonly STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER: number;
-        static readonly STEP_ACTIVEMESH_BOUNDINGBOXRENDERER: number;
+        static readonly STEP_PREACTIVEMESH_BOUNDINGBOXRENDERER: number;
         static readonly STEP_CAMERADRAWRENDERTARGET_EFFECTLAYER: number;
         static readonly STEP_BEFORECAMERADRAW_EFFECTLAYER: number;
         static readonly STEP_BEFORECAMERADRAW_LAYER: number;
@@ -10801,9 +10812,9 @@ declare module BABYLON {
      */
     export type EvaluateSubMeshStageAction = (mesh: AbstractMesh, subMesh: SubMesh) => void;
     /**
-     * Strong typing of a Active Mesh related stage step action
+     * Strong typing of a pre active Mesh related stage step action
      */
-    export type ActiveMeshStageAction = (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
+    export type PreActiveMeshStageAction = (mesh: AbstractMesh) => void;
     /**
      * Strong typing of a Camera related stage step action
      */
@@ -19027,6 +19038,246 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Base class for mouse wheel input..
+     * See FollowCameraMouseWheelInput in src/Cameras/Inputs/freeCameraMouseWheelInput.ts
+     * for example usage.
+     */
+    export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera> {
+        /**
+         * Defines the camera the input is attached to.
+         */
+        abstract camera: Camera;
+        /**
+         * How fast is the camera moves in relation to X axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionX: number;
+        /**
+         * How fast is the camera moves in relation to Y axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionY: number;
+        /**
+         * How fast is the camera moves in relation to Z axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionZ: number;
+        /**
+         * Observable for when a mouse wheel move event occurs.
+         */
+        onChangedObservable: Observable<{
+            wheelDeltaX: number;
+            wheelDeltaY: number;
+            wheelDeltaZ: number;
+        }>;
+        private _wheel;
+        private _observer;
+        /**
+         * Attach the input controls to a specific dom element to get the input from.
+         * @param element Defines the element the controls should be listened from
+         * @param noPreventDefault Defines whether event caught by the controls
+         *   should call preventdefault().
+         *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+         */
+        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        /**
+         * Detach the current controls from the specified dom element.
+         * @param element Defines the element to stop listening the inputs from
+         */
+        detachControl(element: Nullable<HTMLElement>): void;
+        /**
+         * Called for each rendered frame.
+         */
+        checkInputs(): void;
+        /**
+         * Gets the class name of the current intput.
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Get the friendly name associated with the input class.
+         * @returns the input friendly name
+         */
+        getSimpleName(): string;
+        /**
+         * Incremental value of multiple mouse wheel movements of the X axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaX: number;
+        /**
+         * Incremental value of multiple mouse wheel movements of the Y axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaY: number;
+        /**
+         * Incremental value of multiple mouse wheel movements of the Z axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaZ: number;
+        /**
+         * Firefox uses a different scheme to report scroll distances to other
+         * browsers. Rather than use complicated methods to calculate the exact
+         * multiple we need to apply, let's just cheat and use a constant.
+         * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
+         * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
+         */
+        private readonly _ffMultiplier;
+        /**
+         * Different event attributes for wheel data fall into a few set ranges.
+         * Some relevant but dated date here:
+         * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
+         */
+        private readonly _normalize;
+    }
+}
+declare module BABYLON {
+    /**
+     * Manage the mouse wheel inputs to control a free camera.
+     * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
+     */
+    export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
+        /**
+         * Defines the camera the input is attached to.
+         */
+        camera: FreeCamera;
+        /**
+         * Gets the class name of the current input.
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's X axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's Y axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's Z axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's X axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's Y axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's Z axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's X axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXMoveScene(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's Y axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYMoveScene(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's Z axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZMoveScene(): Nullable<Coordinate>;
+        /**
+         * Called for each rendered frame.
+         */
+        checkInputs(): void;
+        private _moveRelative;
+        private _rotateRelative;
+        private _moveScene;
+        /**
+         * These are set to the desired default behaviour.
+         */
+        private _wheelXAction;
+        private _wheelXActionCoordinate;
+        private _wheelYAction;
+        private _wheelYActionCoordinate;
+        private _wheelZAction;
+        private _wheelZActionCoordinate;
+        /**
+         * Update the camera according to any configured properties for the 3
+         * mouse-wheel axis.
+         */
+        private _updateCamera;
+    }
+}
+declare module BABYLON {
+    /**
      * Manage the touch inputs to control the movement of a free camera.
      * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
      */
@@ -19105,6 +19356,10 @@ declare module BABYLON {
          */
         _mouseInput: Nullable<FreeCameraMouseInput>;
         /**
+         * @hidden
+         */
+        _mouseWheelInput: Nullable<FreeCameraMouseWheelInput>;
+        /**
          * Instantiates a new FreeCameraInputsManager.
          * @param camera Defines the camera the inputs belong to
          */
@@ -19126,6 +19381,16 @@ declare module BABYLON {
          */
         removeMouse(): FreeCameraInputsManager;
         /**
+         * Add mouse wheel input support to the input manager.
+         * @returns the current input manager
+         */
+        addMouseWheel(): FreeCameraInputsManager;
+        /**
+         * Removes the mouse wheel input support from the manager
+         * @returns the current input manager
+         */
+        removeMouseWheel(): FreeCameraInputsManager;
+        /**
          * Add touch input support to the input manager.
          * @returns the current input manager
          */
@@ -22583,6 +22848,10 @@ declare module BABYLON {
          */
         get mode(): NodeMaterialModes;
         /**
+         * A free comment about the material
+         */
+        comment: string;
+        /**
          * Create a new node based material
          * @param name defines the material name
          * @param scene defines the hosting scene
@@ -29917,6 +30186,7 @@ declare module BABYLON {
         private _updatable;
         /** @hidden */
         _positions: Nullable<Vector3[]>;
+        private _positionsCache;
         /**
          *  Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
          */
@@ -38174,6 +38444,12 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export class WebGLShaderProcessor implements IShaderProcessor {
+        postProcessor(code: string, defines: string[], isFragment: boolean, engine: ThinEngine): string;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
     export class WebGL2ShaderProcessor implements IShaderProcessor {
         attributeProcessor(attribute: string): string;
         varyingProcessor(varying: string, isFragment: boolean): string;
@@ -41344,6 +41620,15 @@ declare module BABYLON {
          */
         static Slice<T>(data: T, start?: number, end?: number): T;
         /**
+         * Provides a slice function that will work even on IE
+         * The difference between this and Slice is that this will force-convert to array
+         * @param data defines the array to slice
+         * @param start defines the start of the data (optional)
+         * @param end defines the end of the data (optional)
+         * @returns the new sliced array
+         */
+        static SliceToArray<T, P>(data: T, start?: number, end?: number): Array<P>;
+        /**
          * Polyfill for setImmediate
          * @param action defines the action to execute after the current execution block
          */
@@ -43189,7 +43474,7 @@ declare module BABYLON {
          * @hidden
          * Defines the actions happening during the active mesh stage.
          */
-        _activeMeshStage: Stage<ActiveMeshStageAction>;
+        _preActiveMeshStage: Stage<PreActiveMeshStageAction>;
         /**
          * @hidden
          * Defines the actions happening during the per camera render target step.
@@ -51989,6 +52274,24 @@ declare module BABYLON {
          * The first rig camera (left eye) will be used to calculate the projection
          */
         disableScenePointerVectorUpdate: boolean;
+        /**
+         * Enable pointer selection on all controllers instead of switching between them
+         */
+        enablePointerSelectionOnAllControllers?: boolean;
+        /**
+         * The preferred hand to give the pointer selection to. This will be prioritized when the controller initialize.
+         * If switch is enabled, it will still allow the user to switch between the different controllers
+         */
+        preferredHandedness?: XRHandedness;
+        /**
+         * Disable switching the pointer selection from one controller to the other.
+         * If the preferred hand is set it will be fixed on this hand, and if not it will be fixed on the first controller added to the scene
+         */
+        disableSwitchOnClick?: boolean;
+        /**
+         * The maximum distance of the pointer selection feature. Defaults to 100.
+         */
+        maxPointerDistance?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -52000,6 +52303,7 @@ declare module BABYLON {
         private _controllers;
         private _scene;
         private _tmpVectorForPickCompare;
+        private _attachedController;
         /**
          * The module's name
          */
@@ -59072,6 +59376,10 @@ declare module BABYLON {
         get renderingGroupId(): number;
         set renderingGroupId(renderingGroupId: number);
         /**
+         * Specifies if the bounding boxes should be rendered normally or if they should undergo the effect of the layer
+         */
+        disableBoundingBoxesFromEffectLayer: boolean;
+        /**
          * An event triggered when the effect layer has been disposed.
          */
         onDisposeObservable: Observable<EffectLayer>;
@@ -63648,6 +63956,10 @@ declare module BABYLON {
         */
         get specularColor(): NodeMaterialConnectionPoint;
         /**
+        * Gets the view matrix component
+        */
+        get view(): NodeMaterialConnectionPoint;
+        /**
          * Gets the diffuse output component
          */
         get diffuseOutput(): NodeMaterialConnectionPoint;
@@ -65678,6 +65990,10 @@ declare module BABYLON {
          */
         get anisotropy(): NodeMaterialConnectionPoint;
         /**
+         * Gets the view matrix parameter
+         */
+        get view(): NodeMaterialConnectionPoint;
+        /**
          * Gets the ambient output component
          */
         get ambient(): NodeMaterialConnectionPoint;
@@ -67669,6 +67985,18 @@ declare module BABYLON {
          */
         getAgentVelocityToRef(index: number, result: Vector3): void;
         /**
+         * Gets the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @returns world space position
+         */
+        getAgentNextTargetPath(index: number): Vector3;
+        /**
+         * Gets the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @param result output world space position
+         */
+        getAgentNextTargetPathToRef(index: number, result: Vector3): void;
+        /**
          * remove a particular agent previously created
          * @param index agent index returned by addAgent
          */
@@ -68018,6 +68346,18 @@ declare module BABYLON {
          */
         getAgentVelocityToRef(index: number, result: Vector3): void;
         /**
+         * Returns the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @returns world space position
+         */
+        getAgentNextTargetPath(index: number): Vector3;
+        /**
+         * Returns the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @param result output world space position
+         */
+        getAgentNextTargetPathToRef(index: number, result: Vector3): void;
+        /**
          * Asks a particular agent to go to a destination. That destination is constrained by the navigation mesh
          * @param index agent index returned by addAgent
          * @param destination targeted world position
@@ -72493,6 +72833,10 @@ declare module BABYLON {
          */
         onAfterBoxRenderingObservable: Observable<BoundingBox>;
         /**
+         * When false, no bounding boxes will be rendered
+         */
+        enabled: boolean;
+        /**
          * @hidden
          */
         renderList: SmartArray<BoundingBox>;
@@ -72511,7 +72855,7 @@ declare module BABYLON {
          */
         register(): void;
         private _evaluateSubMesh;
-        private _activeMesh;
+        private _preActiveMesh;
         private _prepareRessources;
         private _createIndexBuffer;
         /**

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/babylon.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/babylon.ktx2Decoder.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1017 - 173
dist/preview release/babylon.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/babylon.max.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 717 - 15
dist/preview release/babylon.module.d.ts


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

@@ -1184,7 +1184,7 @@ declare module BABYLON {
         endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean) => string;
         lineProcessor?: (line: string, isFragment: boolean) => string;
         preProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
-        postProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
+        postProcessor?: (code: string, defines: string[], isFragment: boolean, engine: ThinEngine) => string;
     }
 }
 declare module BABYLON {
@@ -1497,7 +1497,7 @@ declare module BABYLON {
 declare module BABYLON {
     /** @hidden */
     export class ShaderProcessor {
-        static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void): void;
+        static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void, engine: ThinEngine): void;
         private static _ProcessPrecision;
         private static _ExtractOperation;
         private static _BuildSubExpression;
@@ -8786,6 +8786,17 @@ declare module BABYLON {
         /** Z axis */
         static Z: Vector3;
     }
+    /**
+     * Defines cartesian components.
+     */
+    export enum Coordinate {
+        /** X axis */
+        X = 0,
+        /** Y axis */
+        Y = 1,
+        /** Z axis */
+        Z = 2
+    }
 }
 declare module BABYLON {
     /**
@@ -10710,7 +10721,7 @@ declare module BABYLON {
         static readonly STEP_ISREADYFORMESH_EFFECTLAYER: number;
         static readonly STEP_BEFOREEVALUATEACTIVEMESH_BOUNDINGBOXRENDERER: number;
         static readonly STEP_EVALUATESUBMESH_BOUNDINGBOXRENDERER: number;
-        static readonly STEP_ACTIVEMESH_BOUNDINGBOXRENDERER: number;
+        static readonly STEP_PREACTIVEMESH_BOUNDINGBOXRENDERER: number;
         static readonly STEP_CAMERADRAWRENDERTARGET_EFFECTLAYER: number;
         static readonly STEP_BEFORECAMERADRAW_EFFECTLAYER: number;
         static readonly STEP_BEFORECAMERADRAW_LAYER: number;
@@ -10801,9 +10812,9 @@ declare module BABYLON {
      */
     export type EvaluateSubMeshStageAction = (mesh: AbstractMesh, subMesh: SubMesh) => void;
     /**
-     * Strong typing of a Active Mesh related stage step action
+     * Strong typing of a pre active Mesh related stage step action
      */
-    export type ActiveMeshStageAction = (sourceMesh: AbstractMesh, mesh: AbstractMesh) => void;
+    export type PreActiveMeshStageAction = (mesh: AbstractMesh) => void;
     /**
      * Strong typing of a Camera related stage step action
      */
@@ -19027,6 +19038,246 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /**
+     * Base class for mouse wheel input..
+     * See FollowCameraMouseWheelInput in src/Cameras/Inputs/freeCameraMouseWheelInput.ts
+     * for example usage.
+     */
+    export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera> {
+        /**
+         * Defines the camera the input is attached to.
+         */
+        abstract camera: Camera;
+        /**
+         * How fast is the camera moves in relation to X axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionX: number;
+        /**
+         * How fast is the camera moves in relation to Y axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionY: number;
+        /**
+         * How fast is the camera moves in relation to Z axis mouseWheel events.
+         * Use negative value to reverse direction.
+         */
+        wheelPrecisionZ: number;
+        /**
+         * Observable for when a mouse wheel move event occurs.
+         */
+        onChangedObservable: Observable<{
+            wheelDeltaX: number;
+            wheelDeltaY: number;
+            wheelDeltaZ: number;
+        }>;
+        private _wheel;
+        private _observer;
+        /**
+         * Attach the input controls to a specific dom element to get the input from.
+         * @param element Defines the element the controls should be listened from
+         * @param noPreventDefault Defines whether event caught by the controls
+         *   should call preventdefault().
+         *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+         */
+        attachControl(element: HTMLElement, noPreventDefault?: boolean): void;
+        /**
+         * Detach the current controls from the specified dom element.
+         * @param element Defines the element to stop listening the inputs from
+         */
+        detachControl(element: Nullable<HTMLElement>): void;
+        /**
+         * Called for each rendered frame.
+         */
+        checkInputs(): void;
+        /**
+         * Gets the class name of the current intput.
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Get the friendly name associated with the input class.
+         * @returns the input friendly name
+         */
+        getSimpleName(): string;
+        /**
+         * Incremental value of multiple mouse wheel movements of the X axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaX: number;
+        /**
+         * Incremental value of multiple mouse wheel movements of the Y axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaY: number;
+        /**
+         * Incremental value of multiple mouse wheel movements of the Z axis.
+         * Should be zero-ed when read.
+         */
+        protected _wheelDeltaZ: number;
+        /**
+         * Firefox uses a different scheme to report scroll distances to other
+         * browsers. Rather than use complicated methods to calculate the exact
+         * multiple we need to apply, let's just cheat and use a constant.
+         * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
+         * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
+         */
+        private readonly _ffMultiplier;
+        /**
+         * Different event attributes for wheel data fall into a few set ranges.
+         * Some relevant but dated date here:
+         * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
+         */
+        private readonly _normalize;
+    }
+}
+declare module BABYLON {
+    /**
+     * Manage the mouse wheel inputs to control a free camera.
+     * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
+     */
+    export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
+        /**
+         * Defines the camera the input is attached to.
+         */
+        camera: FreeCamera;
+        /**
+         * Gets the class name of the current input.
+         * @returns the class name
+         */
+        getClassName(): string;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's X axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's Y axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to camera's orientation) the mouse
+         * wheel's Z axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZMoveRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to camera's orientation) the
+         * mouse wheel's Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZMoveRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's X axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's Y axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which rotation axis (relative to camera's orientation) the mouse
+         * wheel's Z axis controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZRotateRelative(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured rotation axis (relative to camera's orientation) the
+         * mouse wheel's Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZRotateRelative(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's X axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelXMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * X axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelXMoveScene(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's Y axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelYMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * Y axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelYMoveScene(): Nullable<Coordinate>;
+        /**
+         * Set which movement axis (relative to the scene) the mouse wheel's Z axis
+         * controls.
+         * @param axis The axis to be moved. Set null to clear.
+         */
+        set wheelZMoveScene(axis: Nullable<Coordinate>);
+        /**
+         * Get the configured movement axis (relative to the scene) the mouse wheel's
+         * Z axis controls.
+         * @returns The configured axis or null if none.
+         */
+        get wheelZMoveScene(): Nullable<Coordinate>;
+        /**
+         * Called for each rendered frame.
+         */
+        checkInputs(): void;
+        private _moveRelative;
+        private _rotateRelative;
+        private _moveScene;
+        /**
+         * These are set to the desired default behaviour.
+         */
+        private _wheelXAction;
+        private _wheelXActionCoordinate;
+        private _wheelYAction;
+        private _wheelYActionCoordinate;
+        private _wheelZAction;
+        private _wheelZActionCoordinate;
+        /**
+         * Update the camera according to any configured properties for the 3
+         * mouse-wheel axis.
+         */
+        private _updateCamera;
+    }
+}
+declare module BABYLON {
+    /**
      * Manage the touch inputs to control the movement of a free camera.
      * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
      */
@@ -19105,6 +19356,10 @@ declare module BABYLON {
          */
         _mouseInput: Nullable<FreeCameraMouseInput>;
         /**
+         * @hidden
+         */
+        _mouseWheelInput: Nullable<FreeCameraMouseWheelInput>;
+        /**
          * Instantiates a new FreeCameraInputsManager.
          * @param camera Defines the camera the inputs belong to
          */
@@ -19126,6 +19381,16 @@ declare module BABYLON {
          */
         removeMouse(): FreeCameraInputsManager;
         /**
+         * Add mouse wheel input support to the input manager.
+         * @returns the current input manager
+         */
+        addMouseWheel(): FreeCameraInputsManager;
+        /**
+         * Removes the mouse wheel input support from the manager
+         * @returns the current input manager
+         */
+        removeMouseWheel(): FreeCameraInputsManager;
+        /**
          * Add touch input support to the input manager.
          * @returns the current input manager
          */
@@ -22583,6 +22848,10 @@ declare module BABYLON {
          */
         get mode(): NodeMaterialModes;
         /**
+         * A free comment about the material
+         */
+        comment: string;
+        /**
          * Create a new node based material
          * @param name defines the material name
          * @param scene defines the hosting scene
@@ -29917,6 +30186,7 @@ declare module BABYLON {
         private _updatable;
         /** @hidden */
         _positions: Nullable<Vector3[]>;
+        private _positionsCache;
         /**
          *  Gets or sets the Bias Vector to apply on the bounding elements (box/sphere), the max extend is computed as v += v * bias.x + bias.y, the min is computed as v -= v * bias.x + bias.y
          */
@@ -38174,6 +38444,12 @@ declare module BABYLON {
 }
 declare module BABYLON {
     /** @hidden */
+    export class WebGLShaderProcessor implements IShaderProcessor {
+        postProcessor(code: string, defines: string[], isFragment: boolean, engine: ThinEngine): string;
+    }
+}
+declare module BABYLON {
+    /** @hidden */
     export class WebGL2ShaderProcessor implements IShaderProcessor {
         attributeProcessor(attribute: string): string;
         varyingProcessor(varying: string, isFragment: boolean): string;
@@ -41344,6 +41620,15 @@ declare module BABYLON {
          */
         static Slice<T>(data: T, start?: number, end?: number): T;
         /**
+         * Provides a slice function that will work even on IE
+         * The difference between this and Slice is that this will force-convert to array
+         * @param data defines the array to slice
+         * @param start defines the start of the data (optional)
+         * @param end defines the end of the data (optional)
+         * @returns the new sliced array
+         */
+        static SliceToArray<T, P>(data: T, start?: number, end?: number): Array<P>;
+        /**
          * Polyfill for setImmediate
          * @param action defines the action to execute after the current execution block
          */
@@ -43189,7 +43474,7 @@ declare module BABYLON {
          * @hidden
          * Defines the actions happening during the active mesh stage.
          */
-        _activeMeshStage: Stage<ActiveMeshStageAction>;
+        _preActiveMeshStage: Stage<PreActiveMeshStageAction>;
         /**
          * @hidden
          * Defines the actions happening during the per camera render target step.
@@ -51989,6 +52274,24 @@ declare module BABYLON {
          * The first rig camera (left eye) will be used to calculate the projection
          */
         disableScenePointerVectorUpdate: boolean;
+        /**
+         * Enable pointer selection on all controllers instead of switching between them
+         */
+        enablePointerSelectionOnAllControllers?: boolean;
+        /**
+         * The preferred hand to give the pointer selection to. This will be prioritized when the controller initialize.
+         * If switch is enabled, it will still allow the user to switch between the different controllers
+         */
+        preferredHandedness?: XRHandedness;
+        /**
+         * Disable switching the pointer selection from one controller to the other.
+         * If the preferred hand is set it will be fixed on this hand, and if not it will be fixed on the first controller added to the scene
+         */
+        disableSwitchOnClick?: boolean;
+        /**
+         * The maximum distance of the pointer selection feature. Defaults to 100.
+         */
+        maxPointerDistance?: number;
     }
     /**
      * A module that will enable pointer selection for motion controllers of XR Input Sources
@@ -52000,6 +52303,7 @@ declare module BABYLON {
         private _controllers;
         private _scene;
         private _tmpVectorForPickCompare;
+        private _attachedController;
         /**
          * The module's name
          */
@@ -59072,6 +59376,10 @@ declare module BABYLON {
         get renderingGroupId(): number;
         set renderingGroupId(renderingGroupId: number);
         /**
+         * Specifies if the bounding boxes should be rendered normally or if they should undergo the effect of the layer
+         */
+        disableBoundingBoxesFromEffectLayer: boolean;
+        /**
          * An event triggered when the effect layer has been disposed.
          */
         onDisposeObservable: Observable<EffectLayer>;
@@ -63648,6 +63956,10 @@ declare module BABYLON {
         */
         get specularColor(): NodeMaterialConnectionPoint;
         /**
+        * Gets the view matrix component
+        */
+        get view(): NodeMaterialConnectionPoint;
+        /**
          * Gets the diffuse output component
          */
         get diffuseOutput(): NodeMaterialConnectionPoint;
@@ -65678,6 +65990,10 @@ declare module BABYLON {
          */
         get anisotropy(): NodeMaterialConnectionPoint;
         /**
+         * Gets the view matrix parameter
+         */
+        get view(): NodeMaterialConnectionPoint;
+        /**
          * Gets the ambient output component
          */
         get ambient(): NodeMaterialConnectionPoint;
@@ -67669,6 +67985,18 @@ declare module BABYLON {
          */
         getAgentVelocityToRef(index: number, result: Vector3): void;
         /**
+         * Gets the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @returns world space position
+         */
+        getAgentNextTargetPath(index: number): Vector3;
+        /**
+         * Gets the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @param result output world space position
+         */
+        getAgentNextTargetPathToRef(index: number, result: Vector3): void;
+        /**
          * remove a particular agent previously created
          * @param index agent index returned by addAgent
          */
@@ -68018,6 +68346,18 @@ declare module BABYLON {
          */
         getAgentVelocityToRef(index: number, result: Vector3): void;
         /**
+         * Returns the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @returns world space position
+         */
+        getAgentNextTargetPath(index: number): Vector3;
+        /**
+         * Returns the agent next target point on the path
+         * @param index agent index returned by addAgent
+         * @param result output world space position
+         */
+        getAgentNextTargetPathToRef(index: number, result: Vector3): void;
+        /**
          * Asks a particular agent to go to a destination. That destination is constrained by the navigation mesh
          * @param index agent index returned by addAgent
          * @param destination targeted world position
@@ -72493,6 +72833,10 @@ declare module BABYLON {
          */
         onAfterBoxRenderingObservable: Observable<BoundingBox>;
         /**
+         * When false, no bounding boxes will be rendered
+         */
+        enabled: boolean;
+        /**
          * @hidden
          */
         renderList: SmartArray<BoundingBox>;
@@ -72511,7 +72855,7 @@ declare module BABYLON {
          */
         register(): void;
         private _evaluateSubMesh;
-        private _activeMesh;
+        private _preActiveMesh;
         private _prepareRessources;
         private _createIndexBuffer;
         /**
@@ -77916,7 +78260,7 @@ declare module BABYLON.GUI {
         private _isVisible;
         private _isHighlighted;
         /** @hidden */
-        _linkedMesh: BABYLON.Nullable<BABYLON.AbstractMesh>;
+        _linkedMesh: BABYLON.Nullable<BABYLON.TransformNode>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -78170,7 +78514,7 @@ declare module BABYLON.GUI {
         /**
          * Gets the current linked mesh (or null if none)
          */
-        get linkedMesh(): BABYLON.Nullable<BABYLON.AbstractMesh>;
+        get linkedMesh(): BABYLON.Nullable<BABYLON.TransformNode>;
         /**
          * Gets or sets a value indicating the padding to use on the left of the control
          * @see https://doc.babylonjs.com/how_to/gui#position-and-size
@@ -78347,7 +78691,7 @@ declare module BABYLON.GUI {
          * @param mesh defines the mesh to link with
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
-        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.AbstractMesh>): void;
+        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */
@@ -81444,6 +81788,7 @@ declare module BABYLON {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -82594,18 +82939,20 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -82756,6 +83103,7 @@ declare module BABYLON.GLTF2 {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -82875,13 +83223,14 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -83165,9 +83514,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -83417,7 +83765,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
@@ -83439,7 +83787,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

BIN
dist/preview release/draco_decoder_gltf.wasm


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 104 - 119
dist/preview release/draco_wasm_wrapper_gltf.js


+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -717,7 +717,7 @@ declare module BABYLON.GUI {
         private _isVisible;
         private _isHighlighted;
         /** @hidden */
-        _linkedMesh: BABYLON.Nullable<BABYLON.AbstractMesh>;
+        _linkedMesh: BABYLON.Nullable<BABYLON.TransformNode>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -971,7 +971,7 @@ declare module BABYLON.GUI {
         /**
          * Gets the current linked mesh (or null if none)
          */
-        get linkedMesh(): BABYLON.Nullable<BABYLON.AbstractMesh>;
+        get linkedMesh(): BABYLON.Nullable<BABYLON.TransformNode>;
         /**
          * Gets or sets a value indicating the padding to use on the left of the control
          * @see https://doc.babylonjs.com/how_to/gui#position-and-size
@@ -1148,7 +1148,7 @@ declare module BABYLON.GUI {
          * @param mesh defines the mesh to link with
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
-        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.AbstractMesh>): void;
+        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */

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

@@ -5445,7 +5445,7 @@ var Control = /** @class */ (function () {
         }
         this._downCount++;
         this._downPointerIds[pointerId] = true;
-        var canNotify = this.onPointerDownObservable.notifyObservers(new _math2D__WEBPACK_IMPORTED_MODULE_3__["Vector2WithInfo"](coordinates, buttonIndex), -1, target, this);
+        var canNotify = this.onPointerDownObservable.notifyObservers(new _math2D__WEBPACK_IMPORTED_MODULE_3__["Vector2WithInfo"](coordinates, buttonIndex), -1, target, this, pi);
         if (canNotify && this.parent != null) {
             this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex, pi);
         }

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


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

@@ -664,7 +664,7 @@ declare module "babylonjs-gui/2D/controls/control" {
     import { Observable } from "babylonjs/Misc/observable";
     import { Vector2, Vector3 } from "babylonjs/Maths/math.vector";
     import { PointerInfoBase } from 'babylonjs/Events/pointerEvents';
-    import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+    import { TransformNode } from "babylonjs/Meshes/transformNode";
     import { Scene } from "babylonjs/scene";
     import { Container } from "babylonjs-gui/2D/controls/container";
     import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
@@ -749,7 +749,7 @@ declare module "babylonjs-gui/2D/controls/control" {
         private _isVisible;
         private _isHighlighted;
         /** @hidden */
-        _linkedMesh: Nullable<AbstractMesh>;
+        _linkedMesh: Nullable<TransformNode>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -1003,7 +1003,7 @@ declare module "babylonjs-gui/2D/controls/control" {
         /**
          * Gets the current linked mesh (or null if none)
          */
-        get linkedMesh(): Nullable<AbstractMesh>;
+        get linkedMesh(): Nullable<TransformNode>;
         /**
          * Gets or sets a value indicating the padding to use on the left of the control
          * @see https://doc.babylonjs.com/how_to/gui#position-and-size
@@ -1180,7 +1180,7 @@ declare module "babylonjs-gui/2D/controls/control" {
          * @param mesh defines the mesh to link with
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
-        linkWithMesh(mesh: Nullable<AbstractMesh>): void;
+        linkWithMesh(mesh: Nullable<TransformNode>): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: Vector3): void;
         /** @hidden */
@@ -5153,7 +5153,7 @@ declare module BABYLON.GUI {
         private _isVisible;
         private _isHighlighted;
         /** @hidden */
-        _linkedMesh: BABYLON.Nullable<BABYLON.AbstractMesh>;
+        _linkedMesh: BABYLON.Nullable<BABYLON.TransformNode>;
         private _fontSet;
         private _dummyVector2;
         private _downCount;
@@ -5407,7 +5407,7 @@ declare module BABYLON.GUI {
         /**
          * Gets the current linked mesh (or null if none)
          */
-        get linkedMesh(): BABYLON.Nullable<BABYLON.AbstractMesh>;
+        get linkedMesh(): BABYLON.Nullable<BABYLON.TransformNode>;
         /**
          * Gets or sets a value indicating the padding to use on the left of the control
          * @see https://doc.babylonjs.com/how_to/gui#position-and-size
@@ -5584,7 +5584,7 @@ declare module BABYLON.GUI {
          * @param mesh defines the mesh to link with
          * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
          */
-        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.AbstractMesh>): void;
+        linkWithMesh(mesh: BABYLON.Nullable<BABYLON.TransformNode>): void;
         /** @hidden */
         _moveToProjectedPosition(projectedPosition: BABYLON.Vector3): void;
         /** @hidden */

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11"
     },
     "engines": {
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 77 - 73
dist/preview release/inspector/babylon.inspector.bundle.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 3 - 2
dist/preview release/inspector/babylon.inspector.d.ts

@@ -239,11 +239,12 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     export const Null_Value: number;
-    class ListLineOption {
+    export class ListLineOption {
         label: string;
         value: number;
+        selected?: boolean;
     }
-    interface IOptionsLineComponentProps {
+    export interface IOptionsLineComponentProps {
         label: string;
         target: any;
         propertyName: string;

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

@@ -277,11 +277,12 @@ declare module "babylonjs-inspector/components/actionTabs/lines/optionsLineCompo
     import { Observable } from "babylonjs/Misc/observable";
     import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
     export const Null_Value: number;
-    class ListLineOption {
+    export class ListLineOption {
         label: string;
         value: number;
+        selected?: boolean;
     }
-    interface IOptionsLineComponentProps {
+    export interface IOptionsLineComponentProps {
         label: string;
         target: any;
         propertyName: string;
@@ -4781,11 +4782,12 @@ declare module INSPECTOR {
 }
 declare module INSPECTOR {
     export const Null_Value: number;
-    class ListLineOption {
+    export class ListLineOption {
         label: string;
         value: number;
+        selected?: boolean;
     }
-    interface IOptionsLineComponentProps {
+    export interface IOptionsLineComponentProps {
         label: string;
         target: any;
         propertyName: string;

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

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

+ 3 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -1901,7 +1901,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: skeletons,
                     animationGroups: [],
                     lights: [],
-                    transformNodes: []
+                    transformNodes: [],
+                    geometries: []
                 });
             }, onProgress, function (message) {
                 reject(new Error(message));
@@ -3277,6 +3278,7 @@ var GLTFFileLoader = /** @class */ (function () {
                 cameras.push(camera);
             });
             return _this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then(function (result) {
+                Array.prototype.push.apply(container.geometries, result.geometries);
                 Array.prototype.push.apply(container.meshes, result.meshes);
                 Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                 Array.prototype.push.apply(container.skeletons, result.skeletons);

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/loaders/babylon.glTF1FileLoader.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 55 - 31
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -935,9 +935,8 @@ __webpack_require__.r(__webpack_exports__);
 
 var NAME = "KHR_materials_clearcoat";
 /**
- * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+ * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
  * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
- * !!! Experimental Extension Subject to Changes !!!
  */
 var KHR_materials_clearcoat = /** @class */ (function () {
     /** @hidden */
@@ -997,13 +996,13 @@ var KHR_materials_clearcoat = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatRoughnessTexture", properties.clearcoatRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Roughness)";
                 babylonMaterial.clearCoat.textureRoughness = texture;
-            }));
+            }, false));
         }
         if (properties.clearcoatNormalTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatNormalTexture", properties.clearcoatNormalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Normal)";
                 babylonMaterial.clearCoat.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem;
             babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem;
             if (properties.clearcoatNormalTexture.scale != undefined) {
@@ -1167,7 +1166,7 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
-            }));
+            }, false));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
             babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
         }
@@ -1260,7 +1259,7 @@ var KHR_materials_sheen = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/sheenRoughnessTexture", properties.sheenRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Sheen Roughness)";
                 babylonMaterial.sheen.textureRoughness = texture;
-            }));
+            }, false));
         }
         babylonMaterial.sheen.albedoScaling = true;
         babylonMaterial.sheen.useRoughnessFromMainTexture = false;
@@ -1338,7 +1337,7 @@ var KHR_materials_specular = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularTexture", properties.specularTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular F0 Color)";
                 babylonMaterial.metallicReflectanceTexture = texture;
-            }));
+            }, false));
         }
         return Promise.all(promises).then(function () { });
     };
@@ -1617,7 +1616,7 @@ var KHR_materials_transmission = /** @class */ (function () {
             return Promise.resolve();
         }
         if (extension.transmissionTexture) {
-            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture)
+            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture, undefined, false)
                 .then(function (texture) {
                 pbrMaterial.subSurface.thicknessTexture = texture;
                 pbrMaterial.subSurface.useMaskFromThicknessTexture = true;
@@ -1980,14 +1979,15 @@ var KHR_texture_basisu = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign) {
+    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, texture, this.name, function (extensionContext, extension) {
             var sampler = (texture.sampler == undefined ? _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].DefaultSampler : _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(context + "/sampler", _this._loader.gltf.samplers, texture.sampler));
             var image = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/source", _this._loader.gltf.images, extension.source);
             return _this._loader._createTextureAsync(context, sampler, image, function (babylonTexture) {
                 assign(babylonTexture);
-            });
+            }, isColorData ? undefined : { useRGBAIfASTCBC7NotAvailableWhenUASTC: true });
         });
     };
     return KHR_texture_basisu;
@@ -2032,8 +2032,9 @@ var KHR_texture_transform = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, textureInfo, this.name, function (extensionContext, extension) {
             return _this._loader.loadTextureInfoAsync(context, textureInfo, function (babylonTexture) {
                 if (!(babylonTexture instanceof babylonjs_Materials_Textures_texture__WEBPACK_IMPORTED_MODULE_0__["Texture"])) {
@@ -2057,7 +2058,7 @@ var KHR_texture_transform = /** @class */ (function () {
                     babylonTexture.coordinatesIndex = extension.texCoord;
                 }
                 assign(babylonTexture);
-            });
+            }, isColorData);
         });
     };
     return KHR_texture_transform;
@@ -3144,7 +3145,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: _this._getSkeletons(),
                     animationGroups: _this._getAnimationGroups(),
                     lights: _this._babylonLights,
-                    transformNodes: _this._getTransformNodes()
+                    transformNodes: _this._getTransformNodes(),
+                    geometries: _this._getGeometries()
                 };
             });
         });
@@ -3394,14 +3396,30 @@ var GLTFLoader = /** @class */ (function () {
             }
         }
     };
+    GLTFLoader.prototype._getGeometries = function () {
+        var geometries = new Array();
+        var nodes = this._gltf.nodes;
+        if (nodes) {
+            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                var node = nodes_1[_i];
+                this._forEachPrimitive(node, function (babylonMesh) {
+                    var geometry = babylonMesh.geometry;
+                    if (geometry && geometries.indexOf(geometry) === -1) {
+                        geometries.push(geometry);
+                    }
+                });
+            }
+        }
+        return geometries;
+    };
     GLTFLoader.prototype._getMeshes = function () {
         var meshes = new Array();
         // Root mesh is always first.
         meshes.push(this._rootBabylonMesh);
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
-                var node = nodes_1[_i];
+            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
+                var node = nodes_2[_i];
                 this._forEachPrimitive(node, function (babylonMesh) {
                     meshes.push(babylonMesh);
                 });
@@ -3413,8 +3431,8 @@ var GLTFLoader = /** @class */ (function () {
         var transformNodes = new Array();
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
-                var node = nodes_2[_i];
+            for (var _i = 0, nodes_3 = nodes; _i < nodes_3.length; _i++) {
+                var node = nodes_3[_i];
                 if (node._babylonTransformNode && node._babylonTransformNode.getClassName() === "TransformNode") {
                     transformNodes.push(node._babylonTransformNode);
                 }
@@ -3613,7 +3631,9 @@ var GLTFLoader = /** @class */ (function () {
             this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
             promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
                 return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                    _this._babylonScene._blockEntityCollection = _this._forAssetContainer;
                     babylonGeometry.applyToMesh(babylonMesh_1);
+                    _this._babylonScene._blockEntityCollection = false;
                 });
             }));
             var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
@@ -4392,7 +4412,7 @@ var GLTFLoader = /** @class */ (function () {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
                     texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
-                }));
+                }, false));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                 babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                 babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
@@ -4507,7 +4527,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
             babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
             if (material.normalTexture.scale != undefined) {
@@ -4519,7 +4539,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
-            }));
+            }, false));
             babylonMaterial.useAmbientInGrayScale = true;
             if (material.occlusionTexture.strength != undefined) {
                 babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
@@ -4576,12 +4596,14 @@ var GLTFLoader = /** @class */ (function () {
      * @param context The context when loading the asset
      * @param textureInfo The glTF texture info property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete
      */
-    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -4595,14 +4617,15 @@ var GLTFLoader = /** @class */ (function () {
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);
-        });
+        }, isColorData);
         this.logClose();
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign) {
+    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -4614,7 +4637,7 @@ var GLTFLoader = /** @class */ (function () {
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign) {
+    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign, textureLoaderOptions) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
         var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
@@ -4629,7 +4652,7 @@ var GLTFLoader = /** @class */ (function () {
             if (!_this._disposed) {
                 deferred.reject(new Error(context + ": " + ((exception && exception.message) ? exception.message : message || "Failed to load texture")));
             }
-        }, undefined, undefined, undefined, image.mimeType);
+        }, undefined, undefined, undefined, image.mimeType, textureLoaderOptions);
         this._babylonScene._blockEntityCollection = false;
         promises.push(deferred.promise);
         promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
@@ -4928,11 +4951,11 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._extensionsLoadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
         return this._applyExtensions(material, "loadMaterialProperties", function (extension) { return extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign) {
-        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
+        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign, isColorData); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign) {
-        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign, isColorData) {
+        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign, isColorData); });
     };
     GLTFLoader.prototype._extensionsLoadAnimationAsync = function (context, animation) {
         return this._applyExtensions(animation, "loadAnimation", function (extension) { return extension.loadAnimationAsync && extension.loadAnimationAsync(context, animation); });
@@ -5675,6 +5698,7 @@ var GLTFFileLoader = /** @class */ (function () {
                 cameras.push(camera);
             });
             return _this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then(function (result) {
+                Array.prototype.push.apply(container.geometries, result.geometries);
                 Array.prototype.push.apply(container.meshes, result.meshes);
                 Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                 Array.prototype.push.apply(container.skeletons, result.skeletons);

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 57 - 32
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -1901,7 +1901,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: skeletons,
                     animationGroups: [],
                     lights: [],
-                    transformNodes: []
+                    transformNodes: [],
+                    geometries: []
                 });
             }, onProgress, function (message) {
                 reject(new Error(message));
@@ -3286,9 +3287,8 @@ __webpack_require__.r(__webpack_exports__);
 
 var NAME = "KHR_materials_clearcoat";
 /**
- * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+ * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
  * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
- * !!! Experimental Extension Subject to Changes !!!
  */
 var KHR_materials_clearcoat = /** @class */ (function () {
     /** @hidden */
@@ -3348,13 +3348,13 @@ var KHR_materials_clearcoat = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatRoughnessTexture", properties.clearcoatRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Roughness)";
                 babylonMaterial.clearCoat.textureRoughness = texture;
-            }));
+            }, false));
         }
         if (properties.clearcoatNormalTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatNormalTexture", properties.clearcoatNormalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Normal)";
                 babylonMaterial.clearCoat.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem;
             babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem;
             if (properties.clearcoatNormalTexture.scale != undefined) {
@@ -3518,7 +3518,7 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
-            }));
+            }, false));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
             babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
         }
@@ -3611,7 +3611,7 @@ var KHR_materials_sheen = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/sheenRoughnessTexture", properties.sheenRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Sheen Roughness)";
                 babylonMaterial.sheen.textureRoughness = texture;
-            }));
+            }, false));
         }
         babylonMaterial.sheen.albedoScaling = true;
         babylonMaterial.sheen.useRoughnessFromMainTexture = false;
@@ -3689,7 +3689,7 @@ var KHR_materials_specular = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularTexture", properties.specularTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular F0 Color)";
                 babylonMaterial.metallicReflectanceTexture = texture;
-            }));
+            }, false));
         }
         return Promise.all(promises).then(function () { });
     };
@@ -3968,7 +3968,7 @@ var KHR_materials_transmission = /** @class */ (function () {
             return Promise.resolve();
         }
         if (extension.transmissionTexture) {
-            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture)
+            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture, undefined, false)
                 .then(function (texture) {
                 pbrMaterial.subSurface.thicknessTexture = texture;
                 pbrMaterial.subSurface.useMaskFromThicknessTexture = true;
@@ -4331,14 +4331,15 @@ var KHR_texture_basisu = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign) {
+    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, texture, this.name, function (extensionContext, extension) {
             var sampler = (texture.sampler == undefined ? _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].DefaultSampler : _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(context + "/sampler", _this._loader.gltf.samplers, texture.sampler));
             var image = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/source", _this._loader.gltf.images, extension.source);
             return _this._loader._createTextureAsync(context, sampler, image, function (babylonTexture) {
                 assign(babylonTexture);
-            });
+            }, isColorData ? undefined : { useRGBAIfASTCBC7NotAvailableWhenUASTC: true });
         });
     };
     return KHR_texture_basisu;
@@ -4383,8 +4384,9 @@ var KHR_texture_transform = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, textureInfo, this.name, function (extensionContext, extension) {
             return _this._loader.loadTextureInfoAsync(context, textureInfo, function (babylonTexture) {
                 if (!(babylonTexture instanceof babylonjs_Materials_Textures_texture__WEBPACK_IMPORTED_MODULE_0__["Texture"])) {
@@ -4408,7 +4410,7 @@ var KHR_texture_transform = /** @class */ (function () {
                     babylonTexture.coordinatesIndex = extension.texCoord;
                 }
                 assign(babylonTexture);
-            });
+            }, isColorData);
         });
     };
     return KHR_texture_transform;
@@ -5495,7 +5497,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: _this._getSkeletons(),
                     animationGroups: _this._getAnimationGroups(),
                     lights: _this._babylonLights,
-                    transformNodes: _this._getTransformNodes()
+                    transformNodes: _this._getTransformNodes(),
+                    geometries: _this._getGeometries()
                 };
             });
         });
@@ -5745,14 +5748,30 @@ var GLTFLoader = /** @class */ (function () {
             }
         }
     };
+    GLTFLoader.prototype._getGeometries = function () {
+        var geometries = new Array();
+        var nodes = this._gltf.nodes;
+        if (nodes) {
+            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                var node = nodes_1[_i];
+                this._forEachPrimitive(node, function (babylonMesh) {
+                    var geometry = babylonMesh.geometry;
+                    if (geometry && geometries.indexOf(geometry) === -1) {
+                        geometries.push(geometry);
+                    }
+                });
+            }
+        }
+        return geometries;
+    };
     GLTFLoader.prototype._getMeshes = function () {
         var meshes = new Array();
         // Root mesh is always first.
         meshes.push(this._rootBabylonMesh);
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
-                var node = nodes_1[_i];
+            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
+                var node = nodes_2[_i];
                 this._forEachPrimitive(node, function (babylonMesh) {
                     meshes.push(babylonMesh);
                 });
@@ -5764,8 +5783,8 @@ var GLTFLoader = /** @class */ (function () {
         var transformNodes = new Array();
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
-                var node = nodes_2[_i];
+            for (var _i = 0, nodes_3 = nodes; _i < nodes_3.length; _i++) {
+                var node = nodes_3[_i];
                 if (node._babylonTransformNode && node._babylonTransformNode.getClassName() === "TransformNode") {
                     transformNodes.push(node._babylonTransformNode);
                 }
@@ -5964,7 +5983,9 @@ var GLTFLoader = /** @class */ (function () {
             this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
             promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
                 return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                    _this._babylonScene._blockEntityCollection = _this._forAssetContainer;
                     babylonGeometry.applyToMesh(babylonMesh_1);
+                    _this._babylonScene._blockEntityCollection = false;
                 });
             }));
             var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
@@ -6743,7 +6764,7 @@ var GLTFLoader = /** @class */ (function () {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
                     texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
-                }));
+                }, false));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                 babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                 babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
@@ -6858,7 +6879,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
             babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
             if (material.normalTexture.scale != undefined) {
@@ -6870,7 +6891,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
-            }));
+            }, false));
             babylonMaterial.useAmbientInGrayScale = true;
             if (material.occlusionTexture.strength != undefined) {
                 babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
@@ -6927,12 +6948,14 @@ var GLTFLoader = /** @class */ (function () {
      * @param context The context when loading the asset
      * @param textureInfo The glTF texture info property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete
      */
-    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -6946,14 +6969,15 @@ var GLTFLoader = /** @class */ (function () {
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);
-        });
+        }, isColorData);
         this.logClose();
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign) {
+    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -6965,7 +6989,7 @@ var GLTFLoader = /** @class */ (function () {
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign) {
+    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign, textureLoaderOptions) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
         var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
@@ -6980,7 +7004,7 @@ var GLTFLoader = /** @class */ (function () {
             if (!_this._disposed) {
                 deferred.reject(new Error(context + ": " + ((exception && exception.message) ? exception.message : message || "Failed to load texture")));
             }
-        }, undefined, undefined, undefined, image.mimeType);
+        }, undefined, undefined, undefined, image.mimeType, textureLoaderOptions);
         this._babylonScene._blockEntityCollection = false;
         promises.push(deferred.promise);
         promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
@@ -7279,11 +7303,11 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._extensionsLoadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
         return this._applyExtensions(material, "loadMaterialProperties", function (extension) { return extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign) {
-        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
+        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign, isColorData); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign) {
-        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign, isColorData) {
+        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign, isColorData); });
     };
     GLTFLoader.prototype._extensionsLoadAnimationAsync = function (context, animation) {
         return this._applyExtensions(animation, "loadAnimation", function (extension) { return extension.loadAnimationAsync && extension.loadAnimationAsync(context, animation); });
@@ -8026,6 +8050,7 @@ var GLTFFileLoader = /** @class */ (function () {
                 cameras.push(camera);
             });
             return _this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then(function (result) {
+                Array.prototype.push.apply(container.geometries, result.geometries);
                 Array.prototype.push.apply(container.meshes, result.meshes);
                 Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                 Array.prototype.push.apply(container.skeletons, result.skeletons);

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 13 - 9
dist/preview release/loaders/babylonjs.loaders.d.ts

@@ -110,6 +110,7 @@ declare module BABYLON {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -1260,18 +1261,20 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -1422,6 +1425,7 @@ declare module BABYLON.GLTF2 {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -1541,13 +1545,14 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -1831,9 +1836,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -2083,7 +2087,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
@@ -2105,7 +2109,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

+ 57 - 32
dist/preview release/loaders/babylonjs.loaders.js

@@ -3281,7 +3281,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: skeletons,
                     animationGroups: [],
                     lights: [],
-                    transformNodes: []
+                    transformNodes: [],
+                    geometries: []
                 });
             }, onProgress, function (message) {
                 reject(new Error(message));
@@ -4666,9 +4667,8 @@ __webpack_require__.r(__webpack_exports__);
 
 var NAME = "KHR_materials_clearcoat";
 /**
- * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+ * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
  * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
- * !!! Experimental Extension Subject to Changes !!!
  */
 var KHR_materials_clearcoat = /** @class */ (function () {
     /** @hidden */
@@ -4728,13 +4728,13 @@ var KHR_materials_clearcoat = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatRoughnessTexture", properties.clearcoatRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Roughness)";
                 babylonMaterial.clearCoat.textureRoughness = texture;
-            }));
+            }, false));
         }
         if (properties.clearcoatNormalTexture) {
             promises.push(this._loader.loadTextureInfoAsync(context + "/clearcoatNormalTexture", properties.clearcoatNormalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (ClearCoat Normal)";
                 babylonMaterial.clearCoat.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem;
             babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem;
             if (properties.clearcoatNormalTexture.scale != undefined) {
@@ -4898,7 +4898,7 @@ var KHR_materials_pbrSpecularGlossiness = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularGlossinessTexture", properties.specularGlossinessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular Glossiness)";
                 babylonMaterial.reflectivityTexture = texture;
-            }));
+            }, false));
             babylonMaterial.reflectivityTexture.hasAlpha = true;
             babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
         }
@@ -4991,7 +4991,7 @@ var KHR_materials_sheen = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/sheenRoughnessTexture", properties.sheenRoughnessTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Sheen Roughness)";
                 babylonMaterial.sheen.textureRoughness = texture;
-            }));
+            }, false));
         }
         babylonMaterial.sheen.albedoScaling = true;
         babylonMaterial.sheen.useRoughnessFromMainTexture = false;
@@ -5069,7 +5069,7 @@ var KHR_materials_specular = /** @class */ (function () {
             promises.push(this._loader.loadTextureInfoAsync(context + "/specularTexture", properties.specularTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Specular F0 Color)";
                 babylonMaterial.metallicReflectanceTexture = texture;
-            }));
+            }, false));
         }
         return Promise.all(promises).then(function () { });
     };
@@ -5348,7 +5348,7 @@ var KHR_materials_transmission = /** @class */ (function () {
             return Promise.resolve();
         }
         if (extension.transmissionTexture) {
-            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture)
+            return this._loader.loadTextureInfoAsync(context + "/transmissionTexture", extension.transmissionTexture, undefined, false)
                 .then(function (texture) {
                 pbrMaterial.subSurface.thicknessTexture = texture;
                 pbrMaterial.subSurface.useMaskFromThicknessTexture = true;
@@ -5711,14 +5711,15 @@ var KHR_texture_basisu = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign) {
+    KHR_texture_basisu.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].LoadExtensionAsync(context, texture, this.name, function (extensionContext, extension) {
             var sampler = (texture.sampler == undefined ? _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["GLTFLoader"].DefaultSampler : _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(context + "/sampler", _this._loader.gltf.samplers, texture.sampler));
             var image = _glTFLoader__WEBPACK_IMPORTED_MODULE_0__["ArrayItem"].Get(extensionContext + "/source", _this._loader.gltf.images, extension.source);
             return _this._loader._createTextureAsync(context, sampler, image, function (babylonTexture) {
                 assign(babylonTexture);
-            });
+            }, isColorData ? undefined : { useRGBAIfASTCBC7NotAvailableWhenUASTC: true });
         });
     };
     return KHR_texture_basisu;
@@ -5763,8 +5764,9 @@ var KHR_texture_transform = /** @class */ (function () {
         this._loader = null;
     };
     /** @hidden */
-    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    KHR_texture_transform.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
+        if (isColorData === void 0) { isColorData = true; }
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, textureInfo, this.name, function (extensionContext, extension) {
             return _this._loader.loadTextureInfoAsync(context, textureInfo, function (babylonTexture) {
                 if (!(babylonTexture instanceof babylonjs_Materials_Textures_texture__WEBPACK_IMPORTED_MODULE_0__["Texture"])) {
@@ -5788,7 +5790,7 @@ var KHR_texture_transform = /** @class */ (function () {
                     babylonTexture.coordinatesIndex = extension.texCoord;
                 }
                 assign(babylonTexture);
-            });
+            }, isColorData);
         });
     };
     return KHR_texture_transform;
@@ -6875,7 +6877,8 @@ var GLTFLoader = /** @class */ (function () {
                     skeletons: _this._getSkeletons(),
                     animationGroups: _this._getAnimationGroups(),
                     lights: _this._babylonLights,
-                    transformNodes: _this._getTransformNodes()
+                    transformNodes: _this._getTransformNodes(),
+                    geometries: _this._getGeometries()
                 };
             });
         });
@@ -7125,14 +7128,30 @@ var GLTFLoader = /** @class */ (function () {
             }
         }
     };
+    GLTFLoader.prototype._getGeometries = function () {
+        var geometries = new Array();
+        var nodes = this._gltf.nodes;
+        if (nodes) {
+            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
+                var node = nodes_1[_i];
+                this._forEachPrimitive(node, function (babylonMesh) {
+                    var geometry = babylonMesh.geometry;
+                    if (geometry && geometries.indexOf(geometry) === -1) {
+                        geometries.push(geometry);
+                    }
+                });
+            }
+        }
+        return geometries;
+    };
     GLTFLoader.prototype._getMeshes = function () {
         var meshes = new Array();
         // Root mesh is always first.
         meshes.push(this._rootBabylonMesh);
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) {
-                var node = nodes_1[_i];
+            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
+                var node = nodes_2[_i];
                 this._forEachPrimitive(node, function (babylonMesh) {
                     meshes.push(babylonMesh);
                 });
@@ -7144,8 +7163,8 @@ var GLTFLoader = /** @class */ (function () {
         var transformNodes = new Array();
         var nodes = this._gltf.nodes;
         if (nodes) {
-            for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
-                var node = nodes_2[_i];
+            for (var _i = 0, nodes_3 = nodes; _i < nodes_3.length; _i++) {
+                var node = nodes_3[_i];
                 if (node._babylonTransformNode && node._babylonTransformNode.getClassName() === "TransformNode") {
                     transformNodes.push(node._babylonTransformNode);
                 }
@@ -7344,7 +7363,9 @@ var GLTFLoader = /** @class */ (function () {
             this._createMorphTargets(context, node, mesh, primitive, babylonMesh_1);
             promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh_1).then(function (babylonGeometry) {
                 return _this._loadMorphTargetsAsync(context, primitive, babylonMesh_1, babylonGeometry).then(function () {
+                    _this._babylonScene._blockEntityCollection = _this._forAssetContainer;
                     babylonGeometry.applyToMesh(babylonMesh_1);
+                    _this._babylonScene._blockEntityCollection = false;
                 });
             }));
             var babylonDrawMode = GLTFLoader._GetDrawMode(context, primitive.mode);
@@ -8123,7 +8144,7 @@ var GLTFLoader = /** @class */ (function () {
                 promises.push(this.loadTextureInfoAsync(context + "/metallicRoughnessTexture", properties.metallicRoughnessTexture, function (texture) {
                     texture.name = babylonMaterial.name + " (Metallic Roughness)";
                     babylonMaterial.metallicTexture = texture;
-                }));
+                }, false));
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                 babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
                 babylonMaterial.useRoughnessFromMetallicTextureAlpha = false;
@@ -8238,7 +8259,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/normalTexture", material.normalTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Normal)";
                 babylonMaterial.bumpTexture = texture;
-            }));
+            }, false));
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
             babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
             if (material.normalTexture.scale != undefined) {
@@ -8250,7 +8271,7 @@ var GLTFLoader = /** @class */ (function () {
             promises.push(this.loadTextureInfoAsync(context + "/occlusionTexture", material.occlusionTexture, function (texture) {
                 texture.name = babylonMaterial.name + " (Occlusion)";
                 babylonMaterial.ambientTexture = texture;
-            }));
+            }, false));
             babylonMaterial.useAmbientInGrayScale = true;
             if (material.occlusionTexture.strength != undefined) {
                 babylonMaterial.ambientTextureStrength = material.occlusionTexture.strength;
@@ -8307,12 +8328,14 @@ var GLTFLoader = /** @class */ (function () {
      * @param context The context when loading the asset
      * @param textureInfo The glTF texture info property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete
      */
-    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign) {
+    GLTFLoader.prototype.loadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -8326,14 +8349,15 @@ var GLTFLoader = /** @class */ (function () {
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             _this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);
-        });
+        }, isColorData);
         this.logClose();
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign) {
+    GLTFLoader.prototype._loadTextureAsync = function (context, texture, assign, isColorData) {
         if (assign === void 0) { assign = function () { }; }
-        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign);
+        if (isColorData === void 0) { isColorData = true; }
+        var extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -8345,7 +8369,7 @@ var GLTFLoader = /** @class */ (function () {
         return promise;
     };
     /** @hidden */
-    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign) {
+    GLTFLoader.prototype._createTextureAsync = function (context, sampler, image, assign, textureLoaderOptions) {
         var _this = this;
         if (assign === void 0) { assign = function () { }; }
         var samplerData = this._loadSampler("/samplers/" + sampler.index, sampler);
@@ -8360,7 +8384,7 @@ var GLTFLoader = /** @class */ (function () {
             if (!_this._disposed) {
                 deferred.reject(new Error(context + ": " + ((exception && exception.message) ? exception.message : message || "Failed to load texture")));
             }
-        }, undefined, undefined, undefined, image.mimeType);
+        }, undefined, undefined, undefined, image.mimeType, textureLoaderOptions);
         this._babylonScene._blockEntityCollection = false;
         promises.push(deferred.promise);
         promises.push(this.loadImageAsync("/images/" + image.index, image).then(function (data) {
@@ -8659,11 +8683,11 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._extensionsLoadMaterialPropertiesAsync = function (context, material, babylonMaterial) {
         return this._applyExtensions(material, "loadMaterialProperties", function (extension) { return extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign) {
-        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureInfoAsync = function (context, textureInfo, assign, isColorData) {
+        return this._applyExtensions(textureInfo, "loadTextureInfo", function (extension) { return extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign, isColorData); });
     };
-    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign) {
-        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign); });
+    GLTFLoader.prototype._extensionsLoadTextureAsync = function (context, texture, assign, isColorData) {
+        return this._applyExtensions(texture, "loadTexture", function (extension) { return extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign, isColorData); });
     };
     GLTFLoader.prototype._extensionsLoadAnimationAsync = function (context, animation) {
         return this._applyExtensions(animation, "loadAnimation", function (extension) { return extension.loadAnimationAsync && extension.loadAnimationAsync(context, animation); });
@@ -9406,6 +9430,7 @@ var GLTFFileLoader = /** @class */ (function () {
                 cameras.push(camera);
             });
             return _this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then(function (result) {
+                Array.prototype.push.apply(container.geometries, result.geometries);
                 Array.prototype.push.apply(container.meshes, result.meshes);
                 Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                 Array.prototype.push.apply(container.skeletons, result.skeletons);

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 27 - 18
dist/preview release/loaders/babylonjs.loaders.module.d.ts

@@ -49,6 +49,7 @@ declare module "babylonjs-loaders/glTF/glTFFileLoader" {
     import { Light } from 'babylonjs/Lights/light';
     import { TransformNode } from 'babylonjs/Meshes/transformNode';
     import { RequestFileError } from 'babylonjs/Misc/fileTools';
+    import { Geometry } from 'babylonjs/Meshes/geometry';
     /**
      * Mode that determines the coordinate system to use.
      */
@@ -130,6 +131,7 @@ declare module "babylonjs-loaders/glTF/glTFFileLoader" {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -1333,18 +1335,20 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -1512,6 +1516,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -1631,13 +1636,14 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -1965,9 +1971,8 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_clearcoat" {
     import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
     import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -2250,7 +2255,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_basisu" {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform" {
@@ -2277,7 +2282,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform" {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_xmp" {
@@ -3008,6 +3013,7 @@ declare module BABYLON {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -4158,18 +4164,20 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -4320,6 +4328,7 @@ declare module BABYLON.GLTF2 {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -4439,13 +4448,14 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -4729,9 +4739,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -4981,7 +4990,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
@@ -5003,7 +5012,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "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-beta.10",
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs-gltf2interface": "4.2.0-beta.11",
+        "babylonjs": "4.2.0-beta.11"
     },
     "engines": {
         "node": "*"

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11"
     },
     "engines": {
         "node": "*"

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

@@ -430,12 +430,17 @@ declare module NODEEDITOR {
         step?: string;
         digits?: number;
         globalState: GlobalState;
+        min?: number;
+        max?: number;
+        smallUI?: boolean;
+        onEnter?: (newValue: number) => void;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
     }> {
         private _localChange;
         private _store;
+        private _regExp;
         constructor(props: IFloatLineComponentProps);
         shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: {
             value: string;
@@ -796,6 +801,7 @@ declare module NODEEDITOR {
         target?: any;
         propertyName?: string;
         value?: string;
+        multilines?: boolean;
         onChange?: (value: string) => void;
         validator?: (value: string) => boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 6 - 6
dist/preview release/nodeEditor/babylon.nodeEditor.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 59 - 14
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


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

@@ -562,12 +562,17 @@ declare module "babylonjs-node-editor/sharedComponents/floatLineComponent" {
         step?: string;
         digits?: number;
         globalState: GlobalState;
+        min?: number;
+        max?: number;
+        smallUI?: boolean;
+        onEnter?: (newValue: number) => void;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
     }> {
         private _localChange;
         private _store;
+        private _regExp;
         constructor(props: IFloatLineComponentProps);
         shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: {
             value: string;
@@ -989,6 +994,7 @@ declare module "babylonjs-node-editor/sharedComponents/textInputLineComponent" {
         target?: any;
         propertyName?: string;
         value?: string;
+        multilines?: boolean;
         onChange?: (value: string) => void;
         validator?: (value: string) => boolean;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
@@ -2348,12 +2354,17 @@ declare module NODEEDITOR {
         step?: string;
         digits?: number;
         globalState: GlobalState;
+        min?: number;
+        max?: number;
+        smallUI?: boolean;
+        onEnter?: (newValue: number) => void;
     }
     export class FloatLineComponent extends React.Component<IFloatLineComponentProps, {
         value: string;
     }> {
         private _localChange;
         private _store;
+        private _regExp;
         constructor(props: IFloatLineComponentProps);
         shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: {
             value: string;
@@ -2714,6 +2725,7 @@ declare module NODEEDITOR {
         target?: any;
         propertyName?: string;
         value?: string;
+        multilines?: boolean;
         onChange?: (value: string) => void;
         validator?: (value: string) => boolean;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11"
     },
     "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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1 +1 @@
-{"thinEngineOnly":118510,"engineOnly":154950,"sceneOnly":521794,"minGridMaterial":663140,"minStandardMaterial":819347}
+{"thinEngineOnly":118763,"engineOnly":155203,"sceneOnly":522343,"minGridMaterial":671241,"minStandardMaterial":827448}

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11"
     },
     "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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11"
     },
     "engines": {
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 8 - 8
dist/preview release/recast.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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.2.0-beta.10",
-        "babylonjs-gltf2interface": "4.2.0-beta.10"
+        "babylonjs": "4.2.0-beta.11",
+        "babylonjs-gltf2interface": "4.2.0-beta.11"
     },
     "engines": {
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 717 - 15
dist/preview release/viewer/babylon.module.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 62 - 50
dist/preview release/viewer/babylon.viewer.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/viewer/babylon.viewer.max.js


+ 27 - 18
dist/preview release/viewer/babylonjs.loaders.module.d.ts

@@ -49,6 +49,7 @@ declare module "babylonjs-loaders/glTF/glTFFileLoader" {
     import { Light } from 'babylonjs/Lights/light';
     import { TransformNode } from 'babylonjs/Meshes/transformNode';
     import { RequestFileError } from 'babylonjs/Misc/fileTools';
+    import { Geometry } from 'babylonjs/Meshes/geometry';
     /**
      * Mode that determines the coordinate system to use.
      */
@@ -130,6 +131,7 @@ declare module "babylonjs-loaders/glTF/glTFFileLoader" {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -1333,18 +1335,20 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoaderExtension" {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -1512,6 +1516,7 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -1631,13 +1636,14 @@ declare module "babylonjs-loaders/glTF/2.0/glTFLoader" {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -1965,9 +1971,8 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_materials_clearcoat" {
     import { IGLTFLoaderExtension } from "babylonjs-loaders/glTF/2.0/glTFLoaderExtension";
     import { GLTFLoader } from "babylonjs-loaders/glTF/2.0/glTFLoader";
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -2250,7 +2255,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_basisu" {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform" {
@@ -2277,7 +2282,7 @@ declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_texture_transform" {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module "babylonjs-loaders/glTF/2.0/Extensions/KHR_xmp" {
@@ -3008,6 +3013,7 @@ declare module BABYLON {
     /** @hidden */
     export interface IImportMeshAsyncOutput {
         meshes: AbstractMesh[];
+        geometries: Geometry[];
         particleSystems: IParticleSystem[];
         skeletons: Skeleton[];
         animationGroups: AnimationGroup[];
@@ -4158,18 +4164,20 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * @hidden
          * Define this method to modify the default behavior when loading textures.
          * @param context The context when loading the asset
          * @param texture The glTF texture property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
          */
-        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
         /**
          * Define this method to modify the default behavior when loading animations.
          * @param context The context when loading the asset
@@ -4320,6 +4328,7 @@ declare module BABYLON.GLTF2 {
          */
         loadSceneAsync(context: string, scene: IScene): Promise<void>;
         private _forEachPrimitive;
+        private _getGeometries;
         private _getMeshes;
         private _getTransformNodes;
         private _getSkeletons;
@@ -4439,13 +4448,14 @@ declare module BABYLON.GLTF2 {
          * @param context The context when loading the asset
          * @param textureInfo The glTF texture info property
          * @param assign A function called synchronously after parsing the glTF properties
+         * @param isColorData true if the texture held color data, else false
          * @returns A promise that resolves with the loaded Babylon texture when the load is complete
          */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _loadTextureAsync(context: string, texture: ITexture, assign?: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Promise<BaseTexture>;
         /** @hidden */
-        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void): Promise<BaseTexture>;
+        _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign?: (babylonTexture: BaseTexture) => void, textureLoaderOptions?: any): Promise<BaseTexture>;
         private _loadSampler;
         /**
          * Loads a glTF image.
@@ -4729,9 +4739,8 @@ declare module BABYLON.GLTF2.Loader.Extensions {
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
     /**
-     * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+     * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
      * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
-     * !!! Experimental Extension Subject to Changes !!!
      */
     export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
         /**
@@ -4981,7 +4990,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {
@@ -5003,7 +5012,7 @@ declare module BABYLON.GLTF2.Loader.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
-        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+        loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData?: boolean): Nullable<Promise<BaseTexture>>;
     }
 }
 declare module BABYLON.GLTF2.Loader.Extensions {

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

@@ -53,6 +53,7 @@
 - Added optional success and error callbacks for freezeActiveMeshes ([RaananW](https://github.com/RaananW))
 - Allow cross-eye mode in photo and video dome ([#8897](https://github.com/BabylonJS/Babylon.js/issues/8897)) ([RaananW](https://github.com/RaananW))
 - Added noMipMap option to the photo dome construction process ([#8972](https://github.com/BabylonJS/Babylon.js/issues/8972)) ([RaananW](https://github.com/RaananW))
+- Add a `disableBoundingBoxesFromEffectLayer` property to the `EffectLayer` class to render the bounding boxes unaffected by the effect ([Popov72](https://github.com/Popov72))
 
 ### Engine
 
@@ -97,6 +98,7 @@
 - View & edit textures in pop out inspector using tools such as brush and floodfill. Supports region selection, individual channel editing, mipmap previews, and resizing. ([DarraghBurkeMS](https://github.com/DarraghBurkeMS))
 - Added mesh debug tools to display bone influence weights and bone indices maps. ([Pryme8](https://github.com/Pryme8))
 - Added more functionality and options to the skeleton debug panel. ([Pryme8](https://github.com/Pryme8))
+- Along with bone index it is now possible to select a bone using its name when viewing bone weights ([#9117](https://github.com/BabylonJS/Babylon.js/issues/9117)) ([RaananW](https://github.com/RaananW))
 
 ### Cameras
 
@@ -106,6 +108,7 @@
 - Added flag to TargetCamera to invert rotation direction and multiplier to adjust speed ([Exolun](https://github.com/Exolun))
 - Added upwards and downwards keyboard input to `FreeCamera` ([Pheater](https://github.com/pheater))
 - Handle scales in camera matrices ([Popov72](https://github.com/Popov72))
+- Added mouse wheel controls to FreeCamera. ([mrdunk](https://github.com/mrdunk))
 
 ### Debug
 - Added new view modes to the `SkeletonViewer` class. ([Pryme8](https://github.com/Pryme8))
@@ -158,6 +161,7 @@
 ### Navigation
 
 - export/load prebuilt binary navigation mesh ([cedricguillemet](https://github.com/cedricguillemet))
+- get next path step point for an agent ([cedricguillemet](https://github.com/cedricguillemet))
 
 ### Materials
 
@@ -212,6 +216,8 @@
 - XR's main camera uses the first eye's projection matrix ([#8944](https://github.com/BabylonJS/Babylon.js/issues/8944)) ([RaananW](https://github.com/RaananW))
 - pointerX and pointerY of the scene are now updated when using the pointer selection feature ([#8879](https://github.com/BabylonJS/Babylon.js/issues/8879)) ([RaananW](https://github.com/RaananW))
 - XR tracking state was added to the camera ([#9076](https://github.com/BabylonJS/Babylon.js/issues/9076)) ([RaananW](https://github.com/RaananW))
+- Individual post processing can be applied to the XR rig cameras ([#9038](https://github.com/BabylonJS/Babylon.js/issues/9038)) ([RaananW](https://github.com/RaananW))
+- Pointer selection improvements - single/dual hand selection, max ray distance and more ([#7974](https://github.com/BabylonJS/Babylon.js/issues/7974)) ([RaananW](https://github.com/RaananW))
 
 ### Collisions
 
@@ -340,6 +346,7 @@
 - Fix `SkeletonViewer` to use utillity layer with custom lighting to improve debug mesh visibility ([Drigax](https://github.com/drigax))
 - Fix same sub mesh being rendered multiple times in the shadow map ([Popov72](https://github.com/Popov72))
 - Fix incorrect shadows on the master mesh when using a lod mesh ([Popov72](https://github.com/Popov72))
+- Take first gamepad connected when attaching camera (and not only XBOX gamepads) ([#9136](https://github.com/BabylonJS/Babylon.js/issues/9136)) ([RaananW](https://github.com/RaananW))
 
 ## Breaking changes
 
@@ -351,3 +358,4 @@
 - `SceneLoaderProgress` class is now `ISceneLoaderProgress` interface ([bghgary](https://github.com/bghgary))
 - Rendering of transparent meshes: stencil state is now set to the value registered in the engine (when calling `engine.setStencilBuffer(value)`) instead of being set to `false` unconditionally. This change may affect the highlight layer when using transparent meshes. If you are impacted, you may need to exclude the transparent mesh(es) from the layer ([Popov72](https://github.com/Popov72))
 - Fix width/height GUI container computation to take into account paddings when `adaptWithToChildren = true` ([Popov72](https://github.com/Popov72))
+- `smoothstep` in NME is now taking any type of parameters for its `value` input. If you use generated code from the NME ("Generate code" button), you may have to move the smoothstep output connection AFTER the input connections ([Popov72](https://github.com/Popov72))

+ 1 - 1
gui/src/2D/advancedDynamicTexture.ts

@@ -565,7 +565,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
                 if (!control.isVisible) {
                     continue;
                 }
-                let mesh = control._linkedMesh;
+                let mesh = control._linkedMesh as AbstractMesh;
                 if (!mesh || mesh.isDisposed()) {
                     Tools.SetImmediate(() => {
                         control.linkWithMesh(null);

+ 5 - 5
gui/src/2D/controls/control.ts

@@ -4,7 +4,7 @@ import { Vector2, Vector3, Matrix } from "babylonjs/Maths/math.vector";
 import { PointerEventTypes, PointerInfoBase } from 'babylonjs/Events/pointerEvents';
 import { Logger } from "babylonjs/Misc/logger";
 import { Tools } from "babylonjs/Misc/tools";
-import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Scene } from "babylonjs/scene";
 
 import { Container } from "./container";
@@ -87,7 +87,7 @@ export class Control {
     private _isVisible = true;
     private _isHighlighted = false;
     /** @hidden */
-    public _linkedMesh: Nullable<AbstractMesh>;
+    public _linkedMesh: Nullable<TransformNode>;
     private _fontSet = false;
     private _dummyVector2 = Vector2.Zero();
     private _downCount = 0;
@@ -710,7 +710,7 @@ export class Control {
     /**
      * Gets the current linked mesh (or null if none)
      */
-    public get linkedMesh(): Nullable<AbstractMesh> {
+    public get linkedMesh(): Nullable<TransformNode> {
         return this._linkedMesh;
     }
 
@@ -1145,7 +1145,7 @@ export class Control {
      * @param mesh defines the mesh to link with
      * @see https://doc.babylonjs.com/how_to/gui#tracking-positions
      */
-    public linkWithMesh(mesh: Nullable<AbstractMesh>): void {
+    public linkWithMesh(mesh: Nullable<TransformNode>): void {
         if (!this._host || this.parent && this.parent !== this._host._rootContainer) {
             if (mesh) {
                 Tools.Error("Cannot link a control to a mesh if the control is not at root level");
@@ -1812,7 +1812,7 @@ export class Control {
 
         this._downPointerIds[pointerId] = true;
 
-        var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+        var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
 
         if (canNotify && this.parent != null) { this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex, pi); }
 

+ 11 - 13
inspector/src/components/actionTabs/lines/optionsLineComponent.tsx

@@ -5,12 +5,13 @@ import { PropertyChangedEvent } from "../../propertyChangedEvent";
 
 export const Null_Value = Number.MAX_SAFE_INTEGER;
 
-class ListLineOption {
+export class ListLineOption {
     public label: string;
     public value: number;
+    selected?: boolean;
 }
 
-interface IOptionsLineComponentProps {
+export interface IOptionsLineComponentProps {
     label: string;
     target: any;
     propertyName: string;
@@ -90,19 +91,16 @@ export class OptionsLineComponent extends React.Component<IOptionsLineComponentP
     render() {
         return (
             <div className="listLine">
-                <div className="label">
-                    {this.props.label}
-
-                </div>
+                <div className="label">{this.props.label}</div>
                 <div className="options">
                     <select onChange={(evt) => this.updateValue(evt.target.value)} value={this.state.value ?? ""}>
-                        {
-                            this.props.options.map((option, i) => {
-                                return (
-                                    <option key={option.label + i} value={option.value}>{option.label}</option>
-                                );
-                            })
-                        }
+                        {this.props.options.map((option, i) => {
+                            return (
+                                <option selected={option.selected} key={option.label + i} value={option.value}>
+                                    {option.label}
+                                </option>
+                            );
+                        })}
                     </select>
                 </div>
             </div>

+ 155 - 165
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -3,7 +3,7 @@ import * as React from "react";
 import { Observable } from "babylonjs/Misc/observable";
 import { Tools } from "babylonjs/Misc/tools";
 import { Vector3, TmpVectors } from "babylonjs/Maths/math.vector";
-import { Color3 } from 'babylonjs/Maths/math.color';
+import { Color3 } from "babylonjs/Maths/math.color";
 import { Mesh } from "babylonjs/Meshes/mesh";
 import { VertexBuffer } from "babylonjs/Meshes/buffer";
 import { LinesBuilder } from "babylonjs/Meshes/Builders/linesBuilder";
@@ -19,22 +19,22 @@ import { SliderLineComponent } from "../../../lines/sliderLineComponent";
 import { QuaternionLineComponent } from "../../../lines/quaternionLineComponent";
 import { FloatLineComponent } from "../../../lines/floatLineComponent";
 import { LockObject } from "../lockObject";
-import { GlobalState } from '../../../../globalState';
-import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
-import { StandardMaterial } from 'babylonjs/Materials/standardMaterial';
-import { Color3LineComponent } from '../../../lines/color3LineComponent';
-import { MorphTarget } from 'babylonjs/Morph/morphTarget';
-import { OptionsLineComponent } from '../../../lines/optionsLineComponent';
-import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
-import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
-import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
-import { AnimationGridComponent } from '../animations/animationPropertyGridComponent';
-import { RenderingManager } from 'babylonjs/Rendering/renderingManager';
-import { CommonPropertyGridComponent } from '../commonPropertyGridComponent';
-import { VariantsPropertyGridComponent } from '../variantsPropertyGridComponent';
-import { HexLineComponent } from '../../../lines/hexLineComponent';
-import { SkeletonViewer } from 'babylonjs/Debug/skeletonViewer';
-import { ShaderMaterial } from 'babylonjs/Materials/shaderMaterial';
+import { GlobalState } from "../../../../globalState";
+import { CustomPropertyGridComponent } from "../customPropertyGridComponent";
+import { StandardMaterial } from "babylonjs/Materials/standardMaterial";
+import { Color3LineComponent } from "../../../lines/color3LineComponent";
+import { MorphTarget } from "babylonjs/Morph/morphTarget";
+import { OptionsLineComponent, ListLineOption } from "../../../lines/optionsLineComponent";
+import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
+import { ButtonLineComponent } from "../../../lines/buttonLineComponent";
+import { TextInputLineComponent } from "../../../lines/textInputLineComponent";
+import { AnimationGridComponent } from "../animations/animationPropertyGridComponent";
+import { RenderingManager } from "babylonjs/Rendering/renderingManager";
+import { CommonPropertyGridComponent } from "../commonPropertyGridComponent";
+import { VariantsPropertyGridComponent } from "../variantsPropertyGridComponent";
+import { HexLineComponent } from "../../../lines/hexLineComponent";
+import { SkeletonViewer } from "babylonjs/Debug/skeletonViewer";
+import { ShaderMaterial } from "babylonjs/Materials/shaderMaterial";
 
 interface IMeshPropertyGridComponentProps {
     globalState: GlobalState;
@@ -44,21 +44,27 @@ interface IMeshPropertyGridComponentProps {
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
 }
 
-export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGridComponentProps, {
-    displayNormals: boolean,
-    displayVertexColors: boolean,
-    displayBoneWeights: boolean,
-    displayBoneIndex: number,
-    displaySkeletonMap:boolean
-}> {
+export class MeshPropertyGridComponent extends React.Component<
+    IMeshPropertyGridComponentProps,
+    {
+        displayNormals: boolean;
+        displayVertexColors: boolean;
+        displayBoneWeights: boolean;
+        displayBoneIndex: number;
+        displaySkeletonMap: boolean;
+    }
+> {
     constructor(props: IMeshPropertyGridComponentProps) {
         super(props);
+
+        const mesh = this.props.mesh;
+
         this.state = {
             displayNormals: false,
             displayVertexColors: false,
-            displayBoneWeights: false,
+            displayBoneWeights: !!(mesh.material && mesh.material.getClassName() === "BoneWeightShader"),
             displayBoneIndex: 0,
-            displaySkeletonMap: false
+            displaySkeletonMap: false,
         };
     }
 
@@ -156,7 +162,6 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             mesh.reservedDataStore.originalMaterial = null;
             this.setState({ displayNormals: false });
         } else {
-
             if (!(BABYLON as any).NormalMaterial) {
                 this.setState({ displayNormals: true });
                 Tools.LoadScript("https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.js", () => {
@@ -195,7 +200,6 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             mesh.reservedDataStore.originalMaterial = null;
             this.setState({ displayVertexColors: false });
         } else {
-
             if (!mesh.reservedDataStore) {
                 mesh.reservedDataStore = {};
             }
@@ -226,7 +230,6 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             mesh.reservedDataStore.originalMaterial = null;
             this.setState({ displayBoneWeights: false });
         } else {
-          
             if (!mesh.reservedDataStore) {
                 mesh.reservedDataStore = {};
             }
@@ -236,12 +239,12 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             if (!mesh.reservedDataStore.displayBoneIndex) {
                 mesh.reservedDataStore.displayBoneIndex = this.state.displayBoneIndex;
             }
-            if (mesh.skeleton){
-                const boneWeightsShader = SkeletonViewer.CreateBoneWeightShader({skeleton:mesh.skeleton}, scene)
+            if (mesh.skeleton) {
+                const boneWeightsShader = SkeletonViewer.CreateBoneWeightShader({ skeleton: mesh.skeleton }, scene);
                 boneWeightsShader.reservedDataStore = { hidden: true };
                 mesh.material = boneWeightsShader;
                 this.setState({ displayBoneWeights: true });
-            }            
+            }
         }
     }
 
@@ -254,28 +257,28 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
             mesh.material = mesh.reservedDataStore.originalMaterial;
             mesh.reservedDataStore.originalMaterial = null;
             this.setState({ displaySkeletonMap: false });
-        } else {          
+        } else {
             if (!mesh.reservedDataStore) {
                 mesh.reservedDataStore = {};
             }
             if (!mesh.reservedDataStore.originalMaterial) {
                 mesh.reservedDataStore.originalMaterial = mesh.material;
-            }  
-            if (mesh.skeleton){
-                const skeletonMapShader = SkeletonViewer.CreateSkeletonMapShader({skeleton:mesh.skeleton}, scene)
+            }
+            if (mesh.skeleton) {
+                const skeletonMapShader = SkeletonViewer.CreateSkeletonMapShader({ skeleton: mesh.skeleton }, scene);
                 skeletonMapShader.reservedDataStore = { hidden: true };
                 mesh.material = skeletonMapShader;
                 this.setState({ displaySkeletonMap: true });
-            }            
+            }
         }
     }
 
-    onBoneDisplayIndexChange(value:number):void{
-        let mesh = this.props.mesh
-        mesh.reservedDataStore.displayBoneIndex = value
+    onBoneDisplayIndexChange(value: number): void {
+        let mesh = this.props.mesh;
+        mesh.reservedDataStore.displayBoneIndex = value;
         this.setState({ displayBoneIndex: value });
         if (mesh.material && mesh.material.getClassName() === "BoneWeightShader") {
-            (mesh.material as ShaderMaterial).setFloat('targetBoneIndex', value)
+            (mesh.material as ShaderMaterial).setFloat("targetBoneIndex", value);
         }
     }
 
@@ -342,8 +345,8 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
 
         const displayNormals = mesh.material != null && mesh.material.getClassName() === "NormalMaterial";
         const displayVertexColors = !!(mesh.material != null && mesh.material.reservedDataStore && mesh.material.reservedDataStore.isVertexColorMaterial);
-        const renderNormalVectors = (mesh.reservedDataStore && mesh.reservedDataStore.normalLines) ? true : false;
-        const renderWireframeOver = (mesh.reservedDataStore && mesh.reservedDataStore.wireframeOver) ? true : false;
+        const renderNormalVectors = mesh.reservedDataStore && mesh.reservedDataStore.normalLines ? true : false;
+        const renderWireframeOver = mesh.reservedDataStore && mesh.reservedDataStore.wireframeOver ? true : false;
         const displayBoneWeights = mesh.material != null && mesh.material.getClassName() === "BoneWeightShader";
         const displaySkeletonMap = mesh.material != null && mesh.material.getClassName() === "SkeletonMapShader";
 
@@ -368,47 +371,47 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
 
         let sortedMaterials = scene.materials.slice(0).sort((a, b) => (a.name || "no name").localeCompare(b.name || "no name"));
 
-        var materialOptions = sortedMaterials.map((m, i) => {
+        const materialOptions = sortedMaterials.map((m, i) => {
             return {
                 label: m.name || "no name",
-                value: i
-            };});
+                value: i,
+            };
+        });
 
         materialOptions.splice(0, 0, {
             label: "None (Default Fallback)",
-            value: -1
+            value: -1,
         });
 
+        const targetBoneOptions: ListLineOption[] = mesh.skeleton ? mesh.skeleton.bones.map((bone, idx) => {
+            return {
+                label: bone.name,
+                value: idx,
+            };
+        }) : [];
+
         return (
             <div className="pane">
-                <CustomPropertyGridComponent globalState={this.props.globalState} target={mesh}
-                    lockObject={this.props.lockObject}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CustomPropertyGridComponent globalState={this.props.globalState} target={mesh} lockObject={this.props.lockObject} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
                     <TextLineComponent label="ID" value={mesh.id} />
-                    <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={mesh} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                    <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={mesh} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <TextLineComponent label="Unique ID" value={mesh.uniqueId.toString()} />
                     <TextLineComponent label="Class" value={mesh.getClassName()} />
                     <TextLineComponent label="Vertices" value={mesh.getTotalVertices().toString()} />
                     <TextLineComponent label="Faces" value={(mesh.getTotalIndices() / 3).toFixed(0)} />
                     <TextLineComponent label="Sub-meshes" value={mesh.subMeshes ? mesh.subMeshes.length.toString() : "0"} />
-                    {
-                        mesh.parent &&
-                        <TextLineComponent label="Parent" value={mesh.parent.name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(mesh.parent)}/>
-                    }
-                    {
-                        mesh.skeleton &&
-                        <TextLineComponent label="Skeleton" value={mesh.skeleton.name} onLink={() => this.onSkeletonLink()}/>
-                    }
+                    {mesh.parent && <TextLineComponent label="Parent" value={mesh.parent.name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(mesh.parent)} />}
+                    {mesh.skeleton && <TextLineComponent label="Skeleton" value={mesh.skeleton.name} onLink={() => this.onSkeletonLink()} />}
                     <CheckBoxLineComponent label="Is enabled" isSelected={() => mesh.isEnabled()} onSelect={(value) => mesh.setEnabled(value)} />
                     <CheckBoxLineComponent label="Is pickable" target={mesh} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    {
-                        mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) &&
-                        <TextLineComponent label="Link to material" value={mesh.material.name} onLink={() => this.onMaterialLink()} />
-                    }
-                    {   !mesh.isAnInstance &&
-                        <OptionsLineComponent label="Active material" options={materialOptions}
-                            target={mesh} propertyName="material"
+                    {mesh.material && (!mesh.material.reservedDataStore || !mesh.material.reservedDataStore.hidden) && <TextLineComponent label="Link to material" value={mesh.material.name} onLink={() => this.onMaterialLink()} />}
+                    {!mesh.isAnInstance && (
+                        <OptionsLineComponent
+                            label="Active material"
+                            options={materialOptions}
+                            target={mesh}
+                            propertyName="material"
                             noDirectUpdate={true}
                             onSelect={(value: number) => {
                                 if (value < 0) {
@@ -419,77 +422,57 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
 
                                 this.forceUpdate();
                             }}
-                            extractValue={() => mesh.material ? sortedMaterials.indexOf(mesh.material) : -1}
-                            onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    {
-                        mesh.isAnInstance &&
-                        <TextLineComponent label="Source" value={(mesh as any).sourceMesh.name} onLink={() => this.onSourceMeshLink()} />
-                    }
-                    <ButtonLineComponent label="Dispose" onClick={() => {
-                        mesh.dispose();
-                        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
-                    }} />
+                            extractValue={() => (mesh.material ? sortedMaterials.indexOf(mesh.material) : -1)}
+                            onPropertyChangedObservable={this.props.onPropertyChangedObservable}
+                        />
+                    )}
+                    {mesh.isAnInstance && <TextLineComponent label="Source" value={(mesh as any).sourceMesh.name} onLink={() => this.onSourceMeshLink()} />}
+                    <ButtonLineComponent
+                        label="Dispose"
+                        onClick={() => {
+                            mesh.dispose();
+                            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+                        }}
+                    />
                 </LineContainerComponent>
                 <CommonPropertyGridComponent host={mesh} lockObject={this.props.lockObject} globalState={this.props.globalState} />
                 <VariantsPropertyGridComponent host={mesh} lockObject={this.props.lockObject} globalState={this.props.globalState} />
                 <LineContainerComponent globalState={this.props.globalState} title="TRANSFORMS">
                     <Vector3LineComponent label="Position" target={mesh} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    {
-                        !mesh.rotationQuaternion &&
-                        <Vector3LineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotation" step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    {
-                        mesh.rotationQuaternion &&
-                        <QuaternionLineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotationQuaternion" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
+                    {!mesh.rotationQuaternion && <Vector3LineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotation" step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
+                    {mesh.rotationQuaternion && <QuaternionLineComponent label="Rotation" useEuler={this.props.globalState.onlyUseEulers} target={mesh} propertyName="rotationQuaternion" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
                     <Vector3LineComponent label="Scaling" target={mesh} propertyName="scaling" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="DISPLAY" closed={true}>
-                    {
-                        !mesh.isAnInstance &&
-                        <SliderLineComponent label="Visibility" target={mesh} propertyName="visibility" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
+                    {!mesh.isAnInstance && <SliderLineComponent label="Visibility" target={mesh} propertyName="visibility" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
                     <FloatLineComponent lockObject={this.props.lockObject} label="Alpha index" target={mesh} propertyName="alphaIndex" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Receive shadows" target={mesh} propertyName="receiveShadows" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    {
-                        mesh.isVerticesDataPresent(VertexBuffer.ColorKind) &&
-                        <CheckBoxLineComponent label="Use vertex colors" target={mesh} propertyName="useVertexColors" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    {
-                        mesh.isVerticesDataPresent(VertexBuffer.ColorKind) &&
-                        <CheckBoxLineComponent label="Has vertex alpha" target={mesh} propertyName="hasVertexAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    {
-                        scene.fogMode !== Scene.FOGMODE_NONE &&
-                        <CheckBoxLineComponent label="Apply fog" target={mesh} propertyName="applyFog" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    {
-                        !mesh.parent &&
-                        <CheckBoxLineComponent label="Infinite distance" target={mesh} propertyName="infiniteDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
-                    <SliderLineComponent label="Rendering group ID" decimalCount={0} target={mesh} propertyName="renderingGroupId" minimum={RenderingManager.MIN_RENDERINGGROUPS} maximum={RenderingManager.MAX_RENDERINGGROUPS - 1} step={1} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                    
+                    {mesh.isVerticesDataPresent(VertexBuffer.ColorKind) && <CheckBoxLineComponent label="Use vertex colors" target={mesh} propertyName="useVertexColors" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
+                    {mesh.isVerticesDataPresent(VertexBuffer.ColorKind) && <CheckBoxLineComponent label="Has vertex alpha" target={mesh} propertyName="hasVertexAlpha" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
+                    {scene.fogMode !== Scene.FOGMODE_NONE && <CheckBoxLineComponent label="Apply fog" target={mesh} propertyName="applyFog" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
+                    {!mesh.parent && <CheckBoxLineComponent label="Infinite distance" target={mesh} propertyName="infiniteDistance" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
+                    <SliderLineComponent
+                        label="Rendering group ID"
+                        decimalCount={0}
+                        target={mesh}
+                        propertyName="renderingGroupId"
+                        minimum={RenderingManager.MIN_RENDERINGGROUPS}
+                        maximum={RenderingManager.MAX_RENDERINGGROUPS - 1}
+                        step={1}
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable}
+                    />
                     <HexLineComponent isInteger lockObject={this.props.lockObject} label="Layer mask" target={mesh} propertyName="layerMask" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                {
-                    mesh.morphTargetManager != null &&
+                {mesh.morphTargetManager != null && (
                     <LineContainerComponent globalState={this.props.globalState} title="MORPH TARGETS" closed={true}>
-                        {
-                            morphTargets.map((mt, i) => {
-                                return (
-                                    <SliderLineComponent key={i} label={mt.name} target={mt} propertyName="influence" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                                );
-                            })
-                        }
+                        {morphTargets.map((mt, i) => {
+                            return <SliderLineComponent key={i} label={mt.name} target={mt} propertyName="influence" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />;
+                        })}
                     </LineContainerComponent>
-
-                }
+                )}
                 <AnimationGridComponent globalState={this.props.globalState} animatable={mesh} scene={mesh.getScene()} lockObject={this.props.lockObject} />
                 <LineContainerComponent globalState={this.props.globalState} title="ADVANCED" closed={true}>
-                    {
-                        mesh.useBones &&
-                        <CheckBoxLineComponent label="Compute bones using shaders" target={mesh} propertyName="computeBonesUsingShaders" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    }
+                    {mesh.useBones && <CheckBoxLineComponent label="Compute bones using shaders" target={mesh} propertyName="computeBonesUsingShaders" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />}
                     <CheckBoxLineComponent label="Collisions" target={mesh} propertyName="checkCollisions" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <TextLineComponent label="Geometry ID" value={mesh.geometry?.uniqueId.toString()} />
                     <TextLineComponent label="Has normals" value={mesh.isVerticesDataPresent(VertexBuffer.NormalKind) ? "Yes" : "No"} />
@@ -502,73 +485,80 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                     <TextLineComponent label="Has matrix weights" value={mesh.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind) ? "Yes" : "No"} />
                     <TextLineComponent label="Has matrix indices" value={mesh.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) ? "Yes" : "No"} />
                 </LineContainerComponent>
-                {
-                    mesh.physicsImpostor != null &&
+                {mesh.physicsImpostor != null && (
                     <LineContainerComponent globalState={this.props.globalState} title="PHYSICS" closed={true}>
                         <FloatLineComponent lockObject={this.props.lockObject} label="Mass" target={mesh.physicsImpostor} propertyName="mass" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <FloatLineComponent lockObject={this.props.lockObject} label="Friction" target={mesh.physicsImpostor} propertyName="friction" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <FloatLineComponent lockObject={this.props.lockObject} label="Restitution" target={mesh.physicsImpostor} propertyName="restitution" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <TextLineComponent label="Type" value={this.convertPhysicsTypeToString()} />
                     </LineContainerComponent>
-                }
+                )}
                 <LineContainerComponent globalState={this.props.globalState} title="OCCLUSIONS" closed={true}>
                     <OptionsLineComponent label="Type" options={occlusionTypeOptions} target={mesh} propertyName="occlusionType" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <SliderLineComponent label="Retry count" minimum={-1} maximum={10} decimalCount={0} step={1} target={mesh} propertyName="occlusionRetryCount" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <OptionsLineComponent label="Algorithm" options={algorithmOptions} target={mesh} propertyName="occlusionQueryAlgorithmType" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="EDGE RENDERING" closed={true}>
-                    <CheckBoxLineComponent label="Enable" target={mesh} isSelected={() => mesh.edgesRenderer != null} onSelect={(value) => {
-                        if (value) {
-                            mesh.enableEdgesRendering();
-                        } else {
-                            mesh.disableEdgesRendering();
-                        }
-                    }} />
+                    <CheckBoxLineComponent
+                        label="Enable"
+                        target={mesh}
+                        isSelected={() => mesh.edgesRenderer != null}
+                        onSelect={(value) => {
+                            if (value) {
+                                mesh.enableEdgesRendering();
+                            } else {
+                                mesh.disableEdgesRendering();
+                            }
+                        }}
+                    />
                     <SliderLineComponent label="Edge width" minimum={0} maximum={10} step={0.1} target={mesh} propertyName="edgesWidth" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Color3LineComponent label="Edge color" target={mesh} propertyName="edgesColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                 </LineContainerComponent>
-                {
-                        !mesh.isAnInstance &&
+                {!mesh.isAnInstance && (
                     <LineContainerComponent globalState={this.props.globalState} title="OUTLINE & OVERLAY" closed={true}>
                         <CheckBoxLineComponent label="Render overlay" target={mesh} propertyName="renderOverlay" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <Color3LineComponent label="Overlay color" target={mesh} propertyName="overlayColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <CheckBoxLineComponent label="Render outline" target={mesh} propertyName="renderOutline" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         <Color3LineComponent label="Outline color" target={mesh} propertyName="outlineColor" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     </LineContainerComponent>
-                }
+                )}
                 <LineContainerComponent globalState={this.props.globalState} title="DEBUG" closed={true}>
-                    {
-                        !mesh.isAnInstance &&
-                        <CheckBoxLineComponent label="Display normals" isSelected={() => displayNormals} onSelect={() => this.displayNormals()} />
-                    }
-                    {
-                        !mesh.isAnInstance &&
-                        <CheckBoxLineComponent label="Display vertex colors" isSelected={() => displayVertexColors} onSelect={() => this.displayVertexColors()} />
-                    }
-                    {
-                        mesh.isVerticesDataPresent(VertexBuffer.NormalKind) &&
-                        <CheckBoxLineComponent label="Render vertex normals" isSelected={() => renderNormalVectors} onSelect={() => this.renderNormalVectors()} />
-                    }
-                    {
-                        !mesh.isAnInstance &&
-                        <CheckBoxLineComponent label="Render wireframe over mesh" isSelected={() => renderWireframeOver} onSelect={() => this.renderWireframeOver()} />
-                    }
-                    {
-                        !mesh.isAnInstance && mesh.skeleton &&
-                        <CheckBoxLineComponent label="Display BoneWeights" isSelected={() => displayBoneWeights} onSelect={() => this.displayBoneWeights()} />
-                    }
-                    {
-                        !mesh.isAnInstance && this.state.displayBoneWeights && mesh.skeleton &&
-                        <SliderLineComponent label="Target Bone" decimalCount={0} target={mesh.reservedDataStore} propertyName="displayBoneIndex" minimum={0} maximum={mesh.skeleton.bones.length-1 || 0} step={1} onChange={(value)=>{this.onBoneDisplayIndexChange(value)}} />
-                        
-                    }
-                    {
-                        !mesh.isAnInstance && mesh.skeleton &&
-                        <CheckBoxLineComponent label="Display SkeletonMap" isSelected={() => displaySkeletonMap } onSelect={() => this.displaySkeletonMap()} />
-                    }                
-
+                    {!mesh.isAnInstance && <CheckBoxLineComponent label="Display normals" isSelected={() => displayNormals} onSelect={() => this.displayNormals()} />}
+                    {!mesh.isAnInstance && <CheckBoxLineComponent label="Display vertex colors" isSelected={() => displayVertexColors} onSelect={() => this.displayVertexColors()} />}
+                    {mesh.isVerticesDataPresent(VertexBuffer.NormalKind) && <CheckBoxLineComponent label="Render vertex normals" isSelected={() => renderNormalVectors} onSelect={() => this.renderNormalVectors()} />}
+                    {!mesh.isAnInstance && <CheckBoxLineComponent label="Render wireframe over mesh" isSelected={() => renderWireframeOver} onSelect={() => this.renderWireframeOver()} />}
+                    {!mesh.isAnInstance && mesh.skeleton && <CheckBoxLineComponent label="Display BoneWeights" isSelected={() => displayBoneWeights} onSelect={() => this.displayBoneWeights()} />}
+                    {!mesh.isAnInstance && this.state.displayBoneWeights && mesh.skeleton && (
+                        <OptionsLineComponent
+                            label="Target Bone Name"
+                            options={targetBoneOptions}
+                            target={mesh.reservedDataStore}
+                            propertyName="displayBoneIndex"
+                            noDirectUpdate={true}
+                            onSelect={(value: number) => {
+                                this.onBoneDisplayIndexChange(value);
+                                this.forceUpdate();
+                            }}
+                        />
+                    )}
+                    {!mesh.isAnInstance && this.state.displayBoneWeights && mesh.skeleton && (
+                        <SliderLineComponent
+                            label="Target Bone"
+                            decimalCount={0}
+                            target={mesh.reservedDataStore}
+                            propertyName="displayBoneIndex"
+                            minimum={0}
+                            maximum={mesh.skeleton.bones.length - 1 || 0}
+                            step={1}
+                            onChange={(value) => {
+                                this.onBoneDisplayIndexChange(value);
+                                this.forceUpdate();
+                            }}
+                        />
+                    )}
+                    {!mesh.isAnInstance && mesh.skeleton && <CheckBoxLineComponent label="Display SkeletonMap" isSelected={() => displaySkeletonMap} onSelect={() => this.displaySkeletonMap()} />}
                 </LineContainerComponent>
             </div>
         );
     }
-}
+}

+ 12 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/skeletonPropertyGridComponent.tsx

@@ -99,9 +99,21 @@ export class SkeletonPropertyGridComponent extends React.Component<ISkeletonProp
             return;
         }
 
+        var needInit = true;
         for (var mesh of scene.meshes) {
             if (mesh.skeleton === props.skeleton && mesh.reservedDataStore && mesh.reservedDataStore.skeletonViewer) {
                 this._skeletonViewers.push(mesh.reservedDataStore.skeletonViewer);
+
+                if (needInit) {
+                    needInit = false;
+                    this._skeletonViewerDisplayOptions.displayMode = this._skeletonViewers[0].displayMode;
+                    for (var key in this._skeletonViewers[0].options.displayOptions) {
+                        if (!key) {
+                            continue;
+                        }
+                        (this._skeletonViewerDisplayOptions as any)[key] = (this._skeletonViewers[0].options as any).displayOptions[key];
+                    }
+                }
             }
         }
 

+ 2 - 2
ktx2Decoder/src/ktx2Decoder.ts

@@ -54,7 +54,7 @@ export interface ICompressedFormatCapabilities {
 
 export interface IKTX2DecoderOptions {
     /** use RGBA format if ASTC and BC7 are not available as transcoded format */
-    useRGBAIfASTCBC7NotAvailable?: boolean;
+    useRGBAIfASTCBC7NotAvailableWhenUASTC?: boolean;
 
     /** force to always use RGBA for transcoded format */
     forceRGBA?: boolean;
@@ -131,7 +131,7 @@ export class KTX2Decoder {
         } else if (caps.bptc) {
             targetFormat = transcodeTarget.BC7_RGBA;
             transcodedFormat = COMPRESSED_RGBA_BPTC_UNORM_EXT;
-        } else if (options?.useRGBAIfASTCBC7NotAvailable) {
+        } else if (options?.useRGBAIfASTCBC7NotAvailableWhenUASTC && srcTexFormat === sourceTextureFormat.UASTC4x4) {
             targetFormat = transcodeTarget.RGBA32;
             transcodedFormat = RGBA8Format;
             roundToMultiple4 = false;

+ 2 - 1
loaders/src/glTF/1.0/glTFLoader.ts

@@ -1704,7 +1704,8 @@ export class GLTFLoader implements IGLTFLoader {
                     skeletons: skeletons,
                     animationGroups: [],
                     lights: [],
-                    transformNodes: []
+                    transformNodes: [],
+                    geometries: []
                 });
             }, onProgress, (message) => {
                 reject(new Error(message));

+ 3 - 4
loaders/src/glTF/2.0/Extensions/KHR_materials_clearcoat.ts

@@ -10,9 +10,8 @@ import { IKHRMaterialsClearcoat } from 'babylonjs-gltf2interface';
 const NAME = "KHR_materials_clearcoat";
 
 /**
- * [Proposed Specification](https://github.com/KhronosGroup/glTF/pull/1677)
+ * [Specification](https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
  * [Playground Sample](https://www.babylonjs-playground.com/frame.html#7F7PN6#8)
- * !!! Experimental Extension Subject to Changes !!!
  */
 export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
     /**
@@ -89,14 +88,14 @@ export class KHR_materials_clearcoat implements IGLTFLoaderExtension {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/clearcoatRoughnessTexture`, properties.clearcoatRoughnessTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (ClearCoat Roughness)`;
                 babylonMaterial.clearCoat.textureRoughness = texture;
-            }));
+            }, false));
         }
 
         if (properties.clearcoatNormalTexture) {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/clearcoatNormalTexture`, properties.clearcoatNormalTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (ClearCoat Normal)`;
                 babylonMaterial.clearCoat.bumpTexture = texture;
-            }));
+            }, false));
 
             babylonMaterial.invertNormalMapX = !babylonMaterial.getScene().useRightHandedSystem;
             babylonMaterial.invertNormalMapY = babylonMaterial.getScene().useRightHandedSystem;

+ 1 - 1
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -85,7 +85,7 @@ export class KHR_materials_pbrSpecularGlossiness implements IGLTFLoaderExtension
             promises.push(this._loader.loadTextureInfoAsync(`${context}/specularGlossinessTexture`, properties.specularGlossinessTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Specular Glossiness)`;
                 babylonMaterial.reflectivityTexture = texture;
-            }));
+            }, false));
 
             babylonMaterial.reflectivityTexture.hasAlpha = true;
             babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;

+ 1 - 1
loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts

@@ -88,7 +88,7 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/sheenRoughnessTexture`, properties.sheenRoughnessTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Sheen Roughness)`;
                 babylonMaterial.sheen.textureRoughness = texture;
-            }));
+            }, false));
         }
 
         babylonMaterial.sheen.albedoScaling = true;

+ 1 - 1
loaders/src/glTF/2.0/Extensions/KHR_materials_specular.ts

@@ -72,7 +72,7 @@ export class KHR_materials_specular implements IGLTFLoaderExtension {
             promises.push(this._loader.loadTextureInfoAsync(`${context}/specularTexture`, properties.specularTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Specular F0 Color)`;
                 babylonMaterial.metallicReflectanceTexture = texture;
-            }));
+            }, false));
         }
 
         return Promise.all(promises).then(() => { });

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

@@ -324,7 +324,7 @@ export class KHR_materials_transmission implements IGLTFLoaderExtension {
         }
 
         if (extension.transmissionTexture) {
-            return this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture)
+            return this._loader.loadTextureInfoAsync(`${context}/transmissionTexture`, extension.transmissionTexture, undefined, false)
                 .then((texture: BaseTexture) => {
                     pbrMaterial.subSurface.thicknessTexture = texture;
                     pbrMaterial.subSurface.useMaskFromThicknessTexture = true;

+ 2 - 2
loaders/src/glTF/2.0/Extensions/KHR_texture_basisu.ts

@@ -32,13 +32,13 @@ export class KHR_texture_basisu implements IGLTFLoaderExtension {
     }
 
     /** @hidden */
-    public _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>> {
+    public _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData = true): Nullable<Promise<BaseTexture>> {
         return GLTFLoader.LoadExtensionAsync<IKHRTextureBasisU, BaseTexture>(context, texture, this.name, (extensionContext, extension) => {
             const sampler = (texture.sampler == undefined ? GLTFLoader.DefaultSampler : ArrayItem.Get(`${context}/sampler`, this._loader.gltf.samplers, texture.sampler));
             const image = ArrayItem.Get(`${extensionContext}/source`, this._loader.gltf.images, extension.source);
             return this._loader._createTextureAsync(context, sampler, image, (babylonTexture) => {
                 assign(babylonTexture);
-            });
+            }, isColorData ? undefined : { useRGBAIfASTCBC7NotAvailableWhenUASTC: true });
         });
     }
 }

+ 2 - 2
loaders/src/glTF/2.0/Extensions/KHR_texture_transform.ts

@@ -37,7 +37,7 @@ export class KHR_texture_transform implements IGLTFLoaderExtension {
     }
 
     /** @hidden */
-    public loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>> {
+    public loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData = true): Nullable<Promise<BaseTexture>> {
         return GLTFLoader.LoadExtensionAsync<IKHRTextureTransform, BaseTexture>(context, textureInfo, this.name, (extensionContext, extension) => {
             return this._loader.loadTextureInfoAsync(context, textureInfo, (babylonTexture) => {
                 if (!(babylonTexture instanceof Texture)) {
@@ -67,7 +67,7 @@ export class KHR_texture_transform implements IGLTFLoaderExtension {
                 }
 
                 assign(babylonTexture);
-            });
+            }, isColorData);
         });
     }
 }

+ 37 - 15
loaders/src/glTF/2.0/glTFLoader.ts

@@ -262,7 +262,8 @@ export class GLTFLoader implements IGLTFLoader {
                     skeletons: this._getSkeletons(),
                     animationGroups: this._getAnimationGroups(),
                     lights: this._babylonLights,
-                    transformNodes: this._getTransformNodes()
+                    transformNodes: this._getTransformNodes(),
+                    geometries: this._getGeometries()
                 };
             });
         });
@@ -549,6 +550,24 @@ export class GLTFLoader implements IGLTFLoader {
         }
     }
 
+    private _getGeometries(): Geometry[] {
+        const geometries = new Array<Geometry>();
+
+        const nodes = this._gltf.nodes;
+        if (nodes) {
+            for (const node of nodes) {
+                this._forEachPrimitive(node, (babylonMesh) => {
+                    const geometry = (babylonMesh as Mesh).geometry;
+                    if (geometry && geometries.indexOf(geometry) === -1) {
+                        geometries.push(geometry);
+                    }
+                });
+            }
+        }
+
+        return geometries;
+    }
+
     private _getMeshes(): AbstractMesh[] {
         const meshes = new Array<AbstractMesh>();
 
@@ -799,7 +818,9 @@ export class GLTFLoader implements IGLTFLoader {
             this._createMorphTargets(context, node, mesh, primitive, babylonMesh);
             promises.push(this._loadVertexDataAsync(context, primitive, babylonMesh).then((babylonGeometry) => {
                 return this._loadMorphTargetsAsync(context, primitive, babylonMesh, babylonGeometry).then(() => {
+                    this._babylonScene._blockEntityCollection = this._forAssetContainer;
                     babylonGeometry.applyToMesh(babylonMesh);
+                    this._babylonScene._blockEntityCollection = false;
                 });
             }));
 
@@ -1692,7 +1713,7 @@ export class GLTFLoader implements IGLTFLoader {
                 promises.push(this.loadTextureInfoAsync(`${context}/metallicRoughnessTexture`, properties.metallicRoughnessTexture, (texture) => {
                     texture.name = `${babylonMaterial.name} (Metallic Roughness)`;
                     babylonMaterial.metallicTexture = texture;
-                }));
+                }, false));
 
                 babylonMaterial.useMetallnessFromMetallicTextureBlue = true;
                 babylonMaterial.useRoughnessFromMetallicTextureGreen = true;
@@ -1833,7 +1854,7 @@ export class GLTFLoader implements IGLTFLoader {
             promises.push(this.loadTextureInfoAsync(`${context}/normalTexture`, material.normalTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Normal)`;
                 babylonMaterial.bumpTexture = texture;
-            }));
+            }, false));
 
             babylonMaterial.invertNormalMapX = !this._babylonScene.useRightHandedSystem;
             babylonMaterial.invertNormalMapY = this._babylonScene.useRightHandedSystem;
@@ -1848,7 +1869,7 @@ export class GLTFLoader implements IGLTFLoader {
             promises.push(this.loadTextureInfoAsync(`${context}/occlusionTexture`, material.occlusionTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Occlusion)`;
                 babylonMaterial.ambientTexture = texture;
-            }));
+            }, false));
 
             babylonMaterial.useAmbientInGrayScale = true;
             if (material.occlusionTexture.strength != undefined) {
@@ -1911,10 +1932,11 @@ export class GLTFLoader implements IGLTFLoader {
      * @param context The context when loading the asset
      * @param textureInfo The glTF texture info property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete
      */
-    public loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void = () => { }): Promise<BaseTexture> {
-        const extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign);
+    public loadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void = () => { }, isColorData = true): Promise<BaseTexture> {
+        const extensionPromise = this._extensionsLoadTextureInfoAsync(context, textureInfo, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -1931,7 +1953,7 @@ export class GLTFLoader implements IGLTFLoader {
             GLTFLoader.AddPointerMetadata(babylonTexture, context);
             this._parent.onTextureLoadedObservable.notifyObservers(babylonTexture);
             assign(babylonTexture);
-        });
+        }, isColorData);
 
         this.logClose();
 
@@ -1939,8 +1961,8 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     /** @hidden */
-    public _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void = () => { }): Promise<BaseTexture> {
-        const extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign);
+    public _loadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void = () => { }, isColorData = true): Promise<BaseTexture> {
+        const extensionPromise = this._extensionsLoadTextureAsync(context, texture, assign, isColorData);
         if (extensionPromise) {
             return extensionPromise;
         }
@@ -1957,7 +1979,7 @@ export class GLTFLoader implements IGLTFLoader {
     }
 
     /** @hidden */
-    public _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign: (babylonTexture: BaseTexture) => void = () => { }): Promise<BaseTexture> {
+    public _createTextureAsync(context: string, sampler: ISampler, image: IImage, assign: (babylonTexture: BaseTexture) => void = () => { }, textureLoaderOptions?: any): Promise<BaseTexture> {
         const samplerData = this._loadSampler(`/samplers/${sampler.index}`, sampler);
 
         const promises = new Array<Promise<any>>();
@@ -1972,7 +1994,7 @@ export class GLTFLoader implements IGLTFLoader {
             if (!this._disposed) {
                 deferred.reject(new Error(`${context}: ${(exception && exception.message) ? exception.message : message || "Failed to load texture"}`));
             }
-        }, undefined, undefined, undefined, image.mimeType);
+        }, undefined, undefined, undefined, image.mimeType, textureLoaderOptions);
         this._babylonScene._blockEntityCollection = false;
         promises.push(deferred.promise);
 
@@ -2317,12 +2339,12 @@ export class GLTFLoader implements IGLTFLoader {
         return this._applyExtensions(material, "loadMaterialProperties", (extension) => extension.loadMaterialPropertiesAsync && extension.loadMaterialPropertiesAsync(context, material, babylonMaterial));
     }
 
-    private _extensionsLoadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>> {
-        return this._applyExtensions(textureInfo, "loadTextureInfo", (extension) => extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign));
+    private _extensionsLoadTextureInfoAsync(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>> {
+        return this._applyExtensions(textureInfo, "loadTextureInfo", (extension) => extension.loadTextureInfoAsync && extension.loadTextureInfoAsync(context, textureInfo, assign, isColorData));
     }
 
-    private _extensionsLoadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>> {
-        return this._applyExtensions(texture, "loadTexture", (extension) => extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign));
+    private _extensionsLoadTextureAsync(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>> {
+        return this._applyExtensions(texture, "loadTexture", (extension) => extension._loadTextureAsync && extension._loadTextureAsync(context, texture, assign, isColorData));
     }
 
     private _extensionsLoadAnimationAsync(context: string, animation: IAnimation): Nullable<Promise<AnimationGroup>> {

+ 4 - 2
loaders/src/glTF/2.0/glTFLoaderExtension.ts

@@ -107,9 +107,10 @@ export interface IGLTFLoaderExtension extends IGLTFBaseLoaderExtension, IDisposa
      * @param context The context when loading the asset
      * @param textureInfo The glTF texture info property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
      */
-    loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+    loadTextureInfoAsync?(context: string, textureInfo: ITextureInfo, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
 
     /**
      * @hidden
@@ -117,9 +118,10 @@ export interface IGLTFLoaderExtension extends IGLTFBaseLoaderExtension, IDisposa
      * @param context The context when loading the asset
      * @param texture The glTF texture property
      * @param assign A function called synchronously after parsing the glTF properties
+     * @param isColorData true if the texture held color data, else false
      * @returns A promise that resolves with the loaded Babylon texture when the load is complete or null if not handled
      */
-    _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void): Nullable<Promise<BaseTexture>>;
+    _loadTextureAsync?(context: string, texture: ITexture, assign: (babylonTexture: BaseTexture) => void, isColorData: boolean): Nullable<Promise<BaseTexture>>;
 
     /**
      * Define this method to modify the default behavior when loading animations.

+ 3 - 0
loaders/src/glTF/glTFFileLoader.ts

@@ -21,6 +21,7 @@ import { Light } from 'babylonjs/Lights/light';
 import { TransformNode } from 'babylonjs/Meshes/transformNode';
 import { RequestFileError } from 'babylonjs/Misc/fileTools';
 import { StringTools } from 'babylonjs/Misc/stringTools';
+import { Geometry } from 'babylonjs/Meshes/geometry';
 
 interface IFileRequestInfo extends IFileRequest {
     _lengthComputable?: boolean;
@@ -122,6 +123,7 @@ export enum GLTFLoaderState {
 /** @hidden */
 export interface IImportMeshAsyncOutput {
     meshes: AbstractMesh[];
+    geometries: Geometry[];
     particleSystems: IParticleSystem[];
     skeletons: Skeleton[];
     animationGroups: AnimationGroup[];
@@ -650,6 +652,7 @@ export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISc
             });
 
             return this._loader.importMeshAsync(null, scene, true, data, rootUrl, onProgress, fileName).then((result) => {
+                Array.prototype.push.apply(container.geometries, result.geometries);
                 Array.prototype.push.apply(container.meshes, result.meshes);
                 Array.prototype.push.apply(container.particleSystems, result.particleSystems);
                 Array.prototype.push.apply(container.skeletons, result.skeletons);

+ 50 - 2
nodeEditor/src/components/propertyTab/propertyTab.scss

@@ -128,6 +128,31 @@
         }
     }
     
+    .textInputArea {
+        padding-left: $line-padding-left;
+        height: 100%;
+        display: grid;
+        grid-template-columns: 1fr 120px;
+
+        .label {
+            grid-column: 1;
+            display: flex;
+            align-items: center;
+        }
+
+        .value {                        
+            display: flex;
+            align-items: center;
+            grid-column: 2;
+            
+            textarea {
+                width: calc(150% - 5px);
+                margin-left: -50%;
+                height: 40px;
+            }
+        }
+    }
+    
     .paneContainer {
         margin-top: 3px;
         display:grid;
@@ -237,7 +262,7 @@
     .gradient-step {
         display: grid;
         grid-template-rows: 100%;
-        grid-template-columns: 30px 30px 40px auto 20px 30px;
+        grid-template-columns: 20px 30px 40px auto 20px 30px;
         padding-top: 5px;
         padding-left: 5px;
         padding-bottom: 5px;
@@ -267,7 +292,8 @@
             display: grid;
             justify-content: stretch;
             align-content: center;
-            margin-right: 5px;
+            margin-right: -5px;
+            padding-left: 12px;
 
             input {
                 width: 90%;
@@ -331,6 +357,28 @@
                 width: 110px;
             }
         }
+
+        .short {
+            grid-column: 2;
+            
+            display: flex;
+            align-items: center;
+            
+            input {
+                width: 27px;
+
+            }
+            
+            input::-webkit-outer-spin-button,
+            input::-webkit-inner-spin-button {
+              -webkit-appearance: none;
+              margin: 0;
+            }
+
+            input[type=number] {
+                -moz-appearance: textfield;
+            }
+        }
     }
 
     .vector3Line {

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

@@ -34,6 +34,7 @@ import { isFramePortData } from '../../diagram/graphCanvas';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
 import { PreviewType } from '../preview/previewType';
+import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
@@ -369,6 +370,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                         <OptionsLineComponent ref={this._modeSelect} label="Mode" target={this} getSelection={(target) => this.props.globalState.mode} options={modeList} onSelect={(value) => this.changeMode(value)} />
                         <TextLineComponent label="Version" value={Engine.Version}/>
                         <TextLineComponent label="Help" value="doc.babylonjs.com" underline={true} onLink={() => window.open('https://doc.babylonjs.com/how_to/node_material', '_blank')}/>
+                        <TextInputLineComponent label="Comment" multilines={true} value={this.props.globalState.nodeMaterial!.comment} target={this.props.globalState.nodeMaterial} propertyName="comment" globalState={this.props.globalState}/>
                         <ButtonLineComponent label="Reset to default" onClick={() => {
                             switch (this.props.globalState.mode) {
                                 case NodeMaterialModes.Material:

+ 11 - 1
nodeEditor/src/diagram/properties/gradientStepComponent.tsx

@@ -3,6 +3,7 @@ import { GlobalState } from '../../globalState';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { GradientBlockColorStep } from 'babylonjs/Materials/Node/Blocks/gradientBlock';
 import { ColorPickerLineComponent } from '../../sharedComponents/colorPickerComponent';
+import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
 
 const deleteButton = require('../../../imgs/delete.svg');
 const copyIcon: string = require('../../sharedComponents/copy.svg');
@@ -46,6 +47,7 @@ export class GradientStepComponent extends React.Component<IGradientStepComponen
 
     render() {
         let step = this.props.step;
+        
         return (
             <div className="gradient-step">
                 <div className="step">
@@ -59,7 +61,15 @@ export class GradientStepComponent extends React.Component<IGradientStepComponen
                     />  
                 </div>
                 <div className="step-value">
-                    {step.step.toFixed(2)}
+                    <FloatLineComponent globalState={this.props.globalState} smallUI={true} label="" target={step} propertyName="step"
+                    min={0} max={1}
+                    onEnter={ evt => { 
+                            this.props.onUpdateStep();
+                            this.props.onCheckForReOrder();
+                            this.forceUpdate();
+                        }
+                    } 
+                    ></FloatLineComponent>
                 </div>
                 <div className="step-slider">
                     <input className="range" type="range" step={0.01} min={0} max={1.0} value={step.step}

+ 145 - 115
nodeEditor/src/sharedComponents/floatLineComponent.tsx

@@ -1,115 +1,145 @@
-import * as React from "react";
-
-import { Observable } from "babylonjs/Misc/observable";
-import { PropertyChangedEvent } from "./propertyChangedEvent";
-import { GlobalState } from '../globalState';
-
-interface IFloatLineComponentProps {
-    label: string;
-    target: any;
-    propertyName: string;
-    onChange?: (newValue: number) => void;
-    isInteger?: boolean;
-    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
-    additionalClass?: string;
-    step?: string,
-    digits?: number;
-    globalState: GlobalState
-}
-
-export class FloatLineComponent extends React.Component<IFloatLineComponentProps, { value: string }> {
-    private _localChange = false;
-    private _store: number;
-
-    constructor(props: IFloatLineComponentProps) {
-        super(props);
-
-        let currentValue = this.props.target[this.props.propertyName];
-        this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(this.props.digits || 2)) : "0" };
-        this._store = currentValue;
-    }
-
-    shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: { value: string }) {
-        if (this._localChange) {
-            this._localChange = false;
-            return true;
-        }
-
-        const newValue = nextProps.target[nextProps.propertyName];
-        const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(this.props.digits || 2) : "0";
-
-        if (newValueString !== nextState.value) {
-            nextState.value = newValueString;
-            return true;
-        }
-        return false;
-    }
-
-    raiseOnPropertyChanged(newValue: number, previousValue: number) {
-        if (this.props.onChange) {
-            this.props.onChange(newValue);
-        }
-
-        if (!this.props.onPropertyChangedObservable) {
-            return;
-        }
-        this.props.onPropertyChangedObservable.notifyObservers({
-            object: this.props.target,
-            property: this.props.propertyName,
-            value: newValue,
-            initialValue: previousValue
-        });
-    }
-
-    updateValue(valueString: string) {
-
-        if (/[^0-9\.\-]/g.test(valueString)) {
-            return;
-        }
-
-        valueString = valueString.replace(/(.+\...).+/, "$1");
-
-        let valueAsNumber: number;
-
-        if (this.props.isInteger) {
-            valueAsNumber = parseInt(valueString);
-        } else {
-            valueAsNumber = parseFloat(valueString);
-        }
-
-
-        this._localChange = true;
-        this.setState({ value: valueString});
-
-        if (isNaN(valueAsNumber)) {
-            return;
-        }
-
-        this.props.target[this.props.propertyName] = valueAsNumber;
-        this.raiseOnPropertyChanged(valueAsNumber, this._store);
-
-        this._store = valueAsNumber;
-    }
-
-    render() {
-        return (
-            <div>
-                {
-                    <div className={this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine"}>
-                        <div className="label">
-                            {this.props.label}
-                        </div>
-                        <div className="value">
-                            <input type="number" step={this.props.step || "0.01"} className="numeric-input" 
-                            onBlur={evt => {
-                                this.props.globalState.blockKeyboardEvents = false;
-                            }}
-                            onFocus={() => this.props.globalState.blockKeyboardEvents = true}
-                            value={this.state.value} onChange={evt => this.updateValue(evt.target.value)} />
-                        </div>
-                    </div>
-                }
-            </div>
-        );
-    }
-}
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { PropertyChangedEvent } from "./propertyChangedEvent";
+import { GlobalState } from '../globalState';
+
+interface IFloatLineComponentProps {
+    label: string;
+    target: any;
+    propertyName: string;
+    onChange?: (newValue: number) => void;
+    isInteger?: boolean;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    additionalClass?: string;
+    step?: string;
+    digits?: number;
+    globalState: GlobalState;
+    min?: number
+    max?: number
+    smallUI?: boolean;
+    onEnter?: (newValue:number) => void;
+}
+
+export class FloatLineComponent extends React.Component<IFloatLineComponentProps, { value: string }> {
+    private _localChange = false;
+    private _store: number;
+    private _regExp: RegExp;
+
+    constructor(props: IFloatLineComponentProps) {
+        super(props);
+        let currentValue = this.props.target[this.props.propertyName];
+        this.state = { value: currentValue ? (this.props.isInteger ? currentValue.toFixed(0) : currentValue.toFixed(this.props.digits || 2)) : "0" };
+        this._store = currentValue;
+
+        let rexp = "(.*\\.";
+        let numDigits = this.props.digits || 2;
+        while (numDigits--) {
+            rexp += ".";
+        }
+        rexp += ").+";
+
+        this._regExp = new RegExp(rexp);
+    }
+
+    shouldComponentUpdate(nextProps: IFloatLineComponentProps, nextState: { value: string }) {
+        if (this._localChange) {
+            this._localChange = false;
+            return true;
+        }
+
+        const newValue = nextProps.target[nextProps.propertyName];
+        const newValueString = newValue ? this.props.isInteger ? newValue.toFixed(0) : newValue.toFixed(this.props.digits || 2) : "0";
+
+        if (newValueString !== nextState.value) {
+            nextState.value = newValueString;
+            return true;
+        }
+        return false;
+    }
+
+    raiseOnPropertyChanged(newValue: number, previousValue: number) {
+        if (this.props.onChange) {
+            this.props.onChange(newValue);
+        }
+
+        if (!this.props.onPropertyChangedObservable) {
+            return;
+        }
+        this.props.onPropertyChangedObservable.notifyObservers({
+            object: this.props.target,
+            property: this.props.propertyName,
+            value: newValue,
+            initialValue: previousValue
+        });
+    }
+
+    updateValue(valueString: string) {
+        if (/[^0-9\.\-]/g.test(valueString)) {
+            return;
+        }
+
+        valueString = valueString.replace(this._regExp, "$1");
+
+        let valueAsNumber: number;
+
+        if (this.props.isInteger) {
+            valueAsNumber = parseInt(valueString);
+        } else {
+            valueAsNumber = parseFloat(valueString);
+        }
+
+        this._localChange = true;
+        this.setState({ value: valueString});
+
+        if (isNaN(valueAsNumber)) {
+            return;
+        }
+        if(this.props.max != undefined && (valueAsNumber > this.props.max)) {
+            valueAsNumber = this.props.max;
+        }
+        if(this.props.min != undefined && (valueAsNumber < this.props.min)) {
+            valueAsNumber = this.props.min;
+        }
+
+        this.props.target[this.props.propertyName] = valueAsNumber;
+        this.raiseOnPropertyChanged(valueAsNumber, this._store);
+
+        this._store = valueAsNumber;
+    }
+
+    render() {
+        let className = this.props.smallUI ? "short": "value";
+
+        return (
+            <div>
+                {
+                    <div className={this.props.additionalClass ? this.props.additionalClass + " floatLine" : "floatLine"}>
+                        <div className="label">
+                            {this.props.label}
+                        </div>
+                        <div className={className}>
+                            <input type="number" step={this.props.step || "0.01"} className="numeric-input"
+                            onBlur={(evt) => {
+                                this.props.globalState.blockKeyboardEvents = false;
+                                if(this.props.onEnter) {
+                                    this.props.onEnter(this._store);
+                                }
+                            }}
+                            onKeyDown={evt => {
+                                if (evt.keyCode !== 13) {
+                                    return;
+                                }
+                                if(this.props.onEnter) {
+                                    this.props.onEnter(this._store);
+                                }
+                            }}
+                            onFocus={() => this.props.globalState.blockKeyboardEvents = true}
+                            value={this.state.value} onChange={(evt) => this.updateValue(evt.target.value)} />
+                        </div>
+                    </div>
+                }
+            </div>
+        );
+    }
+}

+ 33 - 16
nodeEditor/src/sharedComponents/textInputLineComponent.tsx

@@ -9,6 +9,7 @@ interface ITextInputLineComponentProps {
     target?: any;
     propertyName?: string;
     value?: string;
+    multilines?: boolean;
     onChange?: (value: string) => void;
     validator?: (value: string) => boolean;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
@@ -20,7 +21,7 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
     constructor(props: ITextInputLineComponentProps) {
         super(props);
 
-        this.state = { value: this.props.value !== undefined ? this.props.value : this.props.target[this.props.propertyName!] || "" }
+        this.state = { value: this.props.value !== undefined ? this.props.value : this.props.target[this.props.propertyName!] || "" };
     }
 
     shouldComponentUpdate(nextProps: ITextInputLineComponentProps, nextState: { value: string }) {
@@ -60,8 +61,8 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
         this._localChange = true;
         const store = this.props.value !== undefined ? this.props.value : this.props.target[this.props.propertyName!];
 
-        if(this.props.validator && raisePropertyChanged) {
-            if(this.props.validator(value) == false) {
+        if (this.props.validator && raisePropertyChanged) {
+            if (this.props.validator(value) == false) {
                 value = store;
             }
         }
@@ -79,23 +80,39 @@ export class TextInputLineComponent extends React.Component<ITextInputLineCompon
 
     render() {
         return (
-            <div className="textInputLine">
+            <div className={this.props.multilines ? "textInputArea" : "textInputLine"}>
                 <div className="label">
                     {this.props.label}
                 </div>
                 <div className="value">
-                    <input value={this.state.value} 
-                        onFocus={() => this.props.globalState.blockKeyboardEvents = true}
-                        onChange={evt => this.updateValue(evt.target.value, false)}
-                        onKeyDown={evt => {
-                            if (evt.keyCode !== 13) {
-                                return;
-                            }
-                            this.updateValue(this.state.value, true);
-                        }} onBlur={evt => {
-                            this.updateValue(evt.target.value, true)
-                            this.props.globalState.blockKeyboardEvents = false;
-                        }}/>
+                    {this.props.multilines && <>
+                        <textarea value={this.state.value}
+                            onFocus={() => this.props.globalState.blockKeyboardEvents = true}
+                            onChange={(evt) => this.updateValue(evt.target.value, false)}
+                            onKeyDown={(evt) => {
+                                if (evt.keyCode !== 13) {
+                                    return;
+                                }
+                                this.updateValue(this.state.value, true);
+                            }} onBlur={(evt) => {
+                                this.updateValue(evt.target.value, true);
+                                this.props.globalState.blockKeyboardEvents = false;
+                            }}/>
+                    </>}
+                    {!this.props.multilines && <>
+                        <input value={this.state.value}
+                            onFocus={() => this.props.globalState.blockKeyboardEvents = true}
+                            onChange={(evt) => this.updateValue(evt.target.value, false)}
+                            onKeyDown={(evt) => {
+                                if (evt.keyCode !== 13) {
+                                    return;
+                                }
+                                this.updateValue(this.state.value, true);
+                            }} onBlur={(evt) => {
+                                this.updateValue(evt.target.value, true);
+                                this.props.globalState.blockKeyboardEvents = false;
+                            }}/>
+                        </>}
                 </div>
             </div>
         );

+ 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-beta.10",
+    "version": "4.2.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 8 - 0
sandbox/public/index-local.html

@@ -35,6 +35,14 @@
         BABYLONDEVTOOLS.Loader
             .require("index.js")
             .load(() => {
+                BABYLON.DracoCompression.Configuration.decoder = {
+                    wasmUrl: "../../dist/preview%20release/draco_wasm_wrapper_gltf.js",
+                    wasmBinaryUrl: "../../dist/preview%20release/draco_decoder_gltf.wasm",
+                    fallbackUrl: "../../dist/preview%20release/draco_decoder_gltf.js"
+                };
+                BABYLON.GLTFValidation.Configuration = {
+                    url: "../../dist/preview%20release/gltf_validator.js"
+                };
             });
     </script>
 </body>

+ 6 - 9
sandbox/public/index.html

@@ -4,8 +4,7 @@
 <head>
     <title>Babylon.js Sandbox - View glTF, glb, obj and babylon files</title>
     <meta name="description" content="Viewer for glTF, glb, obj and babylon files powered by Babylon.js" />
-    <meta name="keywords"
-        content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
+    <meta name="keywords" content="Babylon.js, Babylon, BabylonJS, glTF, glb, obj, viewer, online viewer, 3D model viewer, 3D, webgl" />
     <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
     <link rel="stylesheet" href="https://use.typekit.net/cta4xsb.css">
     <link rel="shortcut icon" href="https://www.babylonjs.com/favicon.ico">
@@ -20,10 +19,9 @@
     <script src="https://preview.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
     <script src="https://preview.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
 
-    
     <script src="https://preview.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
     <script src="dist/babylon.sandbox.js"></script>
-    
+
     <style>
         html,
         body {
@@ -36,17 +34,16 @@
 
         #host-element {
             width: 100%;
-            height: 100%;               
+            height: 100%;
             padding: 0;
             margin: 0;
-            overflow: hidden;         
+            overflow: hidden;
         }
     </style>
 </head>
 
-<body>    
-    <div id="host-element">
-    </div>
+<body>
+    <div id="host-element"></div>
     <script src="index.js"></script>
 </body>
 

+ 189 - 0
src/Cameras/Inputs/BaseCameraMouseWheelInput.ts

@@ -0,0 +1,189 @@
+import { Nullable } from "../../types";
+import { serialize } from "../../Misc/decorators";
+import { Observable, Observer } from "../../Misc/observable";
+import { Camera } from "../../Cameras/camera";
+import { ICameraInput } from "../../Cameras/cameraInputsManager";
+import { PointerInfo, PointerEventTypes } from "../../Events/pointerEvents";
+
+/**
+ * Base class for mouse wheel input..
+ * See FollowCameraMouseWheelInput in src/Cameras/Inputs/freeCameraMouseWheelInput.ts
+ * for example usage.
+ */
+export abstract class BaseCameraMouseWheelInput implements ICameraInput<Camera> {
+    /**
+     * Defines the camera the input is attached to.
+     */
+    public abstract camera: Camera;
+
+    /**
+     * How fast is the camera moves in relation to X axis mouseWheel events.
+     * Use negative value to reverse direction.
+     */
+    @serialize()
+    public wheelPrecisionX = 3.0;
+
+    /**
+     * How fast is the camera moves in relation to Y axis mouseWheel events.
+     * Use negative value to reverse direction.
+     */
+    @serialize()
+    public wheelPrecisionY = 3.0;
+
+    /**
+     * How fast is the camera moves in relation to Z axis mouseWheel events.
+     * Use negative value to reverse direction.
+     */
+    @serialize()
+    public wheelPrecisionZ = 3.0;
+
+    /**
+     * Observable for when a mouse wheel move event occurs.
+     */
+    public onChangedObservable = new Observable<
+        {wheelDeltaX: number, wheelDeltaY: number, wheelDeltaZ: number}>();
+
+    private _wheel: Nullable<(pointer: PointerInfo) => void>;
+    private _observer: Nullable<Observer<PointerInfo>>;
+
+    /**
+     * Attach the input controls to a specific dom element to get the input from.
+     * @param element Defines the element the controls should be listened from
+     * @param noPreventDefault Defines whether event caught by the controls
+     *   should call preventdefault().
+     *   (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
+     */
+    public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+        this._wheel = (pointer) => {
+            // sanity check - this should be a PointerWheel event.
+            if (pointer.type !== PointerEventTypes.POINTERWHEEL) { return; }
+
+            const event = <MouseWheelEvent>pointer.event;
+
+            const platformScale =
+                event.deltaMode === WheelEvent.DOM_DELTA_LINE ? this._ffMultiplier : 1;
+
+            if (event.deltaY !== undefined) {
+                // Most recent browsers versions have delta properties.
+                // Firefox >= v17  (Has WebGL >= v4)
+                // Chrome >=  v31  (Has WebGL >= v8)
+                // Edge >=    v12  (Has WebGl >= v12)
+                // https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
+                this._wheelDeltaX +=
+                    this.wheelPrecisionX * platformScale * event.deltaX / this._normalize;
+                this._wheelDeltaY -=
+                    this.wheelPrecisionY * platformScale * event.deltaY / this._normalize;
+                this._wheelDeltaZ +=
+                    this.wheelPrecisionZ * platformScale * event.deltaZ / this._normalize;
+            } else if ((<any>event).wheelDeltaY !== undefined) {
+                // Unsure whether these catch anything more. Documentation
+                // online is contradictory.
+                this._wheelDeltaX +=
+                    this.wheelPrecisionX * platformScale *
+                    (<any>event).wheelDeltaX / this._normalize;
+                this._wheelDeltaY -=
+                    this.wheelPrecisionY * platformScale *
+                    (<any>event).wheelDeltaY / this._normalize;
+                this._wheelDeltaZ +=
+                    this.wheelPrecisionZ * platformScale *
+                    (<any>event).wheelDeltaZ / this._normalize;
+            } else if ((<any>event).wheelDelta) {
+                // IE >= v9   (Has WebGL >= v11)
+                // Maybe others?
+                this._wheelDeltaY -=
+                    this.wheelPrecisionY * (<any>event).wheelDelta / this._normalize;
+            }
+
+            if (event.preventDefault) {
+                if (!noPreventDefault) {
+                    event.preventDefault();
+                }
+            }
+        };
+
+        this._observer = this.camera.getScene().onPointerObservable.add(
+            this._wheel,
+            PointerEventTypes.POINTERWHEEL);
+    }
+
+    /**
+     * Detach the current controls from the specified dom element.
+     * @param element Defines the element to stop listening the inputs from
+     */
+    public detachControl(element: Nullable<HTMLElement>): void {
+        if (this._observer) {
+            this.camera.getScene().onPointerObservable.remove(this._observer);
+            this._observer = null;
+            this._wheel = null;
+        }
+        if (this.onChangedObservable) {
+            this.onChangedObservable.clear();
+        }
+    }
+
+    /**
+     * Called for each rendered frame.
+     */
+    public checkInputs(): void {
+        this.onChangedObservable.notifyObservers({
+            wheelDeltaX: this._wheelDeltaX,
+            wheelDeltaY: this._wheelDeltaY,
+            wheelDeltaZ: this._wheelDeltaZ
+        });
+
+        // Clear deltas.
+        this._wheelDeltaX = 0;
+        this._wheelDeltaY = 0;
+        this._wheelDeltaZ = 0;
+    }
+
+    /**
+     * Gets the class name of the current intput.
+     * @returns the class name
+     */
+    public getClassName(): string {
+        return "BaseCameraMouseWheelInput";
+    }
+
+    /**
+     * Get the friendly name associated with the input class.
+     * @returns the input friendly name
+     */
+    public getSimpleName(): string {
+        return "mousewheel";
+    }
+
+    /**
+     * Incremental value of multiple mouse wheel movements of the X axis.
+     * Should be zero-ed when read.
+     */
+    protected _wheelDeltaX: number = 0;
+
+    /**
+     * Incremental value of multiple mouse wheel movements of the Y axis.
+     * Should be zero-ed when read.
+     */
+    protected _wheelDeltaY: number = 0;
+
+    /**
+     * Incremental value of multiple mouse wheel movements of the Z axis.
+     * Should be zero-ed when read.
+     */
+    protected _wheelDeltaZ: number = 0;
+
+    /**
+     * Firefox uses a different scheme to report scroll distances to other
+     * browsers. Rather than use complicated methods to calculate the exact
+     * multiple we need to apply, let's just cheat and use a constant.
+     * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
+     * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
+     */
+    private readonly _ffMultiplier = 12;
+
+    /**
+     * Different event attributes for wheel data fall into a few set ranges.
+     * Some relevant but dated date here:
+     * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers
+     */
+    private readonly _normalize = 120;
+}

+ 6 - 2
src/Cameras/Inputs/freeCameraGamepadInput.ts

@@ -78,7 +78,12 @@ export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
             }
         });
 
+        // check if there are already other controllers connected
         this.gamepad = manager.getGamepadByType(Gamepad.XBOX);
+        // if no xbox controller was found, but there are gamepad controllers, take the first one
+        if (!this.gamepad && manager.gamepads.length) {
+            this.gamepad = manager.gamepads[0];
+        }
     }
 
     /**
@@ -110,8 +115,7 @@ export class FreeCameraGamepadInput implements ICameraInput<FreeCamera> {
                 var normalizedRY = (RSValues.y / this.gamepadAngularSensibility) * this._yAxisScale;
                 RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
                 RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
-            }
-            else {
+            } else {
                 RSValues = { x: 0, y: 0 };
             }
 

+ 393 - 0
src/Cameras/Inputs/freeCameraMouseWheelInput.ts

@@ -0,0 +1,393 @@
+import { Nullable } from "../../types";
+import { serialize } from "../../Misc/decorators";
+import { FreeCamera } from "../../Cameras/freeCamera";
+import { CameraInputTypes } from "../../Cameras/cameraInputsManager";
+import { BaseCameraMouseWheelInput } from "../../Cameras/Inputs/BaseCameraMouseWheelInput";
+import { Matrix, Vector3 } from "../../Maths/math.vector";
+import { Coordinate } from "../../Maths/math.axis";
+
+enum _CameraProperty {
+    MoveRelative,
+    RotateRelative,
+    MoveScene
+}
+
+/**
+ * Manage the mouse wheel inputs to control a free camera.
+ * @see https://doc.babylonjs.com/how_to/customizing_camera_inputs
+ */
+export class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput {
+
+    /**
+     * Defines the camera the input is attached to.
+     */
+    public camera: FreeCamera;
+
+    /**
+     * Gets the class name of the current input.
+     * @returns the class name
+     */
+    public getClassName(): string {
+        return "FreeCameraMouseWheelInput";
+    }
+
+    /**
+     * Set which movement axis (relative to camera's orientation) the mouse
+     * wheel's X axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelXMoveRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelXAction !== _CameraProperty.MoveRelative) {
+            // Attempting to clear different _wheelXAction.
+            return;
+        }
+        this._wheelXAction = _CameraProperty.MoveRelative;
+        this._wheelXActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to camera's orientation) the
+     * mouse wheel's X axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelXMoveRelative(): Nullable<Coordinate> {
+        if (this._wheelXAction !== _CameraProperty.MoveRelative) {
+            return null;
+        }
+        return this._wheelXActionCoordinate;
+    }
+
+    /**
+     * Set which movement axis (relative to camera's orientation) the mouse
+     * wheel's Y axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelYMoveRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelYAction !== _CameraProperty.MoveRelative) {
+            // Attempting to clear different _wheelYAction.
+            return;
+        }
+        this._wheelYAction = _CameraProperty.MoveRelative;
+        this._wheelYActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to camera's orientation) the
+     * mouse wheel's Y axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelYMoveRelative(): Nullable<Coordinate> {
+        if (this._wheelYAction !== _CameraProperty.MoveRelative) {
+            return null;
+        }
+        return this._wheelYActionCoordinate;
+    }
+
+    /**
+     * Set which movement axis (relative to camera's orientation) the mouse
+     * wheel's Z axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelZMoveRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelZAction !== _CameraProperty.MoveRelative) {
+            // Attempting to clear different _wheelZAction.
+            return;
+        }
+        this._wheelZAction = _CameraProperty.MoveRelative;
+        this._wheelZActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to camera's orientation) the
+     * mouse wheel's Z axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelZMoveRelative(): Nullable<Coordinate> {
+        if (this._wheelZAction !== _CameraProperty.MoveRelative) {
+            return null;
+        }
+        return this._wheelZActionCoordinate;
+    }
+
+    /**
+     * Set which rotation axis (relative to camera's orientation) the mouse
+     * wheel's X axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelXRotateRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelXAction !== _CameraProperty.RotateRelative) {
+            // Attempting to clear different _wheelXAction.
+            return;
+        }
+        this._wheelXAction = _CameraProperty.RotateRelative;
+        this._wheelXActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured rotation axis (relative to camera's orientation) the
+     * mouse wheel's X axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelXRotateRelative(): Nullable<Coordinate> {
+        if (this._wheelXAction !== _CameraProperty.RotateRelative) {
+            return null;
+        }
+        return this._wheelXActionCoordinate;
+    }
+
+    /**
+     * Set which rotation axis (relative to camera's orientation) the mouse
+     * wheel's Y axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelYRotateRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelYAction !== _CameraProperty.RotateRelative) {
+            // Attempting to clear different _wheelYAction.
+            return;
+        }
+        this._wheelYAction = _CameraProperty.RotateRelative;
+        this._wheelYActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured rotation axis (relative to camera's orientation) the
+     * mouse wheel's Y axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelYRotateRelative(): Nullable<Coordinate> {
+        if (this._wheelYAction !== _CameraProperty.RotateRelative) {
+            return null;
+        }
+        return this._wheelYActionCoordinate;
+    }
+
+    /**
+     * Set which rotation axis (relative to camera's orientation) the mouse
+     * wheel's Z axis controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelZRotateRelative(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelZAction !== _CameraProperty.RotateRelative) {
+            // Attempting to clear different _wheelZAction.
+            return;
+        }
+        this._wheelZAction = _CameraProperty.RotateRelative;
+        this._wheelZActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured rotation axis (relative to camera's orientation) the
+     * mouse wheel's Z axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelZRotateRelative(): Nullable<Coordinate> {
+        if (this._wheelZAction !== _CameraProperty.RotateRelative) {
+            return null;
+        }
+        return this._wheelZActionCoordinate;
+    }
+
+    /**
+     * Set which movement axis (relative to the scene) the mouse wheel's X axis
+     * controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelXMoveScene(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelXAction !== _CameraProperty.MoveScene) {
+            // Attempting to clear different _wheelXAction.
+            return;
+        }
+        this._wheelXAction = _CameraProperty.MoveScene;
+        this._wheelXActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to the scene) the mouse wheel's
+     * X axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelXMoveScene(): Nullable<Coordinate> {
+        if (this._wheelXAction !== _CameraProperty.MoveScene) {
+            return null;
+        }
+        return this._wheelXActionCoordinate;
+    }
+
+    /**
+     * Set which movement axis (relative to the scene) the mouse wheel's Y axis
+     * controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelYMoveScene(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelYAction !== _CameraProperty.MoveScene) {
+            // Attempting to clear different _wheelYAction.
+            return;
+        }
+        this._wheelYAction = _CameraProperty.MoveScene;
+        this._wheelYActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to the scene) the mouse wheel's
+     * Y axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelYMoveScene(): Nullable<Coordinate> {
+        if (this._wheelYAction !== _CameraProperty.MoveScene) {
+            return null;
+        }
+        return this._wheelYActionCoordinate;
+    }
+
+    /**
+     * Set which movement axis (relative to the scene) the mouse wheel's Z axis
+     * controls.
+     * @param axis The axis to be moved. Set null to clear.
+     */
+    @serialize()
+    public set wheelZMoveScene(axis: Nullable<Coordinate>) {
+        if (axis === null && this._wheelZAction !== _CameraProperty.MoveScene) {
+            // Attempting to clear different _wheelZAction.
+            return;
+        }
+        this._wheelZAction = _CameraProperty.MoveScene;
+        this._wheelZActionCoordinate = axis;
+    }
+
+    /**
+     * Get the configured movement axis (relative to the scene) the mouse wheel's
+     * Z axis controls.
+     * @returns The configured axis or null if none.
+     */
+    public get wheelZMoveScene(): Nullable<Coordinate> {
+        if (this._wheelZAction !== _CameraProperty.MoveScene) {
+            return null;
+        }
+        return this._wheelZActionCoordinate;
+    }
+
+    /**
+     * Called for each rendered frame.
+     */
+    public checkInputs(): void {
+        if (this._wheelDeltaX === 0 &&
+                this._wheelDeltaY === 0 &&
+                this._wheelDeltaZ == 0) {
+            return;
+        }
+
+        // Clear the camera properties that we might be updating.
+        this._moveRelative.setAll(0);
+        this._rotateRelative.setAll(0);
+        this._moveScene.setAll(0);
+
+        // Set the camera properties that are to be updated.
+        this._updateCamera();
+
+        if (this.camera.getScene().useRightHandedSystem) {
+            // TODO: Does this need done for worldUpdate too?
+            this._moveRelative.z *= -1;
+        }
+
+        // Convert updates relative to camera to world position update.
+        const cameraTransformMatrix = Matrix.Zero();
+        this.camera.getViewMatrix().invertToRef(cameraTransformMatrix);
+
+        const transformedDirection = Vector3.Zero();
+        Vector3.TransformNormalToRef(
+            this._moveRelative, cameraTransformMatrix, transformedDirection);
+
+        // Apply updates to camera position.
+        this.camera.cameraRotation.x += this._rotateRelative.x / 200;
+        this.camera.cameraRotation.y += this._rotateRelative.y / 200;
+        this.camera.cameraDirection.addInPlace(transformedDirection);
+        this.camera.cameraDirection.addInPlace(this._moveScene);
+
+        // Call the base class implementation to handle observers and do cleanup.
+        super.checkInputs();
+    }
+
+    private _moveRelative = Vector3.Zero();
+    private _rotateRelative = Vector3.Zero();
+    private _moveScene = Vector3.Zero();
+
+    /**
+     * These are set to the desired default behaviour.
+     */
+    private _wheelXAction: Nullable<_CameraProperty> = _CameraProperty.MoveRelative;
+    private _wheelXActionCoordinate: Nullable<Coordinate> = Coordinate.X;
+    private _wheelYAction: Nullable<_CameraProperty> = _CameraProperty.MoveRelative;
+    private _wheelYActionCoordinate: Nullable<Coordinate> = Coordinate.Z;
+    private _wheelZAction: Nullable<_CameraProperty> = null;
+    private _wheelZActionCoordinate: Nullable<Coordinate> = null;
+
+    /**
+     * Update the camera according to any configured properties for the 3
+     * mouse-wheel axis.
+     */
+    private _updateCamera(): void {
+        const moveRelative = this._moveRelative;
+        const rotateRelative = this._rotateRelative;
+        const moveScene = this._moveScene;
+
+        let updateCameraProperty = function(/* Mouse-wheel delta. */
+                                            value: number,
+                                            /* Camera property to be changed. */
+                                            cameraProperty: Nullable<_CameraProperty>,
+                                            /* Axis of Camera property to be changed. */
+                                            coordinate: Nullable<Coordinate>): void {
+                if (value === 0) {
+                    // Mouse wheel has not moved.
+                    return;
+                }
+                if (cameraProperty === null || coordinate === null) {
+                    // Mouse wheel axis not configured.
+                    return;
+                }
+
+                let action = null;
+                switch (cameraProperty) {
+                    case _CameraProperty.MoveRelative:
+                        action = moveRelative;
+                        break;
+                    case _CameraProperty.RotateRelative:
+                        action = rotateRelative;
+                        break;
+                    case _CameraProperty.MoveScene:
+                        action = moveScene;
+                        break;
+                }
+
+                switch (coordinate) {
+                    case Coordinate.X:
+                        action.set(value, 0, 0);
+                        break;
+                    case Coordinate.Y:
+                        action.set(0, value, 0);
+                        break;
+                    case Coordinate.Z:
+                        action.set(0, 0, value);
+                        break;
+                }
+            };
+
+        // Do the camera updates for each of the 3 touch-wheel axis.
+        updateCameraProperty(
+            this._wheelDeltaX, this._wheelXAction, this._wheelXActionCoordinate);
+        updateCameraProperty(
+            this._wheelDeltaY, this._wheelYAction, this._wheelYActionCoordinate);
+        updateCameraProperty(
+            this._wheelDeltaZ, this._wheelZAction, this._wheelZActionCoordinate);
+    }
+
+}
+
+(<any>CameraInputTypes)["FreeCameraMouseWheelInput"] = FreeCameraMouseWheelInput;

+ 1 - 0
src/Cameras/Inputs/index.ts

@@ -12,5 +12,6 @@ export * from "./freeCameraDeviceOrientationInput";
 export * from "./freeCameraGamepadInput";
 export * from "./freeCameraKeyboardMoveInput";
 export * from "./freeCameraMouseInput";
+export * from "./freeCameraMouseWheelInput";
 export * from "./freeCameraTouchInput";
 export * from "./freeCameraVirtualJoystickInput";

+ 28 - 0
src/Cameras/freeCameraInputsManager.ts

@@ -2,6 +2,7 @@ import { FreeCamera } from "./freeCamera";
 import { CameraInputsManager } from "./cameraInputsManager";
 import { FreeCameraKeyboardMoveInput } from "../Cameras/Inputs/freeCameraKeyboardMoveInput";
 import { FreeCameraMouseInput } from "../Cameras/Inputs/freeCameraMouseInput";
+import { FreeCameraMouseWheelInput } from "../Cameras/Inputs/freeCameraMouseWheelInput";
 import { FreeCameraTouchInput } from "../Cameras/Inputs/freeCameraTouchInput";
 import { Nullable } from '../types';
 
@@ -16,6 +17,10 @@ export class FreeCameraInputsManager extends CameraInputsManager<FreeCamera> {
      */
     public _mouseInput: Nullable<FreeCameraMouseInput> = null;
     /**
+     * @hidden
+     */
+    public _mouseWheelInput: Nullable<FreeCameraMouseWheelInput> = null;
+    /**
      * Instantiates a new FreeCameraInputsManager.
      * @param camera Defines the camera the inputs belong to
      */
@@ -57,6 +62,29 @@ export class FreeCameraInputsManager extends CameraInputsManager<FreeCamera> {
     }
 
     /**
+     * Add mouse wheel input support to the input manager.
+     * @returns the current input manager
+     */
+    addMouseWheel(): FreeCameraInputsManager {
+        if (!this._mouseWheelInput) {
+            this._mouseWheelInput = new FreeCameraMouseWheelInput();
+            this.add(this._mouseWheelInput);
+        }
+        return this;
+    }
+
+    /**
+     * Removes the mouse wheel input support from the manager
+     * @returns the current input manager
+     */
+    removeMouseWheel(): FreeCameraInputsManager {
+        if (this._mouseWheelInput) {
+            this.remove(this._mouseWheelInput);
+        }
+        return this;
+    }
+
+    /**
      * Add touch input support to the input manager.
      * @returns the current input manager
      */

+ 3 - 1
src/Engines/Processors/iShaderProcessor.ts

@@ -1,3 +1,5 @@
+declare type ThinEngine = import("../thinEngine").ThinEngine;
+
 /** @hidden */
 export interface IShaderProcessor {
     attributeProcessor?: (attribute: string) => string;
@@ -7,5 +9,5 @@ export interface IShaderProcessor {
     endOfUniformBufferProcessor?: (closingBracketLine: string, isFragment: boolean) => string;
     lineProcessor?: (line: string, isFragment: boolean) => string;
     preProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
-    postProcessor?: (code: string, defines: string[], isFragment: boolean) => string;
+    postProcessor?: (code: string, defines: string[], isFragment: boolean, engine: ThinEngine) => string;
 }

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

@@ -14,15 +14,16 @@ declare type WebRequest = import("../../Misc/webRequest").WebRequest;
 declare type LoadFileError = import("../../Misc/fileTools").LoadFileError;
 declare type IOfflineProvider = import("../../Offline/IOfflineProvider").IOfflineProvider;
 declare type IFileRequest  = import("../../Misc/fileRequest").IFileRequest;
+declare type ThinEngine = import("../thinEngine").ThinEngine;
 
 const regexSE = /defined\s*?\((.+?)\)/g;
 const regexSERevert = /defined\s*?\[(.+?)\]/g;
 
 /** @hidden */
 export class ShaderProcessor {
-    public static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void) {
+    public static Process(sourceCode: string, options: ProcessingOptions, callback: (migratedCode: string) => void, engine: ThinEngine) {
         this._ProcessIncludes(sourceCode, options, (codeWithIncludes) => {
-            let migratedCode = this._ProcessShaderConversion(codeWithIncludes, options);
+            let migratedCode = this._ProcessShaderConversion(codeWithIncludes, options, engine);
             callback(migratedCode);
         });
     }
@@ -253,7 +254,7 @@ export class ShaderProcessor {
         return preprocessors;
     }
 
-    private static _ProcessShaderConversion(sourceCode: string, options: ProcessingOptions): string {
+    private static _ProcessShaderConversion(sourceCode: string, options: ProcessingOptions, engine: ThinEngine): string {
 
         var preparedSourceCode = this._ProcessPrecision(sourceCode, options);
 
@@ -279,7 +280,7 @@ export class ShaderProcessor {
 
         // Post processing
         if (options.processor.postProcessor) {
-            preparedSourceCode = options.processor.postProcessor(preparedSourceCode, defines, options.isFragment);
+            preparedSourceCode = options.processor.postProcessor(preparedSourceCode, defines, options.isFragment, engine);
         }
 
         return preparedSourceCode;

+ 18 - 0
src/Engines/WebGL/webGLShaderProcessors.ts

@@ -0,0 +1,18 @@
+import { IShaderProcessor } from '../Processors/iShaderProcessor';
+
+import { ThinEngine } from '../thinEngine';
+
+/** @hidden */
+export class WebGLShaderProcessor implements IShaderProcessor {
+    public postProcessor(code: string, defines: string[], isFragment: boolean, engine: ThinEngine) {
+
+        // Remove extensions
+        if (!engine.getCaps().drawBuffersExtension) {
+            // even if enclosed in #if/#endif, IE11 does parse the #extension declaration, so we need to remove it altogether
+            var regex = /#extension.+GL_EXT_draw_buffers.+(enable|require)/g;
+            code = code.replace(regex, "");
+        }
+
+        return code;
+    }
+}

+ 5 - 2
src/Engines/thinEngine.ts

@@ -17,6 +17,7 @@ import { DataBuffer } from '../Meshes/dataBuffer';
 import { IFileRequest } from '../Misc/fileRequest';
 import { Logger } from '../Misc/logger';
 import { DomManagement } from '../Misc/domManagement';
+import { WebGLShaderProcessor } from './WebGL/webGLShaderProcessors';
 import { WebGL2ShaderProcessor } from './WebGL/webGL2ShaderProcessors';
 import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
 import { IPipelineContext } from './IPipelineContext';
@@ -157,14 +158,14 @@ export class ThinEngine {
      */
     // Not mixed with Version for tooling purpose.
     public static get NpmPackage(): string {
-        return "babylonjs@4.2.0-beta.10";
+        return "babylonjs@4.2.0-beta.11";
     }
 
     /**
      * Returns the current version of the framework
      */
     public static get Version(): string {
-        return "4.2.0-beta.10";
+        return "4.2.0-beta.11";
     }
 
     /**
@@ -702,6 +703,8 @@ export class ThinEngine {
         // Shader processor
         if (this.webGLVersion > 1) {
             this._shaderProcessor = new WebGL2ShaderProcessor();
+        } else {
+            this._shaderProcessor = new WebGLShaderProcessor();
         }
 
         // Detect if we are running on a faulty buggy OS.

+ 16 - 0
src/Layers/effectLayer.ts

@@ -125,6 +125,12 @@ export abstract class EffectLayer {
     }
 
     /**
+     * Specifies if the bounding boxes should be rendered normally or if they should undergo the effect of the layer
+     */
+    @serialize()
+    public disableBoundingBoxesFromEffectLayer = false;
+
+    /**
      * An event triggered when the effect layer has been disposed.
      */
     public onDisposeObservable = new Observable<EffectLayer>();
@@ -374,6 +380,16 @@ export abstract class EffectLayer {
         this._mainTexture.onClearObservable.add((engine: Engine) => {
             engine.clear(this.neutralColor, true, true, true);
         });
+
+        const boundingBoxRendererEnabled = this._scene.getBoundingBoxRenderer().enabled;
+
+        this._mainTexture.onBeforeBindObservable.add(() => {
+            this._scene.getBoundingBoxRenderer().enabled = !this.disableBoundingBoxesFromEffectLayer && boundingBoxRendererEnabled;
+        });
+
+        this._mainTexture.onAfterUnbindObservable.add(() => {
+            this._scene.getBoundingBoxRenderer().enabled = boundingBoxRendererEnabled;
+        });
     }
 
     /**

+ 8 - 0
src/Loading/loadingScreen.ts

@@ -117,11 +117,19 @@ export class DefaultLoadingScreen implements ILoadingScreen {
         imgBack.style.width = "150px";
         imgBack.style.gridColumn = "1";
         imgBack.style.gridRow = "1";
+        imgBack.style.top = "50%";
+        imgBack.style.left = "50%";
+        imgBack.style.transform = "translate(-50%, -50%)";
+        imgBack.style.position = "absolute";
 
         const imageSpinnerContainer = document.createElement("div");
         imageSpinnerContainer.style.width = "300px";
         imageSpinnerContainer.style.gridColumn = "1";
         imageSpinnerContainer.style.gridRow = "1";
+        imageSpinnerContainer.style.top = "50%";
+        imageSpinnerContainer.style.left = "50%";
+        imageSpinnerContainer.style.transform = "translate(-50%, -50%)";
+        imageSpinnerContainer.style.position = "absolute";
 
         // Loading spinner
         var imgSpinner = new Image();

+ 10 - 34
src/Materials/Node/Blocks/Dual/currentScreenBlock.ts

@@ -47,7 +47,7 @@ export class CurrentScreenBlock extends NodeMaterialBlock {
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.VertexAndFragment);
 
-        this._isUnique = true;
+        this._isUnique = false;
 
         this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false, NodeMaterialBlockTargets.VertexAndFragment);
 
@@ -61,7 +61,7 @@ export class CurrentScreenBlock extends NodeMaterialBlock {
         this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector3);
         this._inputs[0].acceptedConnectionPointTypes.push(NodeMaterialBlockConnectionPointTypes.Vector4);
 
-        this._inputs[0]._prioritizeVertex = true;
+        this._inputs[0]._prioritizeVertex = false;
     }
 
     /**
@@ -130,8 +130,6 @@ export class CurrentScreenBlock extends NodeMaterialBlock {
     }
 
     public get target() {
-        // TextureBlock has a special optimizations for uvs that come from the vertex shaders as they can be packed into a single varyings.
-        // But we need to detect uvs coming from fragment then
         if (!this.uv.isConnected) {
             return NodeMaterialBlockTargets.VertexAndFragment;
         }
@@ -140,32 +138,7 @@ export class CurrentScreenBlock extends NodeMaterialBlock {
             return NodeMaterialBlockTargets.VertexAndFragment;
         }
 
-        let parent = this.uv.connectedPoint;
-
-        while (parent) {
-            if (parent.target === NodeMaterialBlockTargets.Fragment) {
-                return NodeMaterialBlockTargets.Fragment;
-            }
-
-            if (parent.target === NodeMaterialBlockTargets.Vertex) {
-                return NodeMaterialBlockTargets.VertexAndFragment;
-            }
-
-            if (parent.target === NodeMaterialBlockTargets.Neutral || parent.target === NodeMaterialBlockTargets.VertexAndFragment) {
-                let parentBlock = parent.ownerBlock;
-
-                parent = null;
-                for (var input of parentBlock.inputs) {
-                    if (input.connectedPoint) {
-                        parent = input.connectedPoint;
-                        break;
-                    }
-                }
-            }
-
-        }
-
-        return NodeMaterialBlockTargets.VertexAndFragment;
+        return NodeMaterialBlockTargets.Fragment;
     }
 
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
@@ -261,18 +234,21 @@ export class CurrentScreenBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
-        if (state.target === NodeMaterialBlockTargets.Vertex) {
-            this._tempTextureRead = state._getFreeVariableName("tempTextureRead");
-
-            state._emit2DSampler(this._samplerName);
+        this._tempTextureRead = state._getFreeVariableName("tempTextureRead");
 
+        if (state.sharedData.blockingBlocks.indexOf(this) < 0) {
             state.sharedData.blockingBlocks.push(this);
+        }
+        if (state.sharedData.textureBlocks.indexOf(this) < 0) {
             state.sharedData.textureBlocks.push(this);
+        }
+        if (state.sharedData.blocksWithDefines.indexOf(this) < 0) {
             state.sharedData.blocksWithDefines.push(this);
         }
 
         if (state.target !== NodeMaterialBlockTargets.Fragment) {
             // Vertex
+            state._emit2DSampler(this._samplerName);
             this._injectVertexCode(state);
             return;
         }

+ 11 - 0
src/Materials/Node/Blocks/Dual/lightBlock.ts

@@ -50,6 +50,7 @@ export class LightBlock extends NodeMaterialBlock {
         this.registerInput("glossPower", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("diffuseColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("specularColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
         this.registerOutput("diffuseOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("specularOutput", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -114,6 +115,13 @@ export class LightBlock extends NodeMaterialBlock {
     }
 
     /**
+    * Gets the view matrix component
+    */
+    public get view(): NodeMaterialConnectionPoint {
+        return this._inputs[7];
+    }
+
+    /**
      * Gets the diffuse output component
      */
     public get diffuseOutput(): NodeMaterialConnectionPoint {
@@ -232,6 +240,9 @@ export class LightBlock extends NodeMaterialBlock {
             });
         } else {
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
+            if (this.view.isConnected) {
+                state.compilationString += `mat4 view = ${this.view.associatedVariableName};\r\n`;
+            }
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
                 repeatKey: "maxSimultaneousLights"
             });

+ 11 - 0
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -93,6 +93,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             new NodeMaterialConnectionPointCustomObject("subsurface", this, NodeMaterialConnectionPointDirection.Input, SubSurfaceBlock, "SubSurfaceBlock"));
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
+        this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
         this.registerOutput("ambient", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("diffuse", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
@@ -477,6 +478,13 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     }
 
     /**
+     * Gets the view matrix parameter
+     */
+    public get view(): NodeMaterialConnectionPoint {
+        return this._inputs[14];
+    }
+
+    /**
      * Gets the ambient output component
      */
     public get ambient(): NodeMaterialConnectionPoint {
@@ -756,6 +764,9 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             });
         } else {
             state.compilationString += `vec4 worldPos = ${worldPos.associatedVariableName};\r\n`;
+            if (this.view.isConnected) {
+                state.compilationString += `mat4 view = ${this.view.associatedVariableName};\r\n`;
+            }
             state.compilationString += state._emitCodeFromInclude("shadowsVertex", comments, {
                 repeatKey: "maxSimultaneousLights"
             });

+ 1 - 1
src/Materials/Node/Blocks/Particle/particleTextureBlock.ts

@@ -46,7 +46,7 @@ export class ParticleTextureBlock extends NodeMaterialBlock {
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.Fragment);
 
-        this._isUnique = true;
+        this._isUnique = false;
 
         this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, false, NodeMaterialBlockTargets.VertexAndFragment);
 

+ 3 - 2
src/Materials/Node/Blocks/smoothStepBlock.ts

@@ -15,11 +15,12 @@ export class SmoothStepBlock extends NodeMaterialBlock {
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.Neutral);
 
-        this.registerInput("value", NodeMaterialBlockConnectionPointTypes.Float);
+        this.registerInput("value", NodeMaterialBlockConnectionPointTypes.AutoDetect);
         this.registerInput("edge0", NodeMaterialBlockConnectionPointTypes.Float);
         this.registerInput("edge1", NodeMaterialBlockConnectionPointTypes.Float);
-        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Float);
+        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.BasedOnInput);
 
+        this._outputs[0]._typeConnectionSource = this._inputs[0];
     }
 
     /**

+ 8 - 8
src/Materials/Node/Blocks/vectorMergerBlock.ts

@@ -129,21 +129,21 @@ export class VectorMergerBlock extends NodeMaterialBlock {
         let v3Output = this._outputs[1];
         let v2Output = this._outputs[2];
 
-        if (xyInput.isConnected) {
+        if (xyzInput.isConnected) {
             if (v4Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v4Output, state) + ` = vec4(${xyInput.associatedVariableName}, ${zInput.isConnected ? this._writeVariable(zInput) : "0.0"}, ${wInput.isConnected ? this._writeVariable(wInput) : "0.0"});\r\n`;
+                state.compilationString += this._declareOutput(v4Output, state) + ` = vec4(${xyzInput.associatedVariableName}, ${wInput.isConnected ? this._writeVariable(wInput) : "0.0"});\r\n`;
             } else if (v3Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v3Output, state) + ` = vec3(${xyInput.associatedVariableName}, ${zInput.isConnected ? this._writeVariable(zInput) : "0.0"});\r\n`;
+                state.compilationString += this._declareOutput(v3Output, state) + ` = ${xyzInput.associatedVariableName};\r\n`;
             } else if (v2Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v2Output, state) + ` = ${xyInput.associatedVariableName};\r\n`;
+                state.compilationString += this._declareOutput(v2Output, state) + ` = ${xyzInput.associatedVariableName}.xy;\r\n`;
             }
-        } else if (xyzInput.isConnected) {
+        } else if (xyInput.isConnected) {
             if (v4Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v4Output, state) + ` = vec4(${xyzInput.associatedVariableName}, ${wInput.isConnected ? this._writeVariable(wInput) : "0.0"});\r\n`;
+                state.compilationString += this._declareOutput(v4Output, state) + ` = vec4(${xyInput.associatedVariableName}, ${zInput.isConnected ? this._writeVariable(zInput) : "0.0"}, ${wInput.isConnected ? this._writeVariable(wInput) : "0.0"});\r\n`;
             } else if (v3Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v3Output, state) + ` = ${xyzInput.associatedVariableName};\r\n`;
+                state.compilationString += this._declareOutput(v3Output, state) + ` = vec3(${xyInput.associatedVariableName}, ${zInput.isConnected ? this._writeVariable(zInput) : "0.0"});\r\n`;
             } else if (v2Output.hasEndpoints) {
-                state.compilationString += this._declareOutput(v2Output, state) + ` = ${xyzInput.associatedVariableName}.xy;\r\n`;
+                state.compilationString += this._declareOutput(v2Output, state) + ` = ${xyInput.associatedVariableName};\r\n`;
             }
         } else {
             if (v4Output.hasEndpoints) {

+ 8 - 0
src/Materials/Node/nodeMaterial.ts

@@ -261,6 +261,12 @@ export class NodeMaterial extends PushMaterial {
     }
 
     /**
+     * A free comment about the material
+     */
+    @serialize("comment")
+    public comment: string;
+
+    /**
      * Create a new node based material
      * @param name defines the material name
      * @param scene defines the hosting scene
@@ -1809,6 +1815,8 @@ export class NodeMaterial extends PushMaterial {
             this.editorData.map = blockMap;
         }
 
+        this.comment = source.comment;
+
         if (!merge) {
             this._mode = source.mode ?? NodeMaterialModes.Material;
         }

+ 0 - 0
src/Materials/Node/nodeMaterialBuildState.ts


Vissa filer visades inte eftersom för många filer har ändrats