ソースを参照

Merge remote-tracking branch 'refs/remotes/BabylonJS/master' into subEmitter2

# Conflicts:
#	dist/preview release/babylon.d.ts
#	dist/preview release/babylon.js
#	dist/preview release/babylon.worker.js
Ibraheem Osama 7 年 前
コミット
9818d303a5
42 ファイル変更31308 行追加29071 行削除
  1. 14 1
      .travis.yml
  2. 8828 8680
      Playground/babylon.d.txt
  3. 0 1
      Tools/Gulp/config.json
  4. 38 15
      Tools/Publisher/index.js
  5. 3 0
      Tools/Publisher/package.json
  6. 248 0
      dist/babylon.glTFInterface.d.ts
  7. 6621 6655
      dist/preview release/babylon.d.ts
  8. 26 26
      dist/preview release/babylon.js
  9. 220 180
      dist/preview release/babylon.max.js
  10. 26 26
      dist/preview release/babylon.worker.js
  11. 12420 12338
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  12. 47 47
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  13. 368 182
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  14. 368 182
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  15. 220 180
      dist/preview release/es6.js
  16. 70 1
      dist/preview release/gui/babylon.gui.d.ts
  17. 74 1
      dist/preview release/gui/babylon.gui.js
  18. 2 2
      dist/preview release/gui/babylon.gui.min.js
  19. 70 1
      dist/preview release/gui/babylon.gui.module.d.ts
  20. 111 31
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  21. 493 83
      dist/preview release/serializers/babylon.glTF2Serializer.js
  22. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  23. 493 83
      dist/preview release/serializers/babylonjs.serializers.js
  24. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  25. 111 31
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  26. 2 63
      dist/preview release/typedocValidationBaseline.json
  27. 47 47
      dist/preview release/viewer/babylon.viewer.js
  28. 11 0
      gui/src/advancedDynamicTexture.ts
  29. 65 3
      gui/src/controls/textBlock.ts
  30. 0 3
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  31. 1 1
      package.json
  32. 5 1
      src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts
  33. 4 4
      src/Cameras/VR/babylon.webVRCamera.ts
  34. 11 9
      src/Cameras/babylon.camera.ts
  35. 14 1
      src/Cameras/babylon.cameraInputsManager.ts
  36. 4 3
      src/Cameras/babylon.deviceOrientationCamera.ts
  37. 9 1
      src/Cameras/babylon.freeCamera.ts
  38. 1 1
      src/Engine/babylon.engine.ts
  39. 212 93
      src/Materials/Textures/babylon.videoTexture.ts
  40. 2 0
      src/Mesh/babylon.abstractMesh.ts
  41. 37 88
      src/Tools/babylon.sceneOptimizer.ts
  42. 10 5
      tests/validation/integration.js

+ 14 - 1
.travis.yml

@@ -3,6 +3,13 @@ dist: trusty
 language: node_js
 node_js:
 - '6'
+cache:
+  directories:
+    - Tools/Gulp/node_modules
+    - Playground/node_modules
+    - tests/unit/node_modules
+git:
+  depth: 3
 before_script:
 - travis_retry npm install -g gulp
 - cd ./Tools/Gulp
@@ -10,7 +17,13 @@ before_script:
 - "export DISPLAY=:99.0"
 - "sh -e /etc/init.d/xvfb start"
 - sleep 3 # give xvfb some time to start
-script: gulp
+script: 
+- set -e
+- gulp typescript-all
+- gulp typedoc-all
+- gulp tests-unit
+- travis_retry gulp tests-validation-virtualscreen
+- travis_retry gulp tests-validation-browserstack
 notifications:
   slack:
     secure: TBYDAN8Dlkx3dM+Q5ClAZem7agAhQ1oB/fGT665qn7D+j2YfWChvlfXegvXL4LPDmQgbI0UfazcjWId5a0EwmmPkRb+kMJItPiMt5jiIp2WKoZQ+qob6H9tBCRJbbpWM430wiPeKfBfbcZP/XSlpVMWhgU5ogAFDSUKjvHT7IuE=

ファイルの差分が大きいため隠しています
+ 8828 - 8680
Playground/babylon.d.txt


+ 0 - 1
Tools/Gulp/config.json

@@ -265,7 +265,6 @@
             "files": [
                 "../../src/Particles/babylon.particle.js",
                 "../../src/Particles/babylon.particleSystem.js",
-                "../../src/Particles/babylon.subParticleSystem.js",
                 "../../src/Particles/babylon.boxParticleEmitter.js",
                 "../../src/Particles/babylon.coneParticleEmitter.js",
                 "../../src/Particles/babylon.sphereParticleEmitter.js",

+ 38 - 15
Tools/Publisher/index.js

@@ -46,6 +46,39 @@ let packages = [
     }
 ];
 
+function updateEngineVersion(newVersion) {
+    console.log("updating version in babylon.engine.ts");
+    let engineContent = fs.readFileSync("../../src/Engine/babylon.engine.ts").toString();
+    let replaced = engineContent.replace(/(public static get Version\(\): string {\s*return ")(.*)(";\s*})/g, "$1" + newVersion + "$3");
+    fs.writeFileSync("../../src/Engine/babylon.engine.ts", replaced);
+}
+
+function runGulp() {
+    // run gulp typescript-all
+    let exec = shelljs.exec("gulp typescript-all --gulpfile ../Gulp/gulpfile.js");
+    if (exec.code) {
+        console.log("error during compilation, aborting");
+        process.exit(1);
+    }
+}
+
+function processPackages() {
+    packages.forEach((package) => {
+        if (package.name === "core") {
+            processCore(package, version);
+        } else {
+            let packageJson = require(package.path + 'package.json');
+            packageJson.version = version;
+            if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
+            fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
+            console.log('Publishing ' + package.name + " from " + package.path);
+            //publish the respected package
+            shelljs.exec('npm publish \"' + package.path + "\"");
+        }
+
+    });
+}
+
 //check if logged in
 console.log("Using npm user:");
 let loginCheck = shelljs.exec('npm whoami');
@@ -55,21 +88,11 @@ if (loginCheck.code === 0) {
 
     prompt.get(['version'], function (err, result) {
         let version = result.version;
-        packages.forEach((package) => {
-            if (package.name === "core") {
-                processCore(package, version);
-            } else {
-                let packageJson = require(package.path + 'package.json');
-                packageJson.version = version;
-                if (packageJson.peerDependencies) packageJson.peerDependencies.babylonjs = minimumDependency;
-                fs.writeFileSync(package.path + 'package.json', JSON.stringify(packageJson, null, 4));
-                console.log('Publishing ' + package.name + " from " + package.path);
-                //publish the respected package
-                shelljs.exec('npm publish \"' + package.path + "\"");
-            }
-
-        });
-        console.log("done, please don't forget to commit the changes")
+        updateEngineVersion(version);
+        runGulp();
+        processPackages();
+
+        console.log("done, please tag git with " + version);
     });
 } else {
     console.log('not logged in.');

+ 3 - 0
Tools/Publisher/package.json

@@ -12,5 +12,8 @@
     "fs-extra": "^5.0.0",
     "prompt": "^1.0.0",
     "shelljs": "^0.7.8"
+  },
+  "devDependencies": {
+    "gulp": "^3.9.1"
   }
 }

+ 248 - 0
dist/babylon.glTFInterface.d.ts

@@ -0,0 +1,248 @@
+declare module BABYLON.GLTF2 {
+    enum AccessorType {
+        SCALAR = "SCALAR",
+        VEC2 = "VEC2",
+        VEC3 = "VEC3",
+        VEC4 = "VEC4",
+        MAT2 = "MAT2",
+        MAT3 = "MAT3",
+        MAT4 = "MAT4",
+    }
+    enum MaterialAlphaMode {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    enum AnimationChannelTargetPath {
+        TRANSLATION = "translation",
+        ROTATION = "rotation",
+        SCALE = "scale",
+        WEIGHTS = "weights",
+    }
+    enum CameraType {
+        PERSPECTIVE = "perspective",
+        ORTHOGRAPHIC = "orthographic",
+    }
+    enum AccessorComponentType {
+        BYTE = 5120,
+        UNSIGNED_BYTE = 5121,
+        SHORT = 5122,
+        UNSIGNED_SHORT = 5123,
+        UNSIGNED_INT = 5125,
+        FLOAT = 5126,
+    }
+    enum AnimationInterpolation {
+        LINEAR = "LINEAR",
+        STEP = "STEP",
+        CUBICSPLINE = "CUBICSPLINE",
+    }
+    enum MeshPrimitiveMode {
+        POINTS = 0,
+        LINES = 1,
+        LINE_LOOP = 2,
+        LINE_STRIP = 3,
+        TRIANGLES = 4,
+        TRIANGLE_STRIP = 5,
+        TRIANGLE_FAN = 6,
+    }
+    enum ImageMimeType {
+        JPEG = "image/jpeg",
+        PNG = "image/png",
+    }
+    enum TextureMagFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+    }
+    enum TextureMinFilter {
+        NEAREST = 9728,
+        LINEAR = 9729,
+        NEAREST_MIPMAP_NEAREST = 9984,
+        LINEAR_MIPMAP_NEAREST = 9985,
+        NEAREST_MIPMAP_LINEAR = 9986,
+        LINEAR_MIPMAP_LINEAR = 9987,
+    }
+    enum TextureWrapMode {
+        CLAMP_TO_EDGE = 33071,
+        MIRRORED_REPEAT = 33648,
+        REPEAT = 10497,
+    }
+    interface IProperty {
+        extensions?: {
+            [key: string]: any;
+        };
+        extras?: any;
+    }
+    interface IChildRootProperty extends IProperty {
+        name?: string;
+    }
+    interface IAccessorSparseIndices extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+    }
+    interface IAccessorSparseValues extends IProperty {
+        bufferView: number;
+        byteOffset?: number;
+    }
+    interface IAccessorSparse extends IProperty {
+        count: number;
+        indices: IAccessorSparseIndices;
+        values: IAccessorSparseValues;
+    }
+    interface IAccessor extends IChildRootProperty {
+        bufferView?: number;
+        byteOffset?: number;
+        componentType: AccessorComponentType;
+        normalized?: boolean;
+        count: number;
+        type: AccessorType;
+        max: number[];
+        min: number[];
+        sparse?: IAccessorSparse;
+    }
+    interface IAnimationChannel extends IProperty {
+        sampler: number;
+        target: IAnimationChannelTarget;
+    }
+    interface IAnimationChannelTarget extends IProperty {
+        node: number;
+        path: AnimationChannelTargetPath;
+    }
+    interface IAnimationSampler extends IProperty {
+        input: number;
+        interpolation?: AnimationInterpolation;
+        output: number;
+    }
+    interface IAnimation extends IChildRootProperty {
+        channels: IAnimationChannel[];
+        samplers: IAnimationSampler[];
+    }
+    interface IAsset extends IChildRootProperty {
+        copyright?: string;
+        generator?: string;
+        version: string;
+        minVersion?: string;
+    }
+    interface IBuffer extends IChildRootProperty {
+        uri?: string;
+        byteLength: number;
+    }
+    interface IBufferView extends IChildRootProperty {
+        buffer: number;
+        byteOffset?: number;
+        byteLength: number;
+        byteStride?: number;
+    }
+    interface ICameraOrthographic extends IProperty {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICameraPerspective extends IProperty {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+    interface ICamera extends IChildRootProperty {
+        orthographic?: ICameraOrthographic;
+        perspective?: ICameraPerspective;
+        type: CameraType;
+    }
+    interface IImage extends IChildRootProperty {
+        uri?: string;
+        mimeType?: ImageMimeType;
+        bufferView?: number;
+    }
+    interface IMaterialNormalTextureInfo extends ITextureInfo {
+        scale: number;
+    }
+    interface IMaterialOcclusionTextureInfo extends ITextureInfo {
+        strength: number;
+    }
+    interface IMaterialPbrMetallicRoughness {
+        baseColorFactor: number[];
+        baseColorTexture: ITextureInfo;
+        metallicFactor: number;
+        roughnessFactor: number;
+        metallicRoughnessTexture: ITextureInfo;
+    }
+    interface IMaterial extends IChildRootProperty {
+        pbrMetallicRoughness?: IMaterialPbrMetallicRoughness;
+        normalTexture?: IMaterialNormalTextureInfo;
+        occlusionTexture?: IMaterialOcclusionTextureInfo;
+        emissiveTexture?: ITextureInfo;
+        emissiveFactor?: number[];
+        alphaMode?: MaterialAlphaMode;
+        alphaCutoff?: number;
+        doubleSided?: boolean;
+    }
+    interface IMeshPrimitive extends IProperty {
+        attributes: {
+            [name: string]: number;
+        };
+        indices?: number;
+        material?: number;
+        mode?: MeshPrimitiveMode;
+        targets?: {
+            [name: string]: number;
+        }[];
+    }
+    interface IMesh extends IChildRootProperty {
+        primitives: IMeshPrimitive[];
+        weights?: number[];
+    }
+    interface INode extends IChildRootProperty {
+        camera?: number;
+        children?: number[];
+        skin?: number;
+        matrix?: number[];
+        mesh?: number;
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+        weights?: number[];
+    }
+    interface ISampler extends IChildRootProperty {
+        magFilter?: TextureMagFilter;
+        minFilter?: TextureMinFilter;
+        wrapS?: TextureWrapMode;
+        wrapT?: TextureWrapMode;
+    }
+    interface IScene extends IChildRootProperty {
+        nodes: number[];
+    }
+    interface ISkin extends IChildRootProperty {
+        inverseBindMatrices?: number;
+        skeleton?: number;
+        joints: number[];
+    }
+    interface ITexture extends IChildRootProperty {
+        sampler?: number;
+        source: number;
+    }
+    interface ITextureInfo {
+        index: number;
+        texCoord?: number;
+    }
+    interface IGLTF extends IProperty {
+        accessors?: IAccessor[];
+        animations?: IAnimation[];
+        asset: IAsset;
+        buffers?: IBuffer[];
+        bufferViews?: IBufferView[];
+        cameras?: ICamera[];
+        extensionsUsed?: string[];
+        extensionsRequired?: string[];
+        images?: IImage[];
+        materials?: IMaterial[];
+        meshes?: IMesh[];
+        nodes?: INode[];
+        samplers?: ISampler[];
+        scene?: number;
+        scenes?: IScene[];
+        skins?: ISkin[];
+        textures?: ITexture[];
+    }
+}

ファイルの差分が大きいため隠しています
+ 6621 - 6655
dist/preview release/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 26 - 26
dist/preview release/babylon.js


+ 220 - 180
dist/preview release/babylon.max.js

@@ -12757,7 +12757,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
-            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+            if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
                 return;
             }
             // Remove
@@ -15924,6 +15924,7 @@ var BABYLON;
                 return;
             }
             this._lightSources.splice(index, 1);
+            this._markSubMeshesAsLightDirty();
         };
         AbstractMesh.prototype._markSubMeshesAsDirty = function (func) {
             if (!this.subMeshes) {
@@ -17819,14 +17820,17 @@ var BABYLON;
         __extends(Camera, _super);
         function Camera(name, position, scene) {
             var _this = _super.call(this, name, scene) || this;
+            /**
+             * The vector the camera should consider as up.
+             * (default is Vector3(0, 1, 0) aka Vector3.Up())
+             */
             _this.upVector = BABYLON.Vector3.Up();
             _this.orthoLeft = null;
             _this.orthoRight = null;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             /**
-             * default : 0.8
-             * FOV is set in Radians.
+             * FOV is set in Radians. (default is 0.8)
              */
             _this.fov = 0.8;
             _this.minZ = 1;
@@ -17836,14 +17840,13 @@ var BABYLON;
             _this.isIntermediate = false;
             _this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
             /**
-            * Restricts the camera to viewing objects with the same layerMask.
-            * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-            */
+             * Restricts the camera to viewing objects with the same layerMask.
+             * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+             */
             _this.layerMask = 0x0FFFFFFF;
             /**
-            * default : FOVMODE_VERTICAL_FIXED
-            * fovMode sets the camera frustum bounds to the viewport bounds.
-            */
+             * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+             */
             _this.fovMode = Camera.FOVMODE_VERTICAL_FIXED;
             // Camera rig members
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
@@ -39193,6 +39196,12 @@ var BABYLON;
             this.camera = camera;
             this.checkInputs = function () { };
         }
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         CameraInputsManager.prototype.add = function (input) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -39210,6 +39219,11 @@ var BABYLON;
                 input.attachControl(this.attachedElement);
             }
         };
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -39278,6 +39292,9 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Remove all attached input methods from a camera
+         */
         CameraInputsManager.prototype.clear = function () {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);
@@ -39982,12 +39999,20 @@ var BABYLON;
         }
         Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
             //-- begin properties for backward compatibility for inputs
