Browse Source

Merge 'upstream/master'

Gary Hsu 7 năm trước cách đây
mục cha
commit
931e0b7f57
51 tập tin đã thay đổi với 30166 bổ sung29463 xóa
  1. 16 0
      .github/ISSUE_TEMPLATE.md
  2. 6883 6753
      Playground/babylon.d.txt
  3. 3 2
      Viewer/src/configuration/configuration.ts
  4. 5 2
      Viewer/src/configuration/loader.ts
  5. 2 0
      Viewer/src/configuration/types/index.ts
  6. 79 29
      Viewer/src/viewer/viewer.ts
  7. 7080 7056
      dist/preview release/babylon.d.ts
  8. 44 44
      dist/preview release/babylon.js
  9. 114 56
      dist/preview release/babylon.max.js
  10. 44 44
      dist/preview release/babylon.worker.js
  11. 14152 14128
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  12. 44 44
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  13. 114 56
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  14. 114 56
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  15. 114 56
      dist/preview release/es6.js
  16. 1 0
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  17. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  18. 1 0
      dist/preview release/materialsLibrary/babylonjs.materials.js
  19. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  20. 65 22
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  21. 297 248
      dist/preview release/serializers/babylon.glTF2Serializer.js
  22. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  23. 297 248
      dist/preview release/serializers/babylonjs.serializers.js
  24. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  25. 65 22
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  26. 2 58
      dist/preview release/typedocValidationBaseline.json
  27. 57 57
      dist/preview release/viewer/babylon.viewer.js
  28. 5 2
      dist/preview release/what's new.md
  29. 10 9
      gui/src/advancedDynamicTexture.ts
  30. 6 6
      gui/src/controls/button.ts
  31. 2 2
      gui/src/controls/checkbox.ts
  32. 6 6
      gui/src/controls/colorpicker.ts
  33. 3 3
      gui/src/controls/container.ts
  34. 22 11
      gui/src/controls/control.ts
  35. 4 4
      gui/src/controls/inputText.ts
  36. 2 2
      gui/src/controls/radioButton.ts
  37. 6 6
      gui/src/controls/slider.ts
  38. 2 0
      materialsLibrary/src/fire/babylon.fireMaterial.ts
  39. 17 17
      readme.md
  40. 22 218
      serializers/src/glTF/2.0/babylon.glTFExporter.ts
  41. 328 113
      serializers/src/glTF/2.0/babylon.glTFMaterial.ts
  42. 5 0
      src/Bones/babylon.skeleton.ts
  43. 3 10
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  44. 30 22
      src/Cameras/VR/babylon.webVRCamera.ts
  45. 43 25
      src/Engine/babylon.engine.ts
  46. 3 1
      src/Mesh/babylon.buffer.ts
  47. 25 5
      src/PostProcess/babylon.refractionPostProcess.ts
  48. 1 0
      src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts
  49. 4 1
      src/Tools/babylon.sceneSerializer.ts
  50. 6 2
      src/babylon.scene.ts
  51. 14 13
      tests/unit/babylon/serializers/babylon.glTFSerializer.tests.ts

+ 16 - 0
.github/ISSUE_TEMPLATE.md

@@ -0,0 +1,16 @@
+Before creating an issue, please make sure to provide the following template (based on why you create the issue):
+(Please do not use Github issues for questions - We have a really active forum to help answering questions (http://www.html5gamedevs.com/forum/16-babylonjs/))
+
+# Bugs
+
+- Bug repro on [playground](https://playground.babylonjs.com):
+- Expected result:
+- Current result:
+
+# Feature request
+
+- Link to [forum](http://www.html5gamedevs.com/forum/16-babylonjs/) discussion about the feature:
+- Feature description
+- Additional links that could help implementing the feature:
+
+

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 6883 - 6753
Playground/babylon.d.txt


+ 3 - 2
Viewer/src/configuration/configuration.ts

@@ -67,7 +67,7 @@ export interface ViewerConfiguration {
 }
 
 export interface IModelConfiguration {
-    url: string;
+    url?: string;
     loader?: string; // obj, gltf?
     position?: { x: number, y: number, z: number };
     rotation?: { x: number, y: number, z: number, w?: number };
@@ -81,7 +81,7 @@ export interface IModelConfiguration {
         parentIndex?: number;
     }; // shoud the model be scaled to unit-size
 
-    title: string;
+    title?: string;
     subtitle?: string;
     thumbnail?: string; // URL or data-url
 
@@ -100,6 +100,7 @@ export interface ISkyboxConfiguration {
     blur?: number; // deprecated
     material?: {
         imageProcessingConfiguration?: IImageProcessingConfiguration;
+        [propName: string]: any;
     };
     infiniteDIstance?: boolean;
 

+ 5 - 2
Viewer/src/configuration/loader.ts

@@ -12,7 +12,7 @@ export class ConfigurationLoader {
         this.configurationCache = {};
     }
 
-    public loadConfiguration(initConfig: ViewerConfiguration = {}): Promise<ViewerConfiguration> {
+    public loadConfiguration(initConfig: ViewerConfiguration = {}, callback?: (config: ViewerConfiguration) => void): Promise<ViewerConfiguration> {
 
         let loadedConfig: ViewerConfiguration = deepmerge({}, initConfig);
 
@@ -55,9 +55,12 @@ export class ConfigurationLoader {
             }).then((data: any) => {
                 let mapper = mapperManager.getMapper(mapperType);
                 let parsed = mapper.map(data);
-                return deepmerge(loadedConfig, parsed);
+                let merged = deepmerge(loadedConfig, parsed);
+                if (callback) callback(merged);
+                return merged;
             });
         } else {
+            if (callback) callback(loadedConfig);
             return Promise.resolve(loadedConfig);
         }
     }

+ 2 - 0
Viewer/src/configuration/types/index.ts

@@ -8,6 +8,8 @@ let getConfigurationType = function (type: string): ViewerConfiguration {
             return defaultConfiguration;
         case 'minimal':
             return minimalConfiguration;
+        case 'none':
+            return {};
         default:
             return defaultConfiguration;
     }

+ 79 - 29
Viewer/src/viewer/viewer.ts

@@ -26,7 +26,7 @@ export abstract class AbstractViewer {
     public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
 
     protected configuration: ViewerConfiguration;
-    protected environmentHelper: EnvironmentHelper;
+    public environmentHelper: EnvironmentHelper;
 
     protected defaultHighpTextureType: number;
     protected shadowGeneratorBias: number;
@@ -43,7 +43,7 @@ export abstract class AbstractViewer {
     public onLoaderInitObservable: Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>;
     public onInitDoneObservable: Observable<AbstractViewer>;
 
-    protected canvas: HTMLCanvasElement;
+    public canvas: HTMLCanvasElement;
 
     protected registeredOnBeforerenderFunctions: Array<() => void>;
 
@@ -74,8 +74,8 @@ export abstract class AbstractViewer {
         this.prepareContainerElement();
 
         // extend the configuration
-        configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
-            this.configuration = configuration;
+        configurationLoader.loadConfiguration(initialConfiguration, (configuration) => {
+            this.configuration = deepmerge(this.configuration || {}, configuration);
             if (this.configuration.observers) {
                 this.configureObservers(this.configuration.observers);
             }
@@ -131,6 +131,9 @@ export abstract class AbstractViewer {
      * @param newConfiguration 
      */
     public updateConfiguration(newConfiguration: Partial<ViewerConfiguration> = this.configuration) {
+        // update this.configuration with the new data
+        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+
         // update scene configuration
         if (newConfiguration.scene) {
             this.configureScene(newConfiguration.scene);
@@ -160,14 +163,17 @@ export abstract class AbstractViewer {
             this.configureEnvironment(newConfiguration.skybox, newConfiguration.ground);
         }
 
-        // update this.configuration with the new data
-        this.configuration = deepmerge(this.configuration || {}, newConfiguration);
+        // camera
+        if (newConfiguration.camera) {
+            this.configureCamera(newConfiguration.camera);
+        }
     }
 
     protected configureEnvironment(skyboxConifguration?: ISkyboxConfiguration | boolean, groundConfiguration?: IGroundConfiguration | boolean) {
         if (!skyboxConifguration && !groundConfiguration) {
             if (this.environmentHelper) {
                 this.environmentHelper.dispose();
+                delete this.environmentHelper;
             };
             return Promise.resolve(this.scene);
         }
@@ -187,7 +193,7 @@ export abstract class AbstractViewer {
             }
 
             options.enableGroundShadow = groundConfig === true || groundConfig.receiveShadows;
-            if (groundConfig.shadowLevel) {
+            if (groundConfig.shadowLevel !== undefined) {
                 options.groundShadowLevel = groundConfig.shadowLevel;
             }
             options.enableGroundMirror = !!groundConfig.mirror;
@@ -198,19 +204,23 @@ export abstract class AbstractViewer {
                 options.groundColor = new Color3(groundConfig.color.r, groundConfig.color.g, groundConfig.color.b)
             }
 
+            if (groundConfig.opacity !== undefined) {
+                options.groundOpacity = groundConfig.opacity;
+            }
+
             if (groundConfig.mirror) {
                 options.enableGroundMirror = true;
                 // to prevent undefines
                 if (typeof groundConfig.mirror === "object") {
-                    if (groundConfig.mirror.amount)
+                    if (groundConfig.mirror.amount !== undefined)
                         options.groundMirrorAmount = groundConfig.mirror.amount;
-                    if (groundConfig.mirror.sizeRatio)
+                    if (groundConfig.mirror.sizeRatio !== undefined)
                         options.groundMirrorSizeRatio = groundConfig.mirror.sizeRatio;
-                    if (groundConfig.mirror.blurKernel)
+                    if (groundConfig.mirror.blurKernel !== undefined)
                         options.groundMirrorBlurKernel = groundConfig.mirror.blurKernel;
-                    if (groundConfig.mirror.fresnelWeight)
+                    if (groundConfig.mirror.fresnelWeight !== undefined)
                         options.groundMirrorFresnelWeight = groundConfig.mirror.fresnelWeight;
-                    if (groundConfig.mirror.fallOffDistance)
+                    if (groundConfig.mirror.fallOffDistance !== undefined)
                         options.groundMirrorFallOffDistance = groundConfig.mirror.fallOffDistance;
                     if (this.defaultHighpTextureType !== undefined)
                         options.groundMirrorTextureType = this.defaultHighpTextureType;
@@ -247,6 +257,8 @@ export abstract class AbstractViewer {
             }
         }
 
+        options.setupImageProcessing = false; // TMP
+
         if (!this.environmentHelper) {
             this.environmentHelper = this.scene.createDefaultEnvironment(options)!;
         } else {
@@ -393,6 +405,8 @@ export abstract class AbstractViewer {
             this.camera.rotationQuaternion = new Quaternion(cameraConfig.rotation.x || 0, cameraConfig.rotation.y || 0, cameraConfig.rotation.z || 0, cameraConfig.rotation.w || 0)
         }
 
+        this.extendClassWithConfig(this.camera, cameraConfig);
+
         this.camera.minZ = cameraConfig.minZ || this.camera.minZ;
         this.camera.maxZ = cameraConfig.maxZ || this.camera.maxZ;
 
@@ -405,7 +419,8 @@ export abstract class AbstractViewer {
         const sceneExtends = this.scene.getWorldExtends();
         const sceneDiagonal = sceneExtends.max.subtract(sceneExtends.min);
         const sceneDiagonalLenght = sceneDiagonal.length();
-        this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
+        if (isFinite(sceneDiagonalLenght))
+            this.camera.upperRadiusLimit = sceneDiagonalLenght * 3;
     }
 
     protected configureLights(lightsConfiguration: { [name: string]: ILightConfiguration | boolean } = {}, focusMeshes: Array<AbstractMesh> = this.scene.meshes) {
@@ -413,6 +428,15 @@ export abstract class AbstractViewer {
         if (!Object.keys(lightsConfiguration).length) return;
 
         let lightsAvailable: Array<string> = this.scene.lights.map(light => light.name);
+        // compare to the global (!) configuration object and dispose unneeded:
+        let lightsToConfigure = Object.keys(this.configuration.lights || []);
+        if (Object.keys(lightsToConfigure).length !== lightsAvailable.length) {
+            lightsAvailable.forEach(lName => {
+                if (lightsToConfigure.indexOf(lName) === -1) {
+                    this.scene.getLightByName(lName)!.dispose()
+                }
+            });
+        }
 
         Object.keys(lightsConfiguration).forEach((name, idx) => {
             let lightConfig: ILightConfiguration = { type: 0 };
@@ -422,7 +446,7 @@ export abstract class AbstractViewer {
 
             lightConfig.name = name;
 
-            let light;
+            let light: Light;
             // light is not already available
             if (lightsAvailable.indexOf(name) === -1) {
                 let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
@@ -430,8 +454,14 @@ export abstract class AbstractViewer {
                 light = constructor();
             } else {
                 // available? get it from the scene
-                light = this.scene.getLightByName(name);
+                light = <Light>this.scene.getLightByName(name);
                 lightsAvailable = lightsAvailable.filter(ln => ln !== name);
+                if (lightConfig.type !== undefined && light.getTypeID() !== lightConfig.type) {
+                    light.dispose();
+                    let constructor = Light.GetConstructorFromName(lightConfig.type, lightConfig.name, this.scene);
+                    if (!constructor) return;
+                    light = constructor();
+                }
             }
 
             // if config set the light to false, dispose it.
@@ -441,18 +471,28 @@ export abstract class AbstractViewer {
             }
 
             //enabled
-            if (light.isEnabled() !== !lightConfig.disabled) {
-                light.setEnabled(!lightConfig.disabled);
-            }
+            var enabled = lightConfig.enabled !== undefined ? lightConfig.enabled : !lightConfig.disabled;
+            light.setEnabled(enabled);
+
 
             this.extendClassWithConfig(light, lightConfig);
 
             //position. Some lights don't support shadows
             if (light instanceof ShadowLight) {
+                if (lightConfig.target) {
+                    if (light.setDirectionToTarget) {
+                        let target = Vector3.Zero().copyFrom(lightConfig.target as Vector3);
+                        light.setDirectionToTarget(target);
+                    }
+                } else if (lightConfig.direction) {
+                    let direction = Vector3.Zero().copyFrom(lightConfig.direction as Vector3);
+                    light.direction = direction;
+                }
                 let shadowGenerator = light.getShadowGenerator();
                 if (lightConfig.shadowEnabled && this.maxShadows) {
                     if (!shadowGenerator) {
                         shadowGenerator = new ShadowGenerator(512, light);
+                        // TODO blur kernel definition
                     }
                     this.extendClassWithConfig(shadowGenerator, lightConfig.shadowConfig || {});
                     // add the focues meshes to the shadow list
@@ -461,7 +501,7 @@ export abstract class AbstractViewer {
                     let renderList = shadownMap.renderList;
                     for (var index = 0; index < focusMeshes.length; index++) {
                         if (Tags.MatchesQuery(focusMeshes[index], 'castShadow')) {
-                            // renderList && renderList.push(focusMeshes[index]);
+                            renderList && renderList.push(focusMeshes[index]);
                         }
                     }
                 } else if (shadowGenerator) {
@@ -473,7 +513,7 @@ export abstract class AbstractViewer {
         // remove the unneeded lights
         /*lightsAvailable.forEach(name => {
             let light = this.scene.getLightByName(name);
-            if (light) {
+            if (light && !Tags.MatchesQuery(light, "fixed")) {
                 light.dispose();
             }
         });*/
@@ -579,9 +619,10 @@ export abstract class AbstractViewer {
 
     public dispose() {
         window.removeEventListener('resize', this.resize);
-
-        this.sceneOptimizer.stop();
-        this.sceneOptimizer.dispose();
+        if (this.sceneOptimizer) {
+            this.sceneOptimizer.stop();
+            this.sceneOptimizer.dispose();
+        }
 
         if (this.scene.activeCamera) {
             this.scene.activeCamera.detachControl(this.canvas);
@@ -699,6 +740,10 @@ export abstract class AbstractViewer {
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
+        // no model was provided? Do nothing!
+        if (!model.url) {
+            return Promise.resolve(this.scene);
+        }
         this.configuration.model = model;
         let modelUrl = (typeof model === 'string') ? model : model.url;
         let parts = modelUrl.split('/');
@@ -816,12 +861,14 @@ export abstract class AbstractViewer {
         if (!config) return;
         Object.keys(config).forEach(key => {
             if (key in object && typeof object[key] !== 'function') {
-                if (typeof object[key] === 'function') return;
+                // if (typeof object[key] === 'function') return;
                 // if it is an object, iterate internally until reaching basic types
                 if (typeof object[key] === 'object') {
                     this.extendClassWithConfig(object[key], config[key]);
                 } else {
-                    object[key] = config[key];
+                    if (config[key] !== undefined) {
+                        object[key] = config[key];
+                    }
                 }
             }
         });
@@ -840,13 +887,16 @@ export abstract class AbstractViewer {
         // constructing behavior
         switch (type) {
             case CameraBehavior.AUTOROTATION:
-                behavior = new AutoRotationBehavior();
+                this.camera.useAutoRotationBehavior = true;
+                behavior = this.camera.autoRotationBehavior;
                 break;
             case CameraBehavior.BOUNCING:
-                behavior = new BouncingBehavior();
+                this.camera.useBouncingBehavior = true;
+                behavior = this.camera.bouncingBehavior;
                 break;
             case CameraBehavior.FRAMING:
-                behavior = new FramingBehavior();
+                this.camera.useFramingBehavior = true;
+                behavior = this.camera.framingBehavior;
                 break;
             default:
                 behavior = null;
@@ -857,7 +907,7 @@ export abstract class AbstractViewer {
             if (typeof behaviorConfig === "object") {
                 this.extendClassWithConfig(behavior, behaviorConfig);
             }
-            this.camera.addBehavior(behavior);
+            //this.camera.addBehavior(behavior);
         }
 
         // post attach configuration. Some functionalities require the attached camera.

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 7080 - 7056
dist/preview release/babylon.d.ts


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 44 - 44
dist/preview release/babylon.js


+ 114 - 56
dist/preview release/babylon.max.js

@@ -11649,7 +11649,21 @@ var BABYLON;
         Engine.prototype.getVRDevice = function () {
             return this._vrDisplay;
         };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns The onVRDisplayChangedObservable.
+         */
         Engine.prototype.initWebVR = function () {
+            this.initWebVRAsync();
+            return this.onVRDisplayChangedObservable;
+        };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns A promise containing a VRDisplay and if vr is supported.
+         */
+        Engine.prototype.initWebVRAsync = function () {
             var _this = this;
             var notifyObservers = function () {
                 var eventArgs = {
@@ -11657,6 +11671,7 @@ var BABYLON;
                     vrSupported: _this._vrSupported
                 };
                 _this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+                _this._webVRInitPromise = new Promise(function (res) { res(eventArgs); });
             };
             if (!this._onVrDisplayConnect) {
                 this._onVrDisplayConnect = function (event) {
@@ -11676,8 +11691,9 @@ var BABYLON;
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
-            this._getVRDisplays(notifyObservers);
-            return this.onVRDisplayChangedObservable;
+            this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+            this._webVRInitPromise.then(notifyObservers);
+            return this._webVRInitPromise;
         };
         Engine.prototype.enableVR = function () {
             var _this = this;
@@ -11698,27 +11714,30 @@ var BABYLON;
                 this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
             }
         };
-        Engine.prototype._getVRDisplays = function (callback) {
+        Engine.prototype._getVRDisplaysAsync = function () {
             var _this = this;
-            var getWebVRDevices = function (devices) {
-                _this._vrSupported = true;
-                // note that devices may actually be an empty array. This is fine;
-                // we expect this._vrDisplay to be undefined in this case.
-                return _this._vrDisplay = devices[0];
-            };
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch(function (error) {
-                    // TODO: System CANNOT support WebVR, despite API presence.
+            return new Promise(function (res, rej) {
+                if (navigator.getVRDisplays) {
+                    navigator.getVRDisplays().then(function (devices) {
+                        _this._vrSupported = true;
+                        // note that devices may actually be an empty array. This is fine;
+                        // we expect this._vrDisplay to be undefined in this case.
+                        _this._vrDisplay = devices[0];
+                        res({
+                            vrDisplay: _this._vrDisplay,
+                            vrSupported: _this._vrSupported
+                        });
+                    });
+                }
+                else {
+                    _this._vrDisplay = undefined;
                     _this._vrSupported = false;
-                    callback();
-                });
-            }
-            else {
-                // TODO: Browser does not support WebVR
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                callback();
-            }
+                    res({
+                        vrDisplay: _this._vrDisplay,
+                        vrSupported: _this._vrSupported
+                    });
+                }
+            });
         };
         Engine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
             if (this._currentRenderTarget) {
@@ -23756,7 +23775,7 @@ var BABYLON;
         Scene.prototype.updateAlternateTransformMatrix = function (alternateCamera) {
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         };
-        Scene.prototype._renderForCamera = function (camera) {
+        Scene.prototype._renderForCamera = function (camera, rigParent) {
             if (camera && camera._skipRendering) {
                 return;
             }
@@ -23790,6 +23809,9 @@ var BABYLON;
             if (camera.customRenderTargets && camera.customRenderTargets.length > 0) {
                 this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
             }
+            if (rigParent && rigParent.customRenderTargets && rigParent.customRenderTargets.length > 0) {
+                this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
+            }
             if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
                 this._intermediateRendering = true;
                 BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -23917,7 +23939,7 @@ var BABYLON;
             }
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
-                this._renderForCamera(camera._rigCameras[index]);
+                this._renderForCamera(camera._rigCameras[index], camera);
             }
             this.activeCamera = camera;
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
@@ -25359,6 +25381,7 @@ var BABYLON;
                 this._engine = engine;
             }
             this._updatable = updatable;
+            this._instanced = instanced;
             this._data = data;
             this._strideSize = stride;
             if (!postponeInternalCreation) {
@@ -25376,7 +25399,7 @@ var BABYLON;
          */
         Buffer.prototype.createVertexBuffer = function (kind, offset, size, stride, instanced) {
             // a lot of these parameters are ignored as they are overriden by the buffer
-            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced, offset, size);
+            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced === undefined ? this._instanced : instanced, offset, size);
         };
         // Properties
         Buffer.prototype.isUpdatable = function () {
@@ -68375,21 +68398,41 @@ var BABYLON;
             _this.color = color;
             _this.depth = depth;
             _this.colorLevel = colorLevel;
+            _this._ownRefractionTexture = true;
             _this.onActivateObservable.add(function (cam) {
-                _this._refRexture = _this._refRexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
+                _this._refTexture = _this._refTexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
             });
             _this.onApplyObservable.add(function (effect) {
                 effect.setColor3("baseColor", _this.color);
                 effect.setFloat("depth", _this.depth);
                 effect.setFloat("colorLevel", _this.colorLevel);
-                effect.setTexture("refractionSampler", _this._refRexture);
+                effect.setTexture("refractionSampler", _this._refTexture);
             });
             return _this;
         }
+        Object.defineProperty(RefractionPostProcess.prototype, "refractionTexture", {
+            /**
+             * Gets or sets the refraction texture
+             * Please note that you are responsible for disposing the texture if you set it manually
+             */
+            get: function () {
+                return this._refTexture;
+            },
+            set: function (value) {
+                if (this._refTexture && this._ownRefractionTexture) {
+                    this._refTexture.dispose();
+                }
+                this._refTexture = value;
+                this._ownRefractionTexture = false;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         RefractionPostProcess.prototype.dispose = function (camera) {
-            if (this._refRexture) {
-                this._refRexture.dispose();
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+                this._refTexture = null;
             }
             _super.prototype.dispose.call(this, camera);
         };
@@ -68670,6 +68713,7 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
+            this._volumetricLightScatteringRTT.ignoreCameraViewport = true;
             var camera = this.getCamera();
             if (camera) {
                 camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
@@ -71203,6 +71247,10 @@ var BABYLON;
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
+            /**
+             * Specifies if the skeleton should be serialized.
+             */
+            this.doNotSerialize = false;
             // Events
             /**
              * An event triggered before computing the skeleton's matrices
@@ -79160,11 +79208,11 @@ var BABYLON;
             return _this;
         }
         /**
-         * Gets the device distance from the ground.
-         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         * Gets the device distance from the ground in meters.
+         * @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
          */
         WebVRFreeCamera.prototype.deviceDistanceToRoomGround = function () {
-            if (this._standingMatrix && this._defaultHeight === undefined) {
+            if (this._standingMatrix) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y;
@@ -79180,28 +79228,35 @@ var BABYLON;
             var _this = this;
             if (callback === void 0) { callback = function (bool) { }; }
             // Use standing matrix if available
-            if (!navigator || !navigator.getVRDisplays) {
-                callback(false);
-            }
-            else {
-                navigator.getVRDisplays().then(function (displays) {
-                    if (!displays || !displays[0] || !displays[0].stageParameters || !displays[0].stageParameters.sittingToStandingTransform) {
-                        callback(false);
-                    }
-                    else {
-                        _this._standingMatrix = new BABYLON.Matrix();
-                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(displays[0].stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
-                        if (!_this.getScene().useRightHandedSystem) {
-                            [2, 6, 8, 9, 14].forEach(function (num) {
-                                if (_this._standingMatrix) {
-                                    _this._standingMatrix.m[num] *= -1;
-                                }
-                            });
-                        }
-                        callback(true);
+            this.getEngine().initWebVRAsync().then(function (result) {
+                if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
+                    callback(false);
+                }
+                else {
+                    _this._standingMatrix = new BABYLON.Matrix();
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
+                    if (!_this.getScene().useRightHandedSystem) {
+                        [2, 6, 8, 9, 14].forEach(function (num) {
+                            if (_this._standingMatrix) {
+                                _this._standingMatrix.m[num] *= -1;
+                            }
+                        });
                     }
+                    callback(true);
+                }
+            });
+        };
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @returns A promise with a boolean set to if the standing matrix is supported.
+         */
+        WebVRFreeCamera.prototype.useStandingMatrixAsync = function () {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                _this.useStandingMatrix(function (supported) {
+                    res(supported);
                 });
-            }
+            });
         };
         /**
          * Disposes the camera
@@ -80209,14 +80264,13 @@ var BABYLON;
         });
         Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", {
             /**
-             * The mesh used to display where the user is selecting.
+             * The mesh used to display where the user is selecting,
+             * when set bakeCurrentTransformIntoVertices will be called on the mesh.
+             * See http://doc.babylonjs.com/resources/baking_transformations
              */
             get: function () {
                 return this._gazeTracker;
             },
-            /**
-             * Sets the mesh to be used to display where the user is selecting.
-             */
             set: function (value) {
                 if (value) {
                     this._gazeTracker = value;
@@ -85557,6 +85611,7 @@ var BABYLON;
             this._waitingTasksCount = this._tasks.length;
             this._totalTasksCount = this._tasks.length;
             if (this._waitingTasksCount === 0) {
+                this._isLoading = false;
                 if (this.onFinish) {
                     this.onFinish(this._tasks);
                 }
@@ -85771,7 +85826,10 @@ var BABYLON;
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
-                serializationObject.skeletons.push(scene.skeletons[index].serialize());
+                var skeleton = scene.skeletons[index];
+                if (!skeleton.doNotSerialize) {
+                    serializationObject.skeletons.push(skeleton.serialize());
+                }
             }
             // Transform nodes
             serializationObject.transformNodes = [];

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 44 - 44
dist/preview release/babylon.worker.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 14152 - 14128
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 44 - 44
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 114 - 56
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -11649,7 +11649,21 @@ var BABYLON;
         Engine.prototype.getVRDevice = function () {
             return this._vrDisplay;
         };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns The onVRDisplayChangedObservable.
+         */
         Engine.prototype.initWebVR = function () {
+            this.initWebVRAsync();
+            return this.onVRDisplayChangedObservable;
+        };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns A promise containing a VRDisplay and if vr is supported.
+         */
+        Engine.prototype.initWebVRAsync = function () {
             var _this = this;
             var notifyObservers = function () {
                 var eventArgs = {
@@ -11657,6 +11671,7 @@ var BABYLON;
                     vrSupported: _this._vrSupported
                 };
                 _this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+                _this._webVRInitPromise = new Promise(function (res) { res(eventArgs); });
             };
             if (!this._onVrDisplayConnect) {
                 this._onVrDisplayConnect = function (event) {
@@ -11676,8 +11691,9 @@ var BABYLON;
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
-            this._getVRDisplays(notifyObservers);
-            return this.onVRDisplayChangedObservable;
+            this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+            this._webVRInitPromise.then(notifyObservers);
+            return this._webVRInitPromise;
         };
         Engine.prototype.enableVR = function () {
             var _this = this;
@@ -11698,27 +11714,30 @@ var BABYLON;
                 this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
             }
         };
-        Engine.prototype._getVRDisplays = function (callback) {
+        Engine.prototype._getVRDisplaysAsync = function () {
             var _this = this;
-            var getWebVRDevices = function (devices) {
-                _this._vrSupported = true;
-                // note that devices may actually be an empty array. This is fine;
-                // we expect this._vrDisplay to be undefined in this case.
-                return _this._vrDisplay = devices[0];
-            };
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch(function (error) {
-                    // TODO: System CANNOT support WebVR, despite API presence.
+            return new Promise(function (res, rej) {
+                if (navigator.getVRDisplays) {
+                    navigator.getVRDisplays().then(function (devices) {
+                        _this._vrSupported = true;
+                        // note that devices may actually be an empty array. This is fine;
+                        // we expect this._vrDisplay to be undefined in this case.
+                        _this._vrDisplay = devices[0];
+                        res({
+                            vrDisplay: _this._vrDisplay,
+                            vrSupported: _this._vrSupported
+                        });
+                    });
+                }
+                else {
+                    _this._vrDisplay = undefined;
                     _this._vrSupported = false;
-                    callback();
-                });
-            }
-            else {
-                // TODO: Browser does not support WebVR
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                callback();
-            }
+                    res({
+                        vrDisplay: _this._vrDisplay,
+                        vrSupported: _this._vrSupported
+                    });
+                }
+            });
         };
         Engine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
             if (this._currentRenderTarget) {
@@ -23756,7 +23775,7 @@ var BABYLON;
         Scene.prototype.updateAlternateTransformMatrix = function (alternateCamera) {
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         };
-        Scene.prototype._renderForCamera = function (camera) {
+        Scene.prototype._renderForCamera = function (camera, rigParent) {
             if (camera && camera._skipRendering) {
                 return;
             }
@@ -23790,6 +23809,9 @@ var BABYLON;
             if (camera.customRenderTargets && camera.customRenderTargets.length > 0) {
                 this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
             }
+            if (rigParent && rigParent.customRenderTargets && rigParent.customRenderTargets.length > 0) {
+                this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
+            }
             if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
                 this._intermediateRendering = true;
                 BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -23917,7 +23939,7 @@ var BABYLON;
             }
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
-                this._renderForCamera(camera._rigCameras[index]);
+                this._renderForCamera(camera._rigCameras[index], camera);
             }
             this.activeCamera = camera;
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
@@ -25359,6 +25381,7 @@ var BABYLON;
                 this._engine = engine;
             }
             this._updatable = updatable;
+            this._instanced = instanced;
             this._data = data;
             this._strideSize = stride;
             if (!postponeInternalCreation) {
@@ -25376,7 +25399,7 @@ var BABYLON;
          */
         Buffer.prototype.createVertexBuffer = function (kind, offset, size, stride, instanced) {
             // a lot of these parameters are ignored as they are overriden by the buffer
-            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced, offset, size);
+            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced === undefined ? this._instanced : instanced, offset, size);
         };
         // Properties
         Buffer.prototype.isUpdatable = function () {
@@ -68001,21 +68024,41 @@ var BABYLON;
             _this.color = color;
             _this.depth = depth;
             _this.colorLevel = colorLevel;
+            _this._ownRefractionTexture = true;
             _this.onActivateObservable.add(function (cam) {
-                _this._refRexture = _this._refRexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
+                _this._refTexture = _this._refTexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
             });
             _this.onApplyObservable.add(function (effect) {
                 effect.setColor3("baseColor", _this.color);
                 effect.setFloat("depth", _this.depth);
                 effect.setFloat("colorLevel", _this.colorLevel);
-                effect.setTexture("refractionSampler", _this._refRexture);
+                effect.setTexture("refractionSampler", _this._refTexture);
             });
             return _this;
         }
+        Object.defineProperty(RefractionPostProcess.prototype, "refractionTexture", {
+            /**
+             * Gets or sets the refraction texture
+             * Please note that you are responsible for disposing the texture if you set it manually
+             */
+            get: function () {
+                return this._refTexture;
+            },
+            set: function (value) {
+                if (this._refTexture && this._ownRefractionTexture) {
+                    this._refTexture.dispose();
+                }
+                this._refTexture = value;
+                this._ownRefractionTexture = false;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         RefractionPostProcess.prototype.dispose = function (camera) {
-            if (this._refRexture) {
-                this._refRexture.dispose();
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+                this._refTexture = null;
             }
             _super.prototype.dispose.call(this, camera);
         };
@@ -68296,6 +68339,7 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
+            this._volumetricLightScatteringRTT.ignoreCameraViewport = true;
             var camera = this.getCamera();
             if (camera) {
                 camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
@@ -70779,6 +70823,10 @@ var BABYLON;
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
+            /**
+             * Specifies if the skeleton should be serialized.
+             */
+            this.doNotSerialize = false;
             // Events
             /**
              * An event triggered before computing the skeleton's matrices
@@ -78736,11 +78784,11 @@ var BABYLON;
             return _this;
         }
         /**
-         * Gets the device distance from the ground.
-         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         * Gets the device distance from the ground in meters.
+         * @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
          */
         WebVRFreeCamera.prototype.deviceDistanceToRoomGround = function () {
-            if (this._standingMatrix && this._defaultHeight === undefined) {
+            if (this._standingMatrix) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y;
@@ -78756,28 +78804,35 @@ var BABYLON;
             var _this = this;
             if (callback === void 0) { callback = function (bool) { }; }
             // Use standing matrix if available
-            if (!navigator || !navigator.getVRDisplays) {
-                callback(false);
-            }
-            else {
-                navigator.getVRDisplays().then(function (displays) {
-                    if (!displays || !displays[0] || !displays[0].stageParameters || !displays[0].stageParameters.sittingToStandingTransform) {
-                        callback(false);
-                    }
-                    else {
-                        _this._standingMatrix = new BABYLON.Matrix();
-                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(displays[0].stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
-                        if (!_this.getScene().useRightHandedSystem) {
-                            [2, 6, 8, 9, 14].forEach(function (num) {
-                                if (_this._standingMatrix) {
-                                    _this._standingMatrix.m[num] *= -1;
-                                }
-                            });
-                        }
-                        callback(true);
+            this.getEngine().initWebVRAsync().then(function (result) {
+                if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
+                    callback(false);
+                }
+                else {
+                    _this._standingMatrix = new BABYLON.Matrix();
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
+                    if (!_this.getScene().useRightHandedSystem) {
+                        [2, 6, 8, 9, 14].forEach(function (num) {
+                            if (_this._standingMatrix) {
+                                _this._standingMatrix.m[num] *= -1;
+                            }
+                        });
                     }
+                    callback(true);
+                }
+            });
+        };
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @returns A promise with a boolean set to if the standing matrix is supported.
+         */
+        WebVRFreeCamera.prototype.useStandingMatrixAsync = function () {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                _this.useStandingMatrix(function (supported) {
+                    res(supported);
                 });
-            }
+            });
         };
         /**
          * Disposes the camera
@@ -79785,14 +79840,13 @@ var BABYLON;
         });
         Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", {
             /**
-             * The mesh used to display where the user is selecting.
+             * The mesh used to display where the user is selecting,
+             * when set bakeCurrentTransformIntoVertices will be called on the mesh.
+             * See http://doc.babylonjs.com/resources/baking_transformations
              */
             get: function () {
                 return this._gazeTracker;
             },
-            /**
-             * Sets the mesh to be used to display where the user is selecting.
-             */
             set: function (value) {
                 if (value) {
                     this._gazeTracker = value;
@@ -85133,6 +85187,7 @@ var BABYLON;
             this._waitingTasksCount = this._tasks.length;
             this._totalTasksCount = this._tasks.length;
             if (this._waitingTasksCount === 0) {
+                this._isLoading = false;
                 if (this.onFinish) {
                     this.onFinish(this._tasks);
                 }
@@ -85347,7 +85402,10 @@ var BABYLON;
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
-                serializationObject.skeletons.push(scene.skeletons[index].serialize());
+                var skeleton = scene.skeletons[index];
+                if (!skeleton.doNotSerialize) {
+                    serializationObject.skeletons.push(skeleton.serialize());
+                }
             }
             // Transform nodes
             serializationObject.transformNodes = [];

+ 114 - 56
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js

@@ -11635,7 +11635,21 @@ var BABYLON;
         Engine.prototype.getVRDevice = function () {
             return this._vrDisplay;
         };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns The onVRDisplayChangedObservable.
+         */
         Engine.prototype.initWebVR = function () {
+            this.initWebVRAsync();
+            return this.onVRDisplayChangedObservable;
+        };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns A promise containing a VRDisplay and if vr is supported.
+         */
+        Engine.prototype.initWebVRAsync = function () {
             var _this = this;
             var notifyObservers = function () {
                 var eventArgs = {
@@ -11643,6 +11657,7 @@ var BABYLON;
                     vrSupported: _this._vrSupported
                 };
                 _this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+                _this._webVRInitPromise = new Promise(function (res) { res(eventArgs); });
             };
             if (!this._onVrDisplayConnect) {
                 this._onVrDisplayConnect = function (event) {
@@ -11662,8 +11677,9 @@ var BABYLON;
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
-            this._getVRDisplays(notifyObservers);
-            return this.onVRDisplayChangedObservable;
+            this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+            this._webVRInitPromise.then(notifyObservers);
+            return this._webVRInitPromise;
         };
         Engine.prototype.enableVR = function () {
             var _this = this;
@@ -11684,27 +11700,30 @@ var BABYLON;
                 this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
             }
         };
-        Engine.prototype._getVRDisplays = function (callback) {
+        Engine.prototype._getVRDisplaysAsync = function () {
             var _this = this;
-            var getWebVRDevices = function (devices) {
-                _this._vrSupported = true;
-                // note that devices may actually be an empty array. This is fine;
-                // we expect this._vrDisplay to be undefined in this case.
-                return _this._vrDisplay = devices[0];
-            };
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch(function (error) {
-                    // TODO: System CANNOT support WebVR, despite API presence.
+            return new Promise(function (res, rej) {
+                if (navigator.getVRDisplays) {
+                    navigator.getVRDisplays().then(function (devices) {
+                        _this._vrSupported = true;
+                        // note that devices may actually be an empty array. This is fine;
+                        // we expect this._vrDisplay to be undefined in this case.
+                        _this._vrDisplay = devices[0];
+                        res({
+                            vrDisplay: _this._vrDisplay,
+                            vrSupported: _this._vrSupported
+                        });
+                    });
+                }
+                else {
+                    _this._vrDisplay = undefined;
                     _this._vrSupported = false;
-                    callback();
-                });
-            }
-            else {
-                // TODO: Browser does not support WebVR
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                callback();
-            }
+                    res({
+                        vrDisplay: _this._vrDisplay,
+                        vrSupported: _this._vrSupported
+                    });
+                }
+            });
         };
         Engine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
             if (this._currentRenderTarget) {
@@ -23742,7 +23761,7 @@ var BABYLON;
         Scene.prototype.updateAlternateTransformMatrix = function (alternateCamera) {
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         };
-        Scene.prototype._renderForCamera = function (camera) {
+        Scene.prototype._renderForCamera = function (camera, rigParent) {
             if (camera && camera._skipRendering) {
                 return;
             }
@@ -23776,6 +23795,9 @@ var BABYLON;
             if (camera.customRenderTargets && camera.customRenderTargets.length > 0) {
                 this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
             }
+            if (rigParent && rigParent.customRenderTargets && rigParent.customRenderTargets.length > 0) {
+                this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
+            }
             if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
                 this._intermediateRendering = true;
                 BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -23903,7 +23925,7 @@ var BABYLON;
             }
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
-                this._renderForCamera(camera._rigCameras[index]);
+                this._renderForCamera(camera._rigCameras[index], camera);
             }
             this.activeCamera = camera;
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
@@ -25345,6 +25367,7 @@ var BABYLON;
                 this._engine = engine;
             }
             this._updatable = updatable;
+            this._instanced = instanced;
             this._data = data;
             this._strideSize = stride;
             if (!postponeInternalCreation) {
@@ -25362,7 +25385,7 @@ var BABYLON;
          */
         Buffer.prototype.createVertexBuffer = function (kind, offset, size, stride, instanced) {
             // a lot of these parameters are ignored as they are overriden by the buffer
-            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced, offset, size);
+            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced === undefined ? this._instanced : instanced, offset, size);
         };
         // Properties
         Buffer.prototype.isUpdatable = function () {
@@ -67987,21 +68010,41 @@ var BABYLON;
             _this.color = color;
             _this.depth = depth;
             _this.colorLevel = colorLevel;
+            _this._ownRefractionTexture = true;
             _this.onActivateObservable.add(function (cam) {
-                _this._refRexture = _this._refRexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
+                _this._refTexture = _this._refTexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
             });
             _this.onApplyObservable.add(function (effect) {
                 effect.setColor3("baseColor", _this.color);
                 effect.setFloat("depth", _this.depth);
                 effect.setFloat("colorLevel", _this.colorLevel);
-                effect.setTexture("refractionSampler", _this._refRexture);
+                effect.setTexture("refractionSampler", _this._refTexture);
             });
             return _this;
         }
+        Object.defineProperty(RefractionPostProcess.prototype, "refractionTexture", {
+            /**
+             * Gets or sets the refraction texture
+             * Please note that you are responsible for disposing the texture if you set it manually
+             */
+            get: function () {
+                return this._refTexture;
+            },
+            set: function (value) {
+                if (this._refTexture && this._ownRefractionTexture) {
+                    this._refTexture.dispose();
+                }
+                this._refTexture = value;
+                this._ownRefractionTexture = false;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         RefractionPostProcess.prototype.dispose = function (camera) {
-            if (this._refRexture) {
-                this._refRexture.dispose();
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+                this._refTexture = null;
             }
             _super.prototype.dispose.call(this, camera);
         };
@@ -68282,6 +68325,7 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
+            this._volumetricLightScatteringRTT.ignoreCameraViewport = true;
             var camera = this.getCamera();
             if (camera) {
                 camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
@@ -70765,6 +70809,10 @@ var BABYLON;
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
+            /**
+             * Specifies if the skeleton should be serialized.
+             */
+            this.doNotSerialize = false;
             // Events
             /**
              * An event triggered before computing the skeleton's matrices
@@ -78722,11 +78770,11 @@ var BABYLON;
             return _this;
         }
         /**
-         * Gets the device distance from the ground.
-         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         * Gets the device distance from the ground in meters.
+         * @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
          */
         WebVRFreeCamera.prototype.deviceDistanceToRoomGround = function () {
-            if (this._standingMatrix && this._defaultHeight === undefined) {
+            if (this._standingMatrix) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y;
@@ -78742,28 +78790,35 @@ var BABYLON;
             var _this = this;
             if (callback === void 0) { callback = function (bool) { }; }
             // Use standing matrix if available
-            if (!navigator || !navigator.getVRDisplays) {
-                callback(false);
-            }
-            else {
-                navigator.getVRDisplays().then(function (displays) {
-                    if (!displays || !displays[0] || !displays[0].stageParameters || !displays[0].stageParameters.sittingToStandingTransform) {
-                        callback(false);
-                    }
-                    else {
-                        _this._standingMatrix = new BABYLON.Matrix();
-                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(displays[0].stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
-                        if (!_this.getScene().useRightHandedSystem) {
-                            [2, 6, 8, 9, 14].forEach(function (num) {
-                                if (_this._standingMatrix) {
-                                    _this._standingMatrix.m[num] *= -1;
-                                }
-                            });
-                        }
-                        callback(true);
+            this.getEngine().initWebVRAsync().then(function (result) {
+                if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
+                    callback(false);
+                }
+                else {
+                    _this._standingMatrix = new BABYLON.Matrix();
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
+                    if (!_this.getScene().useRightHandedSystem) {
+                        [2, 6, 8, 9, 14].forEach(function (num) {
+                            if (_this._standingMatrix) {
+                                _this._standingMatrix.m[num] *= -1;
+                            }
+                        });
                     }
+                    callback(true);
+                }
+            });
+        };
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @returns A promise with a boolean set to if the standing matrix is supported.
+         */
+        WebVRFreeCamera.prototype.useStandingMatrixAsync = function () {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                _this.useStandingMatrix(function (supported) {
+                    res(supported);
                 });
-            }
+            });
         };
         /**
          * Disposes the camera
@@ -79771,14 +79826,13 @@ var BABYLON;
         });
         Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", {
             /**
-             * The mesh used to display where the user is selecting.
+             * The mesh used to display where the user is selecting,
+             * when set bakeCurrentTransformIntoVertices will be called on the mesh.
+             * See http://doc.babylonjs.com/resources/baking_transformations
              */
             get: function () {
                 return this._gazeTracker;
             },
-            /**
-             * Sets the mesh to be used to display where the user is selecting.
-             */
             set: function (value) {
                 if (value) {
                     this._gazeTracker = value;
@@ -85119,6 +85173,7 @@ var BABYLON;
             this._waitingTasksCount = this._tasks.length;
             this._totalTasksCount = this._tasks.length;
             if (this._waitingTasksCount === 0) {
+                this._isLoading = false;
                 if (this.onFinish) {
                     this.onFinish(this._tasks);
                 }
@@ -85333,7 +85388,10 @@ var BABYLON;
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
-                serializationObject.skeletons.push(scene.skeletons[index].serialize());
+                var skeleton = scene.skeletons[index];
+                if (!skeleton.doNotSerialize) {
+                    serializationObject.skeletons.push(skeleton.serialize());
+                }
             }
             // Transform nodes
             serializationObject.transformNodes = [];

+ 114 - 56
dist/preview release/es6.js

@@ -11635,7 +11635,21 @@ var BABYLON;
         Engine.prototype.getVRDevice = function () {
             return this._vrDisplay;
         };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns The onVRDisplayChangedObservable.
+         */
         Engine.prototype.initWebVR = function () {
+            this.initWebVRAsync();
+            return this.onVRDisplayChangedObservable;
+        };
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns A promise containing a VRDisplay and if vr is supported.
+         */
+        Engine.prototype.initWebVRAsync = function () {
             var _this = this;
             var notifyObservers = function () {
                 var eventArgs = {
@@ -11643,6 +11657,7 @@ var BABYLON;
                     vrSupported: _this._vrSupported
                 };
                 _this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+                _this._webVRInitPromise = new Promise(function (res) { res(eventArgs); });
             };
             if (!this._onVrDisplayConnect) {
                 this._onVrDisplayConnect = function (event) {
@@ -11662,8 +11677,9 @@ var BABYLON;
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
-            this._getVRDisplays(notifyObservers);
-            return this.onVRDisplayChangedObservable;
+            this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+            this._webVRInitPromise.then(notifyObservers);
+            return this._webVRInitPromise;
         };
         Engine.prototype.enableVR = function () {
             var _this = this;
@@ -11684,27 +11700,30 @@ var BABYLON;
                 this._vrDisplay.exitPresent().then(this._onVRFullScreenTriggered).catch(this._onVRFullScreenTriggered);
             }
         };
-        Engine.prototype._getVRDisplays = function (callback) {
+        Engine.prototype._getVRDisplaysAsync = function () {
             var _this = this;
-            var getWebVRDevices = function (devices) {
-                _this._vrSupported = true;
-                // note that devices may actually be an empty array. This is fine;
-                // we expect this._vrDisplay to be undefined in this case.
-                return _this._vrDisplay = devices[0];
-            };
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch(function (error) {
-                    // TODO: System CANNOT support WebVR, despite API presence.
+            return new Promise(function (res, rej) {
+                if (navigator.getVRDisplays) {
+                    navigator.getVRDisplays().then(function (devices) {
+                        _this._vrSupported = true;
+                        // note that devices may actually be an empty array. This is fine;
+                        // we expect this._vrDisplay to be undefined in this case.
+                        _this._vrDisplay = devices[0];
+                        res({
+                            vrDisplay: _this._vrDisplay,
+                            vrSupported: _this._vrSupported
+                        });
+                    });
+                }
+                else {
+                    _this._vrDisplay = undefined;
                     _this._vrSupported = false;
-                    callback();
-                });
-            }
-            else {
-                // TODO: Browser does not support WebVR
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                callback();
-            }
+                    res({
+                        vrDisplay: _this._vrDisplay,
+                        vrSupported: _this._vrSupported
+                    });
+                }
+            });
         };
         Engine.prototype.bindFramebuffer = function (texture, faceIndex, requiredWidth, requiredHeight, forceFullscreenViewport) {
             if (this._currentRenderTarget) {
@@ -23742,7 +23761,7 @@ var BABYLON;
         Scene.prototype.updateAlternateTransformMatrix = function (alternateCamera) {
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         };
-        Scene.prototype._renderForCamera = function (camera) {
+        Scene.prototype._renderForCamera = function (camera, rigParent) {
             if (camera && camera._skipRendering) {
                 return;
             }
@@ -23776,6 +23795,9 @@ var BABYLON;
             if (camera.customRenderTargets && camera.customRenderTargets.length > 0) {
                 this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
             }
+            if (rigParent && rigParent.customRenderTargets && rigParent.customRenderTargets.length > 0) {
+                this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
+            }
             if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
                 this._intermediateRendering = true;
                 BABYLON.Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -23903,7 +23925,7 @@ var BABYLON;
             }
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
-                this._renderForCamera(camera._rigCameras[index]);
+                this._renderForCamera(camera._rigCameras[index], camera);
             }
             this.activeCamera = camera;
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
@@ -25345,6 +25367,7 @@ var BABYLON;
                 this._engine = engine;
             }
             this._updatable = updatable;
+            this._instanced = instanced;
             this._data = data;
             this._strideSize = stride;
             if (!postponeInternalCreation) {
@@ -25362,7 +25385,7 @@ var BABYLON;
          */
         Buffer.prototype.createVertexBuffer = function (kind, offset, size, stride, instanced) {
             // a lot of these parameters are ignored as they are overriden by the buffer
-            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced, offset, size);
+            return new BABYLON.VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced === undefined ? this._instanced : instanced, offset, size);
         };
         // Properties
         Buffer.prototype.isUpdatable = function () {
@@ -68361,21 +68384,41 @@ var BABYLON;
             _this.color = color;
             _this.depth = depth;
             _this.colorLevel = colorLevel;
+            _this._ownRefractionTexture = true;
             _this.onActivateObservable.add(function (cam) {
-                _this._refRexture = _this._refRexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
+                _this._refTexture = _this._refTexture || new BABYLON.Texture(refractionTextureUrl, cam.getScene());
             });
             _this.onApplyObservable.add(function (effect) {
                 effect.setColor3("baseColor", _this.color);
                 effect.setFloat("depth", _this.depth);
                 effect.setFloat("colorLevel", _this.colorLevel);
-                effect.setTexture("refractionSampler", _this._refRexture);
+                effect.setTexture("refractionSampler", _this._refTexture);
             });
             return _this;
         }
+        Object.defineProperty(RefractionPostProcess.prototype, "refractionTexture", {
+            /**
+             * Gets or sets the refraction texture
+             * Please note that you are responsible for disposing the texture if you set it manually
+             */
+            get: function () {
+                return this._refTexture;
+            },
+            set: function (value) {
+                if (this._refTexture && this._ownRefractionTexture) {
+                    this._refTexture.dispose();
+                }
+                this._refTexture = value;
+                this._ownRefractionTexture = false;
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         RefractionPostProcess.prototype.dispose = function (camera) {
-            if (this._refRexture) {
-                this._refRexture.dispose();
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+                this._refTexture = null;
             }
             _super.prototype.dispose.call(this, camera);
         };
@@ -68656,6 +68699,7 @@ var BABYLON;
             this._volumetricLightScatteringRTT.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
+            this._volumetricLightScatteringRTT.ignoreCameraViewport = true;
             var camera = this.getCamera();
             if (camera) {
                 camera.customRenderTargets.push(this._volumetricLightScatteringRTT);
@@ -71189,6 +71233,10 @@ var BABYLON;
             this._identity = BABYLON.Matrix.Identity();
             this._ranges = {};
             this._lastAbsoluteTransformsUpdateId = -1;
+            /**
+             * Specifies if the skeleton should be serialized.
+             */
+            this.doNotSerialize = false;
             // Events
             /**
              * An event triggered before computing the skeleton's matrices
@@ -79146,11 +79194,11 @@ var BABYLON;
             return _this;
         }
         /**
-         * Gets the device distance from the ground.
-         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         * Gets the device distance from the ground in meters.
+         * @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
          */
         WebVRFreeCamera.prototype.deviceDistanceToRoomGround = function () {
-            if (this._standingMatrix && this._defaultHeight === undefined) {
+            if (this._standingMatrix) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y;
@@ -79166,28 +79214,35 @@ var BABYLON;
             var _this = this;
             if (callback === void 0) { callback = function (bool) { }; }
             // Use standing matrix if available
-            if (!navigator || !navigator.getVRDisplays) {
-                callback(false);
-            }
-            else {
-                navigator.getVRDisplays().then(function (displays) {
-                    if (!displays || !displays[0] || !displays[0].stageParameters || !displays[0].stageParameters.sittingToStandingTransform) {
-                        callback(false);
-                    }
-                    else {
-                        _this._standingMatrix = new BABYLON.Matrix();
-                        BABYLON.Matrix.FromFloat32ArrayToRefScaled(displays[0].stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
-                        if (!_this.getScene().useRightHandedSystem) {
-                            [2, 6, 8, 9, 14].forEach(function (num) {
-                                if (_this._standingMatrix) {
-                                    _this._standingMatrix.m[num] *= -1;
-                                }
-                            });
-                        }
-                        callback(true);
+            this.getEngine().initWebVRAsync().then(function (result) {
+                if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
+                    callback(false);
+                }
+                else {
+                    _this._standingMatrix = new BABYLON.Matrix();
+                    BABYLON.Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, _this._standingMatrix);
+                    if (!_this.getScene().useRightHandedSystem) {
+                        [2, 6, 8, 9, 14].forEach(function (num) {
+                            if (_this._standingMatrix) {
+                                _this._standingMatrix.m[num] *= -1;
+                            }
+                        });
                     }
+                    callback(true);
+                }
+            });
+        };
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @returns A promise with a boolean set to if the standing matrix is supported.
+         */
+        WebVRFreeCamera.prototype.useStandingMatrixAsync = function () {
+            var _this = this;
+            return new Promise(function (res, rej) {
+                _this.useStandingMatrix(function (supported) {
+                    res(supported);
                 });
-            }
+            });
         };
         /**
          * Disposes the camera
@@ -80195,14 +80250,13 @@ var BABYLON;
         });
         Object.defineProperty(VRExperienceHelper.prototype, "gazeTrackerMesh", {
             /**
-             * The mesh used to display where the user is selecting.
+             * The mesh used to display where the user is selecting,
+             * when set bakeCurrentTransformIntoVertices will be called on the mesh.
+             * See http://doc.babylonjs.com/resources/baking_transformations
              */
             get: function () {
                 return this._gazeTracker;
             },
-            /**
-             * Sets the mesh to be used to display where the user is selecting.
-             */
             set: function (value) {
                 if (value) {
                     this._gazeTracker = value;
@@ -85543,6 +85597,7 @@ var BABYLON;
             this._waitingTasksCount = this._tasks.length;
             this._totalTasksCount = this._tasks.length;
             if (this._waitingTasksCount === 0) {
+                this._isLoading = false;
                 if (this.onFinish) {
                     this.onFinish(this._tasks);
                 }
@@ -85757,7 +85812,10 @@ var BABYLON;
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
-                serializationObject.skeletons.push(scene.skeletons[index].serialize());
+                var skeleton = scene.skeletons[index];
+                if (!skeleton.doNotSerialize) {
+                    serializationObject.skeletons.push(skeleton.serialize());
+                }
             }
             // Transform nodes
             serializationObject.transformNodes = [];

+ 1 - 0
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -88,6 +88,7 @@ var BABYLON;
                     }
                 }
             }
+            defines.ALPHATEST = this._opacityTexture ? true : false;
             // Misc.
             if (defines._areMiscDirty) {
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.min.js


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

@@ -2118,6 +2118,7 @@ var BABYLON;
                     }
                 }
             }
+            defines.ALPHATEST = this._opacityTexture ? true : false;
             // Misc.
             if (defines._areMiscDirty) {
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 65 - 22
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -189,13 +189,6 @@ declare module BABYLON.GLTF2 {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
-         *
-         * @param babylonTexture - Babylon texture to extract.
-         * @param mimeType - Mime Type of the babylonTexture.
-         * @return - glTF texture, or null if the texture format is not supported.
-         */
-        private exportTexture(babylonTexture, mimeType?);
-        /**
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * @param kind - Indicates the type of vertices data.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
@@ -261,9 +254,25 @@ declare module BABYLON.GLTF2 {
          */
         private static readonly dielectricSpecular;
         /**
-         * Epsilon value, used as a small tolerance value for a numeric value.
+         * Allows the maximum specular power to be defined for material calculations.
+         */
+        private static maxSpecularPower;
+        /**
+         * Gets the materials from a Babylon scene and converts them to glTF materials.
+         * @param scene
+         * @param mimeType
+         * @param images
+         * @param textures
+         * @param materials
+         * @param imageData
+         * @param hasTextureCoords
          */
-        private static readonly epsilon;
+        static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
         /**
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * @param babylonStandardMaterial
@@ -271,19 +280,6 @@ declare module BABYLON.GLTF2 {
          */
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         /**
-         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-         * @returns - Babylon metallic roughness values
-         */
-        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
-        /**
-         * 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
@@ -297,5 +293,52 @@ declare module BABYLON.GLTF2 {
          * @returns - The Babylon alpha mode value
          */
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+        /**
+         * Converts a Babylon Standard Material to a glTF Material.
+         * @param babylonStandardMaterial - BJS Standard Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Extracts a texture from a Babylon texture into file data and glTF data.
+         * @param babylonTexture - Babylon texture to extract.
+         * @param mimeType - Mime Type of the babylonTexture.
+         * @param images - Array of glTF images.
+         * @param textures - Array of glTF textures.
+         * @param imageData - map of image file name and data.
+         * @return - glTF texture, or null if the texture format is not supported.
+         */
+        static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }): Nullable<ITextureInfo>;
     }
 }

+ 297 - 248
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -502,84 +502,6 @@ var BABYLON;
                 }
             };
             /**
-             *
-             * @param babylonTexture - Babylon texture to extract.
-             * @param mimeType - Mime Type of the babylonTexture.
-             * @return - glTF texture, or null if the texture format is not supported.
-             */
-            _Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
-                if (mimeType === void 0) { mimeType = "image/jpeg" /* JPEG */; }
-                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 === "image/jpeg" /* JPEG */) {
-                        extension = ".jpg";
-                    }
-                    else if (mimeType === "image/png" /* 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 === "image/jpeg" /* JPEG */) {
-                    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;
-            };
-            /**
              * Creates a bufferview based on the vertices type for the Babylon mesh
              * @param kind - Indicates the type of vertices data.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
@@ -645,7 +567,7 @@ var BABYLON;
                                     break;
                                 }
                                 default: {
-                                    console.warn("Unsupported VertexBuffer kind: " + kind);
+                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
                                 }
                             }
                             if (bufferViewName !== null) {
@@ -799,120 +721,20 @@ var BABYLON;
                             }
                         }
                         if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
-                                console.warn("Standard Material is currently not fully supported/implemented in glTF serializer");
-                                var babylonStandardMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
-                                var glTFMaterial = { name: babylonStandardMaterial.name };
-                                if (!babylonStandardMaterial.backFaceCulling) {
-                                    glTFMaterial.doubleSided = true;
-                                }
-                                if (babylonStandardMaterial.diffuseTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.diffuseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.bumpTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.emissiveTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
-                                    if (glTFEmissiveTexture) {
-                                        glTFMaterial.emissiveTexture = glTFEmissiveTexture;
-                                    }
-                                    glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
-                                }
-                                if (babylonStandardMaterial.ambientTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
-                                    if (glTFOcclusionTexture) {
-                                        glTFMaterial.occlusionTexture = glTFOcclusionTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
-                                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
-                                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
-                                    }
-                                    else {
-                                        console.warn("glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
+                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
+                                meshPrimitive.material = materialIndex;
                             }
-                            else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                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();
+                            else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
+                                var babylonMultiMaterial = bufferMesh.material;
+                                var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
+                                if (material !== null) {
+                                    var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                                    meshPrimitive.material = materialIndex;
                                 }
-                                if (babylonPBRMaterial.transparencyMode) {
-                                    var alphaMode = GLTF2._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
-                                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
-                                        glTFMaterial.alphaMode = alphaMode;
-                                        if (alphaMode === "BLEND" /* BLEND */) {
-                                            glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
-                                        }
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
                             }
                             else {
-                                console.warn("Material type is not yet implemented in glTF serializer: " + bufferMesh.material.name);
+                                BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
                             }
                         }
                         mesh.primitives.push(meshPrimitive);
@@ -932,6 +754,9 @@ var BABYLON;
                 if (babylonScene.meshes.length > 0) {
                     var babylonMeshes = babylonScene.meshes;
                     var scene = { nodes: new Array() };
+                    if (dataBuffer == null) {
+                        GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
+                    }
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                         if (this.options &&
                             this.options.shouldExportMesh !== undefined &&
@@ -1042,70 +867,79 @@ var BABYLON;
             function _GLTFMaterial() {
             }
             /**
+             * Gets the materials from a Babylon scene and converts them to glTF materials.
+             * @param scene
+             * @param mimeType
+             * @param images
+             * @param textures
+             * @param materials
+             * @param imageData
+             * @param hasTextureCoords
+             */
+            _GLTFMaterial.ConvertMaterialsToGLTF = function (babylonMaterials, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                for (var i = 0; i < babylonMaterials.length; ++i) {
+                    var babylonMaterial = babylonMaterials[i];
+                    if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                        _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                    else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                }
+            };
+            /**
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * @param babylonStandardMaterial
              * @returns - glTF Metallic Roughness Material representation
              */
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
-                var babylonSpecularGlossiness = {
-                    diffuse: babylonStandardMaterial.diffuseColor,
-                    opacity: babylonStandardMaterial.alpha,
-                    specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
-                    glossiness: babylonStandardMaterial.specularPower / 256
-                };
-                if (babylonStandardMaterial.specularTexture) {
+                var P0 = new BABYLON.Vector2(0, 1);
+                var P1 = new BABYLON.Vector2(0, 0.1);
+                var P2 = new BABYLON.Vector2(0, 0.1);
+                var P3 = new BABYLON.Vector2(1300, 0.1);
+                /**
+                 * Given the control points, solve for x based on a given t for a cubic bezier curve.
+                 * @param t - a value between 0 and 1.
+                 * @param p0 - first control point.
+                 * @param p1 - second control point.
+                 * @param p2 - third control point.
+                 * @param p3 - fourth control point.
+                 * @returns - number result of cubic bezier curve at the specified t.
+                 */
+                function cubicBezierCurve(t, p0, p1, p2, p3) {
+                    return ((1 - t) * (1 - t) * (1 - t) * p0 +
+                        3 * (1 - t) * (1 - t) * t * p1 +
+                        3 * (1 - t) * t * t * p2 +
+                        t * t * t * p3);
                 }
-                var babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                /**
+                 * Evaluates a specified specular power value to determine the appropriate roughness value,
+                 * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis)
+                 * and roughness on the ordinant axis (y-axis).
+                 * @param specularPower - specular power of standard material.
+                 * @returns - Number representing the roughness value.
+                 */
+                function solveForRoughness(specularPower) {
+                    var t = Math.pow(specularPower / P3.x, 0.333333);
+                    return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
+                }
+                var diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
+                var opacity = babylonStandardMaterial.alpha;
+                var specularPower = BABYLON.Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
+                var roughness = solveForRoughness(specularPower);
                 var glTFPbrMetallicRoughness = {
                     baseColorFactor: [
-                        babylonMetallicRoughness.baseColor.r,
-                        babylonMetallicRoughness.baseColor.g,
-                        babylonMetallicRoughness.baseColor.b,
-                        babylonMetallicRoughness.opacity
+                        diffuse.r,
+                        diffuse.g,
+                        diffuse.b,
+                        opacity
                     ],
-                    metallicFactor: babylonMetallicRoughness.metallic,
-                    roughnessFactor: babylonMetallicRoughness.roughness
+                    metallicFactor: 0,
+                    roughnessFactor: roughness,
                 };
                 return glTFPbrMetallicRoughness;
             };
             /**
-             * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-             * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-             * @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 = BABYLON.Scalar.Clamp(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
@@ -1113,14 +947,15 @@ var BABYLON;
              * @returns - metallic value
              */
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
-                if (specular < this.dielectricSpecular.r) {
+                if (specular < _GLTFMaterial.dielectricSpecular.r) {
+                    _GLTFMaterial.dielectricSpecular;
                     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 a = _GLTFMaterial.dielectricSpecular.r;
+                var b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
+                var c = _GLTFMaterial.dielectricSpecular.r - specular;
                 var D = b * b - 4.0 * a * c;
-                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
             };
             /**
              * Gets the glTF alpha mode from the Babylon Material
@@ -1152,7 +987,7 @@ var BABYLON;
                             return "MASK" /* MASK */;
                         }
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
-                            console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                            BABYLON.Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
                             return "BLEND" /* BLEND */;
                         }
                         default: {
@@ -1165,13 +1000,227 @@ var BABYLON;
                 }
             };
             /**
+             * Converts a Babylon Standard Material to a glTF Material.
+             * @param babylonStandardMaterial - BJS Standard Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertStandardMaterial = function (babylonStandardMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
+                var glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
+                var glTFMaterial = { name: babylonStandardMaterial.name };
+                if (babylonStandardMaterial.backFaceCulling) {
+                    if (!babylonStandardMaterial.twoSidedLighting) {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                    }
+                    glTFMaterial.doubleSided = true;
+                }
+                if (hasTextureCoords) {
+                    if (babylonStandardMaterial.diffuseTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.bumpTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.emissiveTexture) {
+                        var glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFEmissiveTexture) {
+                            glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                        }
+                        glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                    }
+                    if (babylonStandardMaterial.ambientTexture) {
+                        var glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
+                        if (glTFOcclusionTexture) {
+                            glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                        }
+                    }
+                }
+                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
+                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
+                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
+                    }
+                    else {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+             * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial = function (babylonPBRMetalRoughMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                var glTFPbrMetallicRoughness = {};
+                if (babylonPBRMetalRoughMaterial.baseColor) {
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        babylonPBRMetalRoughMaterial.baseColor.r,
+                        babylonPBRMetalRoughMaterial.baseColor.g,
+                        babylonPBRMetalRoughMaterial.baseColor.b,
+                        babylonPBRMetalRoughMaterial.alpha
+                    ];
+                }
+                if (babylonPBRMetalRoughMaterial.metallic != null) {
+                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
+                }
+                if (babylonPBRMetalRoughMaterial.roughness != null) {
+                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
+                }
+                var glTFMaterial = {
+                    name: babylonPBRMetalRoughMaterial.name
+                };
+                if (babylonPBRMetalRoughMaterial.doubleSided) {
+                    glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
+                }
+                if (hasTextureCoords) {
+                    if (babylonPBRMetalRoughMaterial.baseTexture != null) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.normalTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.occlusionTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.occlusionTexture = glTFTexture;
+                            if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
+                                glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
+                            }
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.emissiveTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFMaterial.emissiveTexture = glTFTexture;
+                        }
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                    glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
+                }
+                if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
+                    var alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
+                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
+                        glTFMaterial.alphaMode = alphaMode;
+                        if (alphaMode === "BLEND" /* BLEND */) {
+                            glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.alphaCutOff;
+                        }
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Extracts a texture from a Babylon texture into file data and glTF data.
+             * @param babylonTexture - Babylon texture to extract.
+             * @param mimeType - Mime Type of the babylonTexture.
+             * @param images - Array of glTF images.
+             * @param textures - Array of glTF textures.
+             * @param imageData - map of image file name and data.
+             * @return - glTF texture, or null if the texture format is not supported.
+             */
+            _GLTFMaterial.ExportTexture = function (babylonTexture, mimeType, images, textures, imageData) {
+                var textureInfo = null;
+                var glTFTexture = {
+                    source: images.length
+                };
+                var textureName = "texture_" + (textures.length - 1).toString();
+                var textureData = babylonTexture.getInternalTexture();
+                if (textureData != null) {
+                    textureName = textureData.url;
+                }
+                textureName = BABYLON.Tools.GetFilename(textureName);
+                var baseFile = textureName.split('.')[0];
+                var extension = "";
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === "image/png" /* PNG */) {
+                    extension = ".png";
+                }
+                else {
+                    BABYLON.Tools.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 };
+                imageData[textureName] = imageValues;
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    var glTFImage = {
+                        uri: textureName
+                    };
+                    var foundIndex = -1;
+                    for (var i = 0; i < images.length; ++i) {
+                        if (images[i].uri === textureName) {
+                            foundIndex = i;
+                            break;
+                        }
+                    }
+                    if (foundIndex === -1) {
+                        images.push(glTFImage);
+                        glTFTexture.source = images.length - 1;
+                        textures.push({
+                            source: images.length - 1
+                        });
+                        textureInfo = {
+                            index: images.length - 1
+                        };
+                    }
+                    else {
+                        glTFTexture.source = foundIndex;
+                        textureInfo = {
+                            index: foundIndex
+                        };
+                    }
+                }
+                return textureInfo;
+            };
+            /**
              * Represents the dielectric specular values for R, G and B.
              */
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             /**
-             * Epsilon value, used as a small tolerance value for a numeric value.
+             * Allows the maximum specular power to be defined for material calculations.
              */
-            _GLTFMaterial.epsilon = 1e-6;
+            _GLTFMaterial.maxSpecularPower = 1024;
             return _GLTFMaterial;
         }());
         GLTF2._GLTFMaterial = _GLTFMaterial;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 297 - 248
dist/preview release/serializers/babylonjs.serializers.js

@@ -646,84 +646,6 @@ var BABYLON;
                 }
             };
             /**
-             *
-             * @param babylonTexture - Babylon texture to extract.
-             * @param mimeType - Mime Type of the babylonTexture.
-             * @return - glTF texture, or null if the texture format is not supported.
-             */
-            _Exporter.prototype.exportTexture = function (babylonTexture, mimeType) {
-                if (mimeType === void 0) { mimeType = "image/jpeg" /* JPEG */; }
-                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 === "image/jpeg" /* JPEG */) {
-                        extension = ".jpg";
-                    }
-                    else if (mimeType === "image/png" /* 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 === "image/jpeg" /* JPEG */) {
-                    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;
-            };
-            /**
              * Creates a bufferview based on the vertices type for the Babylon mesh
              * @param kind - Indicates the type of vertices data.
              * @param babylonMesh - The Babylon mesh to get the vertices data from.
@@ -789,7 +711,7 @@ var BABYLON;
                                     break;
                                 }
                                 default: {
-                                    console.warn("Unsupported VertexBuffer kind: " + kind);
+                                    BABYLON.Tools.Warn("Unsupported VertexBuffer kind: " + kind);
                                 }
                             }
                             if (bufferViewName !== null) {
@@ -943,120 +865,20 @@ var BABYLON;
                             }
                         }
                         if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof BABYLON.StandardMaterial) {
-                                console.warn("Standard Material is currently not fully supported/implemented in glTF serializer");
-                                var babylonStandardMaterial = bufferMesh.material;
-                                var glTFPbrMetallicRoughness = GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
-                                var glTFMaterial = { name: babylonStandardMaterial.name };
-                                if (!babylonStandardMaterial.backFaceCulling) {
-                                    glTFMaterial.doubleSided = true;
-                                }
-                                if (babylonStandardMaterial.diffuseTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.diffuseTexture);
-                                    if (glTFTexture !== null) {
-                                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.bumpTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
-                                    if (glTFTexture) {
-                                        glTFMaterial.normalTexture = glTFTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.emissiveTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
-                                    if (glTFEmissiveTexture) {
-                                        glTFMaterial.emissiveTexture = glTFEmissiveTexture;
-                                    }
-                                    glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
-                                }
-                                if (babylonStandardMaterial.ambientTexture && bufferMesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                                    var glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
-                                    if (glTFOcclusionTexture) {
-                                        glTFMaterial.occlusionTexture = glTFOcclusionTexture;
-                                    }
-                                }
-                                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
-                                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
-                                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
-                                    }
-                                    else {
-                                        console.warn("glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
+                            if (bufferMesh.material instanceof BABYLON.StandardMaterial || bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                                var materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
+                                meshPrimitive.material = materialIndex;
                             }
-                            else if (bufferMesh.material instanceof BABYLON.PBRMetallicRoughnessMaterial) {
-                                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();
+                            else if (bufferMesh.material instanceof BABYLON.MultiMaterial) {
+                                var babylonMultiMaterial = bufferMesh.material;
+                                var material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
+                                if (material !== null) {
+                                    var materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                                    meshPrimitive.material = materialIndex;
                                 }
-                                if (babylonPBRMaterial.transparencyMode) {
-                                    var alphaMode = GLTF2._GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
-                                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
-                                        glTFMaterial.alphaMode = alphaMode;
-                                        if (alphaMode === "BLEND" /* BLEND */) {
-                                            glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
-                                        }
-                                    }
-                                }
-                                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-                                this.materials.push(glTFMaterial);
-                                meshPrimitive.material = this.materials.length - 1;
                             }
                             else {
-                                console.warn("Material type is not yet implemented in glTF serializer: " + bufferMesh.material.name);
+                                BABYLON.Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
                             }
                         }
                         mesh.primitives.push(meshPrimitive);
@@ -1076,6 +898,9 @@ var BABYLON;
                 if (babylonScene.meshes.length > 0) {
                     var babylonMeshes = babylonScene.meshes;
                     var scene = { nodes: new Array() };
+                    if (dataBuffer == null) {
+                        GLTF2._GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, "image/jpeg" /* JPEG */, this.images, this.textures, this.materials, this.imageData, true);
+                    }
                     for (var i = 0; i < babylonMeshes.length; ++i) {
                         if (this.options &&
                             this.options.shouldExportMesh !== undefined &&
@@ -1186,70 +1011,79 @@ var BABYLON;
             function _GLTFMaterial() {
             }
             /**
+             * Gets the materials from a Babylon scene and converts them to glTF materials.
+             * @param scene
+             * @param mimeType
+             * @param images
+             * @param textures
+             * @param materials
+             * @param imageData
+             * @param hasTextureCoords
+             */
+            _GLTFMaterial.ConvertMaterialsToGLTF = function (babylonMaterials, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                for (var i = 0; i < babylonMaterials.length; ++i) {
+                    var babylonMaterial = babylonMaterials[i];
+                    if (babylonMaterial instanceof BABYLON.StandardMaterial) {
+                        _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                    else if (babylonMaterial instanceof BABYLON.PBRMetallicRoughnessMaterial) {
+                        _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                    }
+                }
+            };
+            /**
              * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
              * @param babylonStandardMaterial
              * @returns - glTF Metallic Roughness Material representation
              */
             _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness = function (babylonStandardMaterial) {
-                var babylonSpecularGlossiness = {
-                    diffuse: babylonStandardMaterial.diffuseColor,
-                    opacity: babylonStandardMaterial.alpha,
-                    specular: babylonStandardMaterial.specularColor || BABYLON.Color3.Black(),
-                    glossiness: babylonStandardMaterial.specularPower / 256
-                };
-                if (babylonStandardMaterial.specularTexture) {
+                var P0 = new BABYLON.Vector2(0, 1);
+                var P1 = new BABYLON.Vector2(0, 0.1);
+                var P2 = new BABYLON.Vector2(0, 0.1);
+                var P3 = new BABYLON.Vector2(1300, 0.1);
+                /**
+                 * Given the control points, solve for x based on a given t for a cubic bezier curve.
+                 * @param t - a value between 0 and 1.
+                 * @param p0 - first control point.
+                 * @param p1 - second control point.
+                 * @param p2 - third control point.
+                 * @param p3 - fourth control point.
+                 * @returns - number result of cubic bezier curve at the specified t.
+                 */
+                function cubicBezierCurve(t, p0, p1, p2, p3) {
+                    return ((1 - t) * (1 - t) * (1 - t) * p0 +
+                        3 * (1 - t) * (1 - t) * t * p1 +
+                        3 * (1 - t) * t * t * p2 +
+                        t * t * t * p3);
                 }
-                var babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+                /**
+                 * Evaluates a specified specular power value to determine the appropriate roughness value,
+                 * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis)
+                 * and roughness on the ordinant axis (y-axis).
+                 * @param specularPower - specular power of standard material.
+                 * @returns - Number representing the roughness value.
+                 */
+                function solveForRoughness(specularPower) {
+                    var t = Math.pow(specularPower / P3.x, 0.333333);
+                    return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
+                }
+                var diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
+                var opacity = babylonStandardMaterial.alpha;
+                var specularPower = BABYLON.Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
+                var roughness = solveForRoughness(specularPower);
                 var glTFPbrMetallicRoughness = {
                     baseColorFactor: [
-                        babylonMetallicRoughness.baseColor.r,
-                        babylonMetallicRoughness.baseColor.g,
-                        babylonMetallicRoughness.baseColor.b,
-                        babylonMetallicRoughness.opacity
+                        diffuse.r,
+                        diffuse.g,
+                        diffuse.b,
+                        opacity
                     ],
-                    metallicFactor: babylonMetallicRoughness.metallic,
-                    roughnessFactor: babylonMetallicRoughness.roughness
+                    metallicFactor: 0,
+                    roughnessFactor: roughness,
                 };
                 return glTFPbrMetallicRoughness;
             };
             /**
-             * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-             * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-             * @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 = BABYLON.Scalar.Clamp(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
@@ -1257,14 +1091,15 @@ var BABYLON;
              * @returns - metallic value
              */
             _GLTFMaterial.SolveMetallic = function (diffuse, specular, oneMinusSpecularStrength) {
-                if (specular < this.dielectricSpecular.r) {
+                if (specular < _GLTFMaterial.dielectricSpecular.r) {
+                    _GLTFMaterial.dielectricSpecular;
                     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 a = _GLTFMaterial.dielectricSpecular.r;
+                var b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
+                var c = _GLTFMaterial.dielectricSpecular.r - specular;
                 var D = b * b - 4.0 * a * c;
-                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a));
+                return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
             };
             /**
              * Gets the glTF alpha mode from the Babylon Material
@@ -1296,7 +1131,7 @@ var BABYLON;
                             return "MASK" /* MASK */;
                         }
                         case BABYLON.PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
-                            console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                            BABYLON.Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
                             return "BLEND" /* BLEND */;
                         }
                         default: {
@@ -1309,13 +1144,227 @@ var BABYLON;
                 }
             };
             /**
+             * Converts a Babylon Standard Material to a glTF Material.
+             * @param babylonStandardMaterial - BJS Standard Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertStandardMaterial = function (babylonStandardMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
+                var glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
+                var glTFMaterial = { name: babylonStandardMaterial.name };
+                if (babylonStandardMaterial.backFaceCulling) {
+                    if (!babylonStandardMaterial.twoSidedLighting) {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                    }
+                    glTFMaterial.doubleSided = true;
+                }
+                if (hasTextureCoords) {
+                    if (babylonStandardMaterial.diffuseTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.bumpTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonStandardMaterial.emissiveTexture) {
+                        var glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFEmissiveTexture) {
+                            glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                        }
+                        glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                    }
+                    if (babylonStandardMaterial.ambientTexture) {
+                        var glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
+                        if (glTFOcclusionTexture) {
+                            glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                        }
+                    }
+                }
+                if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
+                    if (babylonStandardMaterial.alphaMode === BABYLON.Engine.ALPHA_COMBINE) {
+                        glTFMaterial.alphaMode = "BLEND" /* BLEND */;
+                    }
+                    else {
+                        BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+             * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+             * @param mimeType - mime type to use for the textures.
+             * @param images - array of glTF image interfaces.
+             * @param textures - array of glTF texture interfaces.
+             * @param materials - array of glTF material interfaces.
+             * @param imageData - map of image file name to data.
+             * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+             */
+            _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial = function (babylonPBRMetalRoughMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords) {
+                var glTFPbrMetallicRoughness = {};
+                if (babylonPBRMetalRoughMaterial.baseColor) {
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        babylonPBRMetalRoughMaterial.baseColor.r,
+                        babylonPBRMetalRoughMaterial.baseColor.g,
+                        babylonPBRMetalRoughMaterial.baseColor.b,
+                        babylonPBRMetalRoughMaterial.alpha
+                    ];
+                }
+                if (babylonPBRMetalRoughMaterial.metallic != null) {
+                    glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
+                }
+                if (babylonPBRMetalRoughMaterial.roughness != null) {
+                    glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
+                }
+                var glTFMaterial = {
+                    name: babylonPBRMetalRoughMaterial.name
+                };
+                if (babylonPBRMetalRoughMaterial.doubleSided) {
+                    glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
+                }
+                if (hasTextureCoords) {
+                    if (babylonPBRMetalRoughMaterial.baseTexture != null) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.normalTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.occlusionTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.occlusionTexture = glTFTexture;
+                            if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
+                                glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
+                            }
+                        }
+                    }
+                    if (babylonPBRMetalRoughMaterial.emissiveTexture) {
+                        var glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFMaterial.emissiveTexture = glTFTexture;
+                        }
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                    glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
+                }
+                if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
+                    var alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
+                    if (alphaMode !== "OPAQUE" /* OPAQUE */) {
+                        glTFMaterial.alphaMode = alphaMode;
+                        if (alphaMode === "BLEND" /* BLEND */) {
+                            glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.alphaCutOff;
+                        }
+                    }
+                }
+                glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+                materials.push(glTFMaterial);
+            };
+            /**
+             * Extracts a texture from a Babylon texture into file data and glTF data.
+             * @param babylonTexture - Babylon texture to extract.
+             * @param mimeType - Mime Type of the babylonTexture.
+             * @param images - Array of glTF images.
+             * @param textures - Array of glTF textures.
+             * @param imageData - map of image file name and data.
+             * @return - glTF texture, or null if the texture format is not supported.
+             */
+            _GLTFMaterial.ExportTexture = function (babylonTexture, mimeType, images, textures, imageData) {
+                var textureInfo = null;
+                var glTFTexture = {
+                    source: images.length
+                };
+                var textureName = "texture_" + (textures.length - 1).toString();
+                var textureData = babylonTexture.getInternalTexture();
+                if (textureData != null) {
+                    textureName = textureData.url;
+                }
+                textureName = BABYLON.Tools.GetFilename(textureName);
+                var baseFile = textureName.split('.')[0];
+                var extension = "";
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    extension = ".jpg";
+                }
+                else if (mimeType === "image/png" /* PNG */) {
+                    extension = ".png";
+                }
+                else {
+                    BABYLON.Tools.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 };
+                imageData[textureName] = imageValues;
+                if (mimeType === "image/jpeg" /* JPEG */) {
+                    var glTFImage = {
+                        uri: textureName
+                    };
+                    var foundIndex = -1;
+                    for (var i = 0; i < images.length; ++i) {
+                        if (images[i].uri === textureName) {
+                            foundIndex = i;
+                            break;
+                        }
+                    }
+                    if (foundIndex === -1) {
+                        images.push(glTFImage);
+                        glTFTexture.source = images.length - 1;
+                        textures.push({
+                            source: images.length - 1
+                        });
+                        textureInfo = {
+                            index: images.length - 1
+                        };
+                    }
+                    else {
+                        glTFTexture.source = foundIndex;
+                        textureInfo = {
+                            index: foundIndex
+                        };
+                    }
+                }
+                return textureInfo;
+            };
+            /**
              * Represents the dielectric specular values for R, G and B.
              */
             _GLTFMaterial.dielectricSpecular = new BABYLON.Color3(0.04, 0.04, 0.04);
             /**
-             * Epsilon value, used as a small tolerance value for a numeric value.
+             * Allows the maximum specular power to be defined for material calculations.
              */
-            _GLTFMaterial.epsilon = 1e-6;
+            _GLTFMaterial.maxSpecularPower = 1024;
             return _GLTFMaterial;
         }());
         GLTF2._GLTFMaterial = _GLTFMaterial;

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 65 - 22
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -452,13 +452,6 @@ declare module BABYLON.GLTF2 {
          */
         private setNodeTransformation(node, babylonMesh, useRightHandedSystem);
         /**
-         *
-         * @param babylonTexture - Babylon texture to extract.
-         * @param mimeType - Mime Type of the babylonTexture.
-         * @return - glTF texture, or null if the texture format is not supported.
-         */
-        private exportTexture(babylonTexture, mimeType?);
-        /**
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * @param kind - Indicates the type of vertices data.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
@@ -524,9 +517,25 @@ declare module BABYLON.GLTF2 {
          */
         private static readonly dielectricSpecular;
         /**
-         * Epsilon value, used as a small tolerance value for a numeric value.
+         * Allows the maximum specular power to be defined for material calculations.
+         */
+        private static maxSpecularPower;
+        /**
+         * Gets the materials from a Babylon scene and converts them to glTF materials.
+         * @param scene
+         * @param mimeType
+         * @param images
+         * @param textures
+         * @param materials
+         * @param imageData
+         * @param hasTextureCoords
          */
-        private static readonly epsilon;
+        static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
         /**
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
          * @param babylonStandardMaterial
@@ -534,19 +543,6 @@ declare module BABYLON.GLTF2 {
          */
         static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness;
         /**
-         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-         * @returns - Babylon metallic roughness values
-         */
-        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness);
-        /**
-         * 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
@@ -560,5 +556,52 @@ declare module BABYLON.GLTF2 {
          * @returns - The Babylon alpha mode value
          */
         static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode;
+        /**
+         * Converts a Babylon Standard Material to a glTF Material.
+         * @param babylonStandardMaterial - BJS Standard Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        static ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }, hasTextureCoords: boolean): void;
+        /**
+         * Extracts a texture from a Babylon texture into file data and glTF data.
+         * @param babylonTexture - Babylon texture to extract.
+         * @param mimeType - Mime Type of the babylonTexture.
+         * @param images - Array of glTF images.
+         * @param textures - Array of glTF textures.
+         * @param imageData - map of image file name and data.
+         * @return - glTF texture, or null if the texture format is not supported.
+         */
+        static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: {
+            [fileName: string]: {
+                data: Uint8Array;
+                mimeType: ImageMimeType;
+            };
+        }): Nullable<ITextureInfo>;
     }
 }

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

@@ -1,7 +1,7 @@
 {
-  "errors": 7263,
+  "errors": 7253,
   "babylon.typedoc.json": {
-    "errors": 7263,
+    "errors": 7253,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -5733,13 +5733,6 @@
           }
         }
       },
-      "Property": {
-        "instanceDivisor": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      },
       "Method": {
         "_rebuild": {
           "Comments": {
@@ -5758,33 +5751,6 @@
             }
           }
         },
-        "createVertexBuffer": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "kind": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "offset": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "size": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "stride": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "dispose": {
           "Comments": {
             "MissingText": true
@@ -5800,11 +5766,6 @@
             "MissingText": true
           }
         },
-        "getIsInstanced": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "getStrideSize": {
           "Comments": {
             "MissingText": true
@@ -9733,18 +9694,6 @@
             }
           }
         },
-        "_getRGBABufferInternalSizedFormat": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "type": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "_getRGBAMultiSampleBufferFormat": {
           "Comments": {
             "MissingText": true
@@ -11439,11 +11388,6 @@
             "MissingText": true
           }
         },
-        "initWebVR": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "isDeterministicLockStep": {
           "Comments": {
             "MissingText": true

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 57 - 57
dist/preview release/viewer/babylon.viewer.js


+ 5 - 2
dist/preview release/what's new.md

@@ -54,9 +54,9 @@
 - (Viewer) Introducing the viewer labs - testing new features. ([RaananW](https://github.com/RaananW))
 - AssetContainer Class and loading methods ([trevordev](https://github.com/trevordev))
 - KeepAssets class and AssetContainer.moveAllFromScene ([HoloLite](http://www.html5gamedevs.com/profile/28694-hololite/) [trevordev](https://github.com/trevordev))
-- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. ([RaananW](https://github.com/RaananW))
+- (Viewer) It is now possible to update parts of the configuration without rcreating the objects. Extra configuration can be loaded sync (if provided) ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final declarations during build. ([RaananW](https://github.com/RaananW))
-- (Viewer) Model can be normalized using configuration. ([RaananW](https://github.com/RaananW))
+- (Viewer) Model can be normalized using configuration, camera is dynamically configured. ([RaananW](https://github.com/RaananW))
 - (Gulp) extra/external declarations can be prepended to final NPM declarations during build. ([RaananW](https://github.com/RaananW))
 - GUI.Line can have its world position set from one end or the other ([SvenFrankson](https://github.com/SvenFrankson))
 - Added FOV system to background material for zoom effects in skyboxes without adjusting camera FOV ([DavidHGillen](https://github.com/DavidHGillen))
@@ -66,8 +66,10 @@
 - Added promise-based async functions to the SceneLoader, Scene.whenReadyAsync, and material.forceCompilationAsync. ([bghgary](https://github.com/bghgary)]
 - Added checks to VertexData.merge to ensure data is valid before merging. ([bghgary](https://github.com/bghgary)]
 - Ability to set a mesh to customize the webVR gaze tracker ([trevordev](https://github.com/trevordev))
+- Added promise-based async functions for initWebVRAsync and useStandingMatrixAsync ([trevordev](https://github.com/trevordev))
 - Add stroke (outline) options on GUI text control ([SvenFrankson](https://github.com/SvenFrankson))
 - Add floating point texture support for RenderTargetCubeTexture ([PeapBoy](https://github.com/NicolasBuecher))
+- Support for mutli-touch when interacting with multiple gui elements simultaneously ([trevordev](https://github.com/trevordev))
 - Added Draco mesh compression support to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)) 
 
 ## Bug fixes
@@ -77,6 +79,7 @@
 - Texture extension detection in `Engine.CreateTexture` ([sebavan](https://github.com/sebavan))
 - SPS internal temporary vector3 instead of Tmp.Vector3 to avoid possible concurrent uses ([jbousquie](https://github.com/jbousquie))
 - Fixed a bug when calling load on an empty assets manager - [#3739](https://github.com/BabylonJS/Babylon.js/issues/3739). ([RaananW](https://github.com/RaananW))
+- Enabling teleportation in vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
 
 ## Breaking changes
 

+ 10 - 9
gui/src/advancedDynamicTexture.ts

@@ -20,7 +20,7 @@ module BABYLON.GUI {
         public _lastPickedControl: Control;
         public _lastControlOver: Nullable<Control>;
         public _lastControlDown: Nullable<Control>;
-        public _capturingControl: Nullable<Control>;
+        public _capturingControl: {[pointerId:number]:Control} = {};
         public _shouldBlockPointer: boolean;
         public _layerToDispose: Nullable<Layer>;
         public _linkedControls = new Array<Control>();
@@ -370,7 +370,7 @@ module BABYLON.GUI {
             this._rootContainer._draw(measure, context);
         }
 
-        private _doPicking(x: number, y: number, type: number, buttonIndex: number): void {
+        private _doPicking(x: number, y: number, type: number, pointerId: number, buttonIndex: number): void {
             var scene = this.getScene();
 
             if (!scene) {
@@ -385,12 +385,12 @@ module BABYLON.GUI {
                 y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
             }
 
-            if (this._capturingControl) {
-                this._capturingControl._processObservables(type, x, y, buttonIndex);
+            if (this._capturingControl[pointerId]) {
+                this._capturingControl[pointerId]._processObservables(type, x, y, pointerId, buttonIndex);
                 return;
             }
 
-            if (!this._rootContainer._processPicking(x, y, type, buttonIndex)) {
+            if (!this._rootContainer._processPicking(x, y, type, pointerId, buttonIndex)) {
 
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                     if (this._lastControlOver) {
@@ -432,7 +432,7 @@ module BABYLON.GUI {
                 let y = (scene.pointerY / engine.getHardwareScalingLevel() - viewport.y * engine.getRenderHeight()) / viewport.height;
 
                 this._shouldBlockPointer = false;
-                this._doPicking(x, y, pi.type, pi.event.button);
+                this._doPicking(x, y, pi.type, (pi.event as PointerEvent).pointerId || 0, pi.event.button);
 
                 pi.skipOnPointerObservable = this._shouldBlockPointer;
             });
@@ -451,17 +451,18 @@ module BABYLON.GUI {
                     && pi.type !== BABYLON.PointerEventTypes.POINTERDOWN) {
                     return;
                 }
-
+                var pointerId = (pi.event as PointerEvent).pointerId || 0;
                 if (pi.pickInfo && pi.pickInfo.hit && pi.pickInfo.pickedMesh === mesh) {
                     var uv = pi.pickInfo.getTextureCoordinates();
 
                     if (uv) {
                         let size = this.getSize();
-                        this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pi.event.button);
+                        
+                        this._doPicking(uv.x * size.width, (1.0 - uv.y) * size.height, pi.type, pointerId, pi.event.button);
                     }
                 } else if (pi.type === BABYLON.PointerEventTypes.POINTERUP) {
                     if (this._lastControlDown) {
-                        this._lastControlDown.forcePointerUp();
+                        this._lastControlDown.forcePointerUp(pointerId);
                     }
                     this._lastControlDown = null;
 

+ 6 - 6
gui/src/controls/button.ts

@@ -37,7 +37,7 @@ module BABYLON.GUI {
         }
 
         // While being a container, the button behaves like a control.
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isHitTestVisible || !this.isVisible || this.notRenderable) {
                 return false;
             }
@@ -46,7 +46,7 @@ module BABYLON.GUI {
                 return false;
             }
 
-            this._processObservables(type, x, y, buttonIndex);
+            this._processObservables(type, x, y, pointerId, buttonIndex);
 
             return true;
         }
@@ -71,8 +71,8 @@ module BABYLON.GUI {
             super._onPointerOut(target);
         }
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }
 
@@ -84,12 +84,12 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             if (this.pointerUpAnimation) {
                 this.pointerUpAnimation();
             }
 
-            super._onPointerUp(target, coordinates, buttonIndex);
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }        
 
         // Statics

+ 2 - 2
gui/src/controls/checkbox.ts

@@ -115,8 +115,8 @@ module BABYLON.GUI {
         }
 
         // Events
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }
 

+ 6 - 6
gui/src/controls/colorpicker.ts

@@ -377,8 +377,8 @@ module BABYLON.GUI {
             return false;
         }
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }            
 
@@ -394,7 +394,7 @@ module BABYLON.GUI {
             }
 
             this._updateValueFromPointer(coordinates.x, coordinates.y);
-            this._host._capturingControl = this;
+            this._host._capturingControl[pointerId] = this;
 
             return true;
         }
@@ -407,11 +407,11 @@ module BABYLON.GUI {
             super._onPointerMove(target, coordinates);
         }
 
-        public _onPointerUp (target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp (target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             this._pointerIsDown = false;
             
-            this._host._capturingControl = null;
-            super._onPointerUp(target, coordinates, buttonIndex);
+            delete this._host._capturingControl[pointerId];
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }     
     }    
 }

+ 3 - 3
gui/src/controls/container.ts

@@ -175,7 +175,7 @@ module BABYLON.GUI {
             }
         }
 
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isVisible || this.notRenderable) {
                 return false;
             }
@@ -187,7 +187,7 @@ module BABYLON.GUI {
             // Checking backwards to pick closest first
             for (var index = this._children.length - 1; index >= 0; index--) {
                 var child = this._children[index];
-                if (child._processPicking(x, y, type, buttonIndex)) {
+                if (child._processPicking(x, y, type, pointerId, buttonIndex)) {
                     return true;
                 }
             }
@@ -196,7 +196,7 @@ module BABYLON.GUI {
                 return false;
             }
 
-            return this._processObservables(type, x, y, buttonIndex);
+            return this._processObservables(type, x, y, pointerId, buttonIndex);
         }
 
         protected _clipForChildren(context: CanvasRenderingContext2D): void {

+ 22 - 11
gui/src/controls/control.ts

@@ -46,6 +46,7 @@ module BABYLON.GUI {
         private _downCount = 0;
         private _enterCount = 0;
         private _doNotRender = false;
+        private _downPointerIds:{[id:number] : boolean} = {};
 
         public isHitTestVisible = true;
         public isPointerBlocker = false;
@@ -859,7 +860,7 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _processPicking(x: number, y: number, type: number, buttonIndex: number): boolean {
+        public _processPicking(x: number, y: number, type: number, pointerId:number, buttonIndex: number): boolean {
             if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
                 return false;
             }
@@ -868,7 +869,7 @@ module BABYLON.GUI {
                 return false;
             }
 
-            this._processObservables(type, x, y, buttonIndex);
+            this._processObservables(type, x, y, pointerId, buttonIndex);
 
             return true;
         }
@@ -901,33 +902,43 @@ module BABYLON.GUI {
             if (canNotify && this.parent != null) this.parent._onPointerOut(target);
         }
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
             if (this._downCount !== 0) {
                 return false;
             }
 
             this._downCount++;
 
+            this._downPointerIds[pointerId] = true;
+
             var canNotify: boolean = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, buttonIndex);
+            if (canNotify && this.parent != null) this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
 
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             this._downCount = 0;
 
+            delete this._downPointerIds[pointerId];
+
             var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, buttonIndex);
+            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }
 
-        public forcePointerUp() {
-            this._onPointerUp(this, Vector2.Zero(), 0);
+        public forcePointerUp(pointerId:Nullable<number> = null) {
+            if(pointerId !== null){
+                this._onPointerUp(this, Vector2.Zero(), pointerId, 0);
+            }else{
+                for(var key in this._downPointerIds){
+                    this._onPointerUp(this, Vector2.Zero(), +key as number, 0);
+                }
+            }
         }
 
-        public _processObservables(type: number, x: number, y: number, buttonIndex: number): boolean {
+        public _processObservables(type: number, x: number, y: number, pointerId:number, buttonIndex: number): boolean {
             this._dummyVector2.copyFromFloats(x, y);
             if (type === BABYLON.PointerEventTypes.POINTERMOVE) {
                 this._onPointerMove(this, this._dummyVector2);
@@ -946,7 +957,7 @@ module BABYLON.GUI {
             }
 
             if (type === BABYLON.PointerEventTypes.POINTERDOWN) {
-                this._onPointerDown(this, this._dummyVector2, buttonIndex);
+                this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex);
                 this._host._lastControlDown = this;
                 this._host._lastPickedControl = this;
                 return true;
@@ -954,7 +965,7 @@ module BABYLON.GUI {
 
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (this._host._lastControlDown) {
-                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, buttonIndex);
+                    this._host._lastControlDown._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
                 }
                 this._host._lastControlDown = null;
                 return true;

+ 4 - 4
gui/src/controls/inputText.ts

@@ -432,8 +432,8 @@ module BABYLON.GUI {
             context.restore();
         }
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }
 
@@ -449,8 +449,8 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
-            super._onPointerUp(target, coordinates, buttonIndex);
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }
 
         public dispose() {

+ 2 - 2
gui/src/controls/radioButton.ts

@@ -144,8 +144,8 @@ module BABYLON.GUI {
         }
 
         // Events
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }
             this.isChecked = !this.isChecked;

+ 6 - 6
gui/src/controls/slider.ts

@@ -266,15 +266,15 @@ module BABYLON.GUI {
             this.value = this._minimum + ((x - this._currentMeasure.left) / this._currentMeasure.width) * (this._maximum - this._minimum);
         }
 
-        public _onPointerDown(target: Control, coordinates: Vector2, buttonIndex: number): boolean {
-            if (!super._onPointerDown(target, coordinates, buttonIndex)) {
+        public _onPointerDown(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): boolean {
+            if (!super._onPointerDown(target, coordinates, pointerId, buttonIndex)) {
                 return false;
             }
 
             this._pointerIsDown = true;
 
             this._updateValueFromPointer(coordinates.x, coordinates.y);
-            this._host._capturingControl = this;
+            this._host._capturingControl[pointerId] = this;
 
             return true;
         }
@@ -287,11 +287,11 @@ module BABYLON.GUI {
             super._onPointerMove(target, coordinates);
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
             this._pointerIsDown = false;
 
-            this._host._capturingControl = null;
-            super._onPointerUp(target, coordinates, buttonIndex);
+            delete this._host._capturingControl[pointerId];
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
         }
     }
 }

+ 2 - 0
materialsLibrary/src/fire/babylon.fireMaterial.ts

@@ -100,6 +100,8 @@ module BABYLON {
                 }
             }
 
+            defines.ALPHATEST = this._opacityTexture ? true : false;
+
             // Misc.
             if (defines._areMiscDirty) {
                 defines.POINTSIZE = (this.pointsCloud || scene.forcePointsCloud);

+ 17 - 17
readme.md

@@ -58,29 +58,29 @@ To add a module install the respected package. A list of extra packages and thei
 ## Usage
 See [Getting Started](http://doc.babylonjs.com/#getting-started)
 ```javascript
-// get the canvas DOM element
+// Get the canvas DOM element
 var canvas = document.getElementById('renderCanvas');
-// load the 3D engine
-var engine = new BABYLON.Engine(canvas, true);
-// createScene function that creates and return the scene
+// Load the 3D engine
+var engine = new BABYLON.Engine(canvas, true, {preserveDrawingBuffer: true, stencil: true});
+// CreateScene function that creates and return the scene
 var createScene = function(){
-    // create a basic BJS Scene object
+    // Create a basic BJS Scene object
     var scene = new BABYLON.Scene(engine);
-    // create a FreeCamera, and set its position to (x:0, y:5, z:-10)
-    var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5,-10), scene);
-    // target the camera to scene origin
+    // Create a FreeCamera, and set its position to {x: 0, y: 5, z: -10}
+    var camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);
+    // Target the camera to scene origin
     camera.setTarget(BABYLON.Vector3.Zero());
-    // attach the camera to the canvas
+    // Attach the camera to the canvas
     camera.attachControl(canvas, false);
-    // create a basic light, aiming 0,1,0 - meaning, to the sky
-    var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0,1,0), scene);
-    // create a built-in "sphere" shape; its constructor takes 6 params: name, segment, diameter, scene, updatable, sideOrientation
-    var sphere = BABYLON.Mesh.CreateSphere('sphere1', 16, 2, scene);
-    // move the sphere upward 1/2 of its height
+    // Create a basic light, aiming 0, 1, 0 - meaning, to the sky
+    var light = new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 1, 0), scene);
+    // Create a built-in "sphere" shape; its constructor takes 6 params: name, segment, diameter, scene, updatable, sideOrientation
+    var sphere = BABYLON.Mesh.CreateSphere('sphere1', 16, 2, scene, false, BABYLON.Mesh.FRONTSIDE);
+    // Move the sphere upward 1/2 of its height
     sphere.position.y = 1;
-    // create a built-in "ground" shape; its constructor takes the same 6 params : name, width, height, subdivision, scene, updatable
-    var ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene);
-    // return the created scene
+    // Create a built-in "ground" shape; its constructor takes 6 params : name, width, height, subdivision, scene, updatable
+    var ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene, false);
+    // Return the created scene
     return scene;
 }
 // call the createScene function

+ 22 - 218
serializers/src/glTF/2.0/babylon.glTFExporter.ts

@@ -556,97 +556,6 @@ module BABYLON.GLTF2 {
         }
 
         /**
-         * 
-         * @param babylonTexture - Babylon texture to extract.
-         * @param mimeType - Mime Type of the babylonTexture.
-         * @return - glTF texture, or null if the texture format is not supported.
-         */
-        private exportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType = ImageMimeType.JPEG): Nullable<ITextureInfo> {
-            let textureInfo: Nullable<ITextureInfo> = null;
-
-            let glTFTexture: Nullable<ITexture>;
-
-            glTFTexture = {
-                source: this.images.length
-            };
-
-            let textureName = babylonTexture.getInternalTexture()!.url;
-            if (textureName.search('/') !== -1) {
-                const splitFilename = textureName.split('/');
-                textureName = splitFilename[splitFilename.length - 1];
-                const basefile = textureName.split('.')[0];
-                let extension = textureName.split('.')[1];
-                if (mimeType === ImageMimeType.JPEG) {
-                    extension = ".jpg";
-                }
-                else if (mimeType === ImageMimeType.PNG) {
-                    extension = ".png";
-                }
-                else {
-                    throw new Error("Unsupported mime type " + mimeType);
-                }
-                textureName = basefile + extension;
-            }
-
-            const pixels = babylonTexture!.readPixels() as Uint8Array;
-
-            const imageCanvas = document.createElement('canvas');
-            imageCanvas.id = "ImageCanvas";
-
-            const ctx = <CanvasRenderingContext2D>imageCanvas.getContext('2d');
-            const size = babylonTexture.getSize();
-            imageCanvas.width = size.width;
-            imageCanvas.height = size.height;
-
-            const imgData = ctx.createImageData(size.width, size.height);
-
-
-            imgData.data.set(pixels!);
-            ctx.putImageData(imgData, 0, 0);
-            const base64Data = imageCanvas.toDataURL(mimeType);
-            const binStr = atob(base64Data.split(',')[1]);
-            const arr = new Uint8Array(binStr.length);
-            for (let i = 0; i < binStr.length; ++i) {
-                arr[i] = binStr.charCodeAt(i);
-            }
-            const imageValues = { data: arr, mimeType: mimeType };
-
-            this.imageData[textureName] = imageValues;
-            if (mimeType === ImageMimeType.JPEG) {
-                const glTFImage: IImage = {
-                    uri: textureName
-                }
-                let foundIndex = -1;
-                for (let 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;
-        }
-
-        /**
          * Creates a bufferview based on the vertices type for the Babylon mesh
          * @param kind - Indicates the type of vertices data.
          * @param babylonMesh - The Babylon mesh to get the vertices data from.
@@ -721,7 +630,7 @@ module BABYLON.GLTF2 {
                                 break;
                             }
                             default: {
-                                console.warn("Unsupported VertexBuffer kind: " + kind);
+                                Tools.Warn("Unsupported VertexBuffer kind: " + kind);
                             }
                         }
 
@@ -817,7 +726,6 @@ module BABYLON.GLTF2 {
                 const submesh = babylonMesh.subMeshes[j];
                 const meshPrimitive: IMeshPrimitive = { attributes: {} };
 
-
                 if (bufferMesh !== null) {
                     // Create a bufferview storing all the positions
                     if (!dataBuffer) {
@@ -829,8 +737,8 @@ module BABYLON.GLTF2 {
                             const positionStrideSize = positionVertexBuffer!.getStrideSize();
 
                             // Create accessor
-                            const result = this.calculateMinMax(positions!, 0, positions!.length/positionStrideSize, positionStrideSize!, useRightHandedSystem);
-                            const accessor = this.createAccessor(positionBufferViewIndex, "Position", AccessorType.VEC3, AccessorComponentType.FLOAT, positions!.length/positionStrideSize, 0, result.min, result.max);
+                            const result = this.calculateMinMax(positions!, 0, positions!.length / positionStrideSize, positionStrideSize!, useRightHandedSystem);
+                            const accessor = this.createAccessor(positionBufferViewIndex, "Position", AccessorType.VEC3, AccessorComponentType.FLOAT, positions!.length / positionStrideSize, 0, result.min, result.max);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.POSITION = this.accessors.length - 1;
@@ -842,7 +750,7 @@ module BABYLON.GLTF2 {
                             const normalStrideSize = normalVertexBuffer!.getStrideSize();
 
                             // Create accessor
-                            const accessor = this.createAccessor(normalBufferViewIndex, "Normal", AccessorType.VEC3, AccessorComponentType.FLOAT, normals!.length/normalStrideSize);
+                            const accessor = this.createAccessor(normalBufferViewIndex, "Normal", AccessorType.VEC3, AccessorComponentType.FLOAT, normals!.length / normalStrideSize);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.NORMAL = this.accessors.length - 1;
@@ -854,7 +762,7 @@ module BABYLON.GLTF2 {
                             const tangentStrideSize = tangentVertexBuffer!.getStrideSize();
 
                             // Create accessor
-                            const accessor = this.createAccessor(tangentBufferViewIndex, "Tangent", AccessorType.VEC4, AccessorComponentType.FLOAT, tangents!.length/tangentStrideSize);
+                            const accessor = this.createAccessor(tangentBufferViewIndex, "Tangent", AccessorType.VEC4, AccessorComponentType.FLOAT, tangents!.length / tangentStrideSize);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.TANGENT = this.accessors.length - 1;
@@ -866,7 +774,7 @@ module BABYLON.GLTF2 {
                             const colorStrideSize = colorVertexBuffer!.getStrideSize();
 
                             // Create accessor
-                            const accessor = this.createAccessor(colorBufferViewIndex, "Color", AccessorType.VEC4, AccessorComponentType.FLOAT, colors!.length/colorStrideSize);
+                            const accessor = this.createAccessor(colorBufferViewIndex, "Color", AccessorType.VEC4, AccessorComponentType.FLOAT, colors!.length / colorStrideSize);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.COLOR_0 = this.accessors.length - 1;
@@ -877,7 +785,7 @@ module BABYLON.GLTF2 {
                             const texCoord0VertexBuffer = bufferMesh.getVertexBuffer(VertexBuffer.UVKind);
                             const texCoord0s = texCoord0VertexBuffer!.getData();
                             const texCoord0StrideSize = texCoord0VertexBuffer!.getStrideSize();
-                            const accessor = this.createAccessor(texCoord0BufferViewIndex, "Texture Coords 0", AccessorType.VEC2, AccessorComponentType.FLOAT, texCoord0s!.length/texCoord0StrideSize);
+                            const accessor = this.createAccessor(texCoord0BufferViewIndex, "Texture Coords 0", AccessorType.VEC2, AccessorComponentType.FLOAT, texCoord0s!.length / texCoord0StrideSize);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
@@ -888,7 +796,7 @@ module BABYLON.GLTF2 {
                             const texCoord1VertexBuffer = bufferMesh.getVertexBuffer(VertexBuffer.UV2Kind);
                             const texCoord1s = texCoord1VertexBuffer!.getData();
                             const texCoord1StrideSize = texCoord1VertexBuffer!.getStrideSize();
-                            const accessor = this.createAccessor(texCoord1BufferViewIndex, "Texture Coords 1", AccessorType.VEC2, AccessorComponentType.FLOAT, texCoord1s!.length/texCoord1StrideSize);
+                            const accessor = this.createAccessor(texCoord1BufferViewIndex, "Texture Coords 1", AccessorType.VEC2, AccessorComponentType.FLOAT, texCoord1s!.length / texCoord1StrideSize);
                             this.accessors.push(accessor);
 
                             meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
@@ -904,129 +812,22 @@ module BABYLON.GLTF2 {
                         }
                     }
                     if (bufferMesh.material) {
-                        if (bufferMesh.material instanceof StandardMaterial) {
-                            console.warn("Standard Material is currently not fully supported/implemented in glTF serializer");
-                            const babylonStandardMaterial = bufferMesh.material as StandardMaterial;
-                            const glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
-
-                            const glTFMaterial: IMaterial = { name: babylonStandardMaterial.name };
-                            if (!babylonStandardMaterial.backFaceCulling) {
-                                glTFMaterial.doubleSided = true;
-                            }
-                            if (babylonStandardMaterial.diffuseTexture && bufferMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                                const glTFTexture = this.exportTexture(babylonStandardMaterial.diffuseTexture);
-                                if (glTFTexture !== null) {
-                                    glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                                }
-                            }
-                            if (babylonStandardMaterial.bumpTexture && bufferMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                                const glTFTexture = this.exportTexture(babylonStandardMaterial.bumpTexture);
-                                if (glTFTexture) {
-                                    glTFMaterial.normalTexture = glTFTexture;
-                                }
-                            }
-                            if (babylonStandardMaterial.emissiveTexture && bufferMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                                const glTFEmissiveTexture = this.exportTexture(babylonStandardMaterial.emissiveTexture);
-                                if (glTFEmissiveTexture) {
-                                    glTFMaterial.emissiveTexture = glTFEmissiveTexture;
-                                }
-                                glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
-                            }
-                            if (babylonStandardMaterial.ambientTexture && bufferMesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                                const glTFOcclusionTexture = this.exportTexture(babylonStandardMaterial.ambientTexture);
-                                if (glTFOcclusionTexture) {
-                                    glTFMaterial.occlusionTexture = glTFOcclusionTexture;
-                                }
-                            }
-                            if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
-
-                                if (babylonStandardMaterial.alphaMode === Engine.ALPHA_COMBINE) {
-                                    glTFMaterial.alphaMode = GLTF2.MaterialAlphaMode.BLEND;
-                                }
-                                else {
-                                    console.warn("glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
-                                }
-                            }
-
-                            glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-
-                            this.materials.push(glTFMaterial);
-                            meshPrimitive.material = this.materials.length - 1;
+                        if (bufferMesh.material instanceof StandardMaterial || bufferMesh.material instanceof PBRMetallicRoughnessMaterial) {
+                            const materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
+                            meshPrimitive.material = materialIndex;
                         }
-                        else if (bufferMesh.material instanceof PBRMetallicRoughnessMaterial) {
-                            const babylonPBRMaterial = bufferMesh.material as PBRMetallicRoughnessMaterial;
-                            const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {};
-
-                            if (babylonPBRMaterial.baseColor) {
-                                glTFPbrMetallicRoughness.baseColorFactor = [
-                                    babylonPBRMaterial.baseColor.r,
-                                    babylonPBRMaterial.baseColor.g,
-                                    babylonPBRMaterial.baseColor.b,
-                                    babylonPBRMaterial.alpha
-                                ];
-                            }
-                            if (babylonPBRMaterial.baseTexture !== undefined) {
-                                const 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;
-                            }
+                        else if (bufferMesh.material instanceof MultiMaterial) {
+                            const babylonMultiMaterial = bufferMesh.material as MultiMaterial;
 
-                            const glTFMaterial: IMaterial = {
-                                name: babylonPBRMaterial.name
-                            };
-                            if (babylonPBRMaterial.doubleSided) {
-                                glTFMaterial.doubleSided = babylonPBRMaterial.doubleSided;
-                            }
-                            if (babylonPBRMaterial.normalTexture) {
-                                const glTFTexture = this.exportTexture(babylonPBRMaterial.normalTexture);
-                                if (glTFTexture) {
-                                    glTFMaterial.normalTexture = glTFTexture;
-                                }
-                            }
-                            if (babylonPBRMaterial.occlusionTexture) {
-                                const glTFTexture = this.exportTexture(babylonPBRMaterial.occlusionTexture);
-                                if (glTFTexture) {
-                                    glTFMaterial.occlusionTexture = glTFTexture;
-                                    if (babylonPBRMaterial.occlusionStrength !== undefined) {
-                                        glTFMaterial.occlusionTexture.strength = babylonPBRMaterial.occlusionStrength;
-                                    }
-                                }
-                            }
-                            if (babylonPBRMaterial.emissiveTexture) {
-                                const glTFTexture = this.exportTexture(babylonPBRMaterial.emissiveTexture);
-                                if (glTFTexture !== null) {
-                                    glTFMaterial.emissiveTexture = glTFTexture;
-                                }
-                            }
-                            if (!babylonPBRMaterial.emissiveColor.equals(new Color3(0.0, 0.0, 0.0))) {
-                                glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
-                            }
-                            if (babylonPBRMaterial.transparencyMode) {
-                                const alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
-
-                                if (alphaMode !== MaterialAlphaMode.OPAQUE) { //glTF defaults to opaque
-                                    glTFMaterial.alphaMode = alphaMode;
-                                    if (alphaMode === MaterialAlphaMode.BLEND) {
-                                        glTFMaterial.alphaCutoff = babylonPBRMaterial.alphaCutOff;
-                                    }
-                                }
-                            }
+                            const material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
 
-                            glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
-
-                            this.materials.push(glTFMaterial);
-                            meshPrimitive.material = this.materials.length - 1;
+                            if (material !== null) {
+                                const materialIndex = babylonMesh.getScene().materials.indexOf(material);
+                                meshPrimitive.material = materialIndex;
+                            }
                         }
                         else {
-                            console.warn("Material type is not yet implemented in glTF serializer: " + bufferMesh.material.name);
+                            Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
                         }
                     }
                     mesh.primitives.push(meshPrimitive);
@@ -1047,6 +848,9 @@ module BABYLON.GLTF2 {
             if (babylonScene.meshes.length > 0) {
                 const babylonMeshes = babylonScene.meshes;
                 const scene = { nodes: new Array<number>() };
+                if (dataBuffer == null) {
+                    _GLTFMaterial.ConvertMaterialsToGLTF(babylonScene.materials, ImageMimeType.JPEG, this.images, this.textures, this.materials, this.imageData, true);
+                }
 
                 for (let i = 0; i < babylonMeshes.length; ++i) {
                     if (this.options &&

+ 328 - 113
serializers/src/glTF/2.0/babylon.glTFMaterial.ts

@@ -2,62 +2,40 @@
 
 module BABYLON.GLTF2 {
     /**
-     * Represents the components used for representing a physically-based specular glossiness material
+     * Utility methods for working with glTF material conversion properties.  This class should only be used internally.
      */
-    interface IBabylonPbrSpecularGlossiness {
-        /**
-         * The diffuse color of the model, whose color values should be 
-         * normalized from 0 to 1.  
-         */
-        diffuse: Color3;
-        /**
-         * Represents the transparency of the material, from a range of 0 to 1.
-         */
-        opacity: number;
-        /**
-         * Represents how specular the material is, from a range of 0 to 1.
-         */
-        specular: Color3;
+    export class _GLTFMaterial {
         /**
-         * Represents how glossy the material is, from a range of 0 to 1.
+         * Represents the dielectric specular values for R, G and B.
          */
-        glossiness: number;
-    }
+        private static readonly dielectricSpecular: Color3 = new Color3(0.04, 0.04, 0.04);
 
-    /**
-     * Represents the components used for representing a physically-based metallic roughness material.
-     */
-    interface _IBabylonPbrMetallicRoughness {
-        /**
-         * The albedo color of the material, whose color components should be normalized from 0 to 1.
-         */
-        baseColor: Color3;
-        /**
-         * Represents the transparency of the material, from a range of 0 (transparent) to 1 (opaque).
-         */
-        opacity: number;
-        /**
-         * Represents the "metalness" of a material, from a range of 0 (dielectric) to 1 (metal).
-         */
-        metallic: number;
         /**
-         * Represents the "roughness" of a material, from a range of 0 (completely smooth) to 1 (completely rough).
+         * Allows the maximum specular power to be defined for material calculations.
          */
-        roughness: number;
-    }
+        private static maxSpecularPower = 1024;
 
-    /**
-     * Utility methods for working with glTF material conversion properties.  This class should only be used internally.
-     */
-    export class _GLTFMaterial {
         /**
-         * Represents the dielectric specular values for R, G and B.
-         */
-        private static readonly dielectricSpecular = new Color3(0.04, 0.04, 0.04);
-        /**
-         * Epsilon value, used as a small tolerance value for a numeric value.
+         * Gets the materials from a Babylon scene and converts them to glTF materials.
+         * @param scene
+         * @param mimeType
+         * @param images
+         * @param textures
+         * @param materials
+         * @param imageData
+         * @param hasTextureCoords
          */
-        private static readonly epsilon = 1e-6;
+        public static ConvertMaterialsToGLTF(babylonMaterials: Material[], mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
+            for (let i = 0; i < babylonMaterials.length; ++i) {
+                const babylonMaterial = babylonMaterials[i];
+                if (babylonMaterial instanceof StandardMaterial) {
+                    _GLTFMaterial.ConvertStandardMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                }
+                else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
+                    _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                }
+            }
+        }
 
         /**
          * Converts a Babylon StandardMaterial to a glTF Metallic Roughness Material.
@@ -65,72 +43,61 @@ module BABYLON.GLTF2 {
          * @returns - glTF Metallic Roughness Material representation
          */
         public static ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial: StandardMaterial): IMaterialPbrMetallicRoughness {
-            const babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness = {
-                diffuse: babylonStandardMaterial.diffuseColor,
-                opacity: babylonStandardMaterial.alpha,
-                specular: babylonStandardMaterial.specularColor || Color3.Black(),
-                glossiness: babylonStandardMaterial.specularPower / 256
-            };
-            if (babylonStandardMaterial.specularTexture) {
+            const P0 = new BABYLON.Vector2(0, 1);
+            const P1 = new BABYLON.Vector2(0, 0.1);
+            const P2 = new BABYLON.Vector2(0, 0.1);
+            const P3 = new BABYLON.Vector2(1300, 0.1);
 
+            /**
+             * Given the control points, solve for x based on a given t for a cubic bezier curve.
+             * @param t - a value between 0 and 1.
+             * @param p0 - first control point.
+             * @param p1 - second control point.
+             * @param p2 - third control point.
+             * @param p3 - fourth control point.
+             * @returns - number result of cubic bezier curve at the specified t.
+             */
+            function cubicBezierCurve(t: number, p0: number, p1: number, p2: number, p3: number): number {
+                return (
+                    (1 - t) * (1 - t) * (1 - t) * p0 +
+                    3 * (1 - t) * (1 - t) * t * p1 +
+                    3 * (1 - t) * t * t * p2 +
+                    t * t * t * p3
+                );
             }
-            const babylonMetallicRoughness = _GLTFMaterial._ConvertToMetallicRoughness(babylonSpecularGlossiness);
+
+            /**
+             * Evaluates a specified specular power value to determine the appropriate roughness value, 
+             * based on a pre-defined cubic bezier curve with specular on the abscissa axis (x-axis) 
+             * and roughness on the ordinant axis (y-axis).
+             * @param specularPower - specular power of standard material.
+             * @returns - Number representing the roughness value.
+             */
+            function solveForRoughness(specularPower: number): number {
+                var t = Math.pow(specularPower / P3.x, 0.333333);
+                return cubicBezierCurve(t, P0.y, P1.y, P2.y, P3.y);
+            }
+
+            let diffuse = babylonStandardMaterial.diffuseColor.toLinearSpace().scale(0.5);
+            let opacity = babylonStandardMaterial.alpha;
+            let specularPower = Scalar.Clamp(babylonStandardMaterial.specularPower, 0, this.maxSpecularPower);
+
+            const roughness = solveForRoughness(specularPower);
 
             const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {
                 baseColorFactor: [
-                    babylonMetallicRoughness.baseColor.r,
-                    babylonMetallicRoughness.baseColor.g,
-                    babylonMetallicRoughness.baseColor.b,
-                    babylonMetallicRoughness.opacity
+                    diffuse.r,
+                    diffuse.g,
+                    diffuse.b,
+                    opacity
                 ],
-                metallicFactor: babylonMetallicRoughness.metallic,
-                roughnessFactor: babylonMetallicRoughness.roughness
+                metallicFactor: 0,
+                roughnessFactor: roughness,
             };
 
             return glTFPbrMetallicRoughness;
         }
 
-        /**
-         * Converts Specular Glossiness to Metallic Roughness.  This is based on the algorithm used in the Babylon glTF 3ds Max Exporter.
-         * {@link https://github.com/BabylonJS/Exporters/blob/master/3ds%20Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs}
-         * @param  babylonSpecularGlossiness - Babylon specular glossiness parameters
-         * @returns - Babylon metallic roughness values
-         */
-        private static _ConvertToMetallicRoughness(babylonSpecularGlossiness: IBabylonPbrSpecularGlossiness): _IBabylonPbrMetallicRoughness {
-            const diffuse = babylonSpecularGlossiness.diffuse;
-            const opacity = babylonSpecularGlossiness.opacity;
-            const specular = babylonSpecularGlossiness.specular;
-            const glossiness = BABYLON.Scalar.Clamp(babylonSpecularGlossiness.glossiness);
-            
-            const oneMinusSpecularStrength = 1 - Math.max(specular.r, Math.max(specular.g, specular.b));
-            const diffusePerceivedBrightness = _GLTFMaterial.PerceivedBrightness(diffuse);
-            const specularPerceivedBrightness = _GLTFMaterial.PerceivedBrightness(specular);
-            const metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
-            const diffuseScaleFactor = oneMinusSpecularStrength/(1 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon);
-            const baseColorFromDiffuse = diffuse.scale(diffuseScaleFactor);
-            const baseColorFromSpecular = specular.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1/ Math.max(metallic, this.epsilon));
-            const lerpColor = Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
-            let baseColor = new Color3();
-            lerpColor.clampToRef(0, 1, baseColor);
-
-            const babylonMetallicRoughness: _IBabylonPbrMetallicRoughness = {
-                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
-         */
-        private static PerceivedBrightness(color: Color3): number {
-            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
@@ -140,17 +107,18 @@ module BABYLON.GLTF2 {
          * @returns - metallic value
          */
         public static SolveMetallic(diffuse: number, specular: number, oneMinusSpecularStrength: number): number {
-            if (specular < this.dielectricSpecular.r) {
+            if (specular < _GLTFMaterial.dielectricSpecular.r) {
+                _GLTFMaterial.dielectricSpecular
                 return 0;
             }
 
-            const a = this.dielectricSpecular.r;
-            const b = diffuse * oneMinusSpecularStrength /(1.0 - this.dielectricSpecular.r) + specular - 2.0 * this.dielectricSpecular.r;
-            const c = this.dielectricSpecular.r - specular;
+            const a = _GLTFMaterial.dielectricSpecular.r;
+            const b = diffuse * oneMinusSpecularStrength / (1.0 - _GLTFMaterial.dielectricSpecular.r) + specular - 2.0 * _GLTFMaterial.dielectricSpecular.r;
+            const c = _GLTFMaterial.dielectricSpecular.r - specular;
             const D = b * b - 4.0 * a * c;
-            return BABYLON.Scalar.Clamp((-b + Math.sqrt(D))/(2.0 * a));
+            return BABYLON.Scalar.Clamp((-b + Math.sqrt(D)) / (2.0 * a), 0, 1);
         }
-        
+
         /**
          * Gets the glTF alpha mode from the Babylon Material
          * @param babylonMaterial - Babylon Material
@@ -159,10 +127,10 @@ module BABYLON.GLTF2 {
         public static GetAlphaMode(babylonMaterial: Material): MaterialAlphaMode {
             if (babylonMaterial instanceof StandardMaterial) {
                 const babylonStandardMaterial = babylonMaterial as StandardMaterial;
-                if ((babylonStandardMaterial.alpha != 1.0) || 
+                if ((babylonStandardMaterial.alpha != 1.0) ||
                     (babylonStandardMaterial.diffuseTexture != null && babylonStandardMaterial.diffuseTexture.hasAlpha) ||
                     (babylonStandardMaterial.opacityTexture != null)) {
-                    return  MaterialAlphaMode.BLEND;
+                    return MaterialAlphaMode.BLEND;
                 }
                 else {
                     return MaterialAlphaMode.OPAQUE;
@@ -171,7 +139,7 @@ module BABYLON.GLTF2 {
             else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
                 const babylonPBRMetallicRoughness = babylonMaterial as PBRMetallicRoughnessMaterial;
 
-                switch(babylonPBRMetallicRoughness.transparencyMode) {
+                switch (babylonPBRMetallicRoughness.transparencyMode) {
                     case PBRMaterial.PBRMATERIAL_OPAQUE: {
                         return MaterialAlphaMode.OPAQUE;
                     }
@@ -182,7 +150,7 @@ module BABYLON.GLTF2 {
                         return MaterialAlphaMode.MASK;
                     }
                     case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
-                        console.warn("GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                        Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
                         return MaterialAlphaMode.BLEND;
                     }
                     default: {
@@ -192,7 +160,254 @@ module BABYLON.GLTF2 {
             }
             else {
                 throw new Error("Unsupported Babylon material type");
-            }   
+            }
+        }
+
+        /**
+         * Converts a Babylon Standard Material to a glTF Material.
+         * @param babylonStandardMaterial - BJS Standard Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        public static ConvertStandardMaterial(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
+            Tools.Warn(babylonStandardMaterial.name + ": Standard Material is currently not fully supported/implemented in glTF serializer");
+            const glTFPbrMetallicRoughness = _GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
+
+            const glTFMaterial: IMaterial = { name: babylonStandardMaterial.name };
+            if (babylonStandardMaterial.backFaceCulling) {
+                if (!babylonStandardMaterial.twoSidedLighting) {
+                    Tools.Warn(babylonStandardMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                }
+                glTFMaterial.doubleSided = true;
+            }
+            if (hasTextureCoords) {
+                if (babylonStandardMaterial.diffuseTexture) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.diffuseTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture != null) {
+                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                    }
+                }
+                if (babylonStandardMaterial.bumpTexture) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.bumpTexture, mimeType, images, textures, imageData)
+                    if (glTFTexture) {
+                        glTFMaterial.normalTexture = glTFTexture;
+                    }
+                }
+                if (babylonStandardMaterial.emissiveTexture) {
+                    const glTFEmissiveTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.emissiveTexture, mimeType, images, textures, imageData)
+                    if (glTFEmissiveTexture) {
+                        glTFMaterial.emissiveTexture = glTFEmissiveTexture;
+                    }
+                    glTFMaterial.emissiveFactor = [1.0, 1.0, 1.0];
+                }
+                if (babylonStandardMaterial.ambientTexture) {
+                    const glTFOcclusionTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData)
+                    if (glTFOcclusionTexture) {
+                        glTFMaterial.occlusionTexture = glTFOcclusionTexture;
+                    }
+                }
+            }
+
+            if (babylonStandardMaterial.alpha < 1.0 || babylonStandardMaterial.opacityTexture) {
+
+                if (babylonStandardMaterial.alphaMode === Engine.ALPHA_COMBINE) {
+                    glTFMaterial.alphaMode = GLTF2.MaterialAlphaMode.BLEND;
+                }
+                else {
+                    Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
+                }
+            }
+
+            glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+
+            materials.push(glTFMaterial);
+        }
+
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMetalRoughMaterial - BJS PBR Metallic Roughness Material.
+         * @param mimeType - mime type to use for the textures.
+         * @param images - array of glTF image interfaces.
+         * @param textures - array of glTF texture interfaces.
+         * @param materials - array of glTF material interfaces.
+         * @param imageData - map of image file name to data.
+         * @param hasTextureCoords - specifies if texture coordinates are present on the submesh to determine if textures should be applied.
+         */
+        public static ConvertPBRMetallicRoughnessMaterial(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
+            const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {};
+
+            if (babylonPBRMetalRoughMaterial.baseColor) {
+                glTFPbrMetallicRoughness.baseColorFactor = [
+                    babylonPBRMetalRoughMaterial.baseColor.r,
+                    babylonPBRMetalRoughMaterial.baseColor.g,
+                    babylonPBRMetalRoughMaterial.baseColor.b,
+                    babylonPBRMetalRoughMaterial.alpha
+                ];
+            }
+
+            if (babylonPBRMetalRoughMaterial.metallic != null) {
+                glTFPbrMetallicRoughness.metallicFactor = babylonPBRMetalRoughMaterial.metallic;
+            }
+            if (babylonPBRMetalRoughMaterial.roughness != null) {
+                glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMetalRoughMaterial.roughness;
+            }
+
+            const glTFMaterial: IMaterial = {
+                name: babylonPBRMetalRoughMaterial.name
+            };
+            if (babylonPBRMetalRoughMaterial.doubleSided) {
+                glTFMaterial.doubleSided = babylonPBRMetalRoughMaterial.doubleSided;
+            }
+
+            if (hasTextureCoords) {
+                if (babylonPBRMetalRoughMaterial.baseTexture != null) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.baseTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture != null) {
+                        glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.normalTexture) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.normalTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture) {
+                        glTFMaterial.normalTexture = glTFTexture;
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.occlusionTexture) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.occlusionTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture) {
+                        glTFMaterial.occlusionTexture = glTFTexture;
+                        if (babylonPBRMetalRoughMaterial.occlusionStrength != null) {
+                            glTFMaterial.occlusionTexture.strength = babylonPBRMetalRoughMaterial.occlusionStrength;
+                        }
+                    }
+                }
+                if (babylonPBRMetalRoughMaterial.emissiveTexture) {
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMetalRoughMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture != null) {
+                        glTFMaterial.emissiveTexture = glTFTexture;
+                    }
+                }
+            }
+
+            if (babylonPBRMetalRoughMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                glTFMaterial.emissiveFactor = babylonPBRMetalRoughMaterial.emissiveColor.asArray();
+            }
+            if (babylonPBRMetalRoughMaterial.transparencyMode != null) {
+                const alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMetalRoughMaterial);
+
+                if (alphaMode !== MaterialAlphaMode.OPAQUE) { //glTF defaults to opaque
+                    glTFMaterial.alphaMode = alphaMode;
+                    if (alphaMode === MaterialAlphaMode.BLEND) {
+                        glTFMaterial.alphaCutoff = babylonPBRMetalRoughMaterial.alphaCutOff;
+                    }
+                }
+            }
+
+            glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
+
+            materials.push(glTFMaterial);
+        }
+
+        /**
+         * Extracts a texture from a Babylon texture into file data and glTF data.
+         * @param babylonTexture - Babylon texture to extract.
+         * @param mimeType - Mime Type of the babylonTexture.
+         * @param images - Array of glTF images.
+         * @param textures - Array of glTF textures.
+         * @param imageData - map of image file name and data.
+         * @return - glTF texture, or null if the texture format is not supported.
+         */
+        public static ExportTexture(babylonTexture: BaseTexture, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }): Nullable<ITextureInfo> {
+            let textureInfo: Nullable<ITextureInfo> = null;
+
+            let glTFTexture = {
+                source: images.length
+            };
+
+            let textureName = "texture_" + (textures.length - 1).toString();
+            let textureData = babylonTexture.getInternalTexture();
+
+            if (textureData != null) {
+                textureName = textureData.url;
+            }
+
+            textureName = Tools.GetFilename(textureName);
+            const baseFile = textureName.split('.')[0];
+            let extension = "";
+
+
+            if (mimeType === ImageMimeType.JPEG) {
+                extension = ".jpg";
+            }
+            else if (mimeType === ImageMimeType.PNG) {
+                extension = ".png";
+            }
+            else {
+                Tools.Error("Unsupported mime type " + mimeType);
+            }
+            textureName = baseFile + extension;
+
+
+            const pixels = babylonTexture.readPixels() as Uint8Array;
+
+            const imageCanvas = document.createElement('canvas');
+            imageCanvas.id = "ImageCanvas";
+
+            const ctx = <CanvasRenderingContext2D>imageCanvas.getContext('2d');
+            const size = babylonTexture.getSize();
+            imageCanvas.width = size.width;
+            imageCanvas.height = size.height;
+
+            const imgData = ctx.createImageData(size.width, size.height);
+
+
+            imgData.data.set(pixels);
+            ctx.putImageData(imgData, 0, 0);
+            const base64Data = imageCanvas.toDataURL(mimeType);
+            const binStr = atob(base64Data.split(',')[1]);
+            const arr = new Uint8Array(binStr.length);
+            for (let i = 0; i < binStr.length; ++i) {
+                arr[i] = binStr.charCodeAt(i);
+            }
+            const imageValues = { data: arr, mimeType: mimeType };
+
+            imageData[textureName] = imageValues;
+            if (mimeType === ImageMimeType.JPEG) {
+                const glTFImage: IImage = {
+                    uri: textureName
+                }
+                let foundIndex = -1;
+                for (let i = 0; i < images.length; ++i) {
+                    if (images[i].uri === textureName) {
+                        foundIndex = i;
+                        break;
+                    }
+                }
+                if (foundIndex === -1) {
+                    images.push(glTFImage);
+                    glTFTexture.source = images.length - 1;
+                    textures.push({
+                        source: images.length - 1
+                    });
+
+                    textureInfo = {
+                        index: images.length - 1
+                    }
+                }
+                else {
+                    glTFTexture.source = foundIndex;
+
+                    textureInfo = {
+                        index: foundIndex
+                    }
+                }
+            }
+
+            return textureInfo;
         }
     }
 }

+ 5 - 0
src/Bones/babylon.skeleton.ts

@@ -18,6 +18,11 @@
 
         private _lastAbsoluteTransformsUpdateId = -1;
 
+        /**
+         * Specifies if the skeleton should be serialized.
+         */
+        public doNotSerialize = false;        
+
         // Events
         /**
          * An event triggered before computing the skeleton's matrices

+ 3 - 10
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -120,7 +120,6 @@ module BABYLON {
         private _teleportationTarget: Mesh;
         private _isDefaultTeleportationTarget = true;
         private _postProcessMove: ImageProcessingPostProcess;
-        private _passProcessMove: PassPostProcess;
         private _teleportationFillColor: string = "#444444";
         private _teleportationBorderColor: string = "#FFFFFF";
         private _rotationAngle: number = 0;
@@ -207,15 +206,14 @@ module BABYLON {
         }
 
         /**
-         * The mesh used to display where the user is selecting.
+         * The mesh used to display where the user is selecting, 
+         * when set bakeCurrentTransformIntoVertices will be called on the mesh.
+         * See http://doc.babylonjs.com/resources/baking_transformations 
          */
         public get gazeTrackerMesh(): Mesh {
             return this._gazeTracker;
         }
 
-        /**
-         * Sets the mesh to be used to display where the user is selecting.
-         */
         public set gazeTrackerMesh(value: Mesh) {
             if (value) {
                 this._gazeTracker = value;
@@ -802,7 +800,6 @@ module BABYLON {
                     imageProcessingConfiguration);
 
                 this._webVRCamera.detachPostProcess(this._postProcessMove)
-                this._passProcessMove = new PassPostProcess("pass", 1.0, this._webVRCamera);
                 this._teleportationInitialized = true;
                 if (this._isDefaultTeleportationTarget) {
                     this._createTeleportationCircles();
@@ -1597,10 +1594,6 @@ module BABYLON {
                 this.exitVR();
             }
 
-            if (this._passProcessMove) {
-                this._passProcessMove.dispose();
-            }
-
             if (this._postProcessMove) {
                 this._postProcessMove.dispose();
             }

+ 30 - 22
src/Cameras/VR/babylon.webVRCamera.ts

@@ -114,7 +114,7 @@ module BABYLON {
         rayLength?: number;
 
         /**
-         * To change the default offset from the ground to account for user's height. (default: 1.7)
+         * To change the default offset from the ground to account for user's height in meters. (default: 1.7)
          */
         defaultHeight?: number;
 
@@ -282,11 +282,11 @@ module BABYLON {
         }
 
         /**
-         * Gets the device distance from the ground.
-         * @returns the distance from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
+         * Gets the device distance from the ground in meters.
+         * @returns the distance in meters from the vrDevice to ground in device space. If standing matrix is not supported for the vrDevice 0 is returned.
          */
         public deviceDistanceToRoomGround(): number {
-            if (this._standingMatrix && this._defaultHeight === undefined) {
+            if (this._standingMatrix) {
                 // Add standing matrix offset to get real offset from ground in room
                 this._standingMatrix.getTranslationToRef(this._workingVector);
                 return this._deviceRoomPosition.y + this._workingVector.y
@@ -301,26 +301,34 @@ module BABYLON {
          */
         public useStandingMatrix(callback = (bool: boolean) => { }) {
             // Use standing matrix if available
-            if (!navigator || !navigator.getVRDisplays) {
-                callback(false);
-            } else {
-                navigator.getVRDisplays().then((displays: any) => {
-                    if (!displays || !displays[0] || !displays[0].stageParameters || !displays[0].stageParameters.sittingToStandingTransform) {
-                        callback(false);
-                    } else {
-                        this._standingMatrix = new Matrix();
-                        Matrix.FromFloat32ArrayToRefScaled(displays[0].stageParameters.sittingToStandingTransform, 0, 1, this._standingMatrix);
-                        if (!this.getScene().useRightHandedSystem) {
-                            [2, 6, 8, 9, 14].forEach((num) => {
-                                if (this._standingMatrix) {
-                                    this._standingMatrix.m[num] *= -1;
-                                }
-                            });
-                        }
-                        callback(true);
+            this.getEngine().initWebVRAsync().then((result)=>{
+                if (!result.vrDisplay || !result.vrDisplay.stageParameters || !result.vrDisplay.stageParameters.sittingToStandingTransform) {
+                    callback(false);
+                } else {
+                    this._standingMatrix = new Matrix();
+                    Matrix.FromFloat32ArrayToRefScaled(result.vrDisplay.stageParameters.sittingToStandingTransform, 0, 1, this._standingMatrix);
+                    if (!this.getScene().useRightHandedSystem) {
+                        [2, 6, 8, 9, 14].forEach((num) => {
+                            if (this._standingMatrix) {
+                                this._standingMatrix.m[num] *= -1;
+                            }
+                        });
                     }
+                    callback(true);
+                }
+            });
+        }
+
+        /**
+         * Enables the standing matrix when supported. This can be used to position the user's view the correct height from the ground.
+         * @returns A promise with a boolean set to if the standing matrix is supported.
+         */
+        public useStandingMatrixAsync():Promise<boolean> {
+            return new Promise((res, rej)=>{
+                this.useStandingMatrix((supported)=>{
+                    res(supported);
                 });
-            }
+            });
         }
 
         /**

+ 43 - 25
src/Engine/babylon.engine.ts

@@ -270,7 +270,7 @@
     }
 
     export interface IDisplayChangedEventArgs {
-        vrDisplay: any;
+        vrDisplay: Nullable<any>;
         vrSupported: boolean;
     }
 
@@ -619,6 +619,7 @@
         private _oldSize: Size;
         private _oldHardwareScaleFactor: number;
         private _vrExclusivePointerMode = false;
+        private _webVRInitPromise: Promise<IDisplayChangedEventArgs>;
 
         public get isInVRExclusivePointerMode(): boolean {
             return this._vrExclusivePointerMode;
@@ -1809,13 +1810,29 @@
             return this._vrDisplay;
         }
 
-        public initWebVR(): Observable<{ vrDisplay: any, vrSupported: any }> {
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns The onVRDisplayChangedObservable.
+         */
+        public initWebVR(): Observable<IDisplayChangedEventArgs> {
+            this.initWebVRAsync();
+            return this.onVRDisplayChangedObservable;
+        }
+
+        /**
+         * Initializes a webVR display and starts listening to display change events.
+         * The onVRDisplayChangedObservable will be notified upon these changes.
+         * @returns A promise containing a VRDisplay and if vr is supported.
+         */
+        public initWebVRAsync(): Promise<IDisplayChangedEventArgs> {
             var notifyObservers = () => {
                 var eventArgs = {
                     vrDisplay: this._vrDisplay,
                     vrSupported: this._vrSupported
                 };
                 this.onVRDisplayChangedObservable.notifyObservers(eventArgs);
+                this._webVRInitPromise = new Promise((res)=>{res(eventArgs)});
             }
 
             if (!this._onVrDisplayConnect) {
@@ -1836,10 +1853,9 @@
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
-
-            this._getVRDisplays(notifyObservers);
-
-            return this.onVRDisplayChangedObservable;
+            this._webVRInitPromise = this._webVRInitPromise || this._getVRDisplaysAsync();
+            this._webVRInitPromise.then(notifyObservers);
+            return this._webVRInitPromise;
         }
 
         public enableVR() {
@@ -1879,26 +1895,28 @@
             }
         }
 
-        private _getVRDisplays(callback: () => void) {
-            var getWebVRDevices = (devices: Array<any>) => {
-                this._vrSupported = true;
-                // note that devices may actually be an empty array. This is fine;
-                // we expect this._vrDisplay to be undefined in this case.
-                return this._vrDisplay = devices[0];
-            }
-
-            if (navigator.getVRDisplays) {
-                navigator.getVRDisplays().then(getWebVRDevices).then(callback).catch((error: () => void) => {
-                    // TODO: System CANNOT support WebVR, despite API presence.
+        private _getVRDisplaysAsync():Promise<IDisplayChangedEventArgs> {
+            return new Promise((res, rej)=>{    
+                if (navigator.getVRDisplays) {
+                    navigator.getVRDisplays().then((devices: Array<any>)=>{
+                        this._vrSupported = true;
+                        // note that devices may actually be an empty array. This is fine;
+                        // we expect this._vrDisplay to be undefined in this case.
+                        this._vrDisplay = devices[0];
+                        res({
+                            vrDisplay: this._vrDisplay,
+                            vrSupported: this._vrSupported
+                        });
+                    });
+                } else {
+                    this._vrDisplay = undefined;
                     this._vrSupported = false;
-                    callback();
-                });
-            } else {
-                // TODO: Browser does not support WebVR
-                this._vrDisplay = undefined;
-                this._vrSupported = false;
-                callback();
-            }
+                    res({
+                        vrDisplay: this._vrDisplay,
+                        vrSupported: this._vrSupported
+                    });
+                }
+            });
         }
 
         public bindFramebuffer(texture: InternalTexture, faceIndex?: number, requiredWidth?: number, requiredHeight?: number, forceFullscreenViewport?: boolean): void {

+ 3 - 1
src/Mesh/babylon.buffer.ts

@@ -5,6 +5,7 @@
         private _data: Nullable<FloatArray>;
         private _updatable: boolean;
         private _strideSize: number;
+        private _instanced: boolean;
 
         constructor(engine: any, data: FloatArray, updatable: boolean, stride: number, postponeInternalCreation?: boolean, instanced: boolean = false) {
             if (engine instanceof Mesh) { // old versions of BABYLON.VertexBuffer accepted 'mesh' instead of 'engine'
@@ -15,6 +16,7 @@
             }
 
             this._updatable = updatable;
+            this._instanced = instanced;
 
             this._data = data;
 
@@ -36,7 +38,7 @@
          */
         public createVertexBuffer(kind: string, offset: number, size: number, stride?: number, instanced?: boolean): VertexBuffer {
             // a lot of these parameters are ignored as they are overriden by the buffer
-            return new VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced, offset, size);
+            return new VertexBuffer(this._engine, this, kind, this._updatable, true, stride ? stride : this._strideSize, instanced === undefined ? this._instanced : instanced, offset, size);
         }
 
         // Properties

+ 25 - 5
src/PostProcess/babylon.refractionPostProcess.ts

@@ -1,11 +1,30 @@
 module BABYLON {
     export class RefractionPostProcess extends PostProcess {
-        private _refRexture: Texture;
+        private _refTexture: Texture;
+        private _ownRefractionTexture = true;
+
+        /**
+         * Gets or sets the refraction texture
+         * Please note that you are responsible for disposing the texture if you set it manually
+         */
+        public get refractionTexture(): Texture {
+            return this._refTexture;
+        }
+
+        public set refractionTexture(value: Texture) {
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+            }
+
+            this._refTexture = value;
+            this._ownRefractionTexture = false;
+        }
+
         constructor(name: string, refractionTextureUrl: string, public color: Color3, public depth: number, public colorLevel: number, options: number | PostProcessOptions, camera: Camera, samplingMode?: number, engine?: Engine, reusable?: boolean) {
             super(name, "refraction", ["baseColor", "depth", "colorLevel"], ["refractionSampler"], options, camera, samplingMode, engine, reusable);
 
             this.onActivateObservable.add((cam: Camera) => {
-                this._refRexture = this._refRexture || new Texture(refractionTextureUrl, cam.getScene());
+                this._refTexture = this._refTexture || new Texture(refractionTextureUrl, cam.getScene());
             });
 
             this.onApplyObservable.add((effect: Effect) => {
@@ -13,14 +32,15 @@
                 effect.setFloat("depth", this.depth);
                 effect.setFloat("colorLevel", this.colorLevel);
 
-                effect.setTexture("refractionSampler", this._refRexture);
+                effect.setTexture("refractionSampler", this._refTexture);
             });
         }
 
         // Methods
         public dispose(camera: Camera): void {
-            if (this._refRexture) {
-                this._refRexture.dispose();
+            if (this._refTexture && this._ownRefractionTexture) {
+                this._refTexture.dispose();
+                (<any>this._refTexture) = null;
             }
 
             super.dispose(camera);

+ 1 - 0
src/PostProcess/babylon.volumetricLightScatteringPostProcess.ts

@@ -251,6 +251,7 @@
             this._volumetricLightScatteringRTT.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._volumetricLightScatteringRTT.renderList = null;
             this._volumetricLightScatteringRTT.renderParticles = false;
+            this._volumetricLightScatteringRTT.ignoreCameraViewport = true;
 
             var camera = this.getCamera();
             if (camera) {

+ 4 - 1
src/Tools/babylon.sceneSerializer.ts

@@ -217,7 +217,10 @@
             // Skeletons
             serializationObject.skeletons = [];
             for (index = 0; index < scene.skeletons.length; index++) {
-                serializationObject.skeletons.push(scene.skeletons[index].serialize());
+                let skeleton = scene.skeletons[index];
+                if (!skeleton.doNotSerialize) {
+                    serializationObject.skeletons.push(skeleton.serialize());
+                }
             }
 
             // Transform nodes

+ 6 - 2
src/babylon.scene.ts

@@ -3364,7 +3364,7 @@
             this._setAlternateTransformMatrix(alternateCamera.getViewMatrix(), alternateCamera.getProjectionMatrix());
         }
 
-        private _renderForCamera(camera: Camera): void {
+        private _renderForCamera(camera: Camera, rigParent?: Camera): void {
             if (camera && camera._skipRendering) {
                 return;
             }
@@ -3412,6 +3412,10 @@
                 this._renderTargets.concatWithNoDuplicate(camera.customRenderTargets);
             }
 
+            if (rigParent && rigParent.customRenderTargets && rigParent.customRenderTargets.length > 0) {
+                this._renderTargets.concatWithNoDuplicate(rigParent.customRenderTargets);
+            }
+
             if (this.renderTargetsEnabled && this._renderTargets.length > 0) {
                 this._intermediateRendering = true;
                 Tools.StartPerformanceCounter("Render targets", this._renderTargets.length > 0);
@@ -3566,7 +3570,7 @@
 
             // rig cameras
             for (var index = 0; index < camera._rigCameras.length; index++) {
-                this._renderForCamera(camera._rigCameras[index]);
+                this._renderForCamera(camera._rigCameras[index], camera);
             }
 
             this.activeCamera = camera;

+ 14 - 13
tests/unit/babylon/serializers/babylon.glTFSerializer.tests.ts

@@ -39,10 +39,10 @@ describe('Babylon glTF Serializer', () => {
             const scene = new BABYLON.Scene(subject);
             const babylonMaterial = new BABYLON.PBRMetallicRoughnessMaterial("metallicroughness", scene);
             babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_OPAQUE;
-            
+
             alphaMode = BABYLON.GLTF2._GLTFMaterial.GetAlphaMode(babylonMaterial);
             alphaMode.should.be.equal('OPAQUE');
-            
+
             babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_ALPHABLEND;
             alphaMode = BABYLON.GLTF2._GLTFMaterial.GetAlphaMode(babylonMaterial);
             alphaMode.should.be.equal('BLEND');
@@ -53,7 +53,7 @@ describe('Babylon glTF Serializer', () => {
 
             babylonMaterial.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_ALPHATEST;
             alphaMode = BABYLON.GLTF2._GLTFMaterial.GetAlphaMode(babylonMaterial);
-            alphaMode.should.be.equal('MASK'); 
+            alphaMode.should.be.equal('MASK');
         });
 
         it('should convert Babylon standard material to metallic roughness', () => {
@@ -66,11 +66,11 @@ describe('Babylon glTF Serializer', () => {
 
             const metalRough = BABYLON.GLTF2._GLTFMaterial.ConvertToGLTFPBRMetallicRoughness(babylonStandardMaterial);
 
-            metalRough.baseColorFactor.should.deep.equal([1,1,1,1]);
+            metalRough.baseColorFactor.should.deep.equal([0.5, 0.5, 0.5, 1]);
 
             metalRough.metallicFactor.should.be.equal(0);
-            
-            metalRough.roughnessFactor.should.be.equal(0.75);
+
+            metalRough.roughnessFactor.should.be.approximately(0.328809, 1e-6);
         });
 
         it('should solve for metallic', () => {
@@ -107,8 +107,8 @@ describe('Babylon glTF Serializer', () => {
                 const jsonString = glTFData.glTFFiles['test.gltf'] as string;
                 const jsonData = JSON.parse(jsonString);
 
-                // accessors, asset, buffers, bufferViews, meshes, nodes, scene, scenes, 
-                Object.keys(jsonData).length.should.be.equal(8);
+                // accessors, asset, buffers, bufferViews, meshes, nodes, scene, scenes, materials
+                Object.keys(jsonData).length.should.be.equal(9);
 
                 // positions, normals, texture coords, indices
                 jsonData.accessors.length.should.be.equal(4);
@@ -132,7 +132,7 @@ describe('Babylon glTF Serializer', () => {
                 done();
             });
         });
-        
+
         it('should serialize alpha mode and cutoff', (done) => {
             mocha.timeout(10000);
             const scene = new BABYLON.Scene(subject);
@@ -151,14 +151,15 @@ describe('Babylon glTF Serializer', () => {
                 const jsonString = glTFData.glTFFiles['test.gltf'] as string;
                 const jsonData = JSON.parse(jsonString);
 
+                // accessors, asset, buffers, bufferViews, meshes, nodes, scene, scenes, materials
                 Object.keys(jsonData).length.should.be.equal(9);
 
-                jsonData.materials.length.should.be.equal(1);
-                
+                jsonData.materials.length.should.be.equal(2);
+
                 jsonData.materials[0].alphaMode.should.be.equal('BLEND');
-                
+
                 jsonData.materials[0].alphaCutoff.should.be.equal(alphaCutoff);
-                
+
                 done();
             });
         });