+            /**
+             * Gets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             get: function () {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
                     return mouse.angularSensibility;
                 return 0;
             },
+            /**
+             * Sets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             set: function (value) {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
@@ -54249,104 +54274,167 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    var getName = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src.currentSrc;
+        }
+        if (typeof src === "object") {
+            return src.toString();
+        }
+        return src;
+    };
+    var getVideo = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src;
+        }
+        var video = document.createElement("video");
+        if (typeof src === "string") {
+            video.src = src;
+        }
+        else {
+            src.forEach(function (url) {
+                var source = document.createElement("source");
+                source.src = url;
+                video.appendChild(source);
+            });
+        }
+        return video;
+    };
     var VideoTexture = /** @class */ (function (_super) {
         __extends(VideoTexture, _super);
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
+        function VideoTexture(name, src, scene, generateMipMaps, invertY, samplingMode, settings) {
             if (generateMipMaps === void 0) { generateMipMaps = false; }
             if (invertY === void 0) { invertY = false; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            if (settings === void 0) { settings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }; }
             var _this = _super.call(this, null, scene, !generateMipMaps, invertY) || this;
-            _this._autoLaunch = true;
-            var urls = null;
-            _this.name = name;
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                _this.video = urlsOrVideo;
-            }
-            else {
-                urls = urlsOrVideo;
-                _this.video = document.createElement("video");
-                _this.video.autoplay = false;
-                _this.video.loop = true;
-                BABYLON.Tools.SetCorsBehavior(urls, _this.video);
-            }
+            _this._createInternalTexture = function () {
+                if (_this._texture != null) {
+                    return;
+                }
+                if (!_this._engine.needPOTTextures ||
+                    (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
+                    _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+                }
+                else {
+                    _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._generateMipMaps = false;
+                }
+                _this._texture = _this._engine.createDynamicTexture(_this.video.videoWidth, _this.video.videoHeight, _this._generateMipMaps, _this._samplingMode);
+                _this._texture.width;
+                _this._updateInternalTexture();
+                _this._texture.isReady = true;
+            };
+            _this.reset = function () {
+                if (_this._texture == null) {
+                    return;
+                }
+                _this._texture.dispose();
+                _this._texture = null;
+            };
+            _this._updateInternalTexture = function (e) {
+                if (_this._texture == null || !_this._texture.isReady) {
+                    return;
+                }
+                if (_this.video.readyState < _this.video.HAVE_CURRENT_DATA) {
+                    return;
+                }
+                _this._engine.updateVideoTexture(_this._texture, _this.video, _this._invertY);
+            };
             _this._engine = _this.getScene().getEngine();
             _this._generateMipMaps = generateMipMaps;
             _this._samplingMode = samplingMode;
-            if (!_this._engine.needPOTTextures || (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
-                _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+            _this.autoUpdateTexture = settings.autoUpdateTexture;
+            _this.name = name || getName(src);
+            _this.video = getVideo(src);
+            if (settings.autoPlay !== undefined) {
+                _this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                _this.video.loop = settings.loop;
+            }
+            _this.video.addEventListener("canplay", _this._createInternalTexture);
+            _this.video.addEventListener("paused", _this._updateInternalTexture);
+            _this.video.addEventListener("seeked", _this._updateInternalTexture);
+            _this.video.addEventListener("emptied", _this.reset);
+            if (_this.video.readyState >= _this.video.HAVE_CURRENT_DATA) {
+                _this._createInternalTexture();
             }
-            else {
-                _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this._generateMipMaps = false;
-            }
-            if (urls) {
-                _this.video.addEventListener("canplay", function () {
-                    if (_this._texture === undefined) {
-                        _this._createTexture();
-                    }
-                });
-                urls.forEach(function (url) {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    _this.video.appendChild(source);
-                });
-            }
-            else {
-                _this._createTexture();
-            }
-            _this._lastUpdate = BABYLON.Tools.Now;
             return _this;
         }
-        VideoTexture.prototype.__setTextureReady = function () {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        };
-        VideoTexture.prototype._createTexture = function () {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        };
+        /**
+         * Internal method to initiate `update`.
+         */
         VideoTexture.prototype._rebuild = function () {
             this.update();
         };
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
         VideoTexture.prototype.update = function () {
-            var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
             }
-            this._lastUpdate = now;
-            this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+            this.updateTexture(true);
+        };
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        VideoTexture.prototype.updateTexture = function (isVisible) {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        };
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        VideoTexture.prototype.updateURL = function (url) {
+            this.video.src = url;
         };
         VideoTexture.prototype.dispose = function () {
             _super.prototype.dispose.call(this);
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         };
         VideoTexture.CreateFromWebCam = function (scene, onReady, constraints) {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
+                    exact: constraints.deviceId,
                 };
             }
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                    navigator.webkitGetUserMedia ||
+                    navigator.mozGetUserMedia ||
+                    navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
             if (navigator.getUserMedia) {
                 navigator.getUserMedia({
@@ -54354,15 +54442,16 @@ var BABYLON;
                         deviceId: constraintsDeviceId,
                         width: {
                             min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                            max: (constraints && constraints.maxWidth) || 640,
                         },
                         height: {
                             min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
-                        }
-                    }
+                            max: (constraints && constraints.maxHeight) || 480,
+                        },
+                    },
                 }, function (stream) {
                     if (video.mozSrcObject !== undefined) {
+                        // hack for Firefox < 19
                         video.mozSrcObject = stream;
                     }
                     else {
@@ -74079,6 +74168,10 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     var FreeCameraDeviceOrientationInput = /** @class */ (function () {
         function FreeCameraDeviceOrientationInput() {
             var _this = this;
@@ -74305,16 +74398,15 @@ var BABYLON;
             _this.onControllersAttachedObservable = new BABYLON.Observable();
             _this.onControllerMeshLoadedObservable = new BABYLON.Observable();
             _this.rigParenting = true; // should the rig cameras be used as parent instead of this camera.
-            _this._defaultHeight = 0;
+            _this._defaultHeight = undefined;
             _this.deviceDistanceToRoomGround = function () {
-                if (_this._standingMatrix) {
+                if (_this._standingMatrix && _this._defaultHeight === undefined) {
                     // Add standing matrix offset to get real offset from ground in room
                     _this._standingMatrix.getTranslationToRef(_this._workingVector);
                     return _this._deviceRoomPosition.y + _this._workingVector.y;
                 }
-                else {
-                    return _this._defaultHeight;
-                }
+                //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+                return _this._defaultHeight || 0;
             };
             _this.useStandingMatrix = function (callback) {
                 if (callback === void 0) { callback = function (bool) { }; }
@@ -74726,7 +74818,7 @@ var BABYLON;
         /**
          * Creates a new device orientation camera. @see DeviceOrientationCamera
          * @param name The name of the camera
-         * @param position The starts position camera
+         * @param position The start position camera
          * @param scene The scene the camera belongs to
          */
         function DeviceOrientationCamera(name, position, scene) {
@@ -77399,9 +77491,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        SceneOptimization.prototype.apply = function (scene) {
+        SceneOptimization.prototype.apply = function (scene, optimizer) {
             return true;
         };
         ;
@@ -77452,9 +77545,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        TextureOptimization.prototype.apply = function (scene) {
+        TextureOptimization.prototype.apply = function (scene, optimizer) {
             var allDone = true;
             for (var index = 0; index < scene.textures.length; index++) {
                 var texture = scene.textures[index];
@@ -77519,9 +77613,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        HardwareScalingOptimization.prototype.apply = function (scene) {
+        HardwareScalingOptimization.prototype.apply = function (scene, optimizer) {
             if (this._currentScale === -1) {
                 this._currentScale = scene.getEngine().getHardwareScalingLevel();
                 if (this._currentScale > this.maximumScale) {
@@ -77542,26 +77637,8 @@ var BABYLON;
      */
     var ShadowsOptimization = /** @class */ (function (_super) {
         __extends(ShadowsOptimization, _super);
-        /**
-         * Creates the ShadowsOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
-         */
-        function ShadowsOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.shadowsEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ShadowsOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77573,10 +77650,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ShadowsOptimization.prototype.apply = function (scene) {
-            scene.shadowsEnabled = this.target;
+        ShadowsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.shadowsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77589,26 +77667,8 @@ var BABYLON;
      */
     var PostProcessesOptimization = /** @class */ (function (_super) {
         __extends(PostProcessesOptimization, _super);
-        /**
-         * Creates the PostProcessesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
-         */
-        function PostProcessesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function PostProcessesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77620,10 +77680,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        PostProcessesOptimization.prototype.apply = function (scene) {
-            scene.postProcessesEnabled = this.target;
+        PostProcessesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.postProcessesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77636,26 +77697,8 @@ var BABYLON;
      */
     var LensFlaresOptimization = /** @class */ (function (_super) {
         __extends(LensFlaresOptimization, _super);
-        /**
-         * Creates the LensFlaresOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
-         */
-        function LensFlaresOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function LensFlaresOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77667,10 +77710,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        LensFlaresOptimization.prototype.apply = function (scene) {
-            scene.lensFlaresEnabled = this.target;
+        LensFlaresOptimization.prototype.apply = function (scene, optimizer) {
+            scene.lensFlaresEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77699,11 +77743,12 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        CustomOptimization.prototype.apply = function (scene) {
+        CustomOptimization.prototype.apply = function (scene, optimizer) {
             if (this.onApply) {
-                return this.onApply(scene);
+                return this.onApply(scene, optimizer);
             }
             return true;
         };
@@ -77717,26 +77762,8 @@ var BABYLON;
      */
     var ParticlesOptimization = /** @class */ (function (_super) {
         __extends(ParticlesOptimization, _super);
-        /**
-         * Creates the ParticlesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
-         */
-        function ParticlesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.particlesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ParticlesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77748,10 +77775,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ParticlesOptimization.prototype.apply = function (scene) {
-            scene.particlesEnabled = this.target;
+        ParticlesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.particlesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77777,10 +77805,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        RenderTargetsOptimization.prototype.apply = function (scene) {
-            scene.renderTargetsEnabled = false;
+        RenderTargetsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.renderTargetsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77842,10 +77871,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
          * @returns true if everything that can be done was applied
          */
-        MergeMeshesOptimization.prototype.apply = function (scene, updateSelectionTree) {
+        MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) {
             var globalPool = scene.meshes.slice(0);
             var globalLength = globalPool.length;
             for (var index = 0; index < globalLength; index++) {
@@ -77933,7 +77963,7 @@ var BABYLON;
         };
         /**
          * Add a new custom optimization
-         * @param onApply defines the callback called to apply the custom optimization.
+         * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @returns the current SceneOptimizerOptions
@@ -78081,6 +78111,16 @@ var BABYLON;
                 _this.dispose();
             });
         }
+        Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", {
+            /**
+             * Gets a boolean indicating if the optimizer is in improvement mode
+             */
+            get: function () {
+                return this._improvementMode;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", {
             /**
              * Gets the current priority level (0 at start)
@@ -78193,7 +78233,7 @@ var BABYLON;
                 var optimization = options.optimizations[index];
                 if (optimization.priority === this._currentPriorityLevel) {
                     noOptimizationApplied = false;
-                    allDone = allDone && optimization.apply(scene);
+                    allDone = allDone && optimization.apply(scene, this);
                     this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
                 }
             }

ファイルの差分が大きいため隠しています
+ 26 - 26
dist/preview release/babylon.worker.js


ファイルの差分が大きいため隠しています
+ 12420 - 12338
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


ファイルの差分が大きいため隠しています
+ 47 - 47
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 368 - 182
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -1117,6 +1117,22 @@ var BABYLON;
             return this;
         };
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color3.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color3
+         */
+        Color3.prototype.clampToRef = function (min, max, result) {
+            if (min === void 0) { min = 0; }
+            if (max === void 0) { max = 1; }
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            return this;
+        };
+        /**
          * Returns a new Color3 set with the added values of the current Color3 and of the passed one.
          */
         Color3.prototype.add = function (otherColor) {
@@ -1365,6 +1381,23 @@ var BABYLON;
             return this;
         };
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color4.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color4
+         */
+        Color4.prototype.clampToRef = function (min, max, result) {
+            if (min === void 0) { min = 0; }
+            if (max === void 0) { max = 1; }
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            result.a = BABYLON.Scalar.Clamp(this.a, min, max);
+            return this;
+        };
+        /**
           * Multipy an RGBA Color4 value by another and return a new Color4 object
           * @param color The Color4 (RGBA) value to multiply by
           * @returns A new Color4.
@@ -2357,6 +2390,23 @@ var BABYLON;
             return s;
         };
         /**
+         * Get angle between two vectors.
+         * @param vector0 angle between vector0 and vector1
+         * @param vector1 angle between vector0 and vector1
+         * @param normal direction of the normal.
+         * @return the angle between vector0 and vector1.
+         */
+        Vector3.GetAngleBetweenVectors = function (vector0, vector1, normal) {
+            var v0 = vector0.clone().normalize();
+            var v1 = vector1.clone().normalize();
+            var dot = Vector3.Dot(v0, v1);
+            var n = Vector3.Cross(v0, v1);
+            if (Vector3.Dot(n, normal) > 0) {
+                return Math.acos(dot);
+            }
+            return -Math.acos(dot);
+        };
+        /**
          * Returns a new Vector3 set from the index "offset" of the passed array.
          */
         Vector3.FromArray = function (array, offset) {
@@ -12707,7 +12757,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
-            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+            if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
                 return;
             }
             // Remove
@@ -15874,6 +15924,7 @@ var BABYLON;
                 return;
             }
             this._lightSources.splice(index, 1);
+            this._markSubMeshesAsLightDirty();
         };
         AbstractMesh.prototype._markSubMeshesAsDirty = function (func) {
             if (!this.subMeshes) {
@@ -17769,14 +17820,17 @@ var BABYLON;
         __extends(Camera, _super);
         function Camera(name, position, scene) {
             var _this = _super.call(this, name, scene) || this;
+            /**
+             * The vector the camera should consider as up.
+             * (default is Vector3(0, 1, 0) aka Vector3.Up())
+             */
             _this.upVector = BABYLON.Vector3.Up();
             _this.orthoLeft = null;
             _this.orthoRight = null;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             /**
-             * default : 0.8
-             * FOV is set in Radians.
+             * FOV is set in Radians. (default is 0.8)
              */
             _this.fov = 0.8;
             _this.minZ = 1;
@@ -17786,14 +17840,13 @@ var BABYLON;
             _this.isIntermediate = false;
             _this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
             /**
-            * Restricts the camera to viewing objects with the same layerMask.
-            * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-            */
+             * Restricts the camera to viewing objects with the same layerMask.
+             * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+             */
             _this.layerMask = 0x0FFFFFFF;
             /**
-            * default : FOVMODE_VERTICAL_FIXED
-            * fovMode sets the camera frustum bounds to the viewport bounds.
-            */
+             * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+             */
             _this.fovMode = Camera.FOVMODE_VERTICAL_FIXED;
             // Camera rig members
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
@@ -19988,6 +20041,24 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Scene.prototype, "geometryBufferRenderer", {
+            /**
+             * Gets the current geometry buffer associated to the scene.
+             */
+            get: function () {
+                return this._geometryBufferRenderer;
+            },
+            /**
+             * Sets the current geometry buffer for the scene.
+             */
+            set: function (geometryBufferRenderer) {
+                if (geometryBufferRenderer && geometryBufferRenderer.isSupported) {
+                    this._geometryBufferRenderer = geometryBufferRenderer;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Scene.prototype, "debugLayer", {
             // Properties
             get: function () {
@@ -39125,6 +39196,12 @@ var BABYLON;
             this.camera = camera;
             this.checkInputs = function () { };
         }
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         CameraInputsManager.prototype.add = function (input) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -39142,6 +39219,11 @@ var BABYLON;
                 input.attachControl(this.attachedElement);
             }
         };
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -39210,6 +39292,9 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Remove all attached input methods from a camera
+         */
         CameraInputsManager.prototype.clear = function () {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);
@@ -39914,12 +39999,20 @@ var BABYLON;
         }
         Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
             //-- begin properties for backward compatibility for inputs
+            /**
+             * Gets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             get: function () {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
                     return mouse.angularSensibility;
                 return 0;
             },
+            /**
+             * Sets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             set: function (value) {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
@@ -44482,6 +44575,24 @@ var BABYLON;
             return action;
         };
         /**
+         * Unregisters an action to this action manager
+         * @param action The action to be unregistered
+         * @return whether the action has been unregistered
+         */
+        ActionManager.prototype.unregisterAction = function (action) {
+            var index = this.actions.indexOf(action);
+            if (index !== -1) {
+                this.actions.splice(index, 1);
+                ActionManager.Triggers[action.trigger] -= 1;
+                if (ActionManager.Triggers[action.trigger] === 0) {
+                    delete ActionManager.Triggers[action.trigger];
+                }
+                delete action._actionManager;
+                return true;
+            }
+            return false;
+        };
+        /**
          * Process a specific trigger
          * @param {number} trigger - the trigger to process
          * @param evt {BABYLON.ActionEvent} the event details to be processed
@@ -53792,104 +53903,167 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    var getName = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src.currentSrc;
+        }
+        if (typeof src === "object") {
+            return src.toString();
+        }
+        return src;
+    };
+    var getVideo = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src;
+        }
+        var video = document.createElement("video");
+        if (typeof src === "string") {
+            video.src = src;
+        }
+        else {
+            src.forEach(function (url) {
+                var source = document.createElement("source");
+                source.src = url;
+                video.appendChild(source);
+            });
+        }
+        return video;
+    };
     var VideoTexture = /** @class */ (function (_super) {
         __extends(VideoTexture, _super);
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
+        function VideoTexture(name, src, scene, generateMipMaps, invertY, samplingMode, settings) {
             if (generateMipMaps === void 0) { generateMipMaps = false; }
             if (invertY === void 0) { invertY = false; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            if (settings === void 0) { settings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }; }
             var _this = _super.call(this, null, scene, !generateMipMaps, invertY) || this;
-            _this._autoLaunch = true;
-            var urls = null;
-            _this.name = name;
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                _this.video = urlsOrVideo;
-            }
-            else {
-                urls = urlsOrVideo;
-                _this.video = document.createElement("video");
-                _this.video.autoplay = false;
-                _this.video.loop = true;
-                BABYLON.Tools.SetCorsBehavior(urls, _this.video);
-            }
+            _this._createInternalTexture = function () {
+                if (_this._texture != null) {
+                    return;
+                }
+                if (!_this._engine.needPOTTextures ||
+                    (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
+                    _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+                }
+                else {
+                    _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._generateMipMaps = false;
+                }
+                _this._texture = _this._engine.createDynamicTexture(_this.video.videoWidth, _this.video.videoHeight, _this._generateMipMaps, _this._samplingMode);
+                _this._texture.width;
+                _this._updateInternalTexture();
+                _this._texture.isReady = true;
+            };
+            _this.reset = function () {
+                if (_this._texture == null) {
+                    return;
+                }
+                _this._texture.dispose();
+                _this._texture = null;
+            };
+            _this._updateInternalTexture = function (e) {
+                if (_this._texture == null || !_this._texture.isReady) {
+                    return;
+                }
+                if (_this.video.readyState < _this.video.HAVE_CURRENT_DATA) {
+                    return;
+                }
+                _this._engine.updateVideoTexture(_this._texture, _this.video, _this._invertY);
+            };
             _this._engine = _this.getScene().getEngine();
             _this._generateMipMaps = generateMipMaps;
             _this._samplingMode = samplingMode;
-            if (!_this._engine.needPOTTextures || (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
-                _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-            }
-            else {
-                _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this._generateMipMaps = false;
+            _this.autoUpdateTexture = settings.autoUpdateTexture;
+            _this.name = name || getName(src);
+            _this.video = getVideo(src);
+            if (settings.autoPlay !== undefined) {
+                _this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                _this.video.loop = settings.loop;
+            }
+            _this.video.addEventListener("canplay", _this._createInternalTexture);
+            _this.video.addEventListener("paused", _this._updateInternalTexture);
+            _this.video.addEventListener("seeked", _this._updateInternalTexture);
+            _this.video.addEventListener("emptied", _this.reset);
+            if (_this.video.readyState >= _this.video.HAVE_CURRENT_DATA) {
+                _this._createInternalTexture();
             }
-            if (urls) {
-                _this.video.addEventListener("canplay", function () {
-                    if (_this._texture === undefined) {
-                        _this._createTexture();
-                    }
-                });
-                urls.forEach(function (url) {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    _this.video.appendChild(source);
-                });
-            }
-            else {
-                _this._createTexture();
-            }
-            _this._lastUpdate = BABYLON.Tools.Now;
             return _this;
         }
-        VideoTexture.prototype.__setTextureReady = function () {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        };
-        VideoTexture.prototype._createTexture = function () {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        };
+        /**
+         * Internal method to initiate `update`.
+         */
         VideoTexture.prototype._rebuild = function () {
             this.update();
         };
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
         VideoTexture.prototype.update = function () {
-            var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
             }
-            this._lastUpdate = now;
-            this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+            this.updateTexture(true);
+        };
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        VideoTexture.prototype.updateTexture = function (isVisible) {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        };
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        VideoTexture.prototype.updateURL = function (url) {
+            this.video.src = url;
         };
         VideoTexture.prototype.dispose = function () {
             _super.prototype.dispose.call(this);
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         };
         VideoTexture.CreateFromWebCam = function (scene, onReady, constraints) {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
+                    exact: constraints.deviceId,
                 };
             }
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                    navigator.webkitGetUserMedia ||
+                    navigator.mozGetUserMedia ||
+                    navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
             if (navigator.getUserMedia) {
                 navigator.getUserMedia({
@@ -53897,15 +54071,16 @@ var BABYLON;
                         deviceId: constraintsDeviceId,
                         width: {
                             min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                            max: (constraints && constraints.maxWidth) || 640,
                         },
                         height: {
                             min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
-                        }
-                    }
+                            max: (constraints && constraints.maxHeight) || 480,
+                        },
+                    },
                 }, function (stream) {
                     if (video.mozSrcObject !== undefined) {
+                        // hack for Firefox < 19
                         video.mozSrcObject = stream;
                     }
                     else {
@@ -63011,7 +63186,15 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * This renderer is helpfull to fill one of the render target with a geometry buffer.
+     */
     var GeometryBufferRenderer = /** @class */ (function () {
+        /**
+         * Creates a new G Buffer for the scene. @see GeometryBufferRenderer
+         * @param scene The scene the buffer belongs to
+         * @param ratio How big is the buffer related to the main canvas.
+         */
         function GeometryBufferRenderer(scene, ratio) {
             if (ratio === void 0) { ratio = 1; }
             this._enablePosition = false;
@@ -63021,6 +63204,9 @@ var BABYLON;
             this._createRenderTargets();
         }
         Object.defineProperty(GeometryBufferRenderer.prototype, "renderList", {
+            /**
+             * Set the render list (meshes to be rendered) used in the G buffer.
+             */
             set: function (meshes) {
                 this._multiRenderTarget.renderList = meshes;
             },
@@ -63028,6 +63214,10 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(GeometryBufferRenderer.prototype, "isSupported", {
+            /**
+             * Gets wether or not G buffer are supported by the running hardware.
+             * This requires draw buffer supports
+             */
             get: function () {
                 return this._multiRenderTarget.isSupported;
             },
@@ -63035,9 +63225,15 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(GeometryBufferRenderer.prototype, "enablePosition", {
+            /**
+             * Gets wether or not position are enabled for the G buffer.
+             */
             get: function () {
                 return this._enablePosition;
             },
+            /**
+             * Sets wether or not position are enabled for the G buffer.
+             */
             set: function (enable) {
                 this._enablePosition = enable;
                 this.dispose();
@@ -63046,6 +63242,33 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GeometryBufferRenderer.prototype, "scene", {
+            /**
+             * Gets the scene associated with the buffer.
+             */
+            get: function () {
+                return this._scene;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GeometryBufferRenderer.prototype, "ratio", {
+            /**
+             * Gets the ratio used by the buffer during its creation.
+             * How big is the buffer related to the main canvas.
+             */
+            get: function () {
+                return this._ratio;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Checks wether everything is ready to render a submesh to the G buffer.
+         * @param subMesh the submesh to check readiness for
+         * @param useInstances is the mesh drawn using instance or not
+         * @returns true if ready otherwise false
+         */
         GeometryBufferRenderer.prototype.isReady = function (subMesh, useInstances) {
             var material = subMesh.getMaterial();
             if (material && material.disableDepthWrite) {
@@ -63100,20 +63323,32 @@ var BABYLON;
             }
             return this._effect.isReady();
         };
+        /**
+         * Gets the current underlying G Buffer.
+         * @returns the buffer
+         */
         GeometryBufferRenderer.prototype.getGBuffer = function () {
             return this._multiRenderTarget;
         };
         Object.defineProperty(GeometryBufferRenderer.prototype, "samples", {
+            /**
+             * Gets the number of samples used to render the buffer (anti aliasing).
+             */
             get: function () {
                 return this._multiRenderTarget.samples;
             },
+            /**
+             * Sets the number of samples used to render the buffer (anti aliasing).
+             */
             set: function (value) {
                 this._multiRenderTarget.samples = value;
             },
             enumerable: true,
             configurable: true
         });
-        // Methods
+        /**
+         * Disposes the renderer and frees up associated resources.
+         */
         GeometryBufferRenderer.prototype.dispose = function () {
             this.getGBuffer().dispose();
         };
@@ -72941,7 +73176,7 @@ var BABYLON;
             engine.setDepthFunctionToLess();
             this._scene.resetCachedMaterial();
             this._colorShader.bind(worldMatrix);
-            engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 24);
+            engine.drawElementsType(BABYLON.Material.LineListDrawMode, 0, 24);
             this._colorShader.unbind();
             engine.setDepthFunctionToLessOrEqual();
             engine.setDepthWrite(true);
@@ -73562,6 +73797,10 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     var FreeCameraDeviceOrientationInput = /** @class */ (function () {
         function FreeCameraDeviceOrientationInput() {
             var _this = this;
@@ -73788,16 +74027,15 @@ var BABYLON;
             _this.onControllersAttachedObservable = new BABYLON.Observable();
             _this.onControllerMeshLoadedObservable = new BABYLON.Observable();
             _this.rigParenting = true; // should the rig cameras be used as parent instead of this camera.
-            _this._defaultHeight = 0;
+            _this._defaultHeight = undefined;
             _this.deviceDistanceToRoomGround = function () {
-                if (_this._standingMatrix) {
+                if (_this._standingMatrix && _this._defaultHeight === undefined) {
                     // Add standing matrix offset to get real offset from ground in room
                     _this._standingMatrix.getTranslationToRef(_this._workingVector);
                     return _this._deviceRoomPosition.y + _this._workingVector.y;
                 }
-                else {
-                    return _this._defaultHeight;
-                }
+                //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+                return _this._defaultHeight || 0;
             };
             _this.useStandingMatrix = function (callback) {
                 if (callback === void 0) { callback = function (bool) { }; }
@@ -74209,7 +74447,7 @@ var BABYLON;
         /**
          * Creates a new device orientation camera. @see DeviceOrientationCamera
          * @param name The name of the camera
-         * @param position The starts position camera
+         * @param position The start position camera
          * @param scene The scene the camera belongs to
          */
         function DeviceOrientationCamera(name, position, scene) {
@@ -76882,9 +77120,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        SceneOptimization.prototype.apply = function (scene) {
+        SceneOptimization.prototype.apply = function (scene, optimizer) {
             return true;
         };
         ;
@@ -76935,9 +77174,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        TextureOptimization.prototype.apply = function (scene) {
+        TextureOptimization.prototype.apply = function (scene, optimizer) {
             var allDone = true;
             for (var index = 0; index < scene.textures.length; index++) {
                 var texture = scene.textures[index];
@@ -77002,9 +77242,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        HardwareScalingOptimization.prototype.apply = function (scene) {
+        HardwareScalingOptimization.prototype.apply = function (scene, optimizer) {
             if (this._currentScale === -1) {
                 this._currentScale = scene.getEngine().getHardwareScalingLevel();
                 if (this._currentScale > this.maximumScale) {
@@ -77025,26 +77266,8 @@ var BABYLON;
      */
     var ShadowsOptimization = /** @class */ (function (_super) {
         __extends(ShadowsOptimization, _super);
-        /**
-         * Creates the ShadowsOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
-         */
-        function ShadowsOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.shadowsEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ShadowsOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77056,10 +77279,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ShadowsOptimization.prototype.apply = function (scene) {
-            scene.shadowsEnabled = this.target;
+        ShadowsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.shadowsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77072,26 +77296,8 @@ var BABYLON;
      */
     var PostProcessesOptimization = /** @class */ (function (_super) {
         __extends(PostProcessesOptimization, _super);
-        /**
-         * Creates the PostProcessesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
-         */
-        function PostProcessesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function PostProcessesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77103,10 +77309,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        PostProcessesOptimization.prototype.apply = function (scene) {
-            scene.postProcessesEnabled = this.target;
+        PostProcessesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.postProcessesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77119,26 +77326,8 @@ var BABYLON;
      */
     var LensFlaresOptimization = /** @class */ (function (_super) {
         __extends(LensFlaresOptimization, _super);
-        /**
-         * Creates the LensFlaresOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
-         */
-        function LensFlaresOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function LensFlaresOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77150,10 +77339,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        LensFlaresOptimization.prototype.apply = function (scene) {
-            scene.lensFlaresEnabled = this.target;
+        LensFlaresOptimization.prototype.apply = function (scene, optimizer) {
+            scene.lensFlaresEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77182,11 +77372,12 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        CustomOptimization.prototype.apply = function (scene) {
+        CustomOptimization.prototype.apply = function (scene, optimizer) {
             if (this.onApply) {
-                return this.onApply(scene);
+                return this.onApply(scene, optimizer);
             }
             return true;
         };
@@ -77200,26 +77391,8 @@ var BABYLON;
      */
     var ParticlesOptimization = /** @class */ (function (_super) {
         __extends(ParticlesOptimization, _super);
-        /**
-         * Creates the ParticlesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
-         */
-        function ParticlesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.particlesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ParticlesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77231,10 +77404,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ParticlesOptimization.prototype.apply = function (scene) {
-            scene.particlesEnabled = this.target;
+        ParticlesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.particlesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77260,10 +77434,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        RenderTargetsOptimization.prototype.apply = function (scene) {
-            scene.renderTargetsEnabled = false;
+        RenderTargetsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.renderTargetsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77325,10 +77500,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
          * @returns true if everything that can be done was applied
          */
-        MergeMeshesOptimization.prototype.apply = function (scene, updateSelectionTree) {
+        MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) {
             var globalPool = scene.meshes.slice(0);
             var globalLength = globalPool.length;
             for (var index = 0; index < globalLength; index++) {
@@ -77416,7 +77592,7 @@ var BABYLON;
         };
         /**
          * Add a new custom optimization
-         * @param onApply defines the callback called to apply the custom optimization.
+         * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @returns the current SceneOptimizerOptions
@@ -77564,6 +77740,16 @@ var BABYLON;
                 _this.dispose();
             });
         }
+        Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", {
+            /**
+             * Gets a boolean indicating if the optimizer is in improvement mode
+             */
+            get: function () {
+                return this._improvementMode;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", {
             /**
              * Gets the current priority level (0 at start)
@@ -77676,7 +77862,7 @@ var BABYLON;
                 var optimization = options.optimizations[index];
                 if (optimization.priority === this._currentPriorityLevel) {
                     noOptimizationApplied = false;
-                    allDone = allDone && optimization.apply(scene);
+                    allDone = allDone && optimization.apply(scene, this);
                     this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
                 }
             }

+ 368 - 182
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js

@@ -1103,6 +1103,22 @@ var BABYLON;
             return this;
         };
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color3.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color3
+         */
+        Color3.prototype.clampToRef = function (min, max, result) {
+            if (min === void 0) { min = 0; }
+            if (max === void 0) { max = 1; }
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            return this;
+        };
+        /**
          * Returns a new Color3 set with the added values of the current Color3 and of the passed one.
          */
         Color3.prototype.add = function (otherColor) {
@@ -1351,6 +1367,23 @@ var BABYLON;
             return this;
         };
         /**
+         * Clamps the rgb values by the min and max values and stores the result into "result".
+         * Returns the unmodified current Color4.
+         * @param min - minimum clamping value.  Defaults to 0
+         * @param max - maximum clamping value.  Defaults to 1
+         * @param result - color to store the result into.
+         * @returns - the original Color4
+         */
+        Color4.prototype.clampToRef = function (min, max, result) {
+            if (min === void 0) { min = 0; }
+            if (max === void 0) { max = 1; }
+            result.r = BABYLON.Scalar.Clamp(this.r, min, max);
+            result.g = BABYLON.Scalar.Clamp(this.g, min, max);
+            result.b = BABYLON.Scalar.Clamp(this.b, min, max);
+            result.a = BABYLON.Scalar.Clamp(this.a, min, max);
+            return this;
+        };
+        /**
           * Multipy an RGBA Color4 value by another and return a new Color4 object
           * @param color The Color4 (RGBA) value to multiply by
           * @returns A new Color4.
@@ -2343,6 +2376,23 @@ var BABYLON;
             return s;
         };
         /**
+         * Get angle between two vectors.
+         * @param vector0 angle between vector0 and vector1
+         * @param vector1 angle between vector0 and vector1
+         * @param normal direction of the normal.
+         * @return the angle between vector0 and vector1.
+         */
+        Vector3.GetAngleBetweenVectors = function (vector0, vector1, normal) {
+            var v0 = vector0.clone().normalize();
+            var v1 = vector1.clone().normalize();
+            var dot = Vector3.Dot(v0, v1);
+            var n = Vector3.Cross(v0, v1);
+            if (Vector3.Dot(n, normal) > 0) {
+                return Math.acos(dot);
+            }
+            return -Math.acos(dot);
+        };
+        /**
          * Returns a new Vector3 set from the index "offset" of the passed array.
          */
         Vector3.FromArray = function (array, offset) {
@@ -12693,7 +12743,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
-            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+            if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
                 return;
             }
             // Remove
@@ -15860,6 +15910,7 @@ var BABYLON;
                 return;
             }
             this._lightSources.splice(index, 1);
+            this._markSubMeshesAsLightDirty();
         };
         AbstractMesh.prototype._markSubMeshesAsDirty = function (func) {
             if (!this.subMeshes) {
@@ -17755,14 +17806,17 @@ var BABYLON;
         __extends(Camera, _super);
         function Camera(name, position, scene) {
             var _this = _super.call(this, name, scene) || this;
+            /**
+             * The vector the camera should consider as up.
+             * (default is Vector3(0, 1, 0) aka Vector3.Up())
+             */
             _this.upVector = BABYLON.Vector3.Up();
             _this.orthoLeft = null;
             _this.orthoRight = null;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             /**
-             * default : 0.8
-             * FOV is set in Radians.
+             * FOV is set in Radians. (default is 0.8)
              */
             _this.fov = 0.8;
             _this.minZ = 1;
@@ -17772,14 +17826,13 @@ var BABYLON;
             _this.isIntermediate = false;
             _this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
             /**
-            * Restricts the camera to viewing objects with the same layerMask.
-            * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-            */
+             * Restricts the camera to viewing objects with the same layerMask.
+             * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+             */
             _this.layerMask = 0x0FFFFFFF;
             /**
-            * default : FOVMODE_VERTICAL_FIXED
-            * fovMode sets the camera frustum bounds to the viewport bounds.
-            */
+             * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+             */
             _this.fovMode = Camera.FOVMODE_VERTICAL_FIXED;
             // Camera rig members
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
@@ -19974,6 +20027,24 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(Scene.prototype, "geometryBufferRenderer", {
+            /**
+             * Gets the current geometry buffer associated to the scene.
+             */
+            get: function () {
+                return this._geometryBufferRenderer;
+            },
+            /**
+             * Sets the current geometry buffer for the scene.
+             */
+            set: function (geometryBufferRenderer) {
+                if (geometryBufferRenderer && geometryBufferRenderer.isSupported) {
+                    this._geometryBufferRenderer = geometryBufferRenderer;
+                }
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(Scene.prototype, "debugLayer", {
             // Properties
             get: function () {
@@ -39111,6 +39182,12 @@ var BABYLON;
             this.camera = camera;
             this.checkInputs = function () { };
         }
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         CameraInputsManager.prototype.add = function (input) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -39128,6 +39205,11 @@ var BABYLON;
                 input.attachControl(this.attachedElement);
             }
         };
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -39196,6 +39278,9 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Remove all attached input methods from a camera
+         */
         CameraInputsManager.prototype.clear = function () {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);
@@ -39900,12 +39985,20 @@ var BABYLON;
         }
         Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
             //-- begin properties for backward compatibility for inputs
+            /**
+             * Gets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             get: function () {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
                     return mouse.angularSensibility;
                 return 0;
             },
+            /**
+             * Sets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             set: function (value) {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
@@ -44468,6 +44561,24 @@ var BABYLON;
             return action;
         };
         /**
+         * Unregisters an action to this action manager
+         * @param action The action to be unregistered
+         * @return whether the action has been unregistered
+         */
+        ActionManager.prototype.unregisterAction = function (action) {
+            var index = this.actions.indexOf(action);
+            if (index !== -1) {
+                this.actions.splice(index, 1);
+                ActionManager.Triggers[action.trigger] -= 1;
+                if (ActionManager.Triggers[action.trigger] === 0) {
+                    delete ActionManager.Triggers[action.trigger];
+                }
+                delete action._actionManager;
+                return true;
+            }
+            return false;
+        };
+        /**
          * Process a specific trigger
          * @param {number} trigger - the trigger to process
          * @param evt {BABYLON.ActionEvent} the event details to be processed
@@ -53778,104 +53889,167 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    var getName = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src.currentSrc;
+        }
+        if (typeof src === "object") {
+            return src.toString();
+        }
+        return src;
+    };
+    var getVideo = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src;
+        }
+        var video = document.createElement("video");
+        if (typeof src === "string") {
+            video.src = src;
+        }
+        else {
+            src.forEach(function (url) {
+                var source = document.createElement("source");
+                source.src = url;
+                video.appendChild(source);
+            });
+        }
+        return video;
+    };
     var VideoTexture = /** @class */ (function (_super) {
         __extends(VideoTexture, _super);
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
+        function VideoTexture(name, src, scene, generateMipMaps, invertY, samplingMode, settings) {
             if (generateMipMaps === void 0) { generateMipMaps = false; }
             if (invertY === void 0) { invertY = false; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            if (settings === void 0) { settings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }; }
             var _this = _super.call(this, null, scene, !generateMipMaps, invertY) || this;
-            _this._autoLaunch = true;
-            var urls = null;
-            _this.name = name;
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                _this.video = urlsOrVideo;
-            }
-            else {
-                urls = urlsOrVideo;
-                _this.video = document.createElement("video");
-                _this.video.autoplay = false;
-                _this.video.loop = true;
-                BABYLON.Tools.SetCorsBehavior(urls, _this.video);
-            }
+            _this._createInternalTexture = function () {
+                if (_this._texture != null) {
+                    return;
+                }
+                if (!_this._engine.needPOTTextures ||
+                    (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
+                    _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+                }
+                else {
+                    _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._generateMipMaps = false;
+                }
+                _this._texture = _this._engine.createDynamicTexture(_this.video.videoWidth, _this.video.videoHeight, _this._generateMipMaps, _this._samplingMode);
+                _this._texture.width;
+                _this._updateInternalTexture();
+                _this._texture.isReady = true;
+            };
+            _this.reset = function () {
+                if (_this._texture == null) {
+                    return;
+                }
+                _this._texture.dispose();
+                _this._texture = null;
+            };
+            _this._updateInternalTexture = function (e) {
+                if (_this._texture == null || !_this._texture.isReady) {
+                    return;
+                }
+                if (_this.video.readyState < _this.video.HAVE_CURRENT_DATA) {
+                    return;
+                }
+                _this._engine.updateVideoTexture(_this._texture, _this.video, _this._invertY);
+            };
             _this._engine = _this.getScene().getEngine();
             _this._generateMipMaps = generateMipMaps;
             _this._samplingMode = samplingMode;
-            if (!_this._engine.needPOTTextures || (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
-                _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-            }
-            else {
-                _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this._generateMipMaps = false;
+            _this.autoUpdateTexture = settings.autoUpdateTexture;
+            _this.name = name || getName(src);
+            _this.video = getVideo(src);
+            if (settings.autoPlay !== undefined) {
+                _this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                _this.video.loop = settings.loop;
+            }
+            _this.video.addEventListener("canplay", _this._createInternalTexture);
+            _this.video.addEventListener("paused", _this._updateInternalTexture);
+            _this.video.addEventListener("seeked", _this._updateInternalTexture);
+            _this.video.addEventListener("emptied", _this.reset);
+            if (_this.video.readyState >= _this.video.HAVE_CURRENT_DATA) {
+                _this._createInternalTexture();
             }
-            if (urls) {
-                _this.video.addEventListener("canplay", function () {
-                    if (_this._texture === undefined) {
-                        _this._createTexture();
-                    }
-                });
-                urls.forEach(function (url) {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    _this.video.appendChild(source);
-                });
-            }
-            else {
-                _this._createTexture();
-            }
-            _this._lastUpdate = BABYLON.Tools.Now;
             return _this;
         }
-        VideoTexture.prototype.__setTextureReady = function () {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        };
-        VideoTexture.prototype._createTexture = function () {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        };
+        /**
+         * Internal method to initiate `update`.
+         */
         VideoTexture.prototype._rebuild = function () {
             this.update();
         };
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
         VideoTexture.prototype.update = function () {
-            var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
             }
-            this._lastUpdate = now;
-            this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+            this.updateTexture(true);
+        };
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        VideoTexture.prototype.updateTexture = function (isVisible) {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        };
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        VideoTexture.prototype.updateURL = function (url) {
+            this.video.src = url;
         };
         VideoTexture.prototype.dispose = function () {
             _super.prototype.dispose.call(this);
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         };
         VideoTexture.CreateFromWebCam = function (scene, onReady, constraints) {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
+                    exact: constraints.deviceId,
                 };
             }
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                    navigator.webkitGetUserMedia ||
+                    navigator.mozGetUserMedia ||
+                    navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
             if (navigator.getUserMedia) {
                 navigator.getUserMedia({
@@ -53883,15 +54057,16 @@ var BABYLON;
                         deviceId: constraintsDeviceId,
                         width: {
                             min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                            max: (constraints && constraints.maxWidth) || 640,
                         },
                         height: {
                             min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
-                        }
-                    }
+                            max: (constraints && constraints.maxHeight) || 480,
+                        },
+                    },
                 }, function (stream) {
                     if (video.mozSrcObject !== undefined) {
+                        // hack for Firefox < 19
                         video.mozSrcObject = stream;
                     }
                     else {
@@ -62997,7 +63172,15 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * This renderer is helpfull to fill one of the render target with a geometry buffer.
+     */
     var GeometryBufferRenderer = /** @class */ (function () {
+        /**
+         * Creates a new G Buffer for the scene. @see GeometryBufferRenderer
+         * @param scene The scene the buffer belongs to
+         * @param ratio How big is the buffer related to the main canvas.
+         */
         function GeometryBufferRenderer(scene, ratio) {
             if (ratio === void 0) { ratio = 1; }
             this._enablePosition = false;
@@ -63007,6 +63190,9 @@ var BABYLON;
             this._createRenderTargets();
         }
         Object.defineProperty(GeometryBufferRenderer.prototype, "renderList", {
+            /**
+             * Set the render list (meshes to be rendered) used in the G buffer.
+             */
             set: function (meshes) {
                 this._multiRenderTarget.renderList = meshes;
             },
@@ -63014,6 +63200,10 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(GeometryBufferRenderer.prototype, "isSupported", {
+            /**
+             * Gets wether or not G buffer are supported by the running hardware.
+             * This requires draw buffer supports
+             */
             get: function () {
                 return this._multiRenderTarget.isSupported;
             },
@@ -63021,9 +63211,15 @@ var BABYLON;
             configurable: true
         });
         Object.defineProperty(GeometryBufferRenderer.prototype, "enablePosition", {
+            /**
+             * Gets wether or not position are enabled for the G buffer.
+             */
             get: function () {
                 return this._enablePosition;
             },
+            /**
+             * Sets wether or not position are enabled for the G buffer.
+             */
             set: function (enable) {
                 this._enablePosition = enable;
                 this.dispose();
@@ -63032,6 +63228,33 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Object.defineProperty(GeometryBufferRenderer.prototype, "scene", {
+            /**
+             * Gets the scene associated with the buffer.
+             */
+            get: function () {
+                return this._scene;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(GeometryBufferRenderer.prototype, "ratio", {
+            /**
+             * Gets the ratio used by the buffer during its creation.
+             * How big is the buffer related to the main canvas.
+             */
+            get: function () {
+                return this._ratio;
+            },
+            enumerable: true,
+            configurable: true
+        });
+        /**
+         * Checks wether everything is ready to render a submesh to the G buffer.
+         * @param subMesh the submesh to check readiness for
+         * @param useInstances is the mesh drawn using instance or not
+         * @returns true if ready otherwise false
+         */
         GeometryBufferRenderer.prototype.isReady = function (subMesh, useInstances) {
             var material = subMesh.getMaterial();
             if (material && material.disableDepthWrite) {
@@ -63086,20 +63309,32 @@ var BABYLON;
             }
             return this._effect.isReady();
         };
+        /**
+         * Gets the current underlying G Buffer.
+         * @returns the buffer
+         */
         GeometryBufferRenderer.prototype.getGBuffer = function () {
             return this._multiRenderTarget;
         };
         Object.defineProperty(GeometryBufferRenderer.prototype, "samples", {
+            /**
+             * Gets the number of samples used to render the buffer (anti aliasing).
+             */
             get: function () {
                 return this._multiRenderTarget.samples;
             },
+            /**
+             * Sets the number of samples used to render the buffer (anti aliasing).
+             */
             set: function (value) {
                 this._multiRenderTarget.samples = value;
             },
             enumerable: true,
             configurable: true
         });
-        // Methods
+        /**
+         * Disposes the renderer and frees up associated resources.
+         */
         GeometryBufferRenderer.prototype.dispose = function () {
             this.getGBuffer().dispose();
         };
@@ -72927,7 +73162,7 @@ var BABYLON;
             engine.setDepthFunctionToLess();
             this._scene.resetCachedMaterial();
             this._colorShader.bind(worldMatrix);
-            engine.drawElementsType(BABYLON.Material.TriangleFillMode, 0, 24);
+            engine.drawElementsType(BABYLON.Material.LineListDrawMode, 0, 24);
             this._colorShader.unbind();
             engine.setDepthFunctionToLessOrEqual();
             engine.setDepthWrite(true);
@@ -73548,6 +73783,10 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     var FreeCameraDeviceOrientationInput = /** @class */ (function () {
         function FreeCameraDeviceOrientationInput() {
             var _this = this;
@@ -73774,16 +74013,15 @@ var BABYLON;
             _this.onControllersAttachedObservable = new BABYLON.Observable();
             _this.onControllerMeshLoadedObservable = new BABYLON.Observable();
             _this.rigParenting = true; // should the rig cameras be used as parent instead of this camera.
-            _this._defaultHeight = 0;
+            _this._defaultHeight = undefined;
             _this.deviceDistanceToRoomGround = function () {
-                if (_this._standingMatrix) {
+                if (_this._standingMatrix && _this._defaultHeight === undefined) {
                     // Add standing matrix offset to get real offset from ground in room
                     _this._standingMatrix.getTranslationToRef(_this._workingVector);
                     return _this._deviceRoomPosition.y + _this._workingVector.y;
                 }
-                else {
-                    return _this._defaultHeight;
-                }
+                //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+                return _this._defaultHeight || 0;
             };
             _this.useStandingMatrix = function (callback) {
                 if (callback === void 0) { callback = function (bool) { }; }
@@ -74195,7 +74433,7 @@ var BABYLON;
         /**
          * Creates a new device orientation camera. @see DeviceOrientationCamera
          * @param name The name of the camera
-         * @param position The starts position camera
+         * @param position The start position camera
          * @param scene The scene the camera belongs to
          */
         function DeviceOrientationCamera(name, position, scene) {
@@ -76868,9 +77106,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        SceneOptimization.prototype.apply = function (scene) {
+        SceneOptimization.prototype.apply = function (scene, optimizer) {
             return true;
         };
         ;
@@ -76921,9 +77160,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        TextureOptimization.prototype.apply = function (scene) {
+        TextureOptimization.prototype.apply = function (scene, optimizer) {
             var allDone = true;
             for (var index = 0; index < scene.textures.length; index++) {
                 var texture = scene.textures[index];
@@ -76988,9 +77228,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        HardwareScalingOptimization.prototype.apply = function (scene) {
+        HardwareScalingOptimization.prototype.apply = function (scene, optimizer) {
             if (this._currentScale === -1) {
                 this._currentScale = scene.getEngine().getHardwareScalingLevel();
                 if (this._currentScale > this.maximumScale) {
@@ -77011,26 +77252,8 @@ var BABYLON;
      */
     var ShadowsOptimization = /** @class */ (function (_super) {
         __extends(ShadowsOptimization, _super);
-        /**
-         * Creates the ShadowsOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
-         */
-        function ShadowsOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.shadowsEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ShadowsOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77042,10 +77265,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ShadowsOptimization.prototype.apply = function (scene) {
-            scene.shadowsEnabled = this.target;
+        ShadowsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.shadowsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77058,26 +77282,8 @@ var BABYLON;
      */
     var PostProcessesOptimization = /** @class */ (function (_super) {
         __extends(PostProcessesOptimization, _super);
-        /**
-         * Creates the PostProcessesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
-         */
-        function PostProcessesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function PostProcessesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77089,10 +77295,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        PostProcessesOptimization.prototype.apply = function (scene) {
-            scene.postProcessesEnabled = this.target;
+        PostProcessesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.postProcessesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77105,26 +77312,8 @@ var BABYLON;
      */
     var LensFlaresOptimization = /** @class */ (function (_super) {
         __extends(LensFlaresOptimization, _super);
-        /**
-         * Creates the LensFlaresOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
-         */
-        function LensFlaresOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function LensFlaresOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77136,10 +77325,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        LensFlaresOptimization.prototype.apply = function (scene) {
-            scene.lensFlaresEnabled = this.target;
+        LensFlaresOptimization.prototype.apply = function (scene, optimizer) {
+            scene.lensFlaresEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77168,11 +77358,12 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        CustomOptimization.prototype.apply = function (scene) {
+        CustomOptimization.prototype.apply = function (scene, optimizer) {
             if (this.onApply) {
-                return this.onApply(scene);
+                return this.onApply(scene, optimizer);
             }
             return true;
         };
@@ -77186,26 +77377,8 @@ var BABYLON;
      */
     var ParticlesOptimization = /** @class */ (function (_super) {
         __extends(ParticlesOptimization, _super);
-        /**
-         * Creates the ParticlesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
-         */
-        function ParticlesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.particlesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ParticlesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77217,10 +77390,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ParticlesOptimization.prototype.apply = function (scene) {
-            scene.particlesEnabled = this.target;
+        ParticlesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.particlesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77246,10 +77420,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        RenderTargetsOptimization.prototype.apply = function (scene) {
-            scene.renderTargetsEnabled = false;
+        RenderTargetsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.renderTargetsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77311,10 +77486,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
          * @returns true if everything that can be done was applied
          */
-        MergeMeshesOptimization.prototype.apply = function (scene, updateSelectionTree) {
+        MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) {
             var globalPool = scene.meshes.slice(0);
             var globalLength = globalPool.length;
             for (var index = 0; index < globalLength; index++) {
@@ -77402,7 +77578,7 @@ var BABYLON;
         };
         /**
          * Add a new custom optimization
-         * @param onApply defines the callback called to apply the custom optimization.
+         * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @returns the current SceneOptimizerOptions
@@ -77550,6 +77726,16 @@ var BABYLON;
                 _this.dispose();
             });
         }
+        Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", {
+            /**
+             * Gets a boolean indicating if the optimizer is in improvement mode
+             */
+            get: function () {
+                return this._improvementMode;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", {
             /**
              * Gets the current priority level (0 at start)
@@ -77662,7 +77848,7 @@ var BABYLON;
                 var optimization = options.optimizations[index];
                 if (optimization.priority === this._currentPriorityLevel) {
                     noOptimizationApplied = false;
-                    allDone = allDone && optimization.apply(scene);
+                    allDone = allDone && optimization.apply(scene, this);
                     this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
                 }
             }

+ 220 - 180
dist/preview release/es6.js

@@ -12743,7 +12743,7 @@ var BABYLON;
             this._currentEffect = null;
         };
         Engine.prototype._moveBoundTextureOnTop = function (internalTexture) {
-            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+            if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
                 return;
             }
             // Remove
@@ -15910,6 +15910,7 @@ var BABYLON;
                 return;
             }
             this._lightSources.splice(index, 1);
+            this._markSubMeshesAsLightDirty();
         };
         AbstractMesh.prototype._markSubMeshesAsDirty = function (func) {
             if (!this.subMeshes) {
@@ -17805,14 +17806,17 @@ var BABYLON;
         __extends(Camera, _super);
         function Camera(name, position, scene) {
             var _this = _super.call(this, name, scene) || this;
+            /**
+             * The vector the camera should consider as up.
+             * (default is Vector3(0, 1, 0) aka Vector3.Up())
+             */
             _this.upVector = BABYLON.Vector3.Up();
             _this.orthoLeft = null;
             _this.orthoRight = null;
             _this.orthoBottom = null;
             _this.orthoTop = null;
             /**
-             * default : 0.8
-             * FOV is set in Radians.
+             * FOV is set in Radians. (default is 0.8)
              */
             _this.fov = 0.8;
             _this.minZ = 1;
@@ -17822,14 +17826,13 @@ var BABYLON;
             _this.isIntermediate = false;
             _this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
             /**
-            * Restricts the camera to viewing objects with the same layerMask.
-            * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-            */
+             * Restricts the camera to viewing objects with the same layerMask.
+             * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+             */
             _this.layerMask = 0x0FFFFFFF;
             /**
-            * default : FOVMODE_VERTICAL_FIXED
-            * fovMode sets the camera frustum bounds to the viewport bounds.
-            */
+             * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+             */
             _this.fovMode = Camera.FOVMODE_VERTICAL_FIXED;
             // Camera rig members
             _this.cameraRigMode = Camera.RIG_MODE_NONE;
@@ -39179,6 +39182,12 @@ var BABYLON;
             this.camera = camera;
             this.checkInputs = function () { };
         }
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         CameraInputsManager.prototype.add = function (input) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -39196,6 +39205,11 @@ var BABYLON;
                 input.attachControl(this.attachedElement);
             }
         };
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         CameraInputsManager.prototype.remove = function (inputToRemove) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -39264,6 +39278,9 @@ var BABYLON;
                 }
             }
         };
+        /**
+         * Remove all attached input methods from a camera
+         */
         CameraInputsManager.prototype.clear = function () {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);
@@ -39968,12 +39985,20 @@ var BABYLON;
         }
         Object.defineProperty(FreeCamera.prototype, "angularSensibility", {
             //-- begin properties for backward compatibility for inputs
+            /**
+             * Gets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             get: function () {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
                     return mouse.angularSensibility;
                 return 0;
             },
+            /**
+             * Sets the input sensibility for a mouse input. (default is 2000.0)
+             * Higher values reduce sensitivity.
+             */
             set: function (value) {
                 var mouse = this.inputs.attached["mouse"];
                 if (mouse)
@@ -54235,104 +54260,167 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    var getName = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src.currentSrc;
+        }
+        if (typeof src === "object") {
+            return src.toString();
+        }
+        return src;
+    };
+    var getVideo = function (src) {
+        if (src instanceof HTMLVideoElement) {
+            return src;
+        }
+        var video = document.createElement("video");
+        if (typeof src === "string") {
+            video.src = src;
+        }
+        else {
+            src.forEach(function (url) {
+                var source = document.createElement("source");
+                source.src = url;
+                video.appendChild(source);
+            });
+        }
+        return video;
+    };
     var VideoTexture = /** @class */ (function (_super) {
         __extends(VideoTexture, _super);
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        function VideoTexture(name, urlsOrVideo, scene, generateMipMaps, invertY, samplingMode) {
+        function VideoTexture(name, src, scene, generateMipMaps, invertY, samplingMode, settings) {
             if (generateMipMaps === void 0) { generateMipMaps = false; }
             if (invertY === void 0) { invertY = false; }
             if (samplingMode === void 0) { samplingMode = BABYLON.Texture.TRILINEAR_SAMPLINGMODE; }
+            if (settings === void 0) { settings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }; }
             var _this = _super.call(this, null, scene, !generateMipMaps, invertY) || this;
-            _this._autoLaunch = true;
-            var urls = null;
-            _this.name = name;
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                _this.video = urlsOrVideo;
-            }
-            else {
-                urls = urlsOrVideo;
-                _this.video = document.createElement("video");
-                _this.video.autoplay = false;
-                _this.video.loop = true;
-                BABYLON.Tools.SetCorsBehavior(urls, _this.video);
-            }
+            _this._createInternalTexture = function () {
+                if (_this._texture != null) {
+                    return;
+                }
+                if (!_this._engine.needPOTTextures ||
+                    (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
+                    _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+                }
+                else {
+                    _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+                    _this._generateMipMaps = false;
+                }
+                _this._texture = _this._engine.createDynamicTexture(_this.video.videoWidth, _this.video.videoHeight, _this._generateMipMaps, _this._samplingMode);
+                _this._texture.width;
+                _this._updateInternalTexture();
+                _this._texture.isReady = true;
+            };
+            _this.reset = function () {
+                if (_this._texture == null) {
+                    return;
+                }
+                _this._texture.dispose();
+                _this._texture = null;
+            };
+            _this._updateInternalTexture = function (e) {
+                if (_this._texture == null || !_this._texture.isReady) {
+                    return;
+                }
+                if (_this.video.readyState < _this.video.HAVE_CURRENT_DATA) {
+                    return;
+                }
+                _this._engine.updateVideoTexture(_this._texture, _this.video, _this._invertY);
+            };
             _this._engine = _this.getScene().getEngine();
             _this._generateMipMaps = generateMipMaps;
             _this._samplingMode = samplingMode;
-            if (!_this._engine.needPOTTextures || (BABYLON.Tools.IsExponentOfTwo(_this.video.videoWidth) && BABYLON.Tools.IsExponentOfTwo(_this.video.videoHeight))) {
-                _this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+            _this.autoUpdateTexture = settings.autoUpdateTexture;
+            _this.name = name || getName(src);
+            _this.video = getVideo(src);
+            if (settings.autoPlay !== undefined) {
+                _this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                _this.video.loop = settings.loop;
+            }
+            _this.video.addEventListener("canplay", _this._createInternalTexture);
+            _this.video.addEventListener("paused", _this._updateInternalTexture);
+            _this.video.addEventListener("seeked", _this._updateInternalTexture);
+            _this.video.addEventListener("emptied", _this.reset);
+            if (_this.video.readyState >= _this.video.HAVE_CURRENT_DATA) {
+                _this._createInternalTexture();
             }
-            else {
-                _this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-                _this._generateMipMaps = false;
-            }
-            if (urls) {
-                _this.video.addEventListener("canplay", function () {
-                    if (_this._texture === undefined) {
-                        _this._createTexture();
-                    }
-                });
-                urls.forEach(function (url) {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    _this.video.appendChild(source);
-                });
-            }
-            else {
-                _this._createTexture();
-            }
-            _this._lastUpdate = BABYLON.Tools.Now;
             return _this;
         }
-        VideoTexture.prototype.__setTextureReady = function () {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        };
-        VideoTexture.prototype._createTexture = function () {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
-            }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        };
+        /**
+         * Internal method to initiate `update`.
+         */
         VideoTexture.prototype._rebuild = function () {
             this.update();
         };
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
         VideoTexture.prototype.update = function () {
-            var now = BABYLON.Tools.Now;
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
             }
-            this._lastUpdate = now;
-            this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+            this.updateTexture(true);
+        };
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        VideoTexture.prototype.updateTexture = function (isVisible) {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        };
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        VideoTexture.prototype.updateURL = function (url) {
+            this.video.src = url;
         };
         VideoTexture.prototype.dispose = function () {
             _super.prototype.dispose.call(this);
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         };
         VideoTexture.CreateFromWebCam = function (scene, onReady, constraints) {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
+                    exact: constraints.deviceId,
                 };
             }
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                    navigator.webkitGetUserMedia ||
+                    navigator.mozGetUserMedia ||
+                    navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
             if (navigator.getUserMedia) {
                 navigator.getUserMedia({
@@ -54340,15 +54428,16 @@ var BABYLON;
                         deviceId: constraintsDeviceId,
                         width: {
                             min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                            max: (constraints && constraints.maxWidth) || 640,
                         },
                         height: {
                             min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
-                        }
-                    }
+                            max: (constraints && constraints.maxHeight) || 480,
+                        },
+                    },
                 }, function (stream) {
                     if (video.mozSrcObject !== undefined) {
+                        // hack for Firefox < 19
                         video.mozSrcObject = stream;
                     }
                     else {
@@ -74065,6 +74154,10 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     var FreeCameraDeviceOrientationInput = /** @class */ (function () {
         function FreeCameraDeviceOrientationInput() {
             var _this = this;
@@ -74291,16 +74384,15 @@ var BABYLON;
             _this.onControllersAttachedObservable = new BABYLON.Observable();
             _this.onControllerMeshLoadedObservable = new BABYLON.Observable();
             _this.rigParenting = true; // should the rig cameras be used as parent instead of this camera.
-            _this._defaultHeight = 0;
+            _this._defaultHeight = undefined;
             _this.deviceDistanceToRoomGround = function () {
-                if (_this._standingMatrix) {
+                if (_this._standingMatrix && _this._defaultHeight === undefined) {
                     // Add standing matrix offset to get real offset from ground in room
                     _this._standingMatrix.getTranslationToRef(_this._workingVector);
                     return _this._deviceRoomPosition.y + _this._workingVector.y;
                 }
-                else {
-                    return _this._defaultHeight;
-                }
+                //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+                return _this._defaultHeight || 0;
             };
             _this.useStandingMatrix = function (callback) {
                 if (callback === void 0) { callback = function (bool) { }; }
@@ -74712,7 +74804,7 @@ var BABYLON;
         /**
          * Creates a new device orientation camera. @see DeviceOrientationCamera
          * @param name The name of the camera
-         * @param position The starts position camera
+         * @param position The start position camera
          * @param scene The scene the camera belongs to
          */
         function DeviceOrientationCamera(name, position, scene) {
@@ -77385,9 +77477,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        SceneOptimization.prototype.apply = function (scene) {
+        SceneOptimization.prototype.apply = function (scene, optimizer) {
             return true;
         };
         ;
@@ -77438,9 +77531,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        TextureOptimization.prototype.apply = function (scene) {
+        TextureOptimization.prototype.apply = function (scene, optimizer) {
             var allDone = true;
             for (var index = 0; index < scene.textures.length; index++) {
                 var texture = scene.textures[index];
@@ -77505,9 +77599,10 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        HardwareScalingOptimization.prototype.apply = function (scene) {
+        HardwareScalingOptimization.prototype.apply = function (scene, optimizer) {
             if (this._currentScale === -1) {
                 this._currentScale = scene.getEngine().getHardwareScalingLevel();
                 if (this._currentScale > this.maximumScale) {
@@ -77528,26 +77623,8 @@ var BABYLON;
      */
     var ShadowsOptimization = /** @class */ (function (_super) {
         __extends(ShadowsOptimization, _super);
-        /**
-         * Creates the ShadowsOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
-         */
-        function ShadowsOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.shadowsEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ShadowsOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77559,10 +77636,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ShadowsOptimization.prototype.apply = function (scene) {
-            scene.shadowsEnabled = this.target;
+        ShadowsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.shadowsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77575,26 +77653,8 @@ var BABYLON;
      */
     var PostProcessesOptimization = /** @class */ (function (_super) {
         __extends(PostProcessesOptimization, _super);
-        /**
-         * Creates the PostProcessesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
-         */
-        function PostProcessesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function PostProcessesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77606,10 +77666,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        PostProcessesOptimization.prototype.apply = function (scene) {
-            scene.postProcessesEnabled = this.target;
+        PostProcessesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.postProcessesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77622,26 +77683,8 @@ var BABYLON;
      */
     var LensFlaresOptimization = /** @class */ (function (_super) {
         __extends(LensFlaresOptimization, _super);
-        /**
-         * Creates the LensFlaresOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
-         */
-        function LensFlaresOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function LensFlaresOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77653,10 +77696,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        LensFlaresOptimization.prototype.apply = function (scene) {
-            scene.lensFlaresEnabled = this.target;
+        LensFlaresOptimization.prototype.apply = function (scene, optimizer) {
+            scene.lensFlaresEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77685,11 +77729,12 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        CustomOptimization.prototype.apply = function (scene) {
+        CustomOptimization.prototype.apply = function (scene, optimizer) {
             if (this.onApply) {
-                return this.onApply(scene);
+                return this.onApply(scene, optimizer);
             }
             return true;
         };
@@ -77703,26 +77748,8 @@ var BABYLON;
      */
     var ParticlesOptimization = /** @class */ (function (_super) {
         __extends(ParticlesOptimization, _super);
-        /**
-         * Creates the ParticlesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
-         */
-        function ParticlesOptimization(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            priority, 
-            /**
-             * Defines the value to set the scene.particlesEnabled property to (false by default)
-             */
-            target) {
-            if (priority === void 0) { priority = 0; }
-            if (target === void 0) { target = false; }
-            var _this = _super.call(this, priority) || this;
-            _this.priority = priority;
-            _this.target = target;
-            return _this;
+        function ParticlesOptimization() {
+            return _super !== null && _super.apply(this, arguments) || this;
         }
         /**
          * Gets a string describing the action executed by the current optimization
@@ -77734,10 +77761,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        ParticlesOptimization.prototype.apply = function (scene) {
-            scene.particlesEnabled = this.target;
+        ParticlesOptimization.prototype.apply = function (scene, optimizer) {
+            scene.particlesEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77763,10 +77791,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        RenderTargetsOptimization.prototype.apply = function (scene) {
-            scene.renderTargetsEnabled = false;
+        RenderTargetsOptimization.prototype.apply = function (scene, optimizer) {
+            scene.renderTargetsEnabled = optimizer.isInImprovementMode;
             return true;
         };
         ;
@@ -77828,10 +77857,11 @@ var BABYLON;
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
          * @returns true if everything that can be done was applied
          */
-        MergeMeshesOptimization.prototype.apply = function (scene, updateSelectionTree) {
+        MergeMeshesOptimization.prototype.apply = function (scene, optimizer, updateSelectionTree) {
             var globalPool = scene.meshes.slice(0);
             var globalLength = globalPool.length;
             for (var index = 0; index < globalLength; index++) {
@@ -77919,7 +77949,7 @@ var BABYLON;
         };
         /**
          * Add a new custom optimization
-         * @param onApply defines the callback called to apply the custom optimization.
+         * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @returns the current SceneOptimizerOptions
@@ -78067,6 +78097,16 @@ var BABYLON;
                 _this.dispose();
             });
         }
+        Object.defineProperty(SceneOptimizer.prototype, "isInImprovementMode", {
+            /**
+             * Gets a boolean indicating if the optimizer is in improvement mode
+             */
+            get: function () {
+                return this._improvementMode;
+            },
+            enumerable: true,
+            configurable: true
+        });
         Object.defineProperty(SceneOptimizer.prototype, "currentPriorityLevel", {
             /**
              * Gets the current priority level (0 at start)
@@ -78179,7 +78219,7 @@ var BABYLON;
                 var optimization = options.optimizations[index];
                 if (optimization.priority === this._currentPriorityLevel) {
                     noOptimizationApplied = false;
-                    allDone = allDone && optimization.apply(scene);
+                    allDone = allDone && optimization.apply(scene, this);
                     this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
                 }
             }

+ 70 - 1
dist/preview release/gui/babylon.gui.d.ts

@@ -56,6 +56,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -509,6 +520,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -522,15 +536,70 @@ declare module BABYLON.GUI {
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
         lineSpacing: string | number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;

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

@@ -476,6 +476,17 @@ var BABYLON;
                 result.attachToMesh(mesh, supportPointerMove);
                 return result;
             };
+            /**
+             * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+             * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+             * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+             * layerMask is set through advancedTexture.layer.layerMask
+             * @param name name for the Texture
+             * @param foreground render in foreground (default is true)
+             * @param scene scene to be rendered in
+             * @param sampling method for scaling to fit screen
+             * @returns AdvancedDynamicTexture
+             */
             AdvancedDynamicTexture.CreateFullscreenUI = function (name, foreground, scene, sampling) {
                 if (foreground === void 0) { foreground = true; }
                 if (scene === void 0) { scene = null; }
@@ -3174,7 +3185,16 @@ var BABYLON;
     (function (GUI) {
         var TextBlock = /** @class */ (function (_super) {
             __extends(TextBlock, _super);
-            function TextBlock(name, text) {
+            /**
+             * Creates a new TextBlock object
+             * @param name defines the name of the control
+             * @param text defines the text to display (emptry string by default)
+             */
+            function TextBlock(
+                /**
+                 * Defines the name of the control
+                 */
+                name, text) {
                 if (text === void 0) { text = ""; }
                 var _this = _super.call(this, name) || this;
                 _this.name = name;
@@ -3189,13 +3209,34 @@ var BABYLON;
                 * @type {BABYLON.Observable}
                 */
                 _this.onTextChangedObservable = new BABYLON.Observable();
+                /**
+                * An event triggered after the text was broken up into lines
+                * @type {BABYLON.Observable}
+                */
+                _this.onLinesReadyObservable = new BABYLON.Observable();
                 _this.text = text;
                 return _this;
             }
+            Object.defineProperty(TextBlock.prototype, "lines", {
+                /**
+                 * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+                 */
+                get: function () {
+                    return this._lines;
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(TextBlock.prototype, "resizeToFit", {
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 get: function () {
                     return this._resizeToFit;
                 },
+                /**
+                 * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+                 */
                 set: function (value) {
                     this._resizeToFit = value;
                     if (this._resizeToFit) {
@@ -3207,9 +3248,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textWrapping", {
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 get: function () {
                     return this._textWrapping;
                 },
+                /**
+                 * Gets or sets a boolean indicating if text must be wrapped
+                 */
                 set: function (value) {
                     if (this._textWrapping === value) {
                         return;
@@ -3221,9 +3268,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "text", {
+                /**
+                 * Gets or sets text to display
+                 */
                 get: function () {
                     return this._text;
                 },
+                /**
+                 * Gets or sets text to display
+                 */
                 set: function (value) {
                     if (this._text === value) {
                         return;
@@ -3236,9 +3289,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textHorizontalAlignment", {
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textHorizontalAlignment;
                 },
+                /**
+                 * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textHorizontalAlignment === value) {
                         return;
@@ -3250,9 +3309,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "textVerticalAlignment", {
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 get: function () {
                     return this._textVerticalAlignment;
                 },
+                /**
+                 * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+                 */
                 set: function (value) {
                     if (this._textVerticalAlignment === value) {
                         return;
@@ -3264,9 +3329,15 @@ var BABYLON;
                 configurable: true
             });
             Object.defineProperty(TextBlock.prototype, "lineSpacing", {
+                /**
+                 * Gets or sets line spacing value
+                 */
                 get: function () {
                     return this._lineSpacing.toString(this._host);
                 },
+                /**
+                 * Gets or sets line spacing value
+                 */
                 set: function (value) {
                     if (this._lineSpacing.fromString(value)) {
                         this._markAsDirty();
@@ -3300,6 +3371,7 @@ var BABYLON;
                 }
                 context.fillText(text, this._currentMeasure.left + x, y);
             };
+            /** @ignore */
             TextBlock.prototype._draw = function (parentMeasure, context) {
                 context.save();
                 this._applyStates(context);
@@ -3324,6 +3396,7 @@ var BABYLON;
                         this._lines.push(this._parseLine(_line, context));
                     }
                 }
+                this.onLinesReadyObservable.notifyObservers(this);
             };
             TextBlock.prototype._parseLine = function (line, context) {
                 if (line === void 0) { line = ''; }

ファイルの差分が大きいため隠しています
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


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

@@ -62,6 +62,17 @@ declare module BABYLON.GUI {
         private _manageFocus();
         private _attachToOnPointerOut(scene);
         static CreateForMesh(mesh: AbstractMesh, width?: number, height?: number, supportPointerMove?: boolean): AdvancedDynamicTexture;
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+         * @param name name for the Texture
+         * @param foreground render in foreground (default is true)
+         * @param scene scene to be rendered in
+         * @param sampling method for scaling to fit screen
+         * @returns AdvancedDynamicTexture
+         */
         static CreateFullscreenUI(name: string, foreground?: boolean, scene?: Nullable<Scene>, sampling?: number): AdvancedDynamicTexture;
     }
 }
@@ -515,6 +526,9 @@ declare module BABYLON.GUI {
 
 declare module BABYLON.GUI {
     class TextBlock extends Control {
+        /**
+         * Defines the name of the control
+         */
         name: string | undefined;
         private _text;
         private _textWrapping;
@@ -528,15 +542,70 @@ declare module BABYLON.GUI {
         * @type {BABYLON.Observable}
         */
         onTextChangedObservable: Observable<TextBlock>;
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        onLinesReadyObservable: Observable<TextBlock>;
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        readonly lines: any[];
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
         resizeToFit: boolean;
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         textWrapping: boolean;
+        /**
+         * Gets or sets text to display
+         */
+        /**
+         * Gets or sets text to display
+         */
         text: string;
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         textHorizontalAlignment: number;
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */
         textVerticalAlignment: number;
+        /**
+         * Gets or sets line spacing value
+         */
+        /**
+         * Gets or sets line spacing value
+         */
         lineSpacing: string | number;
-        constructor(name?: string | undefined, text?: string);
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            name?: string | undefined, text?: string);
         protected _getTypeName(): string;
         private _drawText(text, textWidth, y, context);
+        /** @ignore */
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         protected _parseLine(line: string | undefined, context: CanvasRenderingContext2D): object;

+ 111 - 31
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -1,28 +1,65 @@
 
 declare module BABYLON {
+    interface IGLTFExporterOptions {
+        /**
+         * Interface function which indicates whether a babylon mesh should be exported or not.
+         * @param mesh
+         * @returns boolean, which indicates whether the mesh should be exported (true) or not (false)
+         */
+        shouldExportMesh?(mesh: AbstractMesh): boolean;
+    }
     class GLTF2Export {
         /**
          * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
          * @param meshes
          * @param materials
+         * @param options
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * @returns - Returns an object with a .gltf, .glb and associates textures
          * as keys and their data and paths as values.
          */
-        static GLTF(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLTF(scene: Scene, filename: string, options?: IGLTFExporterOptions): _GLTFData;
         /**
          *
          * @param meshes
          * @param filename
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        static GLB(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLB(scene: Scene, filename: string, options?: IGLTFExporterOptions): _GLTFData;
     }
 }
 
 declare module BABYLON {
+    /**
+     * glTF Alpha Mode Enum
+     */
+    enum _EGLTFAlphaModeEnum {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    /**
+     * Babylon Specular Glossiness interface
+     */
+    interface _IBabylonSpecularGlossiness {
+        diffuse: Color3;
+        opacity: number;
+        specular: Color3;
+        glossiness: number;
+    }
+    /**
+     * Babylon Metallic Roughness interface
+     */
+    interface _IBabylonMetallicRoughness {
+        baseColor: Color3;
+        opacity: number;
+        metallic: number;
+        roughness: number;
+    }
+    /**
+     * Converts Babylon Scene into glTF 2.0
+     */
     class _GLTF2Exporter {
         private bufferViews;
         private accessors;
@@ -30,18 +67,22 @@ declare module BABYLON {
         private asset;
         private scenes;
         private meshes;
+        private materials;
+        private textures;
+        private images;
         private totalByteLength;
         private babylonScene;
-        constructor(babylonScene: BABYLON.Scene);
+        private options?;
+        private imageData;
+        constructor(babylonScene: Scene, options?: IGLTFExporterOptions);
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        private createBufferView(bufferIndex, byteOffset, byteLength);
+        private createBufferView(bufferIndex, byteOffset, byteLength, name?);
         /**
          * Creates an accessor based on the supplied arguments
          * @param bufferviewIndex
@@ -51,8 +92,7 @@ declare module BABYLON {
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         private createAccessor(bufferviewIndex, name, type, componentType, count, min?, max?);
         /**
@@ -62,8 +102,7 @@ declare module BABYLON {
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         private calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride);
         /**
@@ -76,8 +115,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         private writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem);
         /**
@@ -85,32 +123,34 @@ declare module BABYLON {
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         private generateJSON(glb, glTFPrefix?, prettyPrint?);
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _generateGLTF(glTFPrefix: string): _GLTFData;
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         private generateBinary();
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        private _getPadding(num);
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _generateGLB(glTFPrefix: string): _GLTFData;
         /**
@@ -121,14 +161,19 @@ declare module BABYLON {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        private exportTexture(babylonTexture, mimeType?);
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer?);
         /**
@@ -138,8 +183,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         private createScene(babylonScene, byteOffset, dataBuffer?);
     }
@@ -150,7 +194,7 @@ declare module BABYLON {
      * Class for holding and downloading glTF file data
      */
     class _GLTFData {
-        _glTFFiles: {
+        glTFFiles: {
             [fileName: string]: string | Blob;
         };
         constructor();
@@ -160,3 +204,39 @@ declare module BABYLON {
         downloadFiles(): void;
     }
 }
+
+declare module BABYLON {
+    /**
+     * Utility methods for working with glTF material conversion properties
+     */
+    class _GLTFMaterial {
+        private static dielectricSpecular;
+        private static epsilon;
+        /**
+         * Converts Specular Glossiness to Metallic Roughness
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        static ConvertToMetallicRoughness(babylonSpecularGlossiness: _IBabylonSpecularGlossiness): _IBabylonMetallicRoughness;
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        private static PerceivedBrightness(color);
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number;
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        static GetAlphaMode(babylonMaterial: Material): string;
+    }
+}

+ 493 - 83
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -1,34 +1,45 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 var BABYLON;
 (function (BABYLON) {
+    ;
     var GLTF2Export = /** @class */ (function () {
         function GLTF2Export() {
         }
         /**
          * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
          * @param meshes
          * @param materials
+         * @param options
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * @returns - Returns an object with a .gltf, .glb and associates textures
          * as keys and their data and paths as values.
          */
-        GLTF2Export.GLTF = function (scene, filename) {
+        GLTF2Export.GLTF = function (scene, filename, options) {
             var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
-            var gltfGenerator = new BABYLON._GLTF2Exporter(scene);
-            return gltfGenerator._generateGLTF(glTFPrefix);
+            var gltfGenerator = new BABYLON._GLTF2Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLTF(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            }
         };
         /**
          *
          * @param meshes
          * @param filename
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        GLTF2Export.GLB = function (scene, filename) {
+        GLTF2Export.GLB = function (scene, filename, options) {
             var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
-            var gltfGenerator = new BABYLON._GLTF2Exporter(scene);
-            return gltfGenerator._generateGLB(glTFPrefix);
+            var gltfGenerator = new BABYLON._GLTF2Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLB(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            }
         };
         return GLTF2Export;
     }());
@@ -39,8 +50,28 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * glTF Image mimetype enum
+     */
+    var _EGLTFImageMimeTypeEnum;
+    (function (_EGLTFImageMimeTypeEnum) {
+        _EGLTFImageMimeTypeEnum["PNG"] = "image/png";
+        _EGLTFImageMimeTypeEnum["JPG"] = "image/jpeg";
+    })(_EGLTFImageMimeTypeEnum || (_EGLTFImageMimeTypeEnum = {}));
+    /**
+     * glTF Alpha Mode Enum
+     */
+    var _EGLTFAlphaModeEnum;
+    (function (_EGLTFAlphaModeEnum) {
+        _EGLTFAlphaModeEnum["OPAQUE"] = "OPAQUE";
+        _EGLTFAlphaModeEnum["MASK"] = "MASK";
+        _EGLTFAlphaModeEnum["BLEND"] = "BLEND";
+    })(_EGLTFAlphaModeEnum = BABYLON._EGLTFAlphaModeEnum || (BABYLON._EGLTFAlphaModeEnum = {}));
+    /**
+     * Converts Babylon Scene into glTF 2.0
+     */
     var _GLTF2Exporter = /** @class */ (function () {
-        function _GLTF2Exporter(babylonScene) {
+        function _GLTF2Exporter(babylonScene, options) {
             this.asset = { generator: "BabylonJS", version: "2.0" };
             this.babylonScene = babylonScene;
             this.bufferViews = new Array();
@@ -48,23 +79,31 @@ var BABYLON;
             this.meshes = new Array();
             this.scenes = new Array();
             this.nodes = new Array();
+            this.images = new Array();
+            this.materials = new Array();
+            this.imageData = {};
+            if (options !== undefined) {
+                this.options = options;
+            }
             var totalByteLength = 0;
             totalByteLength = this.createScene(this.babylonScene, totalByteLength);
             this.totalByteLength = totalByteLength;
         }
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        _GLTF2Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength) {
+        _GLTF2Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, name) {
             var bufferview = { buffer: bufferIndex, byteLength: byteLength };
             if (byteOffset > 0) {
                 bufferview.byteOffset = byteOffset;
             }
+            if (name) {
+                bufferview.name = name;
+            }
             return bufferview;
         };
         /**
@@ -76,8 +115,7 @@ var BABYLON;
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         _GLTF2Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, min, max) {
             var accessor = { name: name, bufferView: bufferviewIndex, componentType: componentType, count: count, type: type };
@@ -96,8 +134,7 @@ var BABYLON;
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         _GLTF2Exporter.prototype.calculateMinMax = function (buff, vertexStart, vertexCount, arrayOffset, stride) {
             var min = [Infinity, Infinity, Infinity];
@@ -129,8 +166,7 @@ var BABYLON;
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         _GLTF2Exporter.prototype.writeAttributeData = function (vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem) {
             var byteOff = byteOffset;
@@ -241,23 +277,65 @@ var BABYLON;
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         _GLTF2Exporter.prototype.generateJSON = function (glb, glTFPrefix, prettyPrint) {
             var buffer = { byteLength: this.totalByteLength };
             var glTF = {
-                buffers: [buffer],
-                asset: this.asset,
-                meshes: this.meshes,
-                scenes: this.scenes,
-                nodes: this.nodes,
-                bufferViews: this.bufferViews,
-                accessors: this.accessors
+                asset: this.asset
             };
-            if (this.scenes.length > 0) {
+            if (buffer.byteLength > 0) {
+                glTF.buffers = [buffer];
+            }
+            if (this.nodes && this.nodes.length !== 0) {
+                glTF.nodes = this.nodes;
+            }
+            if (this.meshes && this.meshes.length !== 0) {
+                glTF.meshes = this.meshes;
+            }
+            if (this.scenes && this.scenes.length !== 0) {
+                glTF.scenes = this.scenes;
                 glTF.scene = 0;
             }
+            if (this.bufferViews && this.bufferViews.length !== 0) {
+                glTF.bufferViews = this.bufferViews;
+            }
+            if (this.accessors && this.accessors.length !== 0) {
+                glTF.accessors = this.accessors;
+            }
+            if (this.materials && this.materials.length !== 0) {
+                glTF.materials = this.materials;
+            }
+            if (this.textures && this.textures.length !== 0) {
+                glTF.textures = this.textures;
+            }
+            if (this.images && this.images.length !== 0) {
+                if (!glb) {
+                    glTF.images = this.images;
+                }
+                else {
+                    glTF.images = [];
+                    // Replace uri with bufferview and mime type for glb
+                    var imageLength = this.images.length;
+                    var byteOffset = this.totalByteLength;
+                    for (var i = 0; i < imageLength; ++i) {
+                        var image = this.images[i];
+                        if (image.uri !== undefined) {
+                            var imageData = this.imageData[image.uri];
+                            var imageName = image.uri.split('.')[0] + " image";
+                            var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, imageName);
+                            byteOffset += imageData.data.buffer.byteLength;
+                            this.bufferViews.push(bufferView);
+                            image.bufferView = this.bufferViews.length - 1;
+                            image.name = imageName;
+                            image.mimeType = imageData.mimeType;
+                            image.uri = undefined;
+                            glTF.images.push(image);
+                        }
+                    }
+                    buffer.byteLength = byteOffset;
+                }
+            }
             if (!glb) {
                 buffer.uri = glTFPrefix + ".bin";
             }
@@ -267,8 +345,7 @@ var BABYLON;
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _GLTF2Exporter.prototype._generateGLTF = function (glTFPrefix) {
@@ -278,14 +355,18 @@ var BABYLON;
             var glTFFileName = glTFPrefix + '.gltf';
             var glTFBinFile = glTFPrefix + '.bin';
             var container = new BABYLON._GLTFData();
-            container._glTFFiles[glTFFileName] = jsonText;
-            container._glTFFiles[glTFBinFile] = bin;
+            container.glTFFiles[glTFFileName] = jsonText;
+            container.glTFFiles[glTFBinFile] = bin;
+            if (this.imageData !== null) {
+                for (var image in this.imageData) {
+                    container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
+                }
+            }
             return container;
         };
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         _GLTF2Exporter.prototype.generateBinary = function () {
             var byteOffset = 0;
@@ -295,13 +376,22 @@ var BABYLON;
             return binaryBuffer;
         };
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        _GLTF2Exporter.prototype._getPadding = function (num) {
+            var remainder = num % 4;
+            var padding = remainder === 0 ? remainder : 4 - remainder;
+            return padding;
+        };
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _GLTF2Exporter.prototype._generateGLB = function (glTFPrefix) {
             var jsonText = this.generateJSON(true);
@@ -310,11 +400,13 @@ var BABYLON;
             var headerLength = 12;
             var chunkLengthPrefix = 8;
             var jsonLength = jsonText.length;
-            var jsonRemainder = jsonLength % 4;
-            var binRemainder = binaryBuffer.byteLength % 4;
-            var jsonPadding = jsonRemainder === 0 ? jsonRemainder : 4 - jsonRemainder;
-            var binPadding = binRemainder === 0 ? binRemainder : 4 - binRemainder;
-            var byteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding;
+            var imageByteLength = 0;
+            for (var key in this.imageData) {
+                imageByteLength += this.imageData[key].data.byteLength;
+            }
+            var jsonPadding = this._getPadding(jsonLength);
+            var binPadding = this._getPadding(binaryBuffer.byteLength);
+            var byteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding + imageByteLength;
             //header
             var headerBuffer = new ArrayBuffer(headerLength);
             var headerBufferView = new DataView(headerBuffer);
@@ -339,7 +431,7 @@ var BABYLON;
             //binary chunk
             var binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
             var binaryChunkBufferView = new DataView(binaryChunkBuffer);
-            binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength, true);
+            binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength + imageByteLength, true);
             binaryChunkBufferView.setUint32(4, 0x004E4942, true);
             // binary padding
             var binPaddingBuffer = new ArrayBuffer(binPadding);
@@ -347,10 +439,15 @@ var BABYLON;
             for (var i = 0; i < binPadding; ++i) {
                 binPaddingView[i] = 0;
             }
+            var glbData = [headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer];
             // binary data
-            var glbFile = new Blob([headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer, binPaddingBuffer], { type: 'application/octet-stream' });
+            for (var key in this.imageData) {
+                glbData.push(this.imageData[key].data.buffer);
+            }
+            glbData.push(binPaddingBuffer);
+            var glbFile = new Blob(glbData, { type: 'application/octet-stream' });
             var container = new BABYLON._GLTFData();
-            container._glTFFiles[glbFileName] = glbFile;
+            container.glTFFiles[glbFileName] = glbFile;
             return container;
         };
         /**
@@ -390,14 +487,90 @@ var BABYLON;
             }
         };
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        _GLTF2Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
+            if (mimeType === void 0) { mimeType = _EGLTFImageMimeTypeEnum.JPG; }
+            var textureInfo = null;
+            var glTFTexture;
+            glTFTexture = {
+                source: this.images.length
+            };
+            var textureName = babylonTexture.getInternalTexture().url;
+            if (textureName.search('/') !== -1) {
+                var splitFilename = textureName.split('/');
+                textureName = splitFilename[splitFilename.length - 1];
+                var basefile = textureName.split('.')[0];
+                var extension = textureName.split('.')[1];
+                if (mimeType === _EGLTFImageMimeTypeEnum.JPG) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === _EGLTFImageMimeTypeEnum.PNG) {
+                    extension = ".png";
+                }
+                else {
+                    throw new Error("Unsupported mime type " + mimeType);
+                }
+                textureName = basefile + extension;
+            }
+            var pixels = babylonTexture.readPixels();
+            var imageCanvas = document.createElement('canvas');
+            imageCanvas.id = "ImageCanvas";
+            var ctx = imageCanvas.getContext('2d');
+            var size = babylonTexture.getSize();
+            imageCanvas.width = size.width;
+            imageCanvas.height = size.height;
+            var imgData = ctx.createImageData(size.width, size.height);
+            imgData.data.set(pixels);
+            ctx.putImageData(imgData, 0, 0);
+            var base64Data = imageCanvas.toDataURL(mimeType);
+            var binStr = atob(base64Data.split(',')[1]);
+            var arr = new Uint8Array(binStr.length);
+            for (var i = 0; i < binStr.length; ++i) {
+                arr[i] = binStr.charCodeAt(i);
+            }
+            var imageValues = { data: arr, mimeType: mimeType };
+            this.imageData[textureName] = imageValues;
+            if (mimeType === _EGLTFImageMimeTypeEnum.JPG) {
+                var glTFImage = {
+                    uri: textureName
+                };
+                var foundIndex = -1;
+                for (var i = 0; i < this.images.length; ++i) {
+                    if (this.images[i].uri === textureName) {
+                        foundIndex = i;
+                        break;
+                    }
+                }
+                if (foundIndex === -1) {
+                    this.images.push(glTFImage);
+                    glTFTexture.source = this.images.length - 1;
+                    this.textures.push({
+                        source: this.images.length - 1
+                    });
+                    textureInfo = {
+                        index: this.images.length - 1
+                    };
+                }
+                else {
+                    glTFTexture.source = foundIndex;
+                    textureInfo = {
+                        index: foundIndex
+                    };
+                }
+            }
+            return textureInfo;
+        };
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         _GLTF2Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
             // go through all mesh primitives (submeshes)
@@ -423,7 +596,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 12;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Positions");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -443,7 +616,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 12;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Normals");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -462,7 +635,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 16;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Tangents");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -481,7 +654,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 16;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Colors");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -500,7 +673,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 8;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords0");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -519,7 +692,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 8;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords 1");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -549,7 +722,7 @@ var BABYLON;
                         // Create bufferview
                         var indicesCount = submesh.indexCount;
                         var byteLength = indicesCount * 4;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Indices");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -559,7 +732,127 @@ var BABYLON;
                     }
                 }
                 if (bufferMesh.material) {
-                    //TODO: Implement Material
+                    if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
+                        var babylonStandardMaterial = bufferMesh.material;
+                        var glTFMaterial = { name: babylonStandardMaterial.name };
+                        if (!babylonStandardMaterial.backFaceCulling) {
+                            glTFMaterial.doubleSided = true;
+                        }
+                        if (babylonStandardMaterial.bumpTexture) {
+                            var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.normalTexture = glTFTexture;
+                            }
+                        }
+                        if (babylonStandardMaterial.emissiveTexture) {
+                            var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
+                            if (glTFEmissiveTexture) {
+                                glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                            }
+                            glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                        }
+                        if (babylonStandardMaterial.ambientTexture) {
+                            var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
+                            if (glTFOcclusionTexture) {
+                                glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                            }
+                        }
+                        // Spec Gloss
+                        var babylonSpecularGlossiness = {
+                            diffuse: babylonStandardMaterial.diffuseColor,
+                            opacity: babylonStandardMaterial.alpha,
+                            specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
+                            glossiness: babylonStandardMaterial.specularPower / 256
+                        };
+                        if (babylonStandardMaterial.specularTexture) {
+                        }
+                        var babylonMetallicRoughness = BABYLON._GLTFMaterial.ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                        var glTFPbrMetallicRoughness = {
+                            baseColorFactor: [
+                                babylonMetallicRoughness.baseColor.r,
+                                babylonMetallicRoughness.baseColor.g,
+                                babylonMetallicRoughness.baseColor.b,
+                                babylonMetallicRoughness.opacity
+                            ],
+                            metallicFactor: babylonMetallicRoughness.metallic,
+                            roughnessFactor: babylonMetallicRoughness.roughness
+                        };
+                        glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                        // TODO: Handle Textures
+                        this.materials.push(glTFMaterial);
+                        meshPrimitive.material = this.materials.length - 1;
+                    }
+                    else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        if (!this.textures) {
+                            this.textures = new Array();
+                        }
+                        var babylonPBRMaterial = bufferMesh.material;
+                        var glTFPbrMetallicRoughness = {};
+                        if (babylonPBRMaterial.baseColor) {
+                            glTFPbrMetallicRoughness.baseColorFactor = [
+                                babylonPBRMaterial.baseColor.r,
+                                babylonPBRMaterial.baseColor.g,
+                                babylonPBRMaterial.baseColor.b,
+                                babylonPBRMaterial.alpha
+                            ];
+                        }
+                        if (babylonPBRMaterial.baseTexture !== undefined) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.baseTexture);
+                            if (glTFTexture !== null) {
+                                glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                            }
+                            glTFPbrMetallicRoughness.baseColorTexture;
+                        }
+                        if (babylonPBRMaterial.metallic !== undefined) {
+                            glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
+                        }
+                        if (babylonPBRMaterial.roughness !== undefined) {
+                            glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
+                        }
+                        var glTFMaterial = {
+                            name: babylonPBRMaterial.name
+                        };
+                        if (babylonPBRMaterial.doubleSided) {
+                            glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
+                        }
+                        if (babylonPBRMaterial.normalTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.normalTexture = glTFTexture;
+                            }
+                        }
+                        if (babylonPBRMaterial.occlusionTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.occlusionTexture = glTFTexture;
+                                if (babylonPBRMaterial.occlusionStrength !== undefined) {
+                                    glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
+                                }
+                            }
+                        }
+                        if (babylonPBRMaterial.emissiveTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
+                            if (glTFTexture !== null) {
+                                glTFMaterial.emissiveTexture = glTFTexture;
+                            }
+                        }
+                        if (!babylonPBRMaterial.emissiveColor.equals(new BABYLON.Color3(0.0, 0.0, 0.0))) {
+                            glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
+                        }
+                        if (babylonPBRMaterial.transparencyMode) {
+                            var alphaMode = BABYLON._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
+                            if (alphaMode !== _EGLTFAlphaModeEnum.OPAQUE) {
+                                glTFMaterial.alphaMode = alphaMode;
+                                if (alphaMode === _EGLTFAlphaModeEnum.BLEND) {
+                                    glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
+                                }
+                            }
+                        }
+                        glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                        // TODO: Handle Textures
+                        this.materials.push(glTFMaterial);
+                        meshPrimitive.material = this.materials.length - 1;
+                    }
                 }
                 mesh.primitives.push(meshPrimitive);
             }
@@ -572,32 +865,38 @@ var BABYLON;
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         _GLTF2Exporter.prototype.createScene = function (babylonScene, byteOffset, dataBuffer) {
             if (babylonScene.meshes.length > 0) {
                 var babylonMeshes = babylonScene.meshes;
                 var scene = { nodes: new Array() };
                 for (var i = 0; i < babylonMeshes.length; ++i) {
-                    // create node to hold translation/rotation/scale and the mesh
-                    var node = { mesh: -1 };
-                    var babylonMesh = babylonMeshes[i];
-                    var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
-                    // Set transformation
-                    this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
-                    // create mesh
-                    var mesh = { primitives: new Array() };
-                    mesh.primitives = [];
-                    byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                    // go through all mesh primitives (submeshes)
-                    this.meshes.push(mesh);
-                    node.mesh = this.meshes.length - 1;
-                    if (babylonMesh.name) {
-                        node.name = babylonMesh.name;
-                    }
-                    this.nodes.push(node);
-                    scene.nodes.push(this.nodes.length - 1);
+                    if (this.options &&
+                        this.options.shouldExportMesh !== undefined &&
+                        !this.options.shouldExportMesh(babylonMeshes[i])) {
+                        continue;
+                    }
+                    else {
+                        // create node to hold translation/rotation/scale and the mesh
+                        var node = { mesh: -1 };
+                        var babylonMesh = babylonMeshes[i];
+                        var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
+                        // Set transformation
+                        this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
+                        // create mesh
+                        var mesh = { primitives: new Array() };
+                        mesh.primitives = [];
+                        byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
+                        // go through all mesh primitives (submeshes)
+                        this.meshes.push(mesh);
+                        node.mesh = this.meshes.length - 1;
+                        if (babylonMesh.name) {
+                            node.name = babylonMesh.name;
+                        }
+                        this.nodes.push(node);
+                        scene.nodes.push(this.nodes.length - 1);
+                    }
                 }
                 this.scenes.push(scene);
             }
@@ -617,7 +916,7 @@ var BABYLON;
      */
     var _GLTFData = /** @class */ (function () {
         function _GLTFData() {
-            this._glTFFiles = {};
+            this.glTFFiles = {};
         }
         /**
          * Downloads glTF data.
@@ -627,18 +926,17 @@ var BABYLON;
             * Checks for a matching suffix at the end of a string (for ES5 and lower)
             * @param str
             * @param suffix
-            *
-            * @returns {boolean} indicating whether the suffix matches or not
+            * @returns - indicating whether the suffix matches or not
             */
             function endsWith(str, suffix) {
                 return str.indexOf(suffix, str.length - suffix.length) !== -1;
             }
-            for (var key in this._glTFFiles) {
+            for (var key in this.glTFFiles) {
                 var link = document.createElement('a');
                 document.body.appendChild(link);
                 link.setAttribute("type", "hidden");
                 link.download = key;
-                var blob = this._glTFFiles[key];
+                var blob = this.glTFFiles[key];
                 var mimeType = void 0;
                 if (endsWith(key, ".glb")) {
                     mimeType = { type: "model/gltf-binary" };
@@ -659,3 +957,115 @@ var BABYLON;
 })(BABYLON || (BABYLON = {}));
 
 //# sourceMappingURL=babylon.glTFData.js.map
+
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Utility methods for working with glTF material conversion properties
+     */
+    var _GLTFMaterial = /** @class */ (function () {
+        function _GLTFMaterial() {
+        }
+        /**
+         * Converts Specular Glossiness to Metallic Roughness
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        _GLTFMaterial.ConvertToMetallicRoughness = function (babylonSpecularGlossiness) {
+            var diffuse = babylonSpecularGlossiness.diffuse;
+            var opacity = babylonSpecularGlossiness.opacity;
+            var specular = babylonSpecularGlossiness.specular;
+            var glossiness = babylonSpecularGlossiness.glossiness;
+            var oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
+            var diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
+            var specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
+            var metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
+            var diffuseScaleFactor = oneMinusSpecularStrength / (1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
+            var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
+            var baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
+            var lerpColor = BABYLON.Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
+            var baseColor = new BABYLON.Color3();
+            lerpColor.clampToRef(0, 1, baseColor);
+            var babylonMetallicRoughness = {
+                baseColor: baseColor,
+                opacity: opacity,
+                metallic: metallic,
+                roughness: 1.0 - glossiness
+            };
+            return babylonMetallicRoughness;
+        };
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        _GLTFMaterial.PerceivedBrightness = function (color) {
+            return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
+        };
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
+            if (specular < this.dielectricSpecular.r) {
+                return 0;
+            }
+            var a = this.dielectricSpecular.r;
+            var b = diffuse * oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
+            var c = this.dielectricSpecular.r - specular;
+            var D = b * b - 4.0 * a * c;
+            return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+        };
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        _GLTFMaterial.GetAlphaMode = function (babylonMaterial) {
+            if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                var babylonStandardMaterial = babylonMaterial;
+                if ((babylonStandardMaterial.alpha != 1.0) ||
+                    (babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
+                    (babylonStandardMaterial.opacityTexture != null)) {
+                    return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                }
+                else {
+                    return BABYLON._EGLTFAlphaModeEnum.OPAQUE;
+                }
+            }
+            else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                var babylonPBRMetallicRoughness = babylonMaterial;
+                switch (babylonPBRMetallicRoughness.transparencyMode) {
+                    case BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE: {
+                        return BABYLON._EGLTFAlphaModeEnum.OPAQUE;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHABLEND: {
+                        return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATEST: {
+                        return BABYLON._EGLTFAlphaModeEnum.MASK;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
+                        console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                        return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                    }
+                    default: {
+                        throw new Error("Unsupported alpha mode " + babylonPBRMetallicRoughness.transparencyMode);
+                    }
+                }
+            }
+            else {
+                throw new Error("Unsupported Babylon material type");
+            }
+        };
+        _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
+        _GLTFMaterial.epsilon = 1e-6;
+        return _GLTFMaterial;
+    }());
+    BABYLON._GLTFMaterial = _GLTFMaterial;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFMaterial.js.map

ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 493 - 83
dist/preview release/serializers/babylonjs.serializers.js

@@ -145,34 +145,45 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    ;
     var GLTF2Export = /** @class */ (function () {
         function GLTF2Export() {
         }
         /**
          * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
          * @param meshes
          * @param materials
+         * @param options
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * @returns - Returns an object with a .gltf, .glb and associates textures
          * as keys and their data and paths as values.
          */
-        GLTF2Export.GLTF = function (scene, filename) {
+        GLTF2Export.GLTF = function (scene, filename, options) {
             var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
-            var gltfGenerator = new BABYLON._GLTF2Exporter(scene);
-            return gltfGenerator._generateGLTF(glTFPrefix);
+            var gltfGenerator = new BABYLON._GLTF2Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLTF(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            }
         };
         /**
          *
          * @param meshes
          * @param filename
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        GLTF2Export.GLB = function (scene, filename) {
+        GLTF2Export.GLB = function (scene, filename, options) {
             var glTFPrefix = filename.replace(/\.[^/.]+$/, "");
-            var gltfGenerator = new BABYLON._GLTF2Exporter(scene);
-            return gltfGenerator._generateGLB(glTFPrefix);
+            var gltfGenerator = new BABYLON._GLTF2Exporter(scene, options);
+            if (scene.isReady) {
+                return gltfGenerator._generateGLB(glTFPrefix);
+            }
+            else {
+                throw new Error("glTF Serializer: Scene is not ready!");
+            }
         };
         return GLTF2Export;
     }());
@@ -183,8 +194,28 @@ var BABYLON;
 
 var BABYLON;
 (function (BABYLON) {
+    /**
+     * glTF Image mimetype enum
+     */
+    var _EGLTFImageMimeTypeEnum;
+    (function (_EGLTFImageMimeTypeEnum) {
+        _EGLTFImageMimeTypeEnum["PNG"] = "image/png";
+        _EGLTFImageMimeTypeEnum["JPG"] = "image/jpeg";
+    })(_EGLTFImageMimeTypeEnum || (_EGLTFImageMimeTypeEnum = {}));
+    /**
+     * glTF Alpha Mode Enum
+     */
+    var _EGLTFAlphaModeEnum;
+    (function (_EGLTFAlphaModeEnum) {
+        _EGLTFAlphaModeEnum["OPAQUE"] = "OPAQUE";
+        _EGLTFAlphaModeEnum["MASK"] = "MASK";
+        _EGLTFAlphaModeEnum["BLEND"] = "BLEND";
+    })(_EGLTFAlphaModeEnum = BABYLON._EGLTFAlphaModeEnum || (BABYLON._EGLTFAlphaModeEnum = {}));
+    /**
+     * Converts Babylon Scene into glTF 2.0
+     */
     var _GLTF2Exporter = /** @class */ (function () {
-        function _GLTF2Exporter(babylonScene) {
+        function _GLTF2Exporter(babylonScene, options) {
             this.asset = { generator: "BabylonJS", version: "2.0" };
             this.babylonScene = babylonScene;
             this.bufferViews = new Array();
@@ -192,23 +223,31 @@ var BABYLON;
             this.meshes = new Array();
             this.scenes = new Array();
             this.nodes = new Array();
+            this.images = new Array();
+            this.materials = new Array();
+            this.imageData = {};
+            if (options !== undefined) {
+                this.options = options;
+            }
             var totalByteLength = 0;
             totalByteLength = this.createScene(this.babylonScene, totalByteLength);
             this.totalByteLength = totalByteLength;
         }
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        _GLTF2Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength) {
+        _GLTF2Exporter.prototype.createBufferView = function (bufferIndex, byteOffset, byteLength, name) {
             var bufferview = { buffer: bufferIndex, byteLength: byteLength };
             if (byteOffset > 0) {
                 bufferview.byteOffset = byteOffset;
             }
+            if (name) {
+                bufferview.name = name;
+            }
             return bufferview;
         };
         /**
@@ -220,8 +259,7 @@ var BABYLON;
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         _GLTF2Exporter.prototype.createAccessor = function (bufferviewIndex, name, type, componentType, count, min, max) {
             var accessor = { name: name, bufferView: bufferviewIndex, componentType: componentType, count: count, type: type };
@@ -240,8 +278,7 @@ var BABYLON;
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         _GLTF2Exporter.prototype.calculateMinMax = function (buff, vertexStart, vertexCount, arrayOffset, stride) {
             var min = [Infinity, Infinity, Infinity];
@@ -273,8 +310,7 @@ var BABYLON;
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         _GLTF2Exporter.prototype.writeAttributeData = function (vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem) {
             var byteOff = byteOffset;
@@ -385,23 +421,65 @@ var BABYLON;
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         _GLTF2Exporter.prototype.generateJSON = function (glb, glTFPrefix, prettyPrint) {
             var buffer = { byteLength: this.totalByteLength };
             var glTF = {
-                buffers: [buffer],
-                asset: this.asset,
-                meshes: this.meshes,
-                scenes: this.scenes,
-                nodes: this.nodes,
-                bufferViews: this.bufferViews,
-                accessors: this.accessors
+                asset: this.asset
             };
-            if (this.scenes.length > 0) {
+            if (buffer.byteLength > 0) {
+                glTF.buffers = [buffer];
+            }
+            if (this.nodes && this.nodes.length !== 0) {
+                glTF.nodes = this.nodes;
+            }
+            if (this.meshes && this.meshes.length !== 0) {
+                glTF.meshes = this.meshes;
+            }
+            if (this.scenes && this.scenes.length !== 0) {
+                glTF.scenes = this.scenes;
                 glTF.scene = 0;
             }
+            if (this.bufferViews && this.bufferViews.length !== 0) {
+                glTF.bufferViews = this.bufferViews;
+            }
+            if (this.accessors && this.accessors.length !== 0) {
+                glTF.accessors = this.accessors;
+            }
+            if (this.materials && this.materials.length !== 0) {
+                glTF.materials = this.materials;
+            }
+            if (this.textures && this.textures.length !== 0) {
+                glTF.textures = this.textures;
+            }
+            if (this.images && this.images.length !== 0) {
+                if (!glb) {
+                    glTF.images = this.images;
+                }
+                else {
+                    glTF.images = [];
+                    // Replace uri with bufferview and mime type for glb
+                    var imageLength = this.images.length;
+                    var byteOffset = this.totalByteLength;
+                    for (var i = 0; i < imageLength; ++i) {
+                        var image = this.images[i];
+                        if (image.uri !== undefined) {
+                            var imageData = this.imageData[image.uri];
+                            var imageName = image.uri.split('.')[0] + " image";
+                            var bufferView = this.createBufferView(0, byteOffset, imageData.data.length, imageName);
+                            byteOffset += imageData.data.buffer.byteLength;
+                            this.bufferViews.push(bufferView);
+                            image.bufferView = this.bufferViews.length - 1;
+                            image.name = imageName;
+                            image.mimeType = imageData.mimeType;
+                            image.uri = undefined;
+                            glTF.images.push(image);
+                        }
+                    }
+                    buffer.byteLength = byteOffset;
+                }
+            }
             if (!glb) {
                 buffer.uri = glTFPrefix + ".bin";
             }
@@ -411,8 +489,7 @@ var BABYLON;
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _GLTF2Exporter.prototype._generateGLTF = function (glTFPrefix) {
@@ -422,14 +499,18 @@ var BABYLON;
             var glTFFileName = glTFPrefix + '.gltf';
             var glTFBinFile = glTFPrefix + '.bin';
             var container = new BABYLON._GLTFData();
-            container._glTFFiles[glTFFileName] = jsonText;
-            container._glTFFiles[glTFBinFile] = bin;
+            container.glTFFiles[glTFFileName] = jsonText;
+            container.glTFFiles[glTFBinFile] = bin;
+            if (this.imageData !== null) {
+                for (var image in this.imageData) {
+                    container.glTFFiles[image] = new Blob([this.imageData[image].data], { type: this.imageData[image].mimeType });
+                }
+            }
             return container;
         };
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         _GLTF2Exporter.prototype.generateBinary = function () {
             var byteOffset = 0;
@@ -439,13 +520,22 @@ var BABYLON;
             return binaryBuffer;
         };
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        _GLTF2Exporter.prototype._getPadding = function (num) {
+            var remainder = num % 4;
+            var padding = remainder === 0 ? remainder : 4 - remainder;
+            return padding;
+        };
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _GLTF2Exporter.prototype._generateGLB = function (glTFPrefix) {
             var jsonText = this.generateJSON(true);
@@ -454,11 +544,13 @@ var BABYLON;
             var headerLength = 12;
             var chunkLengthPrefix = 8;
             var jsonLength = jsonText.length;
-            var jsonRemainder = jsonLength % 4;
-            var binRemainder = binaryBuffer.byteLength % 4;
-            var jsonPadding = jsonRemainder === 0 ? jsonRemainder : 4 - jsonRemainder;
-            var binPadding = binRemainder === 0 ? binRemainder : 4 - binRemainder;
-            var byteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding;
+            var imageByteLength = 0;
+            for (var key in this.imageData) {
+                imageByteLength += this.imageData[key].data.byteLength;
+            }
+            var jsonPadding = this._getPadding(jsonLength);
+            var binPadding = this._getPadding(binaryBuffer.byteLength);
+            var byteLength = headerLength + (2 * chunkLengthPrefix) + jsonLength + jsonPadding + binaryBuffer.byteLength + binPadding + imageByteLength;
             //header
             var headerBuffer = new ArrayBuffer(headerLength);
             var headerBufferView = new DataView(headerBuffer);
@@ -483,7 +575,7 @@ var BABYLON;
             //binary chunk
             var binaryChunkBuffer = new ArrayBuffer(chunkLengthPrefix);
             var binaryChunkBufferView = new DataView(binaryChunkBuffer);
-            binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength, true);
+            binaryChunkBufferView.setUint32(0, binaryBuffer.byteLength + imageByteLength, true);
             binaryChunkBufferView.setUint32(4, 0x004E4942, true);
             // binary padding
             var binPaddingBuffer = new ArrayBuffer(binPadding);
@@ -491,10 +583,15 @@ var BABYLON;
             for (var i = 0; i < binPadding; ++i) {
                 binPaddingView[i] = 0;
             }
+            var glbData = [headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer];
             // binary data
-            var glbFile = new Blob([headerBuffer, jsonChunkBuffer, binaryChunkBuffer, binaryBuffer, binPaddingBuffer], { type: 'application/octet-stream' });
+            for (var key in this.imageData) {
+                glbData.push(this.imageData[key].data.buffer);
+            }
+            glbData.push(binPaddingBuffer);
+            var glbFile = new Blob(glbData, { type: 'application/octet-stream' });
             var container = new BABYLON._GLTFData();
-            container._glTFFiles[glbFileName] = glbFile;
+            container.glTFFiles[glbFileName] = glbFile;
             return container;
         };
         /**
@@ -534,14 +631,90 @@ var BABYLON;
             }
         };
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        _GLTF2Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
+            if (mimeType === void 0) { mimeType = _EGLTFImageMimeTypeEnum.JPG; }
+            var textureInfo = null;
+            var glTFTexture;
+            glTFTexture = {
+                source: this.images.length
+            };
+            var textureName = babylonTexture.getInternalTexture().url;
+            if (textureName.search('/') !== -1) {
+                var splitFilename = textureName.split('/');
+                textureName = splitFilename[splitFilename.length - 1];
+                var basefile = textureName.split('.')[0];
+                var extension = textureName.split('.')[1];
+                if (mimeType === _EGLTFImageMimeTypeEnum.JPG) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === _EGLTFImageMimeTypeEnum.PNG) {
+                    extension = ".png";
+                }
+                else {
+                    throw new Error("Unsupported mime type " + mimeType);
+                }
+                textureName = basefile + extension;
+            }
+            var pixels = babylonTexture.readPixels();
+            var imageCanvas = document.createElement('canvas');
+            imageCanvas.id = "ImageCanvas";
+            var ctx = imageCanvas.getContext('2d');
+            var size = babylonTexture.getSize();
+            imageCanvas.width = size.width;
+            imageCanvas.height = size.height;
+            var imgData = ctx.createImageData(size.width, size.height);
+            imgData.data.set(pixels);
+            ctx.putImageData(imgData, 0, 0);
+            var base64Data = imageCanvas.toDataURL(mimeType);
+            var binStr = atob(base64Data.split(',')[1]);
+            var arr = new Uint8Array(binStr.length);
+            for (var i = 0; i < binStr.length; ++i) {
+                arr[i] = binStr.charCodeAt(i);
+            }
+            var imageValues = { data: arr, mimeType: mimeType };
+            this.imageData[textureName] = imageValues;
+            if (mimeType === _EGLTFImageMimeTypeEnum.JPG) {
+                var glTFImage = {
+                    uri: textureName
+                };
+                var foundIndex = -1;
+                for (var i = 0; i < this.images.length; ++i) {
+                    if (this.images[i].uri === textureName) {
+                        foundIndex = i;
+                        break;
+                    }
+                }
+                if (foundIndex === -1) {
+                    this.images.push(glTFImage);
+                    glTFTexture.source = this.images.length - 1;
+                    this.textures.push({
+                        source: this.images.length - 1
+                    });
+                    textureInfo = {
+                        index: this.images.length - 1
+                    };
+                }
+                else {
+                    glTFTexture.source = foundIndex;
+                    textureInfo = {
+                        index: foundIndex
+                    };
+                }
+            }
+            return textureInfo;
+        };
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         _GLTF2Exporter.prototype.setPrimitiveAttributes = function (mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer) {
             // go through all mesh primitives (submeshes)
@@ -567,7 +740,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 12;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Positions");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -587,7 +760,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 12;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Normals");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -606,7 +779,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 16;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Tangents");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -625,7 +798,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 16;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Colors");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -644,7 +817,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 8;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords0");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -663,7 +836,7 @@ var BABYLON;
                     else {
                         // Create bufferview
                         var byteLength = submesh.verticesCount * 8;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Texture Coords 1");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -693,7 +866,7 @@ var BABYLON;
                         // Create bufferview
                         var indicesCount = submesh.indexCount;
                         var byteLength = indicesCount * 4;
-                        var bufferview = this.createBufferView(0, byteOffset, byteLength);
+                        var bufferview = this.createBufferView(0, byteOffset, byteLength, "Indices");
                         byteOffset += byteLength;
                         this.bufferViews.push(bufferview);
                         // Create accessor
@@ -703,7 +876,127 @@ var BABYLON;
                     }
                 }
                 if (bufferMesh.material) {
-                    //TODO: Implement Material
+                    if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
+                        var babylonStandardMaterial = bufferMesh.material;
+                        var glTFMaterial = { name: babylonStandardMaterial.name };
+                        if (!babylonStandardMaterial.backFaceCulling) {
+                            glTFMaterial.doubleSided = true;
+                        }
+                        if (babylonStandardMaterial.bumpTexture) {
+                            var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.normalTexture = glTFTexture;
+                            }
+                        }
+                        if (babylonStandardMaterial.emissiveTexture) {
+                            var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
+                            if (glTFEmissiveTexture) {
+                                glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                            }
+                            glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                        }
+                        if (babylonStandardMaterial.ambientTexture) {
+                            var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
+                            if (glTFOcclusionTexture) {
+                                glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                            }
+                        }
+                        // Spec Gloss
+                        var babylonSpecularGlossiness = {
+                            diffuse: babylonStandardMaterial.diffuseColor,
+                            opacity: babylonStandardMaterial.alpha,
+                            specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
+                            glossiness: babylonStandardMaterial.specularPower / 256
+                        };
+                        if (babylonStandardMaterial.specularTexture) {
+                        }
+                        var babylonMetallicRoughness = BABYLON._GLTFMaterial.ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                        var glTFPbrMetallicRoughness = {
+                            baseColorFactor: [
+                                babylonMetallicRoughness.baseColor.r,
+                                babylonMetallicRoughness.baseColor.g,
+                                babylonMetallicRoughness.baseColor.b,
+                                babylonMetallicRoughness.opacity
+                            ],
+                            metallicFactor: babylonMetallicRoughness.metallic,
+                            roughnessFactor: babylonMetallicRoughness.roughness
+                        };
+                        glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                        // TODO: Handle Textures
+                        this.materials.push(glTFMaterial);
+                        meshPrimitive.material = this.materials.length - 1;
+                    }
+                    else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        if (!this.textures) {
+                            this.textures = new Array();
+                        }
+                        var babylonPBRMaterial = bufferMesh.material;
+                        var glTFPbrMetallicRoughness = {};
+                        if (babylonPBRMaterial.baseColor) {
+                            glTFPbrMetallicRoughness.baseColorFactor = [
+                                babylonPBRMaterial.baseColor.r,
+                                babylonPBRMaterial.baseColor.g,
+                                babylonPBRMaterial.baseColor.b,
+                                babylonPBRMaterial.alpha
+                            ];
+                        }
+                        if (babylonPBRMaterial.baseTexture !== undefined) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.baseTexture);
+                            if (glTFTexture !== null) {
+                                glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                            }
+                            glTFPbrMetallicRoughness.baseColorTexture;
+                        }
+                        if (babylonPBRMaterial.metallic !== undefined) {
+                            glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
+                        }
+                        if (babylonPBRMaterial.roughness !== undefined) {
+                            glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
+                        }
+                        var glTFMaterial = {
+                            name: babylonPBRMaterial.name
+                        };
+                        if (babylonPBRMaterial.doubleSided) {
+                            glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
+                        }
+                        if (babylonPBRMaterial.normalTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.normalTexture = glTFTexture;
+                            }
+                        }
+                        if (babylonPBRMaterial.occlusionTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
+                            if (glTFTexture) {
+                                glTFMaterial.occlusionTexture = glTFTexture;
+                                if (babylonPBRMaterial.occlusionStrength !== undefined) {
+                                    glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
+                                }
+                            }
+                        }
+                        if (babylonPBRMaterial.emissiveTexture) {
+                            var glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
+                            if (glTFTexture !== null) {
+                                glTFMaterial.emissiveTexture = glTFTexture;
+                            }
+                        }
+                        if (!babylonPBRMaterial.emissiveColor.equals(new BABYLON.Color3(0.0, 0.0, 0.0))) {
+                            glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
+                        }
+                        if (babylonPBRMaterial.transparencyMode) {
+                            var alphaMode = BABYLON._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
+                            if (alphaMode !== _EGLTFAlphaModeEnum.OPAQUE) {
+                                glTFMaterial.alphaMode = alphaMode;
+                                if (alphaMode === _EGLTFAlphaModeEnum.BLEND) {
+                                    glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
+                                }
+                            }
+                        }
+                        glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                        // TODO: Handle Textures
+                        this.materials.push(glTFMaterial);
+                        meshPrimitive.material = this.materials.length - 1;
+                    }
                 }
                 mesh.primitives.push(meshPrimitive);
             }
@@ -716,32 +1009,38 @@ var BABYLON;
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         _GLTF2Exporter.prototype.createScene = function (babylonScene, byteOffset, dataBuffer) {
             if (babylonScene.meshes.length > 0) {
                 var babylonMeshes = babylonScene.meshes;
                 var scene = { nodes: new Array() };
                 for (var i = 0; i < babylonMeshes.length; ++i) {
-                    // create node to hold translation/rotation/scale and the mesh
-                    var node = { mesh: -1 };
-                    var babylonMesh = babylonMeshes[i];
-                    var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
-                    // Set transformation
-                    this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
-                    // create mesh
-                    var mesh = { primitives: new Array() };
-                    mesh.primitives = [];
-                    byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
-                    // go through all mesh primitives (submeshes)
-                    this.meshes.push(mesh);
-                    node.mesh = this.meshes.length - 1;
-                    if (babylonMesh.name) {
-                        node.name = babylonMesh.name;
-                    }
-                    this.nodes.push(node);
-                    scene.nodes.push(this.nodes.length - 1);
+                    if (this.options &&
+                        this.options.shouldExportMesh !== undefined &&
+                        !this.options.shouldExportMesh(babylonMeshes[i])) {
+                        continue;
+                    }
+                    else {
+                        // create node to hold translation/rotation/scale and the mesh
+                        var node = { mesh: -1 };
+                        var babylonMesh = babylonMeshes[i];
+                        var useRightHandedSystem = babylonMesh.getScene().useRightHandedSystem;
+                        // Set transformation
+                        this.setNodeTransformation(node, babylonMesh, useRightHandedSystem);
+                        // create mesh
+                        var mesh = { primitives: new Array() };
+                        mesh.primitives = [];
+                        byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer);
+                        // go through all mesh primitives (submeshes)
+                        this.meshes.push(mesh);
+                        node.mesh = this.meshes.length - 1;
+                        if (babylonMesh.name) {
+                            node.name = babylonMesh.name;
+                        }
+                        this.nodes.push(node);
+                        scene.nodes.push(this.nodes.length - 1);
+                    }
                 }
                 this.scenes.push(scene);
             }
@@ -761,7 +1060,7 @@ var BABYLON;
      */
     var _GLTFData = /** @class */ (function () {
         function _GLTFData() {
-            this._glTFFiles = {};
+            this.glTFFiles = {};
         }
         /**
          * Downloads glTF data.
@@ -771,18 +1070,17 @@ var BABYLON;
             * Checks for a matching suffix at the end of a string (for ES5 and lower)
             * @param str
             * @param suffix
-            *
-            * @returns {boolean} indicating whether the suffix matches or not
+            * @returns - indicating whether the suffix matches or not
             */
             function endsWith(str, suffix) {
                 return str.indexOf(suffix, str.length - suffix.length) !== -1;
             }
-            for (var key in this._glTFFiles) {
+            for (var key in this.glTFFiles) {
                 var link = document.createElement('a');
                 document.body.appendChild(link);
                 link.setAttribute("type", "hidden");
                 link.download = key;
-                var blob = this._glTFFiles[key];
+                var blob = this.glTFFiles[key];
                 var mimeType = void 0;
                 if (endsWith(key, ".glb")) {
                     mimeType = { type: "model/gltf-binary" };
@@ -804,6 +1102,118 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFData.js.map
 
+var BABYLON;
+(function (BABYLON) {
+    /**
+     * Utility methods for working with glTF material conversion properties
+     */
+    var _GLTFMaterial = /** @class */ (function () {
+        function _GLTFMaterial() {
+        }
+        /**
+         * Converts Specular Glossiness to Metallic Roughness
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        _GLTFMaterial.ConvertToMetallicRoughness = function (babylonSpecularGlossiness) {
+            var diffuse = babylonSpecularGlossiness.diffuse;
+            var opacity = babylonSpecularGlossiness.opacity;
+            var specular = babylonSpecularGlossiness.specular;
+            var glossiness = babylonSpecularGlossiness.glossiness;
+            var oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
+            var diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
+            var specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
+            var metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
+            var diffuseScaleFactor = oneMinusSpecularStrength / (1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
+            var baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
+            var baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
+            var lerpColor = BABYLON.Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
+            var baseColor = new BABYLON.Color3();
+            lerpColor.clampToRef(0, 1, baseColor);
+            var babylonMetallicRoughness = {
+                baseColor: baseColor,
+                opacity: opacity,
+                metallic: metallic,
+                roughness: 1.0 - glossiness
+            };
+            return babylonMetallicRoughness;
+        };
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        _GLTFMaterial.PerceivedBrightness = function (color) {
+            return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
+        };
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
+            if (specular < this.dielectricSpecular.r) {
+                return 0;
+            }
+            var a = this.dielectricSpecular.r;
+            var b = diffuse * oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
+            var c = this.dielectricSpecular.r - specular;
+            var D = b * b - 4.0 * a * c;
+            return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+        };
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        _GLTFMaterial.GetAlphaMode = function (babylonMaterial) {
+            if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                var babylonStandardMaterial = babylonMaterial;
+                if ((babylonStandardMaterial.alpha != 1.0) ||
+                    (babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
+                    (babylonStandardMaterial.opacityTexture != null)) {
+                    return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                }
+                else {
+                    return BABYLON._EGLTFAlphaModeEnum.OPAQUE;
+                }
+            }
+            else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                var babylonPBRMetallicRoughness = babylonMaterial;
+                switch (babylonPBRMetallicRoughness.transparencyMode) {
+                    case BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE: {
+                        return BABYLON._EGLTFAlphaModeEnum.OPAQUE;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHABLEND: {
+                        return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATEST: {
+                        return BABYLON._EGLTFAlphaModeEnum.MASK;
+                    }
+                    case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
+                        console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                        return BABYLON._EGLTFAlphaModeEnum.BLEND;
+                    }
+                    default: {
+                        throw new Error("Unsupported alpha mode " + babylonPBRMetallicRoughness.transparencyMode);
+                    }
+                }
+            }
+            else {
+                throw new Error("Unsupported Babylon material type");
+            }
+        };
+        _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
+        _GLTFMaterial.epsilon = 1e-6;
+        return _GLTFMaterial;
+    }());
+    BABYLON._GLTFMaterial = _GLTFMaterial;
+})(BABYLON || (BABYLON = {}));
+
+//# sourceMappingURL=babylon.glTFMaterial.js.map
+
 
 (function universalModuleDefinition(root, factory) {
                 var f = factory();

ファイルの差分が大きいため隠しています
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 111 - 31
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -14,29 +14,66 @@ declare module BABYLON {
 
 
 declare module BABYLON {
+    interface IGLTFExporterOptions {
+        /**
+         * Interface function which indicates whether a babylon mesh should be exported or not.
+         * @param mesh
+         * @returns boolean, which indicates whether the mesh should be exported (true) or not (false)
+         */
+        shouldExportMesh?(mesh: AbstractMesh): boolean;
+    }
     class GLTF2Export {
         /**
          * Exports the geometry of a Mesh array in .gltf file format.
-         * If glb is set to true, exports as .glb.
          * @param meshes
          * @param materials
+         * @param options
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .gltf, .glb and associates textures
+         * @returns - Returns an object with a .gltf, .glb and associates textures
          * as keys and their data and paths as values.
          */
-        static GLTF(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLTF(scene: Scene, filename: string, options?: IGLTFExporterOptions): _GLTFData;
         /**
          *
          * @param meshes
          * @param filename
          *
-         * @returns {[fileName: string]: string | Blob} Returns an object with a .glb filename as key and data as value
+         * @returns - Returns an object with a .glb filename as key and data as value
          */
-        static GLB(scene: BABYLON.Scene, filename: string): _GLTFData;
+        static GLB(scene: Scene, filename: string, options?: IGLTFExporterOptions): _GLTFData;
     }
 }
 
 declare module BABYLON {
+    /**
+     * glTF Alpha Mode Enum
+     */
+    enum _EGLTFAlphaModeEnum {
+        OPAQUE = "OPAQUE",
+        MASK = "MASK",
+        BLEND = "BLEND",
+    }
+    /**
+     * Babylon Specular Glossiness interface
+     */
+    interface _IBabylonSpecularGlossiness {
+        diffuse: Color3;
+        opacity: number;
+        specular: Color3;
+        glossiness: number;
+    }
+    /**
+     * Babylon Metallic Roughness interface
+     */
+    interface _IBabylonMetallicRoughness {
+        baseColor: Color3;
+        opacity: number;
+        metallic: number;
+        roughness: number;
+    }
+    /**
+     * Converts Babylon Scene into glTF 2.0
+     */
     class _GLTF2Exporter {
         private bufferViews;
         private accessors;
@@ -44,18 +81,22 @@ declare module BABYLON {
         private asset;
         private scenes;
         private meshes;
+        private materials;
+        private textures;
+        private images;
         private totalByteLength;
         private babylonScene;
-        constructor(babylonScene: BABYLON.Scene);
+        private options?;
+        private imageData;
+        constructor(babylonScene: Scene, options?: IGLTFExporterOptions);
         /**
          * Creates a buffer view based on teh supplied arguments
-         * @param bufferIndex
-         * @param byteOffset
-         * @param byteLength
-         *
-         * @returns {_IGLTFBufferView}
+         * @param {number} bufferIndex - index value of the specified buffer
+         * @param {number} byteOffset - byte offset value
+         * @param {number} byteLength - byte length of the bufferView
+         * @returns - bufferView for glTF
          */
-        private createBufferView(bufferIndex, byteOffset, byteLength);
+        private createBufferView(bufferIndex, byteOffset, byteLength, name?);
         /**
          * Creates an accessor based on the supplied arguments
          * @param bufferviewIndex
@@ -65,8 +106,7 @@ declare module BABYLON {
          * @param count
          * @param min
          * @param max
-         *
-         * @returns {_IGLTFAccessor}
+         * @returns - accessor for glTF
          */
         private createAccessor(bufferviewIndex, name, type, componentType, count, min?, max?);
         /**
@@ -76,8 +116,7 @@ declare module BABYLON {
          * @param vertexCount
          * @param arrayOffset
          * @param stride
-         *
-         * @returns {min: number[], max: number[]} min number array and max number array
+         * @returns - min number array and max number array
          */
         private calculateMinMax(buff, vertexStart, vertexCount, arrayOffset, stride);
         /**
@@ -90,8 +129,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param dataBuffer
          * @param useRightHandedSystem
-         *
-         * @returns {number} byte length
+         * @returns - byte length
          */
         private writeAttributeData(vertexBufferType, submesh, meshAttributeArray, strideSize, byteOffset, dataBuffer, useRightHandedSystem);
         /**
@@ -99,32 +137,34 @@ declare module BABYLON {
          * @param glb
          * @param glTFPrefix
          * @param prettyPrint
-         *
-         * @returns {string} json data as string
+         * @returns - json data as string
          */
         private generateJSON(glb, glTFPrefix?, prettyPrint?);
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix
-         *
-         * @returns {[x: string]: string | Blob} object with glTF json tex filename
+         * @returns - object with glTF json tex filename
          * and binary file name as keys and their data as values
          */
         _generateGLTF(glTFPrefix: string): _GLTFData;
         /**
          * Creates a binary buffer for glTF
-         *
-         * @returns {ArrayBuffer}
+         * @returns - array buffer for binary data
          */
         private generateBinary();
         /**
+         * Pads the number to a power of 4
+         * @param num - number to pad
+         * @returns - padded number
+         */
+        private _getPadding(num);
+        /**
          * Generates a glb file from the json and binary data.
          * Returns an object with the glb file name as the key and data as the value.
          * @param jsonText
          * @param binaryBuffer
          * @param glTFPrefix
-         *
-         * @returns {[glbFileName: string]: Blob} object with glb filename as key and data as value
+         * @returns - object with glb filename as key and data as value
          */
         _generateGLB(glTFPrefix: string): _GLTFData;
         /**
@@ -135,14 +175,19 @@ declare module BABYLON {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
+         *
+         * @param babylonTexture
+         * @return - glTF texture, or null if the texture format is not supported
+         */
+        private exportTexture(babylonTexture, mimeType?);
+        /**
          * Sets data for the primitive attributes of each submesh
          * @param mesh
          * @param babylonMesh
          * @param byteOffset
          * @param useRightHandedSystem
          * @param dataBuffer
-         *
-         * @returns {number} bytelength of the primitive attributes plus the passed in byteOffset
+         * @returns - bytelength of the primitive attributes plus the passed in byteOffset
          */
         private setPrimitiveAttributes(mesh, babylonMesh, byteOffset, useRightHandedSystem, dataBuffer?);
         /**
@@ -152,8 +197,7 @@ declare module BABYLON {
          * @param byteOffset
          * @param buffer
          * @param dataBuffer
-         *
-         * @returns {number} bytelength + byteoffset
+         * @returns bytelength + byteoffset
          */
         private createScene(babylonScene, byteOffset, dataBuffer?);
     }
@@ -164,7 +208,7 @@ declare module BABYLON {
      * Class for holding and downloading glTF file data
      */
     class _GLTFData {
-        _glTFFiles: {
+        glTFFiles: {
             [fileName: string]: string | Blob;
         };
         constructor();
@@ -174,3 +218,39 @@ declare module BABYLON {
         downloadFiles(): void;
     }
 }
+
+declare module BABYLON {
+    /**
+     * Utility methods for working with glTF material conversion properties
+     */
+    class _GLTFMaterial {
+        private static dielectricSpecular;
+        private static epsilon;
+        /**
+         * Converts Specular Glossiness to Metallic Roughness
+         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
+         * @returns - Babylon metallic roughness values
+         */
+        static ConvertToMetallicRoughness(babylonSpecularGlossiness: _IBabylonSpecularGlossiness): _IBabylonMetallicRoughness;
+        /**
+         * Returns the perceived brightness value based on the provided color
+         * @param color - color used in calculating the perceived brightness
+         * @returns - perceived brightness value
+         */
+        private static PerceivedBrightness(color);
+        /**
+         * Computes the metallic factor
+         * @param diffuse - diffused value
+         * @param specular - specular value
+         * @param oneMinusSpecularStrength - one minus the specular strength
+         * @returns - metallic value
+         */
+        static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number;
+        /**
+         * Gets the glTF alpha mode from the Babylon Material
+         * @param babylonMaterial - Babylon Material
+         * @returns - The Babylon alpha mode value
+         */
+        static GetAlphaMode(babylonMaterial: Material): string;
+    }
+}

+ 2 - 63
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 10550,
+  "errors": 10526,
   "babylon.typedoc.json": {
-    "errors": 10550,
+    "errors": 10526,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -7449,11 +7449,6 @@
             "MissingText": true
           }
         },
-        "upVector": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "viewport": {
           "Comments": {
             "MissingText": true
@@ -7977,18 +7972,6 @@
         }
       },
       "Method": {
-        "add": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "input": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "attachElement": {
           "Comments": {
             "MissingText": true
@@ -8018,11 +8001,6 @@
             }
           }
         },
-        "clear": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "detachElement": {
           "Comments": {
             "MissingText": true
@@ -8057,18 +8035,6 @@
             "MissingText": true
           }
         },
-        "remove": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "inputToRemove": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "removeByType": {
           "Comments": {
             "MissingText": true
@@ -17760,11 +17726,6 @@
             "MissingText": true
           }
         },
-        "angularSensibility": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "applyGravity": {
           "Comments": {
             "MissingText": true
@@ -17891,11 +17852,6 @@
       }
     },
     "FreeCameraDeviceOrientationInput": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
       "Constructor": {
         "new FreeCameraDeviceOrientationInput": {
           "Comments": {
@@ -54262,29 +54218,12 @@
           "MissingText": true
         }
       },
-      "Property": {
-        "video": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
       "Method": {
-        "_rebuild": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "dispose": {
           "Comments": {
             "MissingText": true
           }
         },
-        "update": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "CreateFromWebCam": {
           "Comments": {
             "MissingText": true

ファイルの差分が大きいため隠しています
+ 47 - 47
dist/preview release/viewer/babylon.viewer.js


+ 11 - 0
gui/src/advancedDynamicTexture.ts

@@ -529,6 +529,17 @@ module BABYLON.GUI {
             return result;
         }
 
+        /**
+         * FullScreenUI is created in a layer. This allows it to be treated like any other layer.
+         * As such, if you have a multi camera setup, you can set the layerMask on the GUI as well.
+         * When the GUI is not Created as FullscreenUI it does not respect the layerMask.
+         * layerMask is set through advancedTexture.layer.layerMask
+		 * @param name name for the Texture
+		 * @param foreground render in foreground (default is true)
+		 * @param scene scene to be rendered in
+		 * @param sampling method for scaling to fit screen
+		 * @returns AdvancedDynamicTexture
+         */
         public static CreateFullscreenUI(name: string, foreground: boolean = true, scene: Nullable<Scene> = null, sampling = Texture.BILINEAR_SAMPLINGMODE): AdvancedDynamicTexture {
             var result = new AdvancedDynamicTexture(name, 0, 0, scene, false, sampling);
 

+ 65 - 3
gui/src/controls/textBlock.ts

@@ -16,11 +16,30 @@ module BABYLON.GUI {
         */
         public onTextChangedObservable = new Observable<TextBlock>();
 
-        get resizeToFit(): boolean {
+        /**
+        * An event triggered after the text was broken up into lines
+        * @type {BABYLON.Observable}
+        */
+        public onLinesReadyObservable = new Observable<TextBlock>();
+
+        /**
+         * Return the line list (you may need to use the onLinesReadyObservable to make sure the list is ready)
+         */
+        public get lines(): any[] {
+            return this._lines;
+        }
+        
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */
+        public get resizeToFit(): boolean {
             return this._resizeToFit;
         }
 
-        set resizeToFit(value: boolean) {
+        /**
+         * Gets or sets an boolean indicating that the TextBlock will be resized to fit container
+         */        
+        public set resizeToFit(value: boolean) {
             this._resizeToFit = value;
 
             if (this._resizeToFit) {
@@ -29,10 +48,16 @@ module BABYLON.GUI {
             }
         }
 
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */
         public get textWrapping(): boolean {
             return this._textWrapping;
         }
 
+        /**
+         * Gets or sets a boolean indicating if text must be wrapped
+         */        
         public set textWrapping(value: boolean) {
             if (this._textWrapping === value) {
                 return;
@@ -41,10 +66,16 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets text to display
+         */
         public get text(): string {
             return this._text;
         }
 
+        /**
+         * Gets or sets text to display
+         */
         public set text(value: string) {
             if (this._text === value) {
                 return;
@@ -55,10 +86,16 @@ module BABYLON.GUI {
             this.onTextChangedObservable.notifyObservers(this);
         }
 
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */
         public get textHorizontalAlignment(): number {
             return this._textHorizontalAlignment;
         }
 
+        /**
+         * Gets or sets text horizontal alignment (BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER by default)
+         */        
         public set textHorizontalAlignment(value: number) {
             if (this._textHorizontalAlignment === value) {
                 return;
@@ -68,10 +105,16 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */        
         public get textVerticalAlignment(): number {
             return this._textVerticalAlignment;
         }
 
+        /**
+         * Gets or sets text vertical alignment (BABYLON.GUI.Control.VERTICAL_ALIGNMENT_CENTER by default)
+         */           
         public set textVerticalAlignment(value: number) {
             if (this._textVerticalAlignment === value) {
                 return;
@@ -81,17 +124,33 @@ module BABYLON.GUI {
             this._markAsDirty();
         }
 
+        /**
+         * Gets or sets line spacing value
+         */
         public set lineSpacing(value: string | number) {
             if (this._lineSpacing.fromString(value)) {
                 this._markAsDirty();
             }
         }
 
+        /**
+         * Gets or sets line spacing value
+         */        
         public get lineSpacing(): string | number {
             return this._lineSpacing.toString(this._host);
         }
 
-        constructor(public name?: string, text: string = "") {
+        /**
+         * Creates a new TextBlock object
+         * @param name defines the name of the control
+         * @param text defines the text to display (emptry string by default)
+         */
+        constructor(
+            /**
+             * Defines the name of the control
+             */
+            public name?: string, 
+            text: string = "") {
             super(name);
 
             this.text = text;
@@ -126,6 +185,7 @@ module BABYLON.GUI {
             context.fillText(text, this._currentMeasure.left + x, y);
         }
 
+        /** @ignore */
         public _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
             context.save();
 
@@ -151,6 +211,8 @@ module BABYLON.GUI {
                     this._lines.push(this._parseLine(_line, context));
                 }
             }
+
+            this.onLinesReadyObservable.notifyObservers(this);
         }
 
         protected _parseLine(line: string = '', context: CanvasRenderingContext2D): object {

+ 0 - 3
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1620,9 +1620,6 @@ module BABYLON.GLTF2 {
             }) as IGLTFLoaderFileRequest;
 
             this._requests.push(request);
-            request.onCompleteObservable.add(() => {
-                this._requests.splice(this._requests.indexOf(request), 1);
-            });
         }
 
         public _tryCatchOnError(handler: () => void): void {

+ 1 - 1
package.json

@@ -41,4 +41,4 @@
     },
     "readme": "Babylon.js is a 3D engine based on webgl and javascript",
     "readmeFilename": "README.md"
-}
+}

+ 5 - 1
src/Cameras/Inputs/babylon.freeCameraDeviceOrientationInput.ts

@@ -1,4 +1,8 @@
 module BABYLON {
+    /**
+     * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
+     * Screen rotation is taken into account.
+     */
     export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera> {
         private _camera: FreeCamera;
 
@@ -74,4 +78,4 @@ module BABYLON {
     }
 
     (<any>CameraInputTypes)["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;
-}
+}

+ 4 - 4
src/Cameras/VR/babylon.webVRCamera.ts

@@ -75,7 +75,7 @@ module BABYLON {
 
         private _lightOnControllers: HemisphericLight;
 
-        private _defaultHeight = 0;
+        private _defaultHeight?: number = undefined;
         constructor(name: string, position: Vector3, scene: Scene, private webVROptions: WebVROptions = {}) {
             super(name, position, scene);
             this._cache.position = Vector3.Zero();
@@ -165,13 +165,13 @@ module BABYLON {
         }
 
         public deviceDistanceToRoomGround = () => {
-            if (this._standingMatrix) {
+            if (this._standingMatrix && this._defaultHeight === undefined) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y
-            } else {
-                return this._defaultHeight;
             }
+            //If VRDisplay does not inform stage parameters and no default height is set we fallback to zero.
+            return this._defaultHeight || 0;            
         }
 
         public useStandingMatrix = (callback = (bool: boolean) => { }) => {

+ 11 - 9
src/Cameras/babylon.camera.ts

@@ -34,7 +34,7 @@
             return Camera._FOVMODE_VERTICAL_FIXED;
         }
 
-		/**
+        /**
          * This setting aligns the left and right bounds of the viewport to the left and right bounds of the camera frustum.
          *
          */
@@ -78,6 +78,10 @@
         @serializeAsVector3()
         public position: Vector3;
 
+        /**
+         * The vector the camera should consider as up.
+         * (default is Vector3(0, 1, 0) aka Vector3.Up())
+         */
         @serializeAsVector3()
         public upVector = Vector3.Up();
 
@@ -94,8 +98,7 @@
         public orthoTop: Nullable<number> = null;
 
         /**
-         * default : 0.8
-         * FOV is set in Radians.
+         * FOV is set in Radians. (default is 0.8)
          */
         @serialize()
         public fov = 0.8;
@@ -116,16 +119,15 @@
         public viewport = new Viewport(0, 0, 1.0, 1.0);
 
         /**
-        * Restricts the camera to viewing objects with the same layerMask.
-        * A camera with a layerMask of 1 will render meshes with no layerMask and meshes with a layerMask of 1.
-        */
+         * Restricts the camera to viewing objects with the same layerMask.
+         * A camera with a layerMask of 1 will render mesh.layerMask & camera.layerMask!== 0
+         */
         @serialize()
         public layerMask: number = 0x0FFFFFFF;
 
         /**
-        * default : FOVMODE_VERTICAL_FIXED
-        * fovMode sets the camera frustum bounds to the viewport bounds.
-        */
+         * fovMode sets the camera frustum bounds to the viewport bounds. (default is FOVMODE_VERTICAL_FIXED)
+         */
         @serialize()
         public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
 

+ 14 - 1
src/Cameras/babylon.cameraInputsManager.ts

@@ -28,6 +28,12 @@ module BABYLON {
             this.checkInputs = () => { };
         }
 
+        /**
+         * Add an input method to a camera.
+         * builtin inputs example: camera.inputs.addGamepad();
+         * custom inputs example: camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
+         * @param input camera input method
+         */
         public add(input: ICameraInput<TCamera>) {
             var type = input.getSimpleName();
             if (this.attached[type]) {
@@ -49,7 +55,11 @@ module BABYLON {
                 input.attachControl(this.attachedElement);
             }
         }
-
+        /**
+         * Remove a specific input method from a camera
+         * example: camera.inputs.remove(camera.inputs.attached.mouse);
+         * @param inputToRemove camera input method
+         */
         public remove(inputToRemove: ICameraInput<TCamera>) {
             for (var cam in this.attached) {
                 var input = this.attached[cam];
@@ -129,6 +139,9 @@ module BABYLON {
             }
         }
 
+        /**
+         * Remove all attached input methods from a camera
+         */
         public clear() {
             if (this.attachedElement) {
                 this.detachElement(this.attachedElement, true);

+ 4 - 3
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     // We're mainly based on the logic defined into the FreeCamera code
     /**
-     * This is a camera specifically designed to react to device orientation events such as a modern mobile device 
+     * This is a camera specifically designed to react to device orientation events such as a modern mobile device
      * being tilted forward or back and left or right.
      */
     export class DeviceOrientationCamera extends FreeCamera {
@@ -12,7 +12,7 @@ module BABYLON {
         /**
          * Creates a new device orientation camera. @see DeviceOrientationCamera
          * @param name The name of the camera
-         * @param position The starts position camera
+         * @param position The start position camera
          * @param scene The scene the camera belongs to
          */
         constructor(name: string, position: Vector3, scene: Scene) {
@@ -46,6 +46,7 @@ module BABYLON {
          * @param axis The axis to reset
          */
         public resetToCurrentRotation(axis: Axis = Axis.Y): void {
+
             //can only work if this camera has a rotation quaternion already.
             if (!this.rotationQuaternion) return;
 
@@ -67,4 +68,4 @@ module BABYLON {
             this._initialQuaternion.multiplyToRef(this.rotationQuaternion, this.rotationQuaternion);
         }
     }
-}
+}

+ 9 - 1
src/Cameras/babylon.freeCamera.ts

@@ -15,6 +15,10 @@
         public inputs: FreeCameraInputsManager;
 
         //-- begin properties for backward compatibility for inputs
+        /**
+         * Gets the input sensibility for a mouse input. (default is 2000.0)
+         * Higher values reduce sensitivity.
+         */
         public get angularSensibility(): number {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             if (mouse)
@@ -23,6 +27,10 @@
             return 0;
         }
 
+        /**
+         * Sets the input sensibility for a mouse input. (default is 2000.0)
+         * Higher values reduce sensitivity.
+         */
         public set angularSensibility(value: number) {
             var mouse = <FreeCameraMouseInput>this.inputs.attached["mouse"];
             if (mouse)
@@ -212,4 +220,4 @@
             return "FreeCamera";
         }
     }
-} 
+}

+ 1 - 1
src/Engine/babylon.engine.ts

@@ -4743,7 +4743,7 @@
         }
 
         private _moveBoundTextureOnTop(internalTexture: InternalTexture): void {
-            if (this._lastBoundInternalTextureTracker.previous === internalTexture) {
+            if (this.disableTextureBindingOptimization || this._lastBoundInternalTextureTracker.previous === internalTexture) {
                 return;
             }
 

+ 212 - 93
src/Materials/Textures/babylon.videoTexture.ts

@@ -1,44 +1,127 @@
 module BABYLON {
+    /**
+     * Settings for finer control over video usage
+     */
+    export interface VideoTextureSettings {
+        /**
+         * Applies `autoplay` to video, if specified
+         */
+        autoPlay?: boolean;
+
+        /**
+         * Applies `loop` to video, if specified
+         */
+        loop?: boolean;
+
+        /**
+         * Automatically updates internal texture from video at every frame in the render loop
+         */
+        autoUpdateTexture: boolean;
+    }
+
+    const getName = (src: string | string[] | HTMLVideoElement): string => {
+        if (src instanceof HTMLVideoElement) {
+            return src.currentSrc;
+        }
+
+        if (typeof src === "object") {
+            return src.toString();
+        }
+
+        return src;
+    };
+
+    const getVideo = (src: string | string[] | HTMLVideoElement): HTMLVideoElement => {
+        if (src instanceof HTMLVideoElement) {
+            return src;
+        }
+        const video: HTMLVideoElement = document.createElement("video");
+        if (typeof src === "string") {
+            video.src = src;
+        } else {
+            src.forEach(url => {
+                const source = document.createElement("source");
+                source.src = url;
+                video.appendChild(source);
+            });
+        }
+        return video;
+    };
+
     export class VideoTexture extends Texture {
-        public video: HTMLVideoElement;
+        /**
+         * Tells whether textures will be updated automatically or user is required to call `updateTexture` manually
+         */
+        public readonly autoUpdateTexture: boolean;
+
+        /**
+         * The video instance used by the texture internally
+         */
+        public readonly video: HTMLVideoElement;
 
-        private _autoLaunch = true;
-        private _lastUpdate: number;
-        private _generateMipMaps: boolean
-        private _setTextureReady: () => void;
+        private _generateMipMaps: boolean;
         private _engine: Engine;
 
         /**
          * Creates a video texture.
-         * Sample : https://doc.babylonjs.com/tutorials/01._Advanced_Texturing
-         * @param {Array} urlsOrVideo can be used to provide an array of urls or an already setup HTML video element.
+         * Sample : https://doc.babylonjs.com/how_to/video_texture
+         * @param {string | null} name optional name, will detect from video source, if not defined
+         * @param {(string | string[] | HTMLVideoElement)} src can be used to provide an url, array of urls or an already setup HTML video element.
          * @param {BABYLON.Scene} scene is obviously the current scene.
          * @param {boolean} generateMipMaps can be used to turn on mipmaps (Can be expensive for videoTextures because they are often updated).
          * @param {boolean} invertY is false by default but can be used to invert video on Y axis
          * @param {number} samplingMode controls the sampling method and is set to TRILINEAR_SAMPLINGMODE by default
+         * @param {VideoTextureSettings} [settings] allows finer control over video usage
          */
-        constructor(name: string, urlsOrVideo: string[] | HTMLVideoElement, scene: Scene, generateMipMaps = false, invertY = false, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
+        constructor(
+            name: Nullable<string>,
+            src: string | string[] | HTMLVideoElement,
+            scene: Nullable<Scene>,
+            generateMipMaps = false,
+            invertY = false,
+            samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE,
+            settings: VideoTextureSettings = {
+                autoPlay: true,
+                loop: true,
+                autoUpdateTexture: true,
+            }
+        ) {
             super(null, scene, !generateMipMaps, invertY);
 
-            var urls: Nullable<string[]> = null;
-            this.name = name;
+            this._engine = this.getScene()!.getEngine();
+            this._generateMipMaps = generateMipMaps;
+            this._samplingMode = samplingMode;
+            this.autoUpdateTexture = settings.autoUpdateTexture;
 
-            if (urlsOrVideo instanceof HTMLVideoElement) {
-                this.video = <any>urlsOrVideo;
-            } else {
-                urls = urlsOrVideo;
+            this.name = name || getName(src);
+            this.video = getVideo(src);
 
-                this.video = document.createElement("video");
-                this.video.autoplay = false;
-                this.video.loop = true;
-                Tools.SetCorsBehavior(urls, this.video);
+            if (settings.autoPlay !== undefined) {
+                this.video.autoplay = settings.autoPlay;
+            }
+            if (settings.loop !== undefined) {
+                this.video.loop = settings.loop;
             }
 
-            this._engine = (<Scene>this.getScene()).getEngine();
-            this._generateMipMaps = generateMipMaps;
-            this._samplingMode = samplingMode;
+            this.video.addEventListener("canplay", this._createInternalTexture);
+            this.video.addEventListener("paused", this._updateInternalTexture);
+            this.video.addEventListener("seeked", this._updateInternalTexture);
+            this.video.addEventListener("emptied", this.reset);
+
+            if (this.video.readyState >= this.video.HAVE_CURRENT_DATA) {
+                this._createInternalTexture();
+            }
+        }
 
-            if (!this._engine.needPOTTextures || (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight))) {
+        private _createInternalTexture = (): void => {
+            if (this._texture != null) {
+                return;
+            }
+
+            if (
+                !this._engine.needPOTTextures ||
+                (Tools.IsExponentOfTwo(this.video.videoWidth) && Tools.IsExponentOfTwo(this.video.videoHeight))
+            ) {
                 this.wrapU = Texture.WRAP_ADDRESSMODE;
                 this.wrapV = Texture.WRAP_ADDRESSMODE;
             } else {
@@ -47,110 +130,146 @@
                 this._generateMipMaps = false;
             }
 
-            if (urls) {
-                this.video.addEventListener("canplay", () => {
-                    if (this._texture === undefined){ 
-                      this._createTexture();
-                    }
-                });
-                urls.forEach(url => {
-                    var source = document.createElement("source");
-                    source.src = url;
-                    this.video.appendChild(source);
-                });
-            } else {
-                this._createTexture();
-            }
+            this._texture = this._engine.createDynamicTexture(
+                this.video.videoWidth,
+                this.video.videoHeight,
+                this._generateMipMaps,
+                this._samplingMode
+            );
+            this._texture.width;
 
-            this._lastUpdate = Tools.Now;
-        }
-
-        private __setTextureReady(): void {
-            if (this._texture) {
-                this._texture.isReady = true;
-            }
-        }
+            this._updateInternalTexture();
 
-        private _createTexture(): void {
-            this._texture = this._engine.createDynamicTexture(this.video.videoWidth, this.video.videoHeight, this._generateMipMaps, this._samplingMode);
+            this._texture.isReady = true;
+        };
 
-            if (this._autoLaunch) {
-                this._autoLaunch = false;
-                this.video.play();
+        private reset = (): void => {
+            if (this._texture == null) {
+                return;
             }
-            this._setTextureReady = this.__setTextureReady.bind(this);
-            this.video.addEventListener("playing", this._setTextureReady);
-        }
-
+            this._texture.dispose();
+            this._texture = null;
+        };
 
+        /**
+         * Internal method to initiate `update`.
+         */
         public _rebuild(): void {
             this.update();
         }
 
-        public update(): boolean {
-            var now = Tools.Now;
+        /**
+         * Update Texture in the `auto` mode. Does not do anything if `settings.autoUpdateTexture` is false.
+         */
+        public update(): void {
+            if (!this.autoUpdateTexture) {
+                // Expecting user to call `updateTexture` manually
+                return;
+            }
 
-            if (now - this._lastUpdate < 15 || this.video.readyState !== this.video.HAVE_ENOUGH_DATA) {
-                return false;
+            this.updateTexture(true);
+        }
+
+        /**
+         * Update Texture in `manual` mode. Does not do anything if not visible or paused.
+         * @param isVisible Visibility state, detected by user using `scene.getActiveMeshes()` or othervise.
+         */
+        public updateTexture(isVisible: boolean): void {
+            if (!isVisible) {
+                return;
+            }
+            if (this.video.paused) {
+                return;
+            }
+            this._updateInternalTexture();
+        }
+
+        protected _updateInternalTexture = (e?: Event): void => {
+            if (this._texture == null || !this._texture.isReady) {
+                return;
+            }
+            if (this.video.readyState < this.video.HAVE_CURRENT_DATA) {
+                return;
             }
 
-            this._lastUpdate = now;
             this._engine.updateVideoTexture(this._texture, this.video, this._invertY);
-            return true;
+        };
+
+        /**
+         * Change video content. Changing video instance or setting multiple urls (as in constructor) is not supported.
+         * @param url New url.
+         */
+        public updateURL(url: string): void {
+            this.video.src = url;
         }
 
         public dispose(): void {
             super.dispose();
-            this.video.removeEventListener("playing", this._setTextureReady);
+            this.video.removeEventListener("canplay", this._createInternalTexture);
+            this.video.removeEventListener("paused", this._updateInternalTexture);
+            this.video.removeEventListener("seeked", this._updateInternalTexture);
+            this.video.removeEventListener("emptied", this.reset);
         }
 
-        public static CreateFromWebCam(scene: Scene, onReady: (videoTexture: VideoTexture) => void, constraints: {
-            minWidth: number,
-            maxWidth: number,
-            minHeight: number,
-            maxHeight: number,
-            deviceId: string
-        }): void {
+        public static CreateFromWebCam(
+            scene: Scene,
+            onReady: (videoTexture: VideoTexture) => void,
+            constraints: {
+                minWidth: number;
+                maxWidth: number;
+                minHeight: number;
+                maxHeight: number;
+                deviceId: string;
+            }
+        ): void {
             var video = document.createElement("video");
             var constraintsDeviceId;
             if (constraints && constraints.deviceId) {
                 constraintsDeviceId = {
-                    exact: constraints.deviceId
-                }
+                    exact: constraints.deviceId,
+                };
             }
 
-            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+            navigator.getUserMedia =
+                navigator.getUserMedia ||
+                navigator.webkitGetUserMedia ||
+                navigator.mozGetUserMedia ||
+                navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
 
             if (navigator.getUserMedia) {
-                navigator.getUserMedia({
-                    video: {
-                        deviceId: constraintsDeviceId,
-                        width: {
-                            min: (constraints && constraints.minWidth) || 256,
-                            max: (constraints && constraints.maxWidth) || 640
+                navigator.getUserMedia(
+                    {
+                        video: {
+                            deviceId: constraintsDeviceId,
+                            width: {
+                                min: (constraints && constraints.minWidth) || 256,
+                                max: (constraints && constraints.maxWidth) || 640,
+                            },
+                            height: {
+                                min: (constraints && constraints.minHeight) || 256,
+                                max: (constraints && constraints.maxHeight) || 480,
+                            },
                         },
-                        height: {
-                            min: (constraints && constraints.minHeight) || 256,
-                            max: (constraints && constraints.maxHeight) || 480
+                    },
+                    (stream: any) => {
+                        if (video.mozSrcObject !== undefined) {
+                            // hack for Firefox < 19
+                            video.mozSrcObject = stream;
+                        } else {
+                            video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
                         }
-                    }
-                }, (stream: any) => {
-
-                    if (video.mozSrcObject !== undefined) { // hack for Firefox < 19
-                        video.mozSrcObject = stream;
-                    } else {
-                        video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
-                    }
 
-                    video.play();
+                        video.play();
 
-                    if (onReady) {
-                        onReady(new VideoTexture("video", video, scene, true, true));
+                        if (onReady) {
+                            onReady(new VideoTexture("video", video, scene, true, true));
+                        }
+                    },
+                    function(e: MediaStreamError) {
+                        Tools.Error(e.name);
                     }
-                }, function (e: MediaStreamError) {
-                    Tools.Error(e.name);
-                });
+                );
             }
         }
     }

+ 2 - 0
src/Mesh/babylon.abstractMesh.ts

@@ -539,6 +539,8 @@
                 return;
             }
             this._lightSources.splice(index, 1);
+
+            this._markSubMeshesAsLightDirty();
         }
 
         private _markSubMeshesAsDirty(func: (defines: MaterialDefines) => void) {

+ 37 - 88
src/Tools/babylon.sceneOptimizer.ts

@@ -15,9 +15,10 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
             return true;
         };
 
@@ -72,9 +73,10 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
 
             var allDone = true;
             for (var index = 0; index < scene.textures.length; index++) {
@@ -138,9 +140,10 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
             if (this._currentScale === -1) {
                 this._currentScale = scene.getEngine().getHardwareScalingLevel();
                 if (this._currentScale > this.maximumScale) {
@@ -170,29 +173,13 @@
         }
 
         /**
-         * Creates the ShadowsOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.shadowsEnabled property to (false by default)
-         */
-        constructor(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            public priority: number = 0,
-            /**
-             * Defines the value to set the scene.shadowsEnabled property to (false by default)
-             */
-            public target = false) {
-            super(priority);
-        }
-
-        /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
-            scene.shadowsEnabled = this.target;
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
+            scene.shadowsEnabled = optimizer.isInImprovementMode;
             return true;
         };
     }
@@ -211,29 +198,13 @@
         }
 
         /**
-         * Creates the PostProcessesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.postProcessesEnabled property to (false by default)
-         */
-        constructor(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            public priority: number = 0,
-            /**
-             * Defines the value to set the scene.postProcessesEnabled property to (false by default)
-             */
-            public target = false) {
-            super(priority);
-        }
-
-        /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
-            scene.postProcessesEnabled = this.target;
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
+            scene.postProcessesEnabled = optimizer.isInImprovementMode;
             return true;
         };
     }
@@ -252,29 +223,13 @@
         }
 
         /**
-         * Creates the LensFlaresOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.lensFlaresEnabled property to (false by default)
-         */
-        constructor(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            public priority: number = 0,
-            /**
-             * Defines the value to set the scene.lensFlaresEnabled property to (false by default)
-             */
-            public target = false) {
-            super(priority);
-        }
-
-        /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
-            scene.lensFlaresEnabled = this.target;
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
+            scene.lensFlaresEnabled = optimizer.isInImprovementMode;
             return true;
         };
     }
@@ -287,7 +242,7 @@
         /**
          * Callback called to apply the custom optimization.
          */
-        public onApply: (scene: Scene) => boolean;
+        public onApply: (scene: Scene, optimizer: SceneOptimizer) => boolean;
 
         /**
          * Callback called to get custom description
@@ -309,11 +264,12 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
             if (this.onApply) {
-                return this.onApply(scene);
+                return this.onApply(scene, optimizer);
             }
             return true;
         };
@@ -333,29 +289,13 @@
         }
 
         /**
-         * Creates the ParticlesOptimization object
-         * @param priority defines the priority of this optimization (0 by default which means first in the list)
-         * @param target defines the value to set the scene.particlesEnabled property to (false by default)
-         */
-        constructor(
-            /**
-             * Defines the priority of this optimization (0 by default which means first in the list)
-             */
-            public priority: number = 0,
-            /**
-             * Defines the value to set the scene.particlesEnabled property to (false by default)
-             */
-            public target = false) {
-            super(priority);
-        }
-
-        /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
-            scene.particlesEnabled = this.target;
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
+            scene.particlesEnabled = optimizer.isInImprovementMode;
             return true;
         };
     }
@@ -376,10 +316,11 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene): boolean {
-            scene.renderTargetsEnabled = false;
+        public apply(scene: Scene, optimizer: SceneOptimizer): boolean {
+            scene.renderTargetsEnabled = optimizer.isInImprovementMode;
             return true;
         };
     }
@@ -443,10 +384,11 @@
         /**
          * This function will be called by the SceneOptimizer when its priority is reached in order to apply the change required by the current optimization
          * @param scene defines the current scene where to apply this optimization
+         * @param optimizer defines the current optimizer
          * @param updateSelectionTree defines that the selection octree has to be updated (false by default)
          * @returns true if everything that can be done was applied
          */
-        public apply(scene: Scene, updateSelectionTree?: boolean): boolean {
+        public apply(scene: Scene, optimizer: SceneOptimizer, updateSelectionTree?: boolean): boolean {
 
             var globalPool = scene.meshes.slice(0);
             var globalLength = globalPool.length;
@@ -545,12 +487,12 @@
 
         /**
          * Add a new custom optimization
-         * @param onApply defines the callback called to apply the custom optimization.
+         * @param onApply defines the callback called to apply the custom optimization (true if everything that can be done was applied)
          * @param onGetDescription defines the callback called to get the description attached with the optimization.
          * @param priority defines the priority of this optimization (0 by default which means first in the list)
          * @returns the current SceneOptimizerOptions
          */
-        public addCustomOptimization(onApply: (scene: Scene) => boolean, onGetDescription: () => string, priority: number = 0): SceneOptimizerOptions {
+        public addCustomOptimization(onApply: (scene: Scene, ) => boolean, onGetDescription: () => string, priority: number = 0): SceneOptimizerOptions {
             let optimization = new CustomOptimization(priority);
             optimization.onApply = onApply;
             optimization.onGetDescription = onGetDescription;
@@ -680,6 +622,13 @@
         public onFailureObservable = new Observable<SceneOptimizer>();
 
         /**
+         * Gets a boolean indicating if the optimizer is in improvement mode
+         */
+        public get isInImprovementMode(): boolean {
+            return this._improvementMode;
+        }
+
+        /**
          * Gets the current priority level (0 at start)
          */
         public get currentPriorityLevel(): number {
@@ -823,7 +772,7 @@
 
                 if (optimization.priority === this._currentPriorityLevel) {
                     noOptimizationApplied = false;
-                    allDone = allDone && optimization.apply(scene);
+                    allDone = allDone && optimization.apply(scene, this);
                     this.onNewOptimizationAppliedObservable.notifyObservers(optimization);
                 }
             }

+ 10 - 5
tests/validation/integration.js

@@ -34,25 +34,30 @@ xhr.addEventListener("load", function () {
                 }
 
                 it(test.title, function (done) {
-                    this.timeout(240000);
-                    this.retries(3);
+                    this.timeout(180000);
+
+                    var deferredDone = function() {
+                        setTimeout(function() {
+                            done();
+                        }, 3000);
+                    }
 
                     try {
                         runTest(index, function(result, screenshot) {
                             try {
                                 expect(result).to.be.true; 
-                                done();
+                                deferredDone();
                             }
                             catch (e) {
                                 if (screenshot) {
                                     console.error(screenshot);
                                 }
-                                done(e);
+                                deferredDone(e);
                             }
                         });
                     }
                     catch (e) {
-                        done(e);
+                        deferredDone(e);
                     }
                 });
             };