浏览代码

Merge remote-tracking branch 'upstream/master' into InProgress

sebastien 7 年之前
父节点
当前提交
bffaeec558
共有 100 个文件被更改,包括 23126 次插入18540 次删除
  1. 12775 12635
      Playground/babylon.d.txt
  2. 二进制
      Playground/scenes/Alien/Alien.bin
  3. 1562 0
      Playground/scenes/Alien/Alien.gltf
  4. 二进制
      Playground/scenes/Alien/Alien_baseColor.png
  5. 二进制
      Playground/scenes/Alien/Alien_normal.png
  6. 二进制
      Playground/scenes/Alien/Alien_occlusionRoughnessMetallic.png
  7. 二进制
      Playground/scenes/TwoQuads/LOD0.png
  8. 二进制
      Playground/scenes/TwoQuads/LOD1.png
  9. 二进制
      Playground/scenes/TwoQuads/LOD2.png
  10. 二进制
      Playground/scenes/TwoQuads/TwoQuads.bin
  11. 160 0
      Playground/scenes/TwoQuads/TwoQuads.gltf
  12. 8 2
      Tools/Gulp/config.json
  13. 18 28
      Tools/Gulp/gulp-addModuleExports.js
  14. 1 1
      Tools/Gulp/gulpfile.js
  15. 5 5
      Tools/Gulp/readme.md
  16. 1733 1589
      dist/preview release/babylon.d.ts
  17. 56 56
      dist/preview release/babylon.js
  18. 393 74
      dist/preview release/babylon.max.js
  19. 57 57
      dist/preview release/babylon.worker.js
  20. 3227 3083
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  21. 59 59
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  22. 410 82
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  23. 395 67
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  24. 378 59
      dist/preview release/es6.js
  25. 1 1
      dist/preview release/gltf2Interface/package.json
  26. 13 5
      dist/preview release/gui/babylon.gui.d.ts
  27. 97 40
      dist/preview release/gui/babylon.gui.js
  28. 4 3
      dist/preview release/gui/babylon.gui.min.js
  29. 13 5
      dist/preview release/gui/babylon.gui.module.d.ts
  30. 1 1
      dist/preview release/gui/package.json
  31. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  32. 1 1
      dist/preview release/inspector/package.json
  33. 17 8
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  34. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  35. 17 8
      dist/preview release/loaders/babylon.glTFFileLoader.js
  36. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  37. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  38. 31 26
      dist/preview release/loaders/babylonjs.loaders.js
  39. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  40. 2 2
      dist/preview release/loaders/package.json
  41. 14 18
      dist/preview release/materialsLibrary/babylonjs.materials.js
  42. 7 7
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  43. 1 1
      dist/preview release/materialsLibrary/package.json
  44. 14 18
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.js
  45. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  46. 1 1
      dist/preview release/postProcessesLibrary/package.json
  47. 14 18
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js
  48. 1 1
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js
  49. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  50. 3 0
      dist/preview release/serializers/babylon.glTF2Serializer.js
  51. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  52. 17 18
      dist/preview release/serializers/babylonjs.serializers.js
  53. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  54. 2 2
      dist/preview release/serializers/package.json
  55. 12 89
      dist/preview release/typedocValidationBaseline.json
  56. 69 69
      dist/preview release/viewer/babylon.viewer.js
  57. 507 186
      dist/preview release/viewer/babylon.viewer.max.js
  58. 1 1
      dist/preview release/viewer/package.json
  59. 10 3
      dist/preview release/what's new.md
  60. 17 2
      gui/src/advancedDynamicTexture.ts
  61. 2 2
      gui/src/controls/button.ts
  62. 2 2
      gui/src/controls/colorpicker.ts
  63. 2 0
      gui/src/controls/container.ts
  64. 47 9
      gui/src/controls/control.ts
  65. 2 2
      gui/src/controls/inputText.ts
  66. 2 2
      gui/src/controls/slider.ts
  67. 17 3
      gui/src/valueAndUnit.ts
  68. 62 14
      inspector/src/details/DetailPanel.ts
  69. 84 3
      inspector/src/details/PropertyLine.ts
  70. 39 3
      inspector/src/gui/SearchBar.ts
  71. 17 6
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  72. 3 2
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  73. 1 1
      package.json
  74. 10 1
      sandbox/index.js
  75. 43 32
      serializers/src/glTF/2.0/babylon.glTFExporter.ts
  76. 235 4
      serializers/src/glTF/2.0/babylon.glTFMaterial.ts
  77. 21 0
      src/Animations/babylon.animationPropertiesOverride.ts
  78. 16 5
      src/Animations/babylon.runtimeAnimation.ts
  79. 7 0
      src/Bones/babylon.bone.ts
  80. 5 0
      src/Bones/babylon.skeleton.ts
  81. 45 24
      src/Cameras/VR/babylon.vrExperienceHelper.ts
  82. 4 2
      src/Cameras/VR/babylon.webVRCamera.ts
  83. 3 3
      src/Collisions/babylon.collisionCoordinator.ts
  84. 6 3
      src/Collisions/babylon.collisionWorker.ts
  85. 1 1
      src/Engine/babylon.engine.ts
  86. 50 0
      src/Gamepad/Controllers/babylon.daydreamController.ts
  87. 1 1
      src/Gamepad/Controllers/babylon.gearVRController.ts
  88. 1 1
      src/Gamepad/Controllers/babylon.genericController.ts
  89. 1 1
      src/Gamepad/Controllers/babylon.oculusTouchController.ts
  90. 18 2
      src/Gamepad/Controllers/babylon.poseEnabledController.ts
  91. 1 1
      src/Gamepad/Controllers/babylon.viveController.ts
  92. 2 2
      src/Gamepad/Controllers/babylon.webVRController.ts
  93. 10 11
      src/Gamepad/Controllers/babylon.windowsMotionController.ts
  94. 14 15
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  95. 2 1
      src/Materials/PBR/babylon.pbrMetallicRoughnessMaterial.ts
  96. 56 29
      src/Materials/Textures/babylon.videoTexture.ts
  97. 99 3
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  98. 4 1
      src/PostProcess/RenderPipeline/Pipelines/babylon.lensRenderingPipeline.ts
  99. 50 0
      src/PostProcess/babylon.chromaticAberrationPostProcess.ts
  100. 0 0
      src/PostProcess/babylon.convolutionPostProcess.ts

文件差异内容过多而无法显示
+ 12775 - 12635
Playground/babylon.d.txt


二进制
Playground/scenes/Alien/Alien.bin


文件差异内容过多而无法显示
+ 1562 - 0
Playground/scenes/Alien/Alien.gltf


二进制
Playground/scenes/Alien/Alien_baseColor.png


二进制
Playground/scenes/Alien/Alien_normal.png


二进制
Playground/scenes/Alien/Alien_occlusionRoughnessMetallic.png


二进制
Playground/scenes/TwoQuads/LOD0.png


二进制
Playground/scenes/TwoQuads/LOD1.png


二进制
Playground/scenes/TwoQuads/LOD2.png


二进制
Playground/scenes/TwoQuads/TwoQuads.bin


+ 160 - 0
Playground/scenes/TwoQuads/TwoQuads.gltf

@@ -0,0 +1,160 @@
+{
+  "accessors": [
+    {
+      "bufferView": 0,
+      "componentType": 5126,
+      "count": 4,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 1,
+      "componentType": 5126,
+      "count": 4,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 2,
+      "componentType": 5125,
+      "count": 6,
+      "type": "SCALAR"
+    }
+  ],
+  "asset": {
+    "version": "2.0"
+  },
+  "buffers": [
+    {
+      "uri": "TwoQuads.bin",
+      "byteLength": 104
+    }
+  ],
+  "bufferViews": [
+    {
+      "buffer": 0,
+      "byteLength": 48
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 48,
+      "byteLength": 32
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 80,
+      "byteLength": 24
+    }
+  ],
+  "extensionsUsed": [
+    "MSFT_lod"
+  ],
+  "images": [
+    {
+      "uri": "LOD0.png"
+    },
+    {
+      "uri": "LOD1.png"
+    },
+    {
+      "uri": "LOD2.png"
+    }
+  ],
+  "materials": [
+    {
+      "name": "LOD0",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 0
+        },
+        "metallicFactor": 0
+      },
+      "extensions": {
+        "MSFT_lod": {
+          "ids": [
+            1,
+            2
+          ]
+        }
+      }
+    },
+    {
+      "name": "LOD1",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 1
+        },
+        "metallicFactor": 0
+      }
+    },
+    {
+      "name": "LOD2",
+      "pbrMetallicRoughness": {
+        "baseColorTexture": {
+          "index": 2
+        },
+        "metallicFactor": 0
+      }
+    }
+  ],
+  "meshes": [
+    {
+      "primitives": [
+        {
+          "attributes": {
+            "POSITION": 0,
+            "TEXCOORD_0": 1
+          },
+          "indices": 2,
+          "material": 0
+        }
+      ]
+    }
+  ],
+  "nodes": [
+    {
+      "mesh": 0,
+      "translation": [
+        -0.55,
+        0,
+        0
+      ]
+    },
+    {
+      "mesh": 0,
+      "translation": [
+        0.55,
+        0,
+        0
+      ]
+    }
+  ],
+  "scene": 0,
+  "scenes": [
+    {
+      "nodes": [
+        0,
+        1
+      ]
+    }
+  ],
+  "textures": [
+    {
+      "source": 0
+    },
+    {
+      "source": 1
+    },
+    {
+      "source": 2
+    }
+  ]
+}

+ 8 - 2
Tools/Gulp/config.json

@@ -385,6 +385,7 @@
         },
         "animations": {
             "files": [
+                "../../src/Animations/babylon.animationPropertiesOverride.js",
                 "../../src/Animations/babylon.animation.js",
                 "../../src/Animations/babylon.animationGroup.js",
                 "../../src/Animations/babylon.runtimeAnimation.js",
@@ -660,7 +661,8 @@
                 "../../src/Gamepad/Controllers/babylon.viveController.js",
                 "../../src/Gamepad/Controllers/babylon.genericController.js",
                 "../../src/Gamepad/Controllers/babylon.windowsMotionController.js",
-                "../../src/Gamepad/Controllers/babylon.gearVRController.js"
+                "../../src/Gamepad/Controllers/babylon.gearVRController.js",
+                "../../src/Gamepad/Controllers/babylon.daydreamController.js"
             ],
             "dependUpon": [
                 "core"
@@ -822,6 +824,8 @@
                 "../../src/PostProcess/babylon.refractionPostProcess.js",
                 "../../src/PostProcess/babylon.blackAndWhitePostProcess.js",
                 "../../src/PostProcess/babylon.convolutionPostProcess.js",
+                "../../src/PostProcess/babylon.sharpenPostProcess.js",
+                "../../src/PostProcess/babylon.chromaticAberrationPostProcess.js",
                 "../../src/PostProcess/babylon.filterPostProcess.js",
                 "../../src/PostProcess/babylon.fxaaPostProcess.js",
                 "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
@@ -838,6 +842,7 @@
                 "refraction.fragment",
                 "blackAndWhite.fragment",
                 "convolution.fragment",
+                "sharpen.fragment",
                 "filter.fragment",
                 "fxaa.fragment",
                 "volumetricLightScattering.fragment",
@@ -1686,7 +1691,8 @@
                 "moduleDeclaration": {
                     "name": "INSPECTOR",
                     "module": "babylonjs-inspector"
-                }
+                },
+                "extendsRoot": true
             }
         ],
         "build": {

+ 18 - 28
Tools/Gulp/gulp-addModuleExports.js

@@ -7,44 +7,36 @@ var through = require('through2');
  */
 module.exports = function (varName, subModule, extendsRoot, externalUsingBabylon, noBabylonInit) {
     return through.obj(function (file, enc, cb) {
-
         if (typeof varName === 'string') {
             varName = {
-                base: varName,
+                name: varName,
                 module: varName
             }
+            if (varName.name === 'BABYLON') {
+                varName.module = 'babylonjs';
+            }
         }
 
-        var optionalRequire = `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-var babylonDependency = (globalObject && globalObject.BABYLON) || BABYLON || (typeof require !== 'undefined' && require("babylonjs"));
-var BABYLON = babylonDependency;
-`;
         function moduleExportAddition(varName) {
 
-            let base = subModule ? 'BABYLON' : varName.base;
-
-            let basicInit = `root["${base}"]${(subModule && !extendsRoot) ? '["' + varName + '"]' : ''} = f;`;
-            let sadGlobalPolution = (!subModule) ? `var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-globalObject["${base}"] = f;` : '';
-            /*if (extendsRoot) {
-                basicInit = `__extends(root["BABYLON"], factory()); `
-            }*/
+            let base = subModule ? 'BABYLON' : varName.name;
 
             return `\n\n(function universalModuleDefinition(root, factory) {
-                var f = factory();
-                
-                ${sadGlobalPolution}
     if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = f;
+        module.exports = factory(${subModule || extendsRoot ? 'require("babylonjs")' : ''});
     else if(typeof define === 'function' && define.amd)
-        define("${varName.module}", ${subModule || extendsRoot ? '["BABYLON"],' : ''} factory);
+        define("${varName.module}", ${subModule || extendsRoot ? '["babylonjs"],' : ''} factory);
     else if(typeof exports === 'object')
-        exports["${varName.module}"] = f;
+        exports["${varName.module}"] = factory(${subModule || extendsRoot ? 'require("babylonjs")' : ''});
     else {
-        ${basicInit}
+        root["${base}"]${(subModule && !extendsRoot) ? '["' + varName.name + '"]' : ''} = factory(root["BABYLON"]);
     }
-})(this, function() {
-    return ${base}${(subModule && !extendsRoot) ? '.' + varName.base : ''};
+})(this, function(${varName.name === 'BABYLON' || noBabylonInit ? '' : 'BABYLON'}) {
+    ${String(file.contents)}
+    ${varName.name === 'BABYLON' || varName.name === 'INSPECTOR' ? `
+var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
+globalObject["${varName.name}"] = ${varName.name}` : ''}
+    return ${base}${(subModule && !extendsRoot) ? '.' + varName.name : ''};
 });
 `;
         }
@@ -80,16 +72,14 @@ globalObject["${base}"] = f;` : '';
             return;
         }
 
-        if (noBabylonInit) {
-            optionalRequire = '';
-        }
+        var optionalRequire = '';
 
         try {
             if (externalUsingBabylon) {
-                file.contents = new Buffer(optionalRequire.concat(new Buffer(String(file.contents).concat(moduleExportAddition(varName)))));
+                file.contents = new Buffer(optionalRequire.concat(new Buffer(String('').concat(moduleExportAddition(varName)))));
             } else {
                 let pretext = subModule ? optionalRequire : '';
-                file.contents = new Buffer(pretext.concat(decorateAddition).concat(new Buffer(extendsAddition.concat(String(file.contents)).concat(moduleExportAddition(varName)))));
+                file.contents = new Buffer(pretext.concat(decorateAddition).concat(new Buffer(extendsAddition.concat(String('')).concat(moduleExportAddition(varName)))));
             }
             this.push(file);
         } catch (err) {

+ 1 - 1
Tools/Gulp/gulpfile.js

@@ -480,7 +480,7 @@ var buildExternalLibrary = function (library, settings, watch) {
                 sequence.push(
                     wpBuild
                         .pipe(rename(library.output.replace(".js", library.noBundleInName ? '.js' : ".bundle.js")))
-                        .pipe(addModuleExports(library.moduleDeclaration, false, false, true))
+                        .pipe(addModuleExports(library.moduleDeclaration, false, library.extendsRoot, true))
                         .pipe(uglify())
                         .pipe(optimisejs())
                         .pipe(gulp.dest(outputDirectory))

+ 5 - 5
Tools/Gulp/readme.md

@@ -66,11 +66,11 @@ gulp run
 ```
 
 you can now freely test in the following URLs:
-- [Playground]("http://localhost:1338/Playground/index-local.html")
-- [Materials Library]("http://localhost:1338/materialsLibrary/index.html")
-- [Postprocess Library]("http://localhost:1338/postProcessLibrary/index.html")
-- [Procedural Textures Library]("http://localhost:1338/proceduralTexturesLibrary/index.html")
-- [Local Dev Samples]("http://localhost:1338/localDev/index.html")
+- [Playground](http://localhost:1338/Playground/index-local.html)
+- [Materials Library](http://localhost:1338/materialsLibrary/index.html)
+- [Postprocess Library](http://localhost:1338/postProcessLibrary/index.html)
+- [Procedural Textures Library](http://localhost:1338/proceduralTexturesLibrary/index.html)
+- [Local Dev Samples](http://localhost:1338/localDev/index.html)
 
 ### Compile all the typscript files to their javascript respective files including declaration file
 ```

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


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


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


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


文件差异内容过多而无法显示
+ 3227 - 3083
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


文件差异内容过多而无法显示
+ 410 - 82
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


文件差异内容过多而无法显示
+ 395 - 67
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


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


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

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

+ 13 - 5
dist/preview release/gui/babylon.gui.d.ts

@@ -32,6 +32,7 @@ declare module BABYLON.GUI {
         private _fullscreenViewport;
         private _idealWidth;
         private _idealHeight;
+        private _useSmallestIdeal;
         private _renderAtIdealSize;
         private _focusedControl;
         private _blockNextFocusCheck;
@@ -40,6 +41,7 @@ declare module BABYLON.GUI {
         background: string;
         idealWidth: number;
         idealHeight: number;
+        useSmallestIdeal: boolean;
         renderAtIdealSize: boolean;
         readonly layer: Nullable<Layer>;
         readonly rootContainer: Container;
@@ -185,6 +187,7 @@ declare module BABYLON.GUI {
         private _transformMatrix;
         protected _invertTransformMatrix: Matrix2D;
         protected _transformedPosition: Vector2;
+        private _onlyMeasureMode;
         private _isMatrixDirty;
         private _cachedOffsetX;
         private _cachedOffsetY;
@@ -227,6 +230,11 @@ declare module BABYLON.GUI {
         */
         onPointerUpObservable: Observable<Vector2WithInfo>;
         /**
+        * An event triggered when a control is clicked on
+        * @type {BABYLON.Observable}
+        */
+        onPointerClickObservable: Observable<Vector2WithInfo>;
+        /**
         * An event triggered when pointer enters the control
         * @type {BABYLON.Observable}
         */
@@ -311,7 +319,7 @@ declare module BABYLON.GUI {
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         forcePointerUp(pointerId?: Nullable<number>): void;
         _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number): boolean;
         private _prepareFont();
@@ -496,7 +504,7 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
     }
 }
 
@@ -710,7 +718,7 @@ declare module BABYLON.GUI {
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -753,7 +761,7 @@ declare module BABYLON.GUI {
         private _isPointOnWheel(coordinates);
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
     }
 }
 
@@ -801,7 +809,7 @@ declare module BABYLON.GUI {
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         dispose(): void;
     }
 }

+ 97 - 40
dist/preview release/gui/babylon.gui.js

@@ -1,6 +1,3 @@
-var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-var babylonDependency = (globalObject && globalObject.BABYLON) || BABYLON || (typeof require !== 'undefined' && require("babylonjs"));
-var BABYLON = babylonDependency;
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -17,7 +14,20 @@ var __extends = (this && this.__extends) || (function () {
                 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
             };
         })();
-        /// <reference path="../../dist/preview release/babylon.d.ts"/>
+        
+
+(function universalModuleDefinition(root, factory) {
+    if(typeof exports === 'object' && typeof module === 'object')
+        module.exports = factory(require("babylonjs"));
+    else if(typeof define === 'function' && define.amd)
+        define("babylonjs-gui", ["babylonjs"], factory);
+    else if(typeof exports === 'object')
+        exports["babylonjs-gui"] = factory(require("babylonjs"));
+    else {
+        root["BABYLON"]["GUI"] = factory(root["BABYLON"]);
+    }
+})(this, function(BABYLON) {
+    /// <reference path="../../dist/preview release/babylon.d.ts"/>
 
 var BABYLON;
 (function (BABYLON) {
@@ -41,6 +51,7 @@ var BABYLON;
                 _this._fullscreenViewport = new BABYLON.Viewport(0, 0, 1, 1);
                 _this._idealWidth = 0;
                 _this._idealHeight = 0;
+                _this._useSmallestIdeal = false;
                 _this._renderAtIdealSize = false;
                 _this._blockNextFocusCheck = false;
                 _this._renderScale = 1;
@@ -125,6 +136,21 @@ var BABYLON;
                 enumerable: true,
                 configurable: true
             });
+            Object.defineProperty(AdvancedDynamicTexture.prototype, "useSmallestIdeal", {
+                get: function () {
+                    return this._useSmallestIdeal;
+                },
+                set: function (value) {
+                    if (this._useSmallestIdeal === value) {
+                        return;
+                    }
+                    this._useSmallestIdeal = value;
+                    this.markAsDirty();
+                    this._rootContainer._markAllAsDirty();
+                },
+                enumerable: true,
+                configurable: true
+            });
             Object.defineProperty(AdvancedDynamicTexture.prototype, "renderAtIdealSize", {
                 get: function () {
                     return this._renderAtIdealSize;
@@ -351,8 +377,8 @@ var BABYLON;
                 var engine = scene.getEngine();
                 var textureSize = this.getSize();
                 if (this._isFullscreen) {
-                    x = x * ((textureSize.width / this._renderScale) / engine.getRenderWidth());
-                    y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
+                    x = x * (textureSize.width / engine.getRenderWidth());
+                    y = y * (textureSize.height / engine.getRenderHeight());
                 }
                 if (this._capturingControl[pointerId]) {
                     this._capturingControl[pointerId]._processObservables(type, x, y, pointerId, buttonIndex);
@@ -739,11 +765,22 @@ var BABYLON;
             };
             ValueAndUnit.prototype.getValue = function (host) {
                 if (host && !this.ignoreAdaptiveScaling && this.unit !== ValueAndUnit.UNITMODE_PERCENTAGE) {
+                    var width = 0;
+                    var height = 0;
                     if (host.idealWidth) {
-                        return (this._value * host.getSize().width) / host.idealWidth;
+                        width = (this._value * host.getSize().width) / host.idealWidth;
                     }
                     if (host.idealHeight) {
-                        return (this._value * host.getSize().height) / host.idealHeight;
+                        height = (this._value * host.getSize().height) / host.idealHeight;
+                    }
+                    if (host.useSmallestIdeal && host.idealWidth && host.idealHeight) {
+                        return window.innerWidth < window.innerHeight ? width : height;
+                    }
+                    if (host.idealWidth) {
+                        return width;
+                    }
+                    if (host.idealHeight) {
+                        return height;
                     }
                 }
                 return this._value;
@@ -851,6 +888,7 @@ var BABYLON;
                 this._transformMatrix = GUI.Matrix2D.Identity();
                 this._invertTransformMatrix = GUI.Matrix2D.Identity();
                 this._transformedPosition = BABYLON.Vector2.Zero();
+                this._onlyMeasureMode = false;
                 this._isMatrixDirty = true;
                 this._isVisible = true;
                 this._fontSet = false;
@@ -889,6 +927,11 @@ var BABYLON;
                 */
                 this.onPointerUpObservable = new BABYLON.Observable();
                 /**
+                * An event triggered when a control is clicked on
+                * @type {BABYLON.Observable}
+                */
+                this.onPointerClickObservable = new BABYLON.Observable();
+                /**
                 * An event triggered when pointer enters the control
                 * @type {BABYLON.Observable}
                 */
@@ -1408,7 +1451,9 @@ var BABYLON;
             };
             Control.prototype.linkWithMesh = function (mesh) {
                 if (!this._host || this._root && this._root !== this._host._rootContainer) {
-                    BABYLON.Tools.Error("Cannot link a control to a mesh if the control is not at root level");
+                    if (mesh) {
+                        BABYLON.Tools.Error("Cannot link a control to a mesh if the control is not at root level");
+                    }
                     return;
                 }
                 var index = this._host._linkedControls.indexOf(this);
@@ -1419,14 +1464,30 @@ var BABYLON;
                     }
                     return;
                 }
+                else if (!mesh) {
+                    return;
+                }
                 this.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
                 this.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
                 this._linkedMesh = mesh;
+                this._onlyMeasureMode = true;
                 this._host._linkedControls.push(this);
             };
             Control.prototype._moveToProjectedPosition = function (projectedPosition) {
-                this.left = ((projectedPosition.x + this._linkOffsetX.getValue(this._host)) - this._currentMeasure.width / 2) + "px";
-                this.top = ((projectedPosition.y + this._linkOffsetY.getValue(this._host)) - this._currentMeasure.height / 2) + "px";
+                var oldLeft = this._left.getValue(this._host);
+                var oldTop = this._top.getValue(this._host);
+                var newLeft = ((projectedPosition.x + this._linkOffsetX.getValue(this._host)) - this._currentMeasure.width / 2);
+                var newTop = ((projectedPosition.y + this._linkOffsetY.getValue(this._host)) - this._currentMeasure.height / 2);
+                if (this._left.ignoreAdaptiveScaling && this._top.ignoreAdaptiveScaling) {
+                    if (Math.abs(newLeft - oldLeft) < 0.5) {
+                        newLeft = oldLeft;
+                    }
+                    if (Math.abs(newTop - oldTop) < 0.5) {
+                        newTop = oldTop;
+                    }
+                }
+                this.left = newLeft + "px";
+                this.top = newTop + "px";
                 this._left.ignoreAdaptiveScaling = true;
                 this._top.ignoreAdaptiveScaling = true;
             };
@@ -1523,6 +1584,10 @@ var BABYLON;
                 }
                 // Transform
                 this._transform(context);
+                if (this._onlyMeasureMode) {
+                    this._onlyMeasureMode = false;
+                    return false; // We do not want rendering for this frame as they are measure dependant information that need to be gathered
+                }
                 // Clip
                 this._clip(context);
                 context.clip();
@@ -1706,21 +1771,25 @@ var BABYLON;
                     this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex);
                 return true;
             };
-            Control.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
+            Control.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
                 this._downCount = 0;
                 delete this._downPointerIds[pointerId];
+                var canNotifyClick = notifyClick;
+                if (notifyClick && this._enterCount > 0) {
+                    canNotifyClick = this.onPointerClickObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+                }
                 var canNotify = this.onPointerUpObservable.notifyObservers(new GUI.Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
                 if (canNotify && this.parent != null)
-                    this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex);
+                    this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick);
             };
             Control.prototype.forcePointerUp = function (pointerId) {
                 if (pointerId === void 0) { pointerId = null; }
                 if (pointerId !== null) {
-                    this._onPointerUp(this, BABYLON.Vector2.Zero(), pointerId, 0);
+                    this._onPointerUp(this, BABYLON.Vector2.Zero(), pointerId, 0, true);
                 }
                 else {
                     for (var key in this._downPointerIds) {
-                        this._onPointerUp(this, BABYLON.Vector2.Zero(), +key, 0);
+                        this._onPointerUp(this, BABYLON.Vector2.Zero(), +key, 0, true);
                     }
                 }
             };
@@ -1746,7 +1815,7 @@ var BABYLON;
                 }
                 if (type === BABYLON.PointerEventTypes.POINTERUP) {
                     if (this._host._lastControlDown[pointerId]) {
-                        this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
+                        this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex, true);
                     }
                     delete this._host._lastControlDown[pointerId];
                     return true;
@@ -1768,6 +1837,7 @@ var BABYLON;
                 this.onPointerMoveObservable.clear();
                 this.onPointerOutObservable.clear();
                 this.onPointerUpObservable.clear();
+                this.onPointerClickObservable.clear();
                 if (this._root) {
                     this._root.removeControl(this);
                     this._root = null;
@@ -1982,6 +2052,7 @@ var BABYLON;
                     this._children.splice(index, 1);
                     control.parent = null;
                 }
+                control.linkWithMesh(null);
                 this._markAsDirty();
                 return this;
             };
@@ -2963,10 +3034,10 @@ var BABYLON;
                 }
                 _super.prototype._onPointerMove.call(this, target, coordinates);
             };
-            Slider.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
+            Slider.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
                 this._pointerIsDown = false;
                 delete this._host._capturingControl[pointerId];
-                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
             };
             return Slider;
         }(GUI.Control));
@@ -3978,11 +4049,11 @@ var BABYLON;
                 }
                 return true;
             };
-            Button.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
+            Button.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
                 if (this.pointerUpAnimation) {
                     this.pointerUpAnimation();
                 }
-                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
             };
             // Statics
             Button.CreateImageButton = function (name, text, imageUrl) {
@@ -4387,10 +4458,10 @@ var BABYLON;
                 }
                 _super.prototype._onPointerMove.call(this, target, coordinates);
             };
-            ColorPicker.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
+            ColorPicker.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
                 this._pointerIsDown = false;
                 delete this._host._capturingControl[pointerId];
-                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
             };
             return ColorPicker;
         }(GUI.Control));
@@ -4826,8 +4897,8 @@ var BABYLON;
                 this._host.focusedControl = this;
                 return true;
             };
-            InputText.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex) {
-                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex);
+            InputText.prototype._onPointerUp = function (target, coordinates, pointerId, buttonIndex, notifyClick) {
+                _super.prototype._onPointerUp.call(this, target, coordinates, pointerId, buttonIndex, notifyClick);
             };
             InputText.prototype.dispose = function () {
                 _super.prototype.dispose.call(this);
@@ -5002,20 +5073,6 @@ var BABYLON;
     })(GUI = BABYLON.GUI || (BABYLON.GUI = {}));
 })(BABYLON || (BABYLON = {}));
 
-
-(function universalModuleDefinition(root, factory) {
-                var f = factory();
-                
-                
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = f;
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-gui", ["BABYLON"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-gui"] = f;
-    else {
-        root["BABYLON"]["[object Object]"] = f;
-    }
-})(this, function() {
-    return BABYLON.undefined;
+    
+    return BABYLON.GUI;
 });

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


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

@@ -38,6 +38,7 @@ declare module BABYLON.GUI {
         private _fullscreenViewport;
         private _idealWidth;
         private _idealHeight;
+        private _useSmallestIdeal;
         private _renderAtIdealSize;
         private _focusedControl;
         private _blockNextFocusCheck;
@@ -46,6 +47,7 @@ declare module BABYLON.GUI {
         background: string;
         idealWidth: number;
         idealHeight: number;
+        useSmallestIdeal: boolean;
         renderAtIdealSize: boolean;
         readonly layer: Nullable<Layer>;
         readonly rootContainer: Container;
@@ -191,6 +193,7 @@ declare module BABYLON.GUI {
         private _transformMatrix;
         protected _invertTransformMatrix: Matrix2D;
         protected _transformedPosition: Vector2;
+        private _onlyMeasureMode;
         private _isMatrixDirty;
         private _cachedOffsetX;
         private _cachedOffsetY;
@@ -233,6 +236,11 @@ declare module BABYLON.GUI {
         */
         onPointerUpObservable: Observable<Vector2WithInfo>;
         /**
+        * An event triggered when a control is clicked on
+        * @type {BABYLON.Observable}
+        */
+        onPointerClickObservable: Observable<Vector2WithInfo>;
+        /**
         * An event triggered when pointer enters the control
         * @type {BABYLON.Observable}
         */
@@ -317,7 +325,7 @@ declare module BABYLON.GUI {
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         forcePointerUp(pointerId?: Nullable<number>): void;
         _processObservables(type: number, x: number, y: number, pointerId: number, buttonIndex: number): boolean;
         private _prepareFont();
@@ -502,7 +510,7 @@ declare module BABYLON.GUI {
         private _updateValueFromPointer(x, y);
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
     }
 }
 
@@ -716,7 +724,7 @@ declare module BABYLON.GUI {
         _onPointerEnter(target: Control): boolean;
         _onPointerOut(target: Control): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
         static CreateImageOnlyButton(name: string, imageUrl: string): Button;
         static CreateSimpleButton(name: string, text: string): Button;
@@ -759,7 +767,7 @@ declare module BABYLON.GUI {
         private _isPointOnWheel(coordinates);
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
         _onPointerMove(target: Control, coordinates: Vector2): void;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
     }
 }
 
@@ -807,7 +815,7 @@ declare module BABYLON.GUI {
         processKeyboard(evt: KeyboardEvent): void;
         _draw(parentMeasure: Measure, context: CanvasRenderingContext2D): void;
         _onPointerDown(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): boolean;
-        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number): void;
+        _onPointerUp(target: Control, coordinates: Vector2, pointerId: number, buttonIndex: number, notifyClick: boolean): void;
         dispose(): void;
     }
 }

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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -1074,8 +1074,9 @@ var BABYLON;
                     node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
                 if (skin._loaded) {
-                    assignSkeleton();
-                    return skin._loaded;
+                    return skin._loaded.then(function () {
+                        assignSkeleton();
+                    });
                 }
                 // TODO: split into two parts so that bones are created before inverseBindMatricesData is loaded (for compiling materials).
                 return (skin._loaded = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -1962,7 +1963,9 @@ var BABYLON;
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
-                                _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadNodeSignals[nodeLOD._index]) {
+                                    _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(function () {
                                 if (indexLOD !== 0) {
@@ -1971,8 +1974,10 @@ var BABYLON;
                                 }
                                 if (indexLOD !== nodeLODs.length - 1) {
                                     var nodeIndex = nodeLODs[indexLOD + 1]._index;
-                                    _this._loadNodeSignals[nodeIndex].resolve();
-                                    delete _this._loadNodeSignals[nodeIndex];
+                                    if (_this._loadNodeSignals[nodeIndex]) {
+                                        _this._loadNodeSignals[nodeIndex].resolve();
+                                        delete _this._loadNodeSignals[nodeIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {
@@ -2002,13 +2007,17 @@ var BABYLON;
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
-                                _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadMaterialSignals[materialLOD._index]) {
+                                    _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(function () {
                                 if (indexLOD !== materialLODs.length - 1) {
                                     var materialIndex = materialLODs[indexLOD + 1]._index;
-                                    _this._loadMaterialSignals[materialIndex].resolve();
-                                    delete _this._loadMaterialSignals[materialIndex];
+                                    if (_this._loadMaterialSignals[materialIndex]) {
+                                        _this._loadMaterialSignals[materialIndex].resolve();
+                                        delete _this._loadMaterialSignals[materialIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {

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


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

@@ -3250,8 +3250,9 @@ var BABYLON;
                     node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
                 if (skin._loaded) {
-                    assignSkeleton();
-                    return skin._loaded;
+                    return skin._loaded.then(function () {
+                        assignSkeleton();
+                    });
                 }
                 // TODO: split into two parts so that bones are created before inverseBindMatricesData is loaded (for compiling materials).
                 return (skin._loaded = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -4138,7 +4139,9 @@ var BABYLON;
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
-                                _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadNodeSignals[nodeLOD._index]) {
+                                    _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(function () {
                                 if (indexLOD !== 0) {
@@ -4147,8 +4150,10 @@ var BABYLON;
                                 }
                                 if (indexLOD !== nodeLODs.length - 1) {
                                     var nodeIndex = nodeLODs[indexLOD + 1]._index;
-                                    _this._loadNodeSignals[nodeIndex].resolve();
-                                    delete _this._loadNodeSignals[nodeIndex];
+                                    if (_this._loadNodeSignals[nodeIndex]) {
+                                        _this._loadNodeSignals[nodeIndex].resolve();
+                                        delete _this._loadNodeSignals[nodeIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {
@@ -4178,13 +4183,17 @@ var BABYLON;
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
-                                _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadMaterialSignals[materialLOD._index]) {
+                                    _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(function () {
                                 if (indexLOD !== materialLODs.length - 1) {
                                     var materialIndex = materialLODs[indexLOD + 1]._index;
-                                    _this._loadMaterialSignals[materialIndex].resolve();
-                                    delete _this._loadMaterialSignals[materialIndex];
+                                    if (_this._loadMaterialSignals[materialIndex]) {
+                                        _this._loadMaterialSignals[materialIndex].resolve();
+                                        delete _this._loadMaterialSignals[materialIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {

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


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


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

@@ -1,6 +1,3 @@
-var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-var babylonDependency = (globalObject && globalObject.BABYLON) || BABYLON || (typeof require !== 'undefined' && require("babylonjs"));
-var BABYLON = babylonDependency;
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -18,6 +15,19 @@ var __extends = (this && this.__extends) || (function () {
             };
         })();
         
+
+(function universalModuleDefinition(root, factory) {
+    if(typeof exports === 'object' && typeof module === 'object')
+        module.exports = factory(require("babylonjs"));
+    else if(typeof define === 'function' && define.amd)
+        define("babylonjs-loaders", ["babylonjs"], factory);
+    else if(typeof exports === 'object')
+        exports["babylonjs-loaders"] = factory(require("babylonjs"));
+    else {
+        root["BABYLON"] = factory(root["BABYLON"]);
+    }
+})(this, function(BABYLON) {
+    
 var BABYLON;
 (function (BABYLON) {
     var STLFileLoader = /** @class */ (function () {
@@ -4218,8 +4228,9 @@ var BABYLON;
                     node._babylonMesh.scaling = BABYLON.Vector3.One();
                 };
                 if (skin._loaded) {
-                    assignSkeleton();
-                    return skin._loaded;
+                    return skin._loaded.then(function () {
+                        assignSkeleton();
+                    });
                 }
                 // TODO: split into two parts so that bones are created before inverseBindMatricesData is loaded (for compiling materials).
                 return (skin._loaded = this._loadSkinInverseBindMatricesDataAsync(context, skin).then(function (inverseBindMatricesData) {
@@ -5097,7 +5108,9 @@ var BABYLON;
                             var nodeLOD = nodeLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingNodeLOD = nodeLOD;
-                                _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadNodeSignals[nodeLOD._index]) {
+                                    _this._loadNodeSignals[nodeLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(function () {
                                 if (indexLOD !== 0) {
@@ -5106,8 +5119,10 @@ var BABYLON;
                                 }
                                 if (indexLOD !== nodeLODs.length - 1) {
                                     var nodeIndex = nodeLODs[indexLOD + 1]._index;
-                                    _this._loadNodeSignals[nodeIndex].resolve();
-                                    delete _this._loadNodeSignals[nodeIndex];
+                                    if (_this._loadNodeSignals[nodeIndex]) {
+                                        _this._loadNodeSignals[nodeIndex].resolve();
+                                        delete _this._loadNodeSignals[nodeIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {
@@ -5137,13 +5152,17 @@ var BABYLON;
                             var materialLOD = materialLODs[indexLOD];
                             if (indexLOD !== 0) {
                                 _this._loadingMaterialLOD = materialLOD;
-                                _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                if (!_this._loadMaterialSignals[materialLOD._index]) {
+                                    _this._loadMaterialSignals[materialLOD._index] = new BABYLON.Deferred();
+                                }
                             }
                             var promise = _this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(function () {
                                 if (indexLOD !== materialLODs.length - 1) {
                                     var materialIndex = materialLODs[indexLOD + 1]._index;
-                                    _this._loadMaterialSignals[materialIndex].resolve();
-                                    delete _this._loadMaterialSignals[materialIndex];
+                                    if (_this._loadMaterialSignals[materialIndex]) {
+                                        _this._loadMaterialSignals[materialIndex].resolve();
+                                        delete _this._loadMaterialSignals[materialIndex];
+                                    }
                                 }
                             });
                             if (indexLOD === 0) {
@@ -5457,20 +5476,6 @@ var BABYLON;
 
 //# sourceMappingURL=KHR_lights.js.map
 
-
-(function universalModuleDefinition(root, factory) {
-                var f = factory();
-                
-                
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = f;
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-loaders", ["BABYLON"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-loaders"] = f;
-    else {
-        root["BABYLON"] = f;
-    }
-})(this, function() {
+    
     return BABYLON;
 });

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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.2.0-alpha10"
+        "babylonjs-gltf2interface": "3.2.0-alphaA"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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


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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

文件差异内容过多而无法显示
+ 14 - 18
dist/preview release/postProcessesLibrary/babylonjs.postProcess.js


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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

文件差异内容过多而无法显示
+ 14 - 18
dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js


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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 3 - 0
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -973,6 +973,9 @@ var BABYLON;
                         BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
                     }
                 }
+                if (babylonStandardMaterial.emissiveColor) {
+                    glTFMaterial.emissiveFactor = babylonStandardMaterial.emissiveColor.asArray();
+                }
                 glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
                 materials.push(glTFMaterial);
             };

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


+ 17 - 18
dist/preview release/serializers/babylonjs.serializers.js

@@ -1,6 +1,3 @@
-var globalObject = (typeof global !== 'undefined') ? global : ((typeof window !== 'undefined') ? window : this);
-var babylonDependency = (globalObject && globalObject.BABYLON) || BABYLON || (typeof require !== 'undefined' && require("babylonjs"));
-var BABYLON = babylonDependency;
 var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -18,6 +15,19 @@ var __extends = (this && this.__extends) || (function () {
             };
         })();
         
+
+(function universalModuleDefinition(root, factory) {
+    if(typeof exports === 'object' && typeof module === 'object')
+        module.exports = factory(require("babylonjs"));
+    else if(typeof define === 'function' && define.amd)
+        define("babylonjs-serializers", ["babylonjs"], factory);
+    else if(typeof exports === 'object')
+        exports["babylonjs-serializers"] = factory(require("babylonjs"));
+    else {
+        root["BABYLON"] = factory(root["BABYLON"]);
+    }
+})(this, function(BABYLON) {
+    
 var BABYLON;
 (function (BABYLON) {
     var OBJExport = /** @class */ (function () {
@@ -1117,6 +1127,9 @@ var BABYLON;
                         BABYLON.Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
                     }
                 }
+                if (babylonStandardMaterial.emissiveColor) {
+                    glTFMaterial.emissiveFactor = babylonStandardMaterial.emissiveColor.asArray();
+                }
                 glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
                 materials.push(glTFMaterial);
             };
@@ -1292,20 +1305,6 @@ var BABYLON;
 
 //# sourceMappingURL=babylon.glTFMaterial.js.map
 
-
-(function universalModuleDefinition(root, factory) {
-                var f = factory();
-                
-                
-    if(typeof exports === 'object' && typeof module === 'object')
-        module.exports = f;
-    else if(typeof define === 'function' && define.amd)
-        define("babylonjs-serializers", ["BABYLON"], factory);
-    else if(typeof exports === 'object')
-        exports["babylonjs-serializers"] = f;
-    else {
-        root["BABYLON"] = f;
-    }
-})(this, function() {
+    
     return BABYLON;
 });

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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -27,7 +27,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "3.2.0-alpha10"
+        "babylonjs-gltf2interface": "3.2.0-alphaA"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 12 - 89
dist/preview release/typedocValidationBaseline.json

@@ -1,7 +1,7 @@
 {
-  "errors": 7232,
+  "errors": 7219,
   "babylon.typedoc.json": {
-    "errors": 7232,
+    "errors": 7219,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -8113,50 +8113,6 @@
         }
       }
     },
-    "ConvolutionPostProcess": {
-      "Class": {
-        "Comments": {
-          "MissingText": true
-        }
-      },
-      "Property": {
-        "kernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EdgeDetect0Kernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EdgeDetect1Kernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EdgeDetect2Kernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "EmbossKernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "GaussianKernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
-        "SharpenKernel": {
-          "Comments": {
-            "MissingText": true
-          }
-        }
-      }
-    },
     "CubeTexture": {
       "Class": {
         "Comments": {
@@ -8841,6 +8797,11 @@
             "NotCamelCase": true
           }
         },
+        "ChromaticAberrationPostProcessId": {
+          "Naming": {
+            "NotCamelCase": true
+          }
+        },
         "CopyBackPostProcessId": {
           "Naming": {
             "NotCamelCase": true
@@ -8870,6 +8831,11 @@
           "Naming": {
             "NotCamelCase": true
           }
+        },
+        "SharpenPostProcessId": {
+          "Naming": {
+            "NotCamelCase": true
+          }
         }
       }
     },
@@ -14211,13 +14177,6 @@
             "MissingText": true
           }
         }
-      },
-      "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        }
       }
     },
     "GenericController": {
@@ -14237,13 +14196,6 @@
             "MissingText": true
           }
         }
-      },
-      "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        }
       }
     },
     "GenericPad": {
@@ -20416,13 +20368,6 @@
             "MissingText": true
           }
         }
-      },
-      "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        }
       }
     },
     "OimoJSPlugin": {
@@ -25315,11 +25260,6 @@
             "MissingText": true
           }
         },
-        "invertYAxis": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "name": {
           "Comments": {
             "MissingText": true
@@ -37371,13 +37311,6 @@
             "MissingText": true
           }
         }
-      },
-      "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        }
       }
     },
     "VolumetricLightScatteringPostProcess": {
@@ -37473,11 +37406,6 @@
         }
       },
       "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        },
         "initControllerMesh": {
           "Comments": {
             "MissingText": true
@@ -37583,11 +37511,6 @@
         }
       },
       "Method": {
-        "handleButtonChange": {
-          "Naming": {
-            "NotUnderscoreCamelCase": true
-          }
-        },
         "lerpAxisTransform": {
           "Naming": {
             "NotUnderscoreCamelCase": true

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


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


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

@@ -4,7 +4,7 @@
     },
     "name": "babylonjs-viewer",
     "description": "A simple-to-use viewer based on BabylonJS to display 3D elements natively",
-    "version": "3.2.0-alpha10",
+    "version": "3.2.0-alphaA",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 10 - 3
dist/preview release/what's new.md

@@ -6,7 +6,7 @@
 - Improved building process: We now run a full visual validation test for each pull request. Furthermore, code comments and what's new updates are now mandatory ([sebavan](https://github.com/sebavan))
 - Introduced texture binding atlas. This optimization allows the engine to reuse texture bindings instead of rebinding textures when they are not on constant sampler indexes ([deltakosh](https://github.com/deltakosh))
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
-- `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
+- `WebVRCamera` add basic support for Daydream and Gear VR ([brianzinn](https://github.com/brianzinn))
 - New glTF [serializer](https://github.com/BabylonJS/Babylon.js/tree/master/serializers/src/glTF/2.0). You can now export glTF or glb files directly from a Babylon scene ([kcoley](https://github.com/kcoley))
 - Babylon.js now uses Promises in addition to callbacks. We created several `xxxAsync` functions all over the framework (`SceneLoader.AppendAsync` for instance, which returns a Promise). A polyfill is also integrated to support older browsers ([deltakosh](https://github.com/deltakosh))
 - Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture) ([lostink](https://github.com/lostink))
@@ -14,11 +14,12 @@
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials ([sebavan](https://github.com/sebavan))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) Class and loading methods ([trevordev](https://github.com/trevordev))
-- Added depth of field effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added depth of field, MSAA, sharpening and chromatic aberration effect to the default pipeline ([trevordev](https://github.com/trevordev))
 
 ## Updates
 
 - Tons of functions and classes received the code comments they deserved (All the community)
+- New `AnimationPropertiesOverride` class used to simplify setting animation properties on child animations. [Documentation](http://doc.babylonjs.com/babylon101/animations#overriding-properties) ([deltakosh](https://github.com/deltakosh))
 - New `Texture.UseSerializedUrlIfAny` static property to let textures serialize complete URL instead of using side by side loading ([deltakosh](https://github.com/deltakosh))
 - Added `particleSystem.reset()` to clear a particle system ([deltakosh](https://github.com/deltakosh))
 - Added support for all RGBA orders (BGR, RGB, etc..) for the DDS loader ([deltakosh](https://github.com/deltakosh))
@@ -80,7 +81,9 @@
 - Support depth maps for multiple active cameras for post processes like depth of field ([trevordev](https://github.com/trevordev))
 - Integrates depth texture support in the engine ([sebavan](https://github.com/sebavan))
 - NPM package now has a dependency system, updated during build. ([RaananW](https://github.com/RaananW))
-- Default pipeline will use webGL 2.0 anti aliasing by default if supported, webVR post processing will render to eye texture size ([trevordev](https://github.com/trevordev))
+- WebVRExperienceHelper will create an empty controller model so that controller interactions can be used while the actual model is still loading ([trevordev](https://github.com/trevordev))
+- Default fragment shader will clamp negative values to avoid underflow, webVR post processing will render to eye texture size ([trevordev](https://github.com/trevordev))
+- Supports Environment Drag and Drop in Sandbox ([sebavan](https://github.com/sebavan))
 
 ## Bug fixes
 
@@ -91,8 +94,12 @@
 - 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 the vr helper class caused a redundant post process to be added ([trevordev](https://github.com/trevordev))
 - (Viewer) Fixed a bug where loading another mesh positioned it incorrectly ([RaananW](https://github.com/RaananW))
+- Scale vr controllers by deviceScale when it is set in VRExperienceHelper ([trevordev](https://github.com/trevordev))
 - (Viewer) Disabling templates now work correctly ([RaananW](https://github.com/RaananW))
 - AMD "define" declaration is no longer anonymous ([RaananW](https://github.com/RaananW))
+- Collision worker didn't initialize instanced meshes correctly - [#3819](https://github.com/BabylonJS/Babylon.js/issues/3819) ([RaananW](https://github.com/RaananW))
+- postMessage calls in webworkers were fixed. ([RaananW](https://github.com/RaananW))
+- fixed WebCam Texture on Firefox and Edge - [#3825](https://github.com/BabylonJS/Babylon.js/issues/3825) ([sebavan](https://github.com/sebavan))
 
 ## Breaking changes
 

+ 17 - 2
gui/src/advancedDynamicTexture.ts

@@ -28,6 +28,7 @@ module BABYLON.GUI {
         private _fullscreenViewport = new Viewport(0, 0, 1, 1);
         private _idealWidth = 0;
         private _idealHeight = 0;
+        private _useSmallestIdeal: boolean = false;
         private _renderAtIdealSize = false;
         private _focusedControl: Nullable<IFocusableControl>;
         private _blockNextFocusCheck = false;
@@ -88,6 +89,20 @@ module BABYLON.GUI {
             this._rootContainer._markAllAsDirty();
         }
 
+        public get useSmallestIdeal(): boolean {
+            return this._useSmallestIdeal;
+        }
+
+        public set useSmallestIdeal(value: boolean) {
+            if (this._useSmallestIdeal === value) {
+                return;
+            }
+
+            this._useSmallestIdeal = value;
+            this.markAsDirty();
+            this._rootContainer._markAllAsDirty();
+        }
+
         public get renderAtIdealSize(): boolean {
             return this._renderAtIdealSize;
         }
@@ -381,8 +396,8 @@ module BABYLON.GUI {
             var textureSize = this.getSize();
 
             if (this._isFullscreen) {
-                x = x * ((textureSize.width / this._renderScale) / engine.getRenderWidth());
-                y = y * ((textureSize.height / this._renderScale) / engine.getRenderHeight());
+                x = x * (textureSize.width / engine.getRenderWidth());
+                y = y * (textureSize.height / engine.getRenderHeight());
             }
 
             if (this._capturingControl[pointerId]) {

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

@@ -84,12 +84,12 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
             if (this.pointerUpAnimation) {
                 this.pointerUpAnimation();
             }
 
-            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
         }        
 
         // Statics

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

@@ -407,11 +407,11 @@ module BABYLON.GUI {
             super._onPointerMove(target, coordinates);
         }
 
-        public _onPointerUp (target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+        public _onPointerUp (target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
             this._pointerIsDown = false;
             
             delete this._host._capturingControl[pointerId];
-            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
         }     
     }    
 }

+ 2 - 0
gui/src/controls/container.ts

@@ -80,6 +80,8 @@ module BABYLON.GUI {
                 control.parent = null;
             }
 
+            control.linkWithMesh(null);
+
             this._markAsDirty();
             return this;
         }

+ 47 - 9
gui/src/controls/control.ts

@@ -36,6 +36,7 @@ module BABYLON.GUI {
         private _transformMatrix = Matrix2D.Identity();
         protected _invertTransformMatrix = Matrix2D.Identity();
         protected _transformedPosition = Vector2.Zero();
+        private _onlyMeasureMode = false;
         private _isMatrixDirty = true;
         private _cachedOffsetX: number;
         private _cachedOffsetY: number;
@@ -91,6 +92,12 @@ module BABYLON.GUI {
         public onPointerUpObservable = new Observable<Vector2WithInfo>();
 
         /**
+        * An event triggered when a control is clicked on
+        * @type {BABYLON.Observable}
+        */
+        public onPointerClickObservable = new Observable<Vector2WithInfo>();
+
+        /**
         * An event triggered when pointer enters the control
         * @type {BABYLON.Observable}
         */
@@ -545,7 +552,9 @@ module BABYLON.GUI {
 
         public linkWithMesh(mesh: Nullable<AbstractMesh>): void {
             if (!this._host || this._root && this._root !== this._host._rootContainer) {
-                Tools.Error("Cannot link a control to a mesh if the control is not at root level");
+                if (mesh) {
+                    Tools.Error("Cannot link a control to a mesh if the control is not at root level");
+                }
                 return;
             }
 
@@ -556,17 +565,36 @@ module BABYLON.GUI {
                     this._host._linkedControls.splice(index, 1);
                 }
                 return;
+            } else if (!mesh) {
+                return;
             }
 
             this.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_LEFT;
             this.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_TOP;
             this._linkedMesh = mesh;
+            this._onlyMeasureMode = true;
             this._host._linkedControls.push(this);
         }
 
         public _moveToProjectedPosition(projectedPosition: Vector3): void {
-            this.left = ((projectedPosition.x + this._linkOffsetX.getValue(this._host)) - this._currentMeasure.width / 2) + "px";
-            this.top = ((projectedPosition.y + this._linkOffsetY.getValue(this._host)) - this._currentMeasure.height / 2) + "px";
+            let oldLeft = this._left.getValue(this._host);
+            let oldTop = this._top.getValue(this._host);
+            
+            var newLeft = ((projectedPosition.x + this._linkOffsetX.getValue(this._host)) - this._currentMeasure.width / 2);
+            var newTop = ((projectedPosition.y + this._linkOffsetY.getValue(this._host)) - this._currentMeasure.height / 2);
+
+            if (this._left.ignoreAdaptiveScaling && this._top.ignoreAdaptiveScaling) {
+                if (Math.abs(newLeft - oldLeft) < 0.5) {
+                    newLeft = oldLeft;
+                }
+
+                if (Math.abs(newTop - oldTop) < 0.5) {
+                    newTop = oldTop;
+                }                
+            }
+
+            this.left = newLeft + "px";
+            this.top = newTop + "px";
 
             this._left.ignoreAdaptiveScaling = true;
             this._top.ignoreAdaptiveScaling = true;
@@ -695,6 +723,11 @@ module BABYLON.GUI {
             // Transform
             this._transform(context);
 
+            if (this._onlyMeasureMode) {
+                this._onlyMeasureMode = false;
+                return false; // We do not want rendering for this frame as they are measure dependant information that need to be gathered
+            }
+
             // Clip
             this._clip(context);
             context.clip();
@@ -918,22 +951,26 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
             this._downCount = 0;
 
             delete this._downPointerIds[pointerId];
 
-            var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+            var canNotifyClick: boolean = notifyClick;
+			if (notifyClick && this._enterCount > 0) {
+				canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
+			}
+			var canNotify: boolean = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this);
 
-            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex);
+            if (canNotify && this.parent != null) this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick);
         }
 
         public forcePointerUp(pointerId:Nullable<number> = null) {
             if(pointerId !== null){
-                this._onPointerUp(this, Vector2.Zero(), pointerId, 0);
+                this._onPointerUp(this, Vector2.Zero(), pointerId, 0, true);
             }else{
                 for(var key in this._downPointerIds){
-                    this._onPointerUp(this, Vector2.Zero(), +key as number, 0);
+                    this._onPointerUp(this, Vector2.Zero(), +key as number, 0, true);
                 }
             }
         }
@@ -965,7 +1002,7 @@ module BABYLON.GUI {
 
             if (type === BABYLON.PointerEventTypes.POINTERUP) {
                 if (this._host._lastControlDown[pointerId]) {
-                    this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex);
+                    this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex, true);
                 }
                 delete this._host._lastControlDown[pointerId];
                 return true;
@@ -993,6 +1030,7 @@ module BABYLON.GUI {
             this.onPointerMoveObservable.clear();
             this.onPointerOutObservable.clear();
             this.onPointerUpObservable.clear();
+			this.onPointerClickObservable.clear();
 
             if (this._root) {
                 this._root.removeControl(this);

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

@@ -449,8 +449,8 @@ module BABYLON.GUI {
             return true;
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
-            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
         }
 
         public dispose() {

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

@@ -287,11 +287,11 @@ module BABYLON.GUI {
             super._onPointerMove(target, coordinates);
         }
 
-        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number): void {
+        public _onPointerUp(target: Control, coordinates: Vector2, pointerId:number, buttonIndex: number, notifyClick: boolean): void {
             this._pointerIsDown = false;
 
             delete this._host._capturingControl[pointerId];
-            super._onPointerUp(target, coordinates, pointerId, buttonIndex);
+            super._onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick);
         }
     }
 }

+ 17 - 3
gui/src/valueAndUnit.ts

@@ -31,13 +31,27 @@ module BABYLON.GUI {
 
         public getValue(host: AdvancedDynamicTexture): number {
             if (host && !this.ignoreAdaptiveScaling && this.unit !== ValueAndUnit.UNITMODE_PERCENTAGE) {
+                var width: number = 0;
+                var height: number = 0;
 
-                if (host.idealWidth) { // horizontal
-                    return (this._value * host.getSize().width) / host.idealWidth;
+                if (host.idealWidth) {
+                    width = (this._value * host.getSize().width) / host.idealWidth;
+                }
+                
+                if (host.idealHeight) {
+                    height = (this._value * host.getSize().height) / host.idealHeight;
+                }
+
+                if (host.useSmallestIdeal && host.idealWidth && host.idealHeight) {
+                    return window.innerWidth < window.innerHeight ? width : height;
                 }
 
+                if (host.idealWidth) { // horizontal
+                    return width;
+                }
+                
                 if (host.idealHeight) { // vertical
-                    return (this._value * host.getSize().height) / host.idealHeight;
+                    return height;
                 }
             }
             return this._value;

+ 62 - 14
inspector/src/details/DetailPanel.ts

@@ -11,6 +11,9 @@
         private _detailRows : Array<PropertyLine> = [];
         // Store the sort direction of each header column
         private _sortDirection : SortDirection = {};
+        // The search bar
+        private _searchDetails : SearchBarDetails;
+        private _details : HTMLElement;
 
         constructor(dr? : Array<PropertyLine>) {
             super();
@@ -23,36 +26,72 @@
         }
 
         set details(detailsRow : Array<PropertyLine>) {
-            this.clean();   
+            this.clean();
+            //add the searchBar
+            this._addSearchBarDetails();
+            this._details = Helpers.CreateDiv('details', this._div);
             this._detailRows = detailsRow;
-            
             // Refresh HTML
             this.update();
         }
-        protected _build() {            
+
+        protected _build() {
             this._div.className = 'insp-details';
             this._div.id = 'insp-details';
-            
             // Create header row
             this._createHeaderRow();
             this._div.appendChild(this._headerRow);
             
-        }
+        } 
         
         /** Updates the HTML of the detail panel */
-        public update() {                 
-            this._sortDetails('name', 1);  
-            this._addDetails();
+        public update(_items?: Array<PropertyLine>) {            
+            this._sortDetails('name', 1);
+            // Check the searchbar
+            if (_items) {
+                this.cleanRow();
+                this._addSearchDetails(_items);
+                //console.log(_items);
+            } else {
+                this._addDetails();
+                //console.log("np");
+            }
+        }
+
+         /** Add the search bar for the details */
+        private _addSearchBarDetails() {
+            let searchDetails = Helpers.CreateDiv('searchbar-details', this._div);
+            // Create search bar
+            this._searchDetails = new SearchBarDetails(this);
+
+            searchDetails.appendChild(this._searchDetails.toHtml());
+            this._div.appendChild(searchDetails);
+        }
+
+        /** Search an element by name  */
+        public searchByName(searchName: string) {
+            let rows = [];
+            for (let row of this._detailRows) {
+                if(row.name.indexOf(searchName) >= 0){
+                    rows.push(row);
+                }
+            }
+            this.update(rows);
         }
 
         /** Add all lines in the html div. Does not sort them! */
         private _addDetails() {
-            let details = Helpers.CreateDiv('details', this._div);
             for (let row of this._detailRows) {
-                details.appendChild(row.toHtml());
+                this._details.appendChild(row.toHtml());
             }
         }
 
+        private _addSearchDetails(_items: Array<PropertyLine>) {
+            for (let row of _items) {
+                this._details.appendChild(row.toHtml());
+            }   
+        }
+
         /**
          * Sort the details row by comparing the given property of each row
          */
@@ -108,18 +147,27 @@
         /**
          * Removes all data in the detail panel but keep the header row
          */
-        public clean() {   
-                        
+        public clean() {         
             // Delete all details row
             for (let pline of this._detailRows) {
                 pline.dispose();
             }
-            
             Helpers.CleanDiv(this._div);
             // Header row
             this._div.appendChild(this._headerRow);
         }
 
+        /**
+         * Clean the rows only
+         */
+        public cleanRow() {           
+            // Delete all details row
+            for (let pline of this._detailRows) {
+                pline.dispose();
+            }
+            Helpers.CleanDiv(this._details);
+        }
+
         /** Overrides basicelement.dispose */
         public dispose() {
             // Delete all details row
@@ -139,7 +187,7 @@
 
                 // Column title - first letter in uppercase
                 let spanName = Inspector.DOCUMENT.createElement('span');
-                spanName.textContent = name.charAt(0).toUpperCase() + name.slice(1); 
+                spanName.textContent = name.charAt(0).toUpperCase() + name.slice(1);
                 
                 // sort direction
                 let spanDirection = Inspector.DOCUMENT.createElement('i');

+ 84 - 3
inspector/src/details/PropertyLine.ts

@@ -223,6 +223,8 @@ module INSPECTOR {
             if (this._parent) {
                 this._property.obj = this._parent.updateObject();
             }
+            
+            
             return this._property.value;
         }
 
@@ -319,6 +321,60 @@ module INSPECTOR {
                 this._rangeInput();
             } else {
                 this._valueDiv.childNodes[0].nodeValue = this._displayValueContent();
+
+            //Doing the Hexa convertion
+            if((this._property.type == "Color3" && this._children.length == 5 && this._children[1].value == true) || (this._property.type == "Color4" && this._children.length == 6 && this._children[1].value == true)){
+                if(this._children[0] != undefined &&  this._children[0].name == "hex"){
+                    let hexLineString = this._children[0].value;
+                    let rValue = (parseInt((hexLineString.slice(1,3)), 16)) * (1/255);
+                    let rValueRound = Math.round(100*rValue)/100 ;
+                    this.value.r = rValueRound;
+                    let gValue = (parseInt((hexLineString.slice(3,5)), 16)) * (1/255);
+                    let gValueRound = Math.round(100*gValue)/100 ;
+                    this.value.g = gValueRound;
+                    let bValue = (parseInt((hexLineString.slice(5,7)), 16)) * (1/255);
+                    let bValueRound = Math.round(100*bValue)/100 ;
+                    this.value.b = bValueRound;
+                        if(this._children[2].name == "a"){
+                            let aValue = (parseInt((hexLineString.slice(7,9)), 16)) * (1/255);
+                            let aValueRound = Math.round(100*aValue)/100;
+                            this.value.a = aValueRound;
+                        }
+                    }
+            }else if(this._property.type == "Color3" || this._property.type == "Color4"){
+                if(this._property.value.hex != undefined && this._property.value.hex != null){
+                    let hexLineInfos = [];
+                    let valHexR = ((this._property.value.r * 255)|0).toString(16);
+                    hexLineInfos.push(valHexR);
+                    if(valHexR == "0"){
+                        hexLineInfos.push("0");
+                    }
+                    let valHexG = ((this._property.value.g * 255)|0).toString(16);
+                    hexLineInfos.push(valHexG);
+                    if(valHexG == "0"){
+                        hexLineInfos.push("0");
+                    }
+                    let valHexB = ((this._property.value.b * 255)|0).toString(16);
+                    hexLineInfos.push(valHexB);
+                    if(valHexB == "0"){
+                        hexLineInfos.push("0");
+                    }
+                    if(this._property.value.a != undefined){
+                        let valHexA = ((this._property.value.a * 255)|0).toString(16);
+                        hexLineInfos.push(valHexA);
+                        if(valHexA == "0"){
+                            hexLineInfos.push("0");
+                        }
+                    }
+                    hexLineInfos.unshift("#");
+                    let hexLineString = hexLineInfos.join("");
+                    this._property.value.hex = hexLineString; 
+                    hexLineInfos.length = 0;
+                }
+
+            }
+            
+
             }
             for (let elem of this._elements) {
                 elem.update(this.value);
@@ -386,22 +442,47 @@ module INSPECTOR {
                 // if children does not exists, generate it
                 this._div.classList.toggle('unfolded');
                 if (this._children.length == 0) {
+                    
                     let objToDetail = this.value;
+                    
                     // Display all properties that are not functions
                     let propToDisplay = Helpers.GetAllLinesPropertiesAsString(objToDetail);
-
                     // special case for color3
                     if ((propToDisplay.indexOf('r') && propToDisplay.indexOf('g') && propToDisplay.indexOf('b')) == 0) {
                         propToDisplay.sort();
                     } else {
                         propToDisplay.sort().reverse();
                     }
-
                     for (let prop of propToDisplay) {
                         let infos = new Property(prop, this._property.value);
-                        let child = new PropertyLine(infos, this, this._level + PropertyLine._MARGIN_LEFT);
+                        let child = new PropertyLine(infos, this, this._level + PropertyLine._MARGIN_LEFT);                   
                         this._children.push(child);
                     }
+                    //Add the Hexa converter
+                    if ((propToDisplay.indexOf('r') && propToDisplay.indexOf('g') && propToDisplay.indexOf('b') && propToDisplay.indexOf('a')) == 0){
+                        let hexLineInfos = [];
+                        let hexLinePropCheck = new Property("hexEnable", this._property.value);
+                        hexLinePropCheck.value = false;
+                        let hexLineCheck = new PropertyLine(hexLinePropCheck, this, this._level + PropertyLine._MARGIN_LEFT);
+                        this._children.unshift(hexLineCheck);
+                        for (let prop of propToDisplay) {
+                                let infos = new Property(prop, this._property.value);
+                                let  valHex = ((infos.value * 255)|0).toString(16);
+                                hexLineInfos.push(valHex);
+                                if(valHex == "0"){
+                                    hexLineInfos.push("0");
+                                }
+                        }
+                        hexLineInfos.push("#");
+                        hexLineInfos.reverse();
+                        let hexLineString = hexLineInfos.join("");
+                        
+                        let hexLineProp = new Property("hex", this._property.value);
+                        hexLineProp.value = hexLineString;
+                        let hexLine = new PropertyLine(hexLineProp, this, this._level + PropertyLine._MARGIN_LEFT);
+                   
+                        this._children.unshift(hexLine);
+                    } 
                 }
                 // otherwise display it    
                 if (this._div.parentNode) {

+ 39 - 3
inspector/src/gui/SearchBar.ts

@@ -6,12 +6,12 @@ module INSPECTOR {
      */
     export class SearchBar extends BasicElement {
 
-        private _tab   : PropertyTab;
+        private _propTab   : PropertyTab;
         private _inputElement: HTMLInputElement;
 
         constructor(tab:PropertyTab) {
             super();
-            this._tab = tab;
+            this._propTab = tab;
             this._div.classList.add('searchbar');
             
             let filter = Inspector.DOCUMENT.createElement('i');
@@ -25,7 +25,43 @@ module INSPECTOR {
             
             this._inputElement.addEventListener('keyup', (evt : KeyboardEvent)=> {
                 let filter = this._inputElement.value;
-                this._tab.filter(filter);
+                this._propTab.filter(filter);
+            })
+        }
+
+        /** Delete all characters typped in the input element */
+        public reset() {
+            this._inputElement.value = '';
+        }
+
+        public update() {
+            // Nothing to update
+        }
+
+    }
+
+    export class SearchBarDetails extends BasicElement {
+
+        private _detailTab  : DetailPanel;
+        private _inputElement: HTMLInputElement;
+
+        constructor(tab:DetailPanel) {
+            super();
+            this._detailTab = tab;
+            this._div.classList.add('searchbar');
+            
+            let filter = Inspector.DOCUMENT.createElement('i');
+            filter.className = 'fa fa-search';
+            
+            this._div.appendChild(filter);
+            // Create input
+            this._inputElement = Inspector.DOCUMENT.createElement('input');
+            this._inputElement.placeholder = 'Filter by name...';
+            this._div.appendChild(this._inputElement);
+            
+            this._inputElement.addEventListener('keyup', (evt : KeyboardEvent)=> {
+                let filter = this._inputElement.value;
+                this._detailTab.searchByName(filter);
             })
         }
 

+ 17 - 6
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -33,7 +33,10 @@ module BABYLON.GLTF2.Extensions {
 
                     if (indexLOD !== 0) {
                         this._loadingNodeLOD = nodeLOD;
-                        this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
+
+                        if (!this._loadNodeSignals[nodeLOD._index]) {
+                            this._loadNodeSignals[nodeLOD._index] = new Deferred<void>();
+                        }
                     }
 
                     const promise = this._loader._loadNodeAsync("#/nodes/" + nodeLOD._index, nodeLOD).then(() => {
@@ -44,8 +47,11 @@ module BABYLON.GLTF2.Extensions {
 
                         if (indexLOD !== nodeLODs.length - 1) {
                             const nodeIndex = nodeLODs[indexLOD + 1]._index;
-                            this._loadNodeSignals[nodeIndex].resolve();
-                            delete this._loadNodeSignals[nodeIndex];
+
+                            if (this._loadNodeSignals[nodeIndex]) {
+                                this._loadNodeSignals[nodeIndex].resolve();
+                                delete this._loadNodeSignals[nodeIndex];
+                            }
                         }
                     });
 
@@ -77,14 +83,19 @@ module BABYLON.GLTF2.Extensions {
 
                     if (indexLOD !== 0) {
                         this._loadingMaterialLOD = materialLOD;
-                        this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
+
+                        if (!this._loadMaterialSignals[materialLOD._index]) {
+                            this._loadMaterialSignals[materialLOD._index] = new Deferred<void>();
+                        }
                     }
 
                     const promise = this._loader._loadMaterialAsync("#/materials/" + materialLOD._index, materialLOD, babylonMesh).then(() => {
                         if (indexLOD !== materialLODs.length - 1) {
                             const materialIndex = materialLODs[indexLOD + 1]._index;
-                            this._loadMaterialSignals[materialIndex].resolve();
-                            delete this._loadMaterialSignals[materialIndex];
+                            if (this._loadMaterialSignals[materialIndex]) {
+                                this._loadMaterialSignals[materialIndex].resolve();
+                                delete this._loadMaterialSignals[materialIndex];
+                            }
                         }
                     });
 

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

@@ -706,8 +706,9 @@ module BABYLON.GLTF2 {
             };
 
             if (skin._loaded) {
-                assignSkeleton();
-                return skin._loaded;
+                return skin._loaded.then(() => {
+                    assignSkeleton();
+                });
             }
 
             // TODO: split into two parts so that bones are created before inverseBindMatricesData is loaded (for compiling materials).

+ 1 - 1
package.json

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

+ 10 - 1
sandbox/index.js

@@ -20,6 +20,7 @@ if (BABYLON.Engine.isSupported()) {
     var currentSkybox;
     var enableDebugLayer = false;
     var currentPluginName;
+    var skyboxPath = "Assets/environment.dds";
 
     canvas.addEventListener("contextmenu", function (evt) {
         evt.preventDefault();
@@ -98,7 +99,7 @@ if (BABYLON.Engine.isSupported()) {
 
         // Environment
         if (currentPluginName === "gltf") {
-            var hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData("Assets/environment.dds", currentScene);
+            var hdrTexture = BABYLON.CubeTexture.CreateFromPrefilteredData(skyboxPath, currentScene);
             currentSkybox = currentScene.createDefaultSkybox(hdrTexture, true, (currentScene.activeCamera.maxZ - currentScene.activeCamera.minZ) / 2, 0.3);
 
             // glTF assets use a +Z forward convention while the default camera faces +Z. Rotate the camera to look at the front of the asset.
@@ -147,6 +148,14 @@ if (BABYLON.Engine.isSupported()) {
     };
 
     filesInput = new BABYLON.FilesInput(engine, null, sceneLoaded, null, null, null, function () { BABYLON.Tools.ClearLogCache() }, null, sceneError);
+    filesInput.onProcessFileCallback = (function (file, name, extension) {
+        if (filesInput._filesToLoad && filesInput._filesToLoad.length === 1 && extension && extension.toLowerCase() === "dds") {
+            BABYLON.FilesInput.FilesToLoad[name] = file;
+            skyboxPath = "file:" + file.correctName;
+            return false;
+        }
+        return true;
+    }).bind(this);
     filesInput.monitorElementForDragNDrop(canvas);
 
     window.addEventListener("keydown", function (evt) {

+ 43 - 32
serializers/src/glTF/2.0/babylon.glTFExporter.ts

@@ -114,7 +114,7 @@ module BABYLON.GLTF2 {
             this.materials = new Array<IMaterial>();
             this.textures = new Array<ITexture>();
             this.imageData = {};
-            this.convertToRightHandedSystem = !this.babylonScene.useRightHandedSystem;
+            this.convertToRightHandedSystem = this.babylonScene.useRightHandedSystem ? false : true;
 
             if (options) {
                 this.options = options;
@@ -268,7 +268,6 @@ module BABYLON.GLTF2 {
                 }
                 else {
                     Tools.Warn("Unsupported Vertex Buffer Type: " + vertexBufferKind);
-                    
                 }
 
                 for (let i = 0; i < vector.length; ++i) {
@@ -498,11 +497,12 @@ module BABYLON.GLTF2 {
          * @param babylonMesh - Babylon mesh used as the source for the transformation data.
          */
         private setNodeTransformation(node: INode, babylonMesh: AbstractMesh): void {
-            if (!(babylonMesh.position.x === 0 && babylonMesh.position.y === 0 && babylonMesh.position.z === 0)) {
+            
+            if (!babylonMesh.position.equalsToFloats(0, 0, 0)) {
                 node.translation = this.convertToRightHandedSystem ? _Exporter.GetRightHandedVector3(babylonMesh.position).asArray() : babylonMesh.position.asArray();
             }
 
-            if (!(babylonMesh.scaling.x === 1 && babylonMesh.scaling.y === 1 && babylonMesh.scaling.z === 1)) {
+            if (!babylonMesh.scaling.equalsToFloats(1, 1, 1)) {
                 node.scale = babylonMesh.scaling.asArray();
             }
 
@@ -629,6 +629,7 @@ module BABYLON.GLTF2 {
                 }
 
                 if (babylonMesh.subMeshes) {
+                    let uvCoordsPresent = false;
                     // go through all mesh primitives (submeshes)
                     for (const submesh of babylonMesh.subMeshes) {
                         const meshPrimitive: IMeshPrimitive = { attributes: {} };
@@ -676,10 +677,12 @@ module BABYLON.GLTF2 {
                                                     }
                                                     case VertexBuffer.UVKind: {
                                                         meshPrimitive.attributes.TEXCOORD_0 = this.accessors.length - 1;
+                                                        uvCoordsPresent = true;
                                                         break;
                                                     }
                                                     case VertexBuffer.UV2Kind: {
                                                         meshPrimitive.attributes.TEXCOORD_1 = this.accessors.length - 1;
+                                                        uvCoordsPresent = true;
                                                         break;
                                                     }
                                                     default: {
@@ -697,13 +700,12 @@ module BABYLON.GLTF2 {
                                 this.accessors.push(accessor);
 
                                 meshPrimitive.indices = this.accessors.length - 1;
-
                             }
                         }
                         if (bufferMesh.material) {
-                            if (bufferMesh.material instanceof StandardMaterial || bufferMesh.material instanceof PBRMetallicRoughnessMaterial) {
-                                const materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
-                                meshPrimitive.material = materialIndex;
+                            let materialIndex: Nullable<number> = null;
+                            if (bufferMesh.material instanceof StandardMaterial || bufferMesh.material instanceof PBRMetallicRoughnessMaterial || bufferMesh.material instanceof PBRMaterial) {
+                                materialIndex = babylonMesh.getScene().materials.indexOf(bufferMesh.material);
                             }
                             else if (bufferMesh.material instanceof MultiMaterial) {
                                 const babylonMultiMaterial = bufferMesh.material as MultiMaterial;
@@ -711,16 +713,25 @@ module BABYLON.GLTF2 {
                                 const material = babylonMultiMaterial.subMaterials[submesh.materialIndex];
 
                                 if (material) {
-                                    const materialIndex = babylonMesh.getScene().materials.indexOf(material);
-                                    meshPrimitive.material = materialIndex;
+                                    materialIndex = babylonMesh.getScene().materials.indexOf(material);
                                 }
                             }
                             else {
                                 Tools.Warn("Material type " + bufferMesh.material.getClassName() + " for material " + bufferMesh.material.name + " is not yet implemented in glTF serializer.");
                             }
+                            if (materialIndex != null) {
+                                if (uvCoordsPresent || !_GLTFMaterial.HasTexturesPresent(this.materials[materialIndex])) {
+                                    meshPrimitive.material = materialIndex;
+                                }
+                                else {
+                                    // If no texture coordinate information is present, make a copy of the material without the textures to be glTF compliant.
+                                    const newMat = _GLTFMaterial.StripTexturesFromMaterial(this.materials[materialIndex]);
+                                    this.materials.push(newMat);
+                                    meshPrimitive.material = this.materials.length - 1;
+                                }
+                            }
                         }
                         mesh.primitives.push(meshPrimitive);
-
                     }
                 }
             }
@@ -749,32 +760,32 @@ module BABYLON.GLTF2 {
 
 
                 for (let i = 0; i < babylonMeshes.length; ++i) {
-                    if (this.options &&
-                        this.options.shouldExportMesh != undefined &&
-                        !this.options.shouldExportMesh(babylonMeshes[i])) {
-                        continue;
-                    }
-                    else {
-                        const babylonMesh = babylonMeshes[i];
-
-                        // Build Hierarchy with the node map.
-                        const glTFNodeIndex = this.nodeMap[babylonMesh.uniqueId];
-                        const glTFNode = this.nodes[glTFNodeIndex];
-                        if (!babylonMesh.parent) {
+                    const babylonMesh = babylonMeshes[i];
+
+                    // Build Hierarchy with the node map.
+                    const glTFNodeIndex = this.nodeMap[babylonMesh.uniqueId];
+                    const glTFNode = this.nodes[glTFNodeIndex];
+                    if (!babylonMesh.parent) {
+                        if (this.options &&
+                            this.options.shouldExportMesh != undefined &&
+                            !this.options.shouldExportMesh(babylonMesh)) {
+                            Tools.Log("Omitting " + babylonMesh.name + " from scene.");
+                        }
+                        else {
                             scene.nodes.push(glTFNodeIndex);
                         }
 
-                        const directDescendents = babylonMesh.getDescendants(true);
-                        if (!glTFNode.children && directDescendents && directDescendents.length) {
-                            glTFNode.children = [];
-                            for (let descendent of directDescendents) {
-                                glTFNode.children.push(this.nodeMap[descendent.uniqueId]);
-                            }
-                        }
+                    }
 
-                        const mesh = { primitives: new Array<IMeshPrimitive>() };
-                        byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
+                    const directDescendents = babylonMesh.getDescendants(true);
+                    if (!glTFNode.children && directDescendents && directDescendents.length) {
+                        glTFNode.children = [];
+                        for (let descendent of directDescendents) {
+                            glTFNode.children.push(this.nodeMap[descendent.uniqueId]);
+                        }
                     }
+                    const mesh = { primitives: new Array<IMeshPrimitive>() };
+                    byteOffset = this.setPrimitiveAttributes(mesh, babylonMesh, byteOffset, dataBuffer);
                 }
                 this.scenes.push(scene);
             }

+ 235 - 4
serializers/src/glTF/2.0/babylon.glTFMaterial.ts

@@ -15,6 +15,8 @@ module BABYLON.GLTF2 {
          */
         private static maxSpecularPower = 1024;
 
+        private static epsilon = 1e-6;
+
         /**
          * Gets the materials from a Babylon scene and converts them to glTF materials.
          * @param scene
@@ -34,7 +36,56 @@ module BABYLON.GLTF2 {
                 else if (babylonMaterial instanceof PBRMetallicRoughnessMaterial) {
                     _GLTFMaterial.ConvertPBRMetallicRoughnessMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
                 }
+                else if (babylonMaterial instanceof PBRMaterial) {
+                    _GLTFMaterial.ConvertPBRMaterial(babylonMaterial, mimeType, images, textures, materials, imageData, hasTextureCoords);
+                }
+                else {
+                    Tools.Error("Unsupported material type: " + babylonMaterial.name);
+                }
+            }
+        }
+
+        /**
+         * Makes a copy of the glTF material without the texture parameters.
+         * @param originalMaterial - original glTF material.
+         * @returns glTF material without texture parameters
+         */
+        public static StripTexturesFromMaterial(originalMaterial: IMaterial): IMaterial {
+            let newMaterial: IMaterial = {};
+            if (originalMaterial) {
+                newMaterial.name = originalMaterial.name;
+                newMaterial.doubleSided = originalMaterial.doubleSided;
+                newMaterial.alphaMode = originalMaterial.alphaMode;
+                newMaterial.alphaCutoff = originalMaterial.alphaCutoff;
+                newMaterial.emissiveFactor = originalMaterial.emissiveFactor;
+                const originalPBRMetallicRoughness = originalMaterial.pbrMetallicRoughness;
+                if (originalPBRMetallicRoughness) {
+                    newMaterial.pbrMetallicRoughness = {};
+                    newMaterial.pbrMetallicRoughness.baseColorFactor = originalPBRMetallicRoughness.baseColorFactor;
+                    newMaterial.pbrMetallicRoughness.metallicFactor = originalPBRMetallicRoughness.metallicFactor;
+                    newMaterial.pbrMetallicRoughness.roughnessFactor = originalPBRMetallicRoughness.roughnessFactor;
+                }
+            }
+            return newMaterial;
+        }
+
+        /**
+         * Specifies if the material has any texture parameters present.
+         * @param material - glTF Material.
+         * @returns boolean specifying if texture parameters are present
+         */
+        public static HasTexturesPresent(material: IMaterial): boolean {
+            if (material.emissiveTexture || material.normalTexture || material.occlusionTexture) {
+                return true;
+            }
+            const pbrMat = material.pbrMetallicRoughness;
+            if (pbrMat) {
+                if (pbrMat.baseColorTexture || pbrMat.metallicRoughnessTexture) {
+                    return true;
+                }
             }
+
+            return false;
         }
 
         /**
@@ -98,7 +149,6 @@ module BABYLON.GLTF2 {
             return glTFPbrMetallicRoughness;
         }
 
-
         /**
          * Computes the metallic factor
          * @param diffuse - diffused value
@@ -158,6 +208,28 @@ module BABYLON.GLTF2 {
                     }
                 }
             }
+            else if (babylonMaterial instanceof PBRMaterial) {
+                const babylonPBRMaterial = babylonMaterial as PBRMaterial;
+
+                switch (babylonPBRMaterial.transparencyMode) {
+                    case PBRMaterial.PBRMATERIAL_OPAQUE: {
+                        return MaterialAlphaMode.OPAQUE;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHABLEND: {
+                        return MaterialAlphaMode.BLEND;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHATEST: {
+                        return MaterialAlphaMode.MASK;
+                    }
+                    case PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND: {
+                        Tools.Warn(babylonMaterial.name + ": GLTF Exporter | Alpha test and blend mode not supported in glTF.  Alpha blend used instead.");
+                        return MaterialAlphaMode.BLEND;
+                    }
+                    default: {
+                        throw new Error("Unsupported alpha mode " + babylonPBRMaterial.transparencyMode);
+                    }
+                }
+            }
             else {
                 throw new Error("Unsupported Babylon material type");
             }
@@ -205,9 +277,13 @@ module BABYLON.GLTF2 {
                     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;
+                    const glTFTexture = _GLTFMaterial.ExportTexture(babylonStandardMaterial.ambientTexture, mimeType, images, textures, imageData);
+                    if (glTFTexture) {
+                        const occlusionTexture: IMaterialOcclusionTextureInfo = {
+                            index: glTFTexture.index
+                        };
+                        glTFMaterial.occlusionTexture = occlusionTexture;
+                        occlusionTexture.strength = 1.0;
                     }
                 }
             }
@@ -221,6 +297,9 @@ module BABYLON.GLTF2 {
                     Tools.Warn(babylonStandardMaterial.name + ": glTF 2.0 does not support alpha mode: " + babylonStandardMaterial.alphaMode.toString());
                 }
             }
+            if (babylonStandardMaterial.emissiveColor) {
+                glTFMaterial.emissiveFactor = babylonStandardMaterial.emissiveColor.asArray();
+            }
 
             glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
 
@@ -313,6 +392,158 @@ module BABYLON.GLTF2 {
         }
 
         /**
+         * See link below for info on the material conversions from PBR Metallic/Roughness and Specular/Glossiness
+         * @link https://github.com/KhronosGroup/glTF/blob/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/examples/convert-between-workflows-bjs/js/babylon.pbrUtilities.js
+         * @param color - Color source to calculate brightness from.
+         * @returns number representing the perceived brightness, or zero if color is undefined. 
+         */
+        public static GetPerceivedBrightness(color: Color3): number {
+            if (color) {
+                return Math.sqrt(0.299 * color.r * color.r + 0.587 * color.g * color.g + 0.114 * color.b * color.b);
+            }
+            return 0;
+        }
+
+        /**
+         * Returns the maximum color component value.
+         * @param color 
+         * @returns maximum color component value, or zero if color is null or undefined.
+         */
+        public static GetMaxComponent(color: Color3): number {
+            if (color) {
+                return Math.max(color.r, Math.max(color.g, color.b));
+            }
+            return 0;
+        }
+
+        /**
+         * Converts a Babylon PBR Metallic Roughness Material to a glTF Material.
+         * @param babylonPBRMaterial - 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 ConvertPBRMaterial(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, images: IImage[], textures: ITexture[], materials: IMaterial[], imageData: { [fileName: string]: { data: Uint8Array, mimeType: ImageMimeType } }, hasTextureCoords: boolean) {
+            const glTFPbrMetallicRoughness: IMaterialPbrMetallicRoughness = {};
+            const glTFMaterial: IMaterial = {
+                name: babylonPBRMaterial.name
+            };
+            const useMetallicRoughness = babylonPBRMaterial.isMetallicWorkflow();
+
+            if (babylonPBRMaterial) {
+                if (useMetallicRoughness) {
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        babylonPBRMaterial.albedoColor.r,
+                        babylonPBRMaterial.albedoColor.g,
+                        babylonPBRMaterial.albedoColor.b,
+                        babylonPBRMaterial.alpha
+                    ];
+                    if (babylonPBRMaterial.metallic != null) {
+                        if (babylonPBRMaterial.metallic !== 1) {
+                            glTFPbrMetallicRoughness.metallicFactor = babylonPBRMaterial.metallic;
+                        }
+                    }
+                    if (babylonPBRMaterial.roughness != null) {
+                        if (babylonPBRMaterial.roughness !== 1) {
+                            glTFPbrMetallicRoughness.roughnessFactor = babylonPBRMaterial.roughness;
+                        }
+                    }
+                }
+                else {
+                    const diffuseColor = babylonPBRMaterial.albedoColor || Color3.Black();
+                    const specularColor = babylonPBRMaterial.reflectionColor || Color3.Black();
+                    const diffusePerceivedBrightness = _GLTFMaterial.GetPerceivedBrightness(diffuseColor);
+                    const specularPerceivedBrightness = _GLTFMaterial.GetPerceivedBrightness(specularColor);
+                    const oneMinusSpecularStrength = 1 - _GLTFMaterial.GetMaxComponent(babylonPBRMaterial.reflectionColor);
+                    const metallic = _GLTFMaterial.SolveMetallic(diffusePerceivedBrightness, specularPerceivedBrightness, oneMinusSpecularStrength);
+                    const glossiness = babylonPBRMaterial.microSurface || 0;
+                    const baseColorFromDiffuse = diffuseColor.scale(oneMinusSpecularStrength / (1.0 - this.dielectricSpecular.r) / Math.max(1 - metallic, this.epsilon));
+                    const baseColorFromSpecular = specularColor.subtract(this.dielectricSpecular.scale(1 - metallic)).scale(1 / Math.max(metallic, this.epsilon));
+                    let baseColor = Color3.Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallic * metallic);
+                    baseColor = baseColor.clampToRef(0, 1, baseColor);
+
+                    glTFPbrMetallicRoughness.baseColorFactor = [
+                        baseColor.r,
+                        baseColor.g,
+                        baseColor.b,
+                        babylonPBRMaterial.alpha
+                    ];
+                    if (metallic !== 1) {
+                        glTFPbrMetallicRoughness.metallicFactor = metallic;
+                    }
+                    if (glossiness) {
+                        glTFPbrMetallicRoughness.roughnessFactor = 1 - glossiness;
+                    }
+                }
+                if (babylonPBRMaterial.backFaceCulling) {
+                    if (!babylonPBRMaterial.twoSidedLighting) {
+                        Tools.Warn(babylonPBRMaterial.name + ": Back-face culling enabled and two-sided lighting disabled is not supported in glTF.");
+                    }
+                    glTFMaterial.doubleSided = true;
+                }
+                if (hasTextureCoords) {
+                    if (babylonPBRMaterial.albedoTexture) {
+                        const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMaterial.bumpTexture) {
+                        const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.bumpTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFMaterial.normalTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMaterial.ambientTexture) {
+                        const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.ambientTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            let occlusionTexture: IMaterialOcclusionTextureInfo = {
+                                index: glTFTexture.index
+                            };
+
+                            glTFMaterial.occlusionTexture = occlusionTexture;
+
+                            if (babylonPBRMaterial.ambientTextureStrength) {
+                                occlusionTexture.strength = babylonPBRMaterial.ambientTextureStrength;
+                            }
+                        }
+                    }
+                    if (babylonPBRMaterial.emissiveTexture) {
+                        const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.emissiveTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFMaterial.emissiveTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMaterial.metallicTexture) {
+                        const glTFTexture = _GLTFMaterial.ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
+                        }
+                    }
+                }
+                if (!babylonPBRMaterial.emissiveColor.equalsFloats(0.0, 0.0, 0.0)) {
+                    glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();
+                }
+                if (babylonPBRMaterial.transparencyMode != null) {
+                    const alphaMode = _GLTFMaterial.GetAlphaMode(babylonPBRMaterial);
+
+                    if (alphaMode !== MaterialAlphaMode.OPAQUE) { //glTF defaults to opaque
+                        glTFMaterial.alphaMode = alphaMode;
+                        if (alphaMode === MaterialAlphaMode.BLEND) {
+                            glTFMaterial.alphaCutoff = babylonPBRMaterial.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.

+ 21 - 0
src/Animations/babylon.animationPropertiesOverride.ts

@@ -0,0 +1,21 @@
+module BABYLON {
+    /**
+     * Class used to override all child animations of a given target
+     */
+    export class AnimationPropertiesOverride {
+        /**
+         * Gets or sets a value indicating if animation blending must be used
+         */
+        public enableBlending = false;
+
+        /**
+         * Gets or sets the blending speed to use when enableBlending is true
+         */
+        public blendingSpeed = 0.01;
+
+        /**
+         * Gets or sets the default loop mode to use
+         */
+        public loopMode = Animation.ANIMATIONLOOPMODE_CYCLE;
+    }
+}

+ 16 - 5
src/Animations/babylon.runtimeAnimation.ts

@@ -197,7 +197,10 @@
             }
 
             // Blending
-            if (this._animation.enableBlending && this._blendingFactor <= 1.0) {
+            let enableBlending = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.enableBlending : this._animation.enableBlending;
+            let blendingSpeed = this._target && this._target.animationPropertiesOverride ? this._target.animationPropertiesOverride.blendingSpeed : this._animation.blendingSpeed;
+            
+            if (enableBlending && this._blendingFactor <= 1.0) {
                 if (!this._originalBlendValue) {
                     if (destination[path].clone) {
                         this._originalBlendValue = destination[path].clone();
@@ -219,7 +222,7 @@
                 } else { // Direct value
                     destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
-                this._blendingFactor += this._animation.blendingSpeed;
+                this._blendingFactor += blendingSpeed;
             } else {
                 destination[path] = currentValue;
             }
@@ -229,6 +232,14 @@
             }
         }
 
+        private _getCorrectLoopMode(): number | undefined {
+            if ( this._target && this._target.animationPropertiesOverride) {
+                return this._target.animationPropertiesOverride.loopMode;
+            }
+
+            return this._animation.loopMode;
+        }
+
         public goToFrame(frame: number): void {
             let keys = this._animation.getKeys();
 
@@ -238,7 +249,7 @@
                 frame = keys[keys.length - 1].frame;
             }
 
-            var currentValue = this._interpolate(frame, 0, this._animation.loopMode);
+            var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
 
             this.setValue(currentValue);
         }
@@ -301,7 +312,7 @@
             } else {
                 // Get max value if required
 
-                if (this._animation.loopMode !== Animation.ANIMATIONLOOPMODE_CYCLE) {
+                if (this._getCorrectLoopMode() !== Animation.ANIMATIONLOOPMODE_CYCLE) {
 
                     var keyOffset = to.toString() + from.toString();
                     if (!this._offsetsCache[keyOffset]) {
@@ -371,7 +382,7 @@
             // Compute value
             var repeatCount = (ratio / range) >> 0;
             var currentFrame = returnValue ? from + ratio % range : to;
-            var currentValue = this._interpolate(currentFrame, repeatCount, this._animation.loopMode, offsetValue, highLimitValue);
+            var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
             // Set value
             this.setValue(currentValue);

+ 7 - 0
src/Bones/babylon.bone.ts

@@ -147,6 +147,13 @@
         public set scaling(newScaling: Vector3) {
             this.setScale(newScaling.x, newScaling.y, newScaling.z);
         }
+        
+        /**
+         * Gets the animation properties override
+         */
+        public get animationPropertiesOverride(): AnimationPropertiesOverride {
+            return this._skeleton.animationPropertiesOverride;
+        }
 
         // Methods
         public updateMatrix(matrix: Matrix, updateDifferenceMatrix = true): void {

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

@@ -23,6 +23,11 @@
          */
         public doNotSerialize = false;        
 
+        /**
+         * Gets or sets the animation properties override
+         */
+        public animationPropertiesOverride: AnimationPropertiesOverride;        
+
         // Events
         /**
          * An event triggered before computing the skeleton's matrices

+ 45 - 24
src/Cameras/VR/babylon.vrExperienceHelper.ts

@@ -116,7 +116,17 @@ module BABYLON {
             this._laserPointer.rotation.x = Math.PI / 2;
             this._laserPointer.position.z = -0.5;
             this._laserPointer.isVisible = false;
-            this._laserPointer.parent = webVRController.mesh;
+
+            if(!webVRController.mesh){
+                // Create an empty mesh that is used prior to loading the high quality model
+                var preloadMesh = new Mesh("preloadControllerMesh", scene);
+                var preloadPointerPose = new Mesh(PoseEnabledController.POINTING_POSE, scene);
+                preloadPointerPose.rotation.x = -0.7;
+                preloadMesh.addChild(preloadPointerPose);
+                webVRController.attachToMesh(preloadMesh);
+            }
+
+            this._setLaserPointerParent(webVRController.mesh!);
         }
 
         _getForwardRay(length:number):Ray{
@@ -138,6 +148,22 @@ module BABYLON {
         }
 
         public _setLaserPointerParent(mesh:AbstractMesh){
+            var makeNotPick = (root: AbstractMesh) => {
+                root.name += " laserPointer";
+                root.getChildMeshes().forEach((c) => {
+                    makeNotPick(c);
+                });
+            }
+            makeNotPick(mesh);
+            var childMeshes = mesh.getChildMeshes();
+
+            for (var i = 0; i < childMeshes.length; i++) {
+                if (childMeshes[i].name && childMeshes[i].name.indexOf(PoseEnabledController.POINTING_POSE) >= 0) {
+                    mesh = childMeshes[i];
+                    this.webVRController._pointingPoseNode = mesh;
+                    break;
+                }
+            }
             this._laserPointer.parent = mesh;
         }
 
@@ -486,6 +512,11 @@ module BABYLON {
             }
             this._defaultHeight = webVROptions.defaultHeight;
 
+            if(webVROptions.positionScale){
+                this._rayLength *= webVROptions.positionScale;
+                this._defaultHeight *= webVROptions.positionScale;
+            }
+
             // Set position
             if (this._scene.activeCamera) {
                 this._position = this._scene.activeCamera.position.clone();
@@ -527,6 +558,8 @@ module BABYLON {
             }
             this._webVRCamera = new WebVRFreeCamera("WebVRHelper", this._position, this._scene, webVROptions);
             this._webVRCamera.useStandingMatrix()
+
+            this._cameraGazer = new VRExperienceHelperCameraGazer(()=>{return this.currentVRCamera;}, scene);
             // Create default button
             if (!this._useCustomVRButton) {
                 this._btnVR = <HTMLButtonElement>document.createElement("BUTTON");
@@ -624,17 +657,19 @@ module BABYLON {
             //create easing functions
             this._circleEase = new CircleEase();
             this._circleEase.setEasingMode(EasingFunction.EASINGMODE_EASEINOUT);
-
-            this._cameraGazer = new VRExperienceHelperCameraGazer(()=>{return this.currentVRCamera;}, scene)
         }
 
         // Raised when one of the controller has loaded successfully its associated default mesh
         private _onDefaultMeshLoaded(webVRController: WebVRController) {
             if(this.leftController && this.leftController.webVRController == webVRController){
-                this._tryEnableInteractionOnController(this.leftController);
+                if(webVRController.mesh){
+                    this.leftController._setLaserPointerParent(webVRController.mesh)
+                }
             }
             if(this.rightController && this.rightController.webVRController == webVRController){
-                this._tryEnableInteractionOnController(this.rightController);
+                if(webVRController.mesh){
+                    this.rightController._setLaserPointerParent(webVRController.mesh)
+                }
             }
             
             try {
@@ -973,6 +1008,7 @@ module BABYLON {
                 this._teleportationInitialized = true;
                 if (this._isDefaultTeleportationTarget) {
                     this._createTeleportationCircles();
+                    this._teleportationTarget.scaling.scaleInPlace(this._webVRCamera.deviceScaleFactor);
                 }
             }
         }
@@ -1052,22 +1088,7 @@ module BABYLON {
         private _enableInteractionOnController(controller: VRExperienceHelperControllerGazer) {
             var controllerMesh = controller.webVRController.mesh;
             if (controllerMesh) {
-                var makeNotPick = (root: AbstractMesh) => {
-                    root.name += " laserPointer";
-                    root.getChildMeshes().forEach((c) => {
-                        makeNotPick(c);
-                    });
-                }
-                makeNotPick(controllerMesh);
-                var childMeshes = controllerMesh.getChildMeshes();
-
-                for (var i = 0; i < childMeshes.length; i++) {
-                    if (childMeshes[i].name && childMeshes[i].name.indexOf("POINTING_POSE") >= 0) {
-                        controllerMesh = childMeshes[i];
-                        break;
-                    }
-                }
-                controller._setLaserPointerParent(controllerMesh);
+                
                 controller._interactionsEnabled = true;
                 controller._activatePointer();
                 controller.webVRController.onMainButtonStateChangedObservable.add((stateObject) => {
@@ -1429,7 +1450,7 @@ module BABYLON {
             }
             // Add height to account for user's height offset
             if (this.isInVRMode) {
-                this._workingVector.y += this.webVRCamera.deviceDistanceToRoomGround();
+                this._workingVector.y += this.webVRCamera.deviceDistanceToRoomGround() * this._webVRCamera.deviceScaleFactor;
             } else {
                 this._workingVector.y += this._defaultHeight;
             }
@@ -1673,7 +1694,7 @@ module BABYLON {
             if (this.isInVRMode) {
                 this.exitVR();
             }
-
+            
             if (this._postProcessMove) {
                 this._postProcessMove.dispose();
             }
@@ -1736,4 +1757,4 @@ module BABYLON {
             return "VRExperienceHelper";
         }
     }
-}
+}

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

@@ -109,12 +109,12 @@ module BABYLON {
         customVRButton?: HTMLButtonElement;
 
         /**
-         * To change the length of the ray for gaze/controllers. (default: 100)
+         * To change the length of the ray for gaze/controllers. Will be scaled by positionScale. (default: 100)
          */
         rayLength?: number;
 
         /**
-         * To change the default offset from the ground to account for user's height in meters. (default: 1.7)
+         * To change the default offset from the ground to account for user's height in meters. Will be scaled by positionScale. (default: 1.7)
          */
         defaultHeight?: number;
 
@@ -663,6 +663,7 @@ module BABYLON {
             this._onGamepadConnectedObserver = manager.onGamepadConnectedObservable.add((gamepad) => {
                 if (gamepad.type === Gamepad.POSE_ENABLED) {
                     let webVrController: WebVRController = <WebVRController>gamepad;
+                    webVrController.deviceScaleFactor = this.deviceScaleFactor;
                     webVrController._deviceToWorld.copyFrom(this._deviceToWorld);
                     if (this.webVROptions.controllerMeshes) {
                         if (webVrController.defaultModel) {
@@ -670,6 +671,7 @@ module BABYLON {
                         } else {
                             // Load the meshes
                             webVrController.initControllerMesh(this.getScene(), (loadedMesh) => {
+                                loadedMesh.scaling.scaleInPlace(this.deviceScaleFactor);
                                 this.onControllerMeshLoadedObservable.notifyObservers(webVrController);
                                 if (this.webVROptions.defaultLightingOnControllers) {
                                     if (!this._lightOnControllers) {

+ 3 - 3
src/Collisions/babylon.collisionCoordinator.ts

@@ -58,11 +58,11 @@ module BABYLON {
         positions: Float32Array;
         /**
          * Defines the array containing the indices
-         */        
+         */
         indices: Uint32Array;
         /**
          * Defines the array containing the normals
-         */        
+         */
         normals: Float32Array;
     }
 
@@ -173,7 +173,7 @@ module BABYLON {
                 let geometry = (<Mesh>mesh).geometry;
                 geometryId = geometry ? geometry.id : null;
             } else if (mesh instanceof InstancedMesh) {
-                let geometry = (<InstancedMesh>mesh).sourceMesh.geometry;
+                let geometry = (<InstancedMesh>mesh).sourceMesh && (<InstancedMesh>mesh).sourceMesh.geometry;
                 geometryId = geometry ? geometry.id : null;
             }
 

+ 6 - 3
src/Collisions/babylon.collisionWorker.ts

@@ -1,5 +1,8 @@
 declare function importScripts(...urls: string[]): void;
 
+// since typescript doesn't understand the file's execution context, we need to override postMessage's signature for error-free compilation
+const safePostMessage: any = self.postMessage;
+
 module BABYLON {
 
     //If this file is included in the main thread, this will be initialized.
@@ -192,7 +195,7 @@ module BABYLON {
                 error: WorkerReplyType.SUCCESS,
                 taskType: WorkerTaskType.INIT
             }
-            postMessage(reply, "");
+            safePostMessage(reply);
         }
 
         public onUpdate(payload: UpdatePayload) {
@@ -226,7 +229,7 @@ module BABYLON {
             }
 
 
-            postMessage(replay, "");
+            safePostMessage(replay);
         }
 
         public onCollision(payload: CollidePayload) {
@@ -247,7 +250,7 @@ module BABYLON {
                 taskType: WorkerTaskType.COLLIDE,
                 payload: replyPayload
             }
-            postMessage(reply, "");
+            safePostMessage(reply);
         }
     }
 

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

@@ -588,7 +588,7 @@
         }
 
         public static get Version(): string {
-            return "3.2.0-alpha10";
+            return "3.2.0-alphaA";
         }
 
         // Updatable statics so stick with vars here

+ 50 - 0
src/Gamepad/Controllers/babylon.daydreamController.ts

@@ -0,0 +1,50 @@
+module BABYLON {
+    /**
+     * Google Daydream controller
+     */
+    export class DaydreamController extends WebVRController {
+        /**
+         * Base Url for the controller model.
+         */
+        public static MODEL_BASE_URL: string = 'https://controllers.babylonjs.com/generic/';
+
+        /**
+         * File name for the controller model.
+         */
+        public static MODEL_FILENAME: string = 'generic.babylon';
+
+        /**
+         * Gamepad Id prefix used to identify Daydream Controller.
+         */
+        public static readonly GAMEPAD_ID_PREFIX: string = 'Daydream'; // id is 'Daydream Controller'
+
+        constructor(vrGamepad: any) {
+            super(vrGamepad);
+            this.controllerType = PoseEnabledControllerType.DAYDREAM;
+        }
+
+        public initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void) {
+            SceneLoader.ImportMesh("", DaydreamController.MODEL_BASE_URL, DaydreamController.MODEL_FILENAME, scene, (newMeshes) => {
+                this._defaultModel = newMeshes[1];
+                this.attachToMesh(this._defaultModel);
+
+                if (meshLoaded) {
+                    meshLoaded(this._defaultModel);
+                }
+            });
+        }
+
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+            // Daydream controller only has 1 GamepadButton (on the trackpad).
+            if (buttonIdx === 0) {
+                let observable = this.onTriggerStateChangedObservable;
+                if (observable) {
+                    observable.notifyObservers(state);
+                }
+            } else {
+                // If the app or home buttons are ever made available
+                Tools.Warn(`Unrecognized Daydream button index: ${buttonIdx}`)
+            }
+        }
+    }
+}

+ 1 - 1
src/Gamepad/Controllers/babylon.gearVRController.ts

@@ -26,7 +26,7 @@ module BABYLON {
             });
         }
 
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
             if (buttonIdx < this._buttonIndexToObservableNameMap.length) {
                 const observableName : string = this._buttonIndexToObservableNameMap[buttonIdx];
                 

+ 1 - 1
src/Gamepad/Controllers/babylon.genericController.ts

@@ -18,7 +18,7 @@ module BABYLON {
             });
         }
 
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
             console.log("Button id: " + buttonIdx + "state: ");
             console.dir(state);
         }

+ 1 - 1
src/Gamepad/Controllers/babylon.oculusTouchController.ts

@@ -87,7 +87,7 @@ module BABYLON {
          4) B / Y 
          5) thumb rest
         */
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
             let notifyObject = state; //{ state: state, changes: changes };
             let triggerDirection = this.hand === 'right' ? -1 : 1;
             switch (buttonIdx) {

+ 18 - 2
src/Gamepad/Controllers/babylon.poseEnabledController.ts

@@ -5,6 +5,10 @@ module BABYLON {
         OCULUS,
         WINDOWS,
         GEAR_VR,
+        /**
+         * Google Daydream
+         */
+        DAYDREAM,
         GENERIC
     }
 
@@ -38,6 +42,10 @@ module BABYLON {
             else if (vrGamepad.id.indexOf(GearVRController.GAMEPAD_ID_PREFIX) === 0) {
                 return new GearVRController(vrGamepad);
             }
+            // Google Daydream
+            else if (vrGamepad.id.indexOf(DaydreamController.GAMEPAD_ID_PREFIX) === 0) {
+                return new DaydreamController(vrGamepad);
+            }
             // Generic 
             else {
                 return new GenericController(vrGamepad);
@@ -72,6 +80,15 @@ module BABYLON {
 
         public _deviceToWorld = Matrix.Identity();
 
+        /**
+         * Node to be used when casting a ray from the controller
+         */
+        public _pointingPoseNode:Nullable<AbstractMesh> = null;
+        /**
+         * Name of the child mesh that can be used to cast a ray from the controller
+         */
+        public static readonly POINTING_POSE = "POINTING_POSE";
+
         constructor(browserGamepad: any) {
             super(browserGamepad.id, browserGamepad.index, browserGamepad);
             this.type = Gamepad.POSE_ENABLED;
@@ -115,7 +132,6 @@ module BABYLON {
 
                     this._deviceRoomPosition.scaleToRef(this.deviceScaleFactor, this._calculatedPosition);
                     this._calculatedPosition.addInPlace(this.position);
-
                 }
                 let pose = this.rawPose;
                 if (poseData.orientation && pose.orientation) {
@@ -174,7 +190,7 @@ module BABYLON {
                 return new Ray(Vector3.Zero(), new Vector3(0, 0, 1), length);
             }
 
-            var m = this.mesh.getWorldMatrix();
+            var m = this._pointingPoseNode ? this._pointingPoseNode.getWorldMatrix() : this.mesh.getWorldMatrix();
             var origin = m.getTranslation();
 
             var forward = new Vector3(0, 0, -1);

+ 1 - 1
src/Gamepad/Controllers/babylon.viveController.ts

@@ -50,7 +50,7 @@ module BABYLON {
          * 2: left AND right buttons
          * 3: menu button
          */
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
             let notifyObject = state; //{ state: state, changes: changes };
             switch (buttonIdx) {
                 case 0:

+ 2 - 2
src/Gamepad/Controllers/babylon.webVRController.ts

@@ -45,7 +45,7 @@ module BABYLON {
             }
         }
 
-        protected abstract handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges): void;
+        protected abstract _handleButtonChange(buttonIdx: number, value: ExtendedGamepadButton, changes: GamepadButtonChanges): void;
 
         public abstract initControllerMesh(scene: Scene, meshLoaded?: (mesh: AbstractMesh) => void): void;
 
@@ -69,7 +69,7 @@ module BABYLON {
             if (this._changes.changed) {
                 this._onButtonStateChange && this._onButtonStateChange(this.index, buttonIndex, newState);
 
-                this.handleButtonChange(buttonIndex, newState, this._changes);
+                this._handleButtonChange(buttonIndex, newState, this._changes);
             }
             this._buttons[buttonIndex].pressed = newState.pressed;
             this._buttons[buttonIndex].touched = newState.touched;

+ 10 - 11
src/Gamepad/Controllers/babylon.windowsMotionController.ts

@@ -62,7 +62,7 @@ module BABYLON {
                 'TOUCHPAD_TOUCH_X',
                 'TOUCHPAD_TOUCH_Y'
             ],
-            pointingPoseMeshName: 'POINTING_POSE'
+            pointingPoseMeshName: PoseEnabledController.POINTING_POSE
         };
 
         public onTrackpadChangedObservable = new Observable<ExtendedGamepadButton>();
@@ -104,15 +104,14 @@ module BABYLON {
          */
         public update() {
             super.update();
-
-            // Only need to animate axes if there is a loaded mesh
-            if (this._loadedMeshInfo) {
-                if (this.browserGamepad.axes) {
-                    if (this.browserGamepad.axes[2] != this.trackpad.x || this.browserGamepad.axes[3] != this.trackpad.y) {
-                        this.trackpad.x = this.browserGamepad["axes"][2];
-                        this.trackpad.y = this.browserGamepad["axes"][3];
-                        this.onTrackpadValuesChangedObservable.notifyObservers(this.trackpad);
-                    }
+            if (this.browserGamepad.axes) {
+                if (this.browserGamepad.axes[2] != this.trackpad.x || this.browserGamepad.axes[3] != this.trackpad.y) {
+                    this.trackpad.x = this.browserGamepad["axes"][2];
+                    this.trackpad.y = this.browserGamepad["axes"][3];
+                    this.onTrackpadValuesChangedObservable.notifyObservers(this.trackpad);
+                }
+                // Only need to animate axes if there is a loaded mesh
+                if (this._loadedMeshInfo) {
                     for (let axis = 0; axis < this._mapping.axisMeshNames.length; axis++) {
                         this.lerpAxisTransform(axis, this.browserGamepad.axes[axis]);
                     }
@@ -126,7 +125,7 @@ module BABYLON {
          * @param state New state of the button
          * @param changes Which properties on the state changed since last frame
          */
-        protected handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
+        protected _handleButtonChange(buttonIdx: number, state: ExtendedGamepadButton, changes: GamepadButtonChanges) {
             let buttonName = this._mapping.buttons[buttonIdx];
             if (!buttonName) {
                 return;

+ 14 - 15
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -477,11 +477,6 @@
         protected _forceNormalForward = false;
 
         /**
-         * Force metallic workflow.
-         */
-        protected _forceMetallicWorkflow = false;
-
-        /**
          * Default configuration related to image processing available in the PBR Material.
          */
         @serializeAsImageProcessingConfiguration()
@@ -822,6 +817,18 @@
             return true;
         }
 
+        /** 
+         * Specifies if the material uses metallic roughness workflow.
+         * @returns boolean specifiying if the material uses metallic roughness workflow.
+        */
+        public isMetallicWorkflow(): boolean {
+            if (this._metallic != null || this._roughness != null || this._metallicTexture) {
+                return true;
+            }
+
+            return false;
+        }
+
         private _prepareEffect(mesh: AbstractMesh, defines: PBRMaterialDefines, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, useInstances: Nullable<boolean> = null, useClipPlane: Nullable<boolean> = null): Nullable<Effect> {
             this._prepareDefines(mesh, defines, useInstances, useClipPlane);
             if (!defines.isDirty) {
@@ -989,7 +996,8 @@
             defines._needNormals = true;
 
             // Textures
-            if (defines._areTexturesDirty) {
+            defines.METALLICWORKFLOW = this.isMetallicWorkflow();
+            if (defines._areTexturesDirty) {     
                 defines._needUVs = false;
                 if (scene.texturesEnabled) {
                     if (scene.getEngine().getCaps().textureLOD) {
@@ -1109,19 +1117,16 @@
                     if (StandardMaterial.SpecularTextureEnabled) {
                         if (this._metallicTexture) {
                             MaterialHelper.PrepareDefinesForMergedUV(this._metallicTexture, defines, "REFLECTIVITY");
-                            defines.METALLICWORKFLOW = true;
                             defines.ROUGHNESSSTOREINMETALMAPALPHA = this._useRoughnessFromMetallicTextureAlpha;
                             defines.ROUGHNESSSTOREINMETALMAPGREEN = !this._useRoughnessFromMetallicTextureAlpha && this._useRoughnessFromMetallicTextureGreen;
                             defines.METALLNESSSTOREINMETALMAPBLUE = this._useMetallnessFromMetallicTextureBlue;
                             defines.AOSTOREINMETALMAPRED = this._useAmbientOcclusionFromMetallicTextureRed;
                         }
                         else if (this._reflectivityTexture) {
-                            defines.METALLICWORKFLOW = false;
                             MaterialHelper.PrepareDefinesForMergedUV(this._reflectivityTexture, defines, "REFLECTIVITY");
                             defines.MICROSURFACEFROMREFLECTIVITYMAP = this._useMicroSurfaceFromReflectivityMapAlpha;
                             defines.MICROSURFACEAUTOMATIC = this._useAutoMicroSurfaceFromReflectivityMap;
                         } else {
-                            defines.METALLICWORKFLOW = false;
                             defines.REFLECTIVITY = false;
                         }
 
@@ -1185,12 +1190,6 @@
 
                 defines.RADIANCEOVERALPHA = this._useRadianceOverAlpha;
 
-                if (this._forceMetallicWorkflow || (this._metallic !== undefined && this._metallic !== null) || (this._roughness !== undefined && this._roughness !== null)) {
-                    defines.METALLICWORKFLOW = true;
-                } else {
-                    defines.METALLICWORKFLOW = false;
-                }
-
                 if (!this.backFaceCulling && this._twoSidedLighting) {
                     defines.TWOSIDEDLIGHTING = true;
                 } else {

+ 2 - 1
src/Materials/PBR/babylon.pbrMetallicRoughnessMaterial.ts

@@ -60,7 +60,8 @@
             this._useRoughnessFromMetallicTextureAlpha = false;
             this._useRoughnessFromMetallicTextureGreen = true;
             this._useMetallnessFromMetallicTextureBlue = true;
-            this._forceMetallicWorkflow = true;
+            this.metallic = 1.0;
+            this.roughness = 1.0;
         }
 
         /**

+ 56 - 29
src/Materials/Textures/babylon.videoTexture.ts

@@ -232,46 +232,73 @@
                 };
             }
 
-            navigator.getUserMedia =
-                navigator.getUserMedia ||
-                navigator.webkitGetUserMedia ||
-                navigator.mozGetUserMedia ||
-                navigator.msGetUserMedia;
             window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
 
-            if (navigator.getUserMedia) {
-                navigator.getUserMedia(
-                    {
-                        video: {
-                            deviceId: constraintsDeviceId,
-                            width: {
-                                min: (constraints && constraints.minWidth) || 256,
-                                max: (constraints && constraints.maxWidth) || 640,
-                            },
-                            height: {
-                                min: (constraints && constraints.minHeight) || 256,
-                                max: (constraints && constraints.maxHeight) || 480,
-                            },
-                        },
-                    },
-                    (stream: any) => {
+            if (navigator.mediaDevices) {
+                navigator.mediaDevices.getUserMedia({ video: constraints })
+                    .then(function(stream) {
                         if (video.mozSrcObject !== undefined) {
                             // hack for Firefox < 19
                             video.mozSrcObject = stream;
                         } else {
-                            video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
+                            video.srcObject = stream;
                         }
 
+                        let onPlaying = () => {
+                            if (onReady) {
+                                onReady(new VideoTexture("video", video, scene, true, true));
+                            }
+                            video.removeEventListener("playing", onPlaying);
+                        };
+
+                        video.addEventListener("playing", onPlaying);
                         video.play();
+                    })
+                    .catch(function(err) {
+                        Tools.Error(err.name);
+                    });
+            }
+            else {
+                navigator.getUserMedia =
+                    navigator.getUserMedia ||
+                    navigator.webkitGetUserMedia ||
+                    navigator.mozGetUserMedia ||
+                    navigator.msGetUserMedia;
 
-                        if (onReady) {
-                            onReady(new VideoTexture("video", video, scene, true, true));
+                if (navigator.getUserMedia) {
+                    navigator.getUserMedia(
+                        {
+                            video: {
+                                deviceId: constraintsDeviceId,
+                                width: {
+                                    min: (constraints && constraints.minWidth) || 256,
+                                    max: (constraints && constraints.maxWidth) || 640,
+                                },
+                                height: {
+                                    min: (constraints && constraints.minHeight) || 256,
+                                    max: (constraints && constraints.maxHeight) || 480,
+                                },
+                            },
+                        },
+                        (stream: any) => {
+                            if (video.mozSrcObject !== undefined) {
+                                // hack for Firefox < 19
+                                video.mozSrcObject = stream;
+                            } else {
+                                video.src = (window.URL && window.URL.createObjectURL(stream)) || stream;
+                            }
+
+                            video.play();
+
+                            if (onReady) {
+                                onReady(new VideoTexture("video", video, scene, true, true));
+                            }
+                        },
+                        function(e: MediaStreamError) {
+                            Tools.Error(e.name);
                         }
-                    },
-                    function(e: MediaStreamError) {
-                        Tools.Error(e.name);
-                    }
-                );
+                    );
+                }
             }
         }
     }

+ 99 - 3
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -7,6 +7,10 @@
         private _scene: Scene;
 
         /**
+		 * ID of the sharpen post process,
+		 */
+        readonly SharpenPostProcessId: string = "SharpenPostProcessEffect";
+        /**
 		 * ID of the pass post process used for bloom,
 		 */
         readonly PassPostProcessId: string = "PassPostProcessEffect";
@@ -38,9 +42,17 @@
 		 * ID of the final merge post process;
 		 */
         readonly FinalMergePostProcessId: string = "FinalMergePostProcessEffect";
+        /**
+		 * ID of the chromatic aberration post process,
+		 */
+        readonly ChromaticAberrationPostProcessId: string = "ChromaticAberrationPostProcessEffect";
 
         // Post-processes
         /**
+		 * Sharpen post process which will apply a sharpen convolution to enhance edges
+		 */
+        public sharpen: SharpenPostProcess;
+        /**
 		 * First pass of bloom to capture the original image texture for later use.
 		 */
         public pass: PassPostProcess;
@@ -76,24 +88,49 @@
          * Final post process to merge results of all previous passes
          */
         public finalMerge: PassPostProcess;
+        /**
+		 * Chromatic aberration post process which will shift rgb colors in the image
+		 */
+        public chromaticAberration: ChromaticAberrationPostProcess;
 
         /**
          * Animations which can be used to tweak settings over a period of time
          */
         public animations: Animation[] = [];
 
-        // Values       
+        // Values   
+        private _sharpenEnabled:boolean = false;    
         private _bloomEnabled: boolean = false;
         private _depthOfFieldEnabled: boolean = false;
         private _depthOfFieldBlurLevel = DepthOfFieldEffectBlurLevel.Low;
         private _fxaaEnabled: boolean = false;
+        private _msaaEnabled: boolean = false;
         private _imageProcessingEnabled: boolean = true;
         private _defaultPipelineTextureType: number;
         private _bloomScale: number = 0.6;
+        private _chromaticAberrationEnabled:boolean = false;  
 
         private _buildAllowed = true;
 
         /**
+         * Enable or disable the sharpen process from the pipeline
+         */
+        public set sharpenEnabled(enabled: boolean) {
+            if (this._sharpenEnabled === enabled) {
+                return;
+            }
+            this._sharpenEnabled = enabled;
+
+            this._buildPipeline();
+        }
+
+        @serialize()
+        public get sharpenEnabled(): boolean {
+            return this._sharpenEnabled;
+        }
+
+
+        /**
 		 * Specifies the size of the bloom blur kernel, relative to the final output size
 		 */
         @serialize()
@@ -212,6 +249,23 @@
         }
 
         /**
+         * If the multisample anti-aliasing is enabled.
+         */
+        public set msaaEnabled(enabled: boolean) {
+            if (this._msaaEnabled === enabled) {
+                return;
+            }
+            this._msaaEnabled = enabled;
+
+            this._buildPipeline();
+        }
+
+        @serialize()
+        public get msaaEnabled(): boolean {
+            return this._msaaEnabled;
+        }
+
+        /**
          * If image processing is enabled.
          */
         public set imageProcessingEnabled(enabled: boolean) {
@@ -229,6 +283,23 @@
         }
 
         /**
+         * Enable or disable the chromaticAberration process from the pipeline
+         */
+        public set chromaticAberrationEnabled(enabled: boolean) {
+            if (this._chromaticAberrationEnabled === enabled) {
+                return;
+            }
+            this._chromaticAberrationEnabled = enabled;
+
+            this._buildPipeline();
+        }
+
+        @serialize()
+        public get chromaticAberrationEnabled(): boolean {
+            return this._chromaticAberrationEnabled;
+        }
+
+        /**
          * @constructor
          * @param {string} name - The rendering pipeline name
          * @param {BABYLON.Scene} scene - The scene linked to this pipeline
@@ -285,6 +356,11 @@
             this._disposePostProcesses();
             this._reset();
 
+            if (this.sharpenEnabled) {
+                this.sharpen = new SharpenPostProcess("sharpen", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
+                this.addEffect(new PostProcessRenderEffect(engine, this.SharpenPostProcessId, () => { return this.sharpen; }, true));
+            }
+
             if(this.depthOfFieldEnabled){
                 // Enable and get current depth map
                 var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
@@ -379,17 +455,31 @@
                 }
             }
 
+            if (this.chromaticAberrationEnabled) {
+                this.chromaticAberration = new ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
+                this.addEffect(new PostProcessRenderEffect(engine, this.ChromaticAberrationPostProcessId, () => { return this.chromaticAberration; }, true));
+            }
+
+
             if (this._cameras !== null) {
                 this._scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(this._name, this._cameras);
             }
-
-            this._enableMSAAOnFirstPostProcess();
+            
+            if(this.msaaEnabled){
+                if(!this._enableMSAAOnFirstPostProcess()){
+                    BABYLON.Tools.Warn("MSAA failed to enable, MSAA is only supported in browsers that support webGL >= 2.0");
+                }
+            }
         }
 
         private _disposePostProcesses(): void {
             for (var i = 0; i < this._cameras.length; i++) {
                 var camera = this._cameras[i];
 
+                if (this.sharpen) {
+                    this.sharpen.dispose(camera);
+                }
+
                 if (this.pass) {
                     this.pass.dispose(camera);
                 }
@@ -425,8 +515,13 @@
                 if(this.depthOfField){
                     this.depthOfField.disposeEffects(camera);
                 }
+
+                if(this.chromaticAberration){
+                    this.chromaticAberration.dispose(camera);
+                }
             }
 
+            (<any>this.sharpen) = null;
             (<any>this.pass) = null;
             (<any>this.highlights) = null;
             (<any>this.blurX) = null;
@@ -436,6 +531,7 @@
             (<any>this.fxaa) = null;
             (<any>this.finalMerge) = null;
             (<any>this.depthOfField) = null;
+            (<any>this.chromaticAberration) = null;
         }
 
         /**

+ 4 - 1
src/PostProcess/RenderPipeline/Pipelines/babylon.lensRenderingPipeline.ts

@@ -180,7 +180,7 @@ module BABYLON {
         // colors shifting and distortion
         private _createChromaticAberrationPostProcess(ratio: number): void {
             this._chromaticAberrationPostProcess = new PostProcess("LensChromaticAberration", "chromaticAberration",
-                ["chromatic_aberration", "screen_width", "screen_height"],      // uniforms
+                ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"],      // uniforms
                 [],                                         // samplers
                 ratio, null, Texture.TRILINEAR_SAMPLINGMODE,
                 this._scene.getEngine(), false);
@@ -189,6 +189,9 @@ module BABYLON {
                 effect.setFloat('chromatic_aberration', this._chromaticAberration);
                 effect.setFloat('screen_width', this._scene.getEngine().getRenderWidth());
                 effect.setFloat('screen_height', this._scene.getEngine().getRenderHeight());
+                effect.setFloat('radialIntensity', 1);
+                effect.setFloat2('direction', 17, 17);
+                effect.setFloat2('centerPosition', 0.5,0.5);
             };
         }
 

+ 50 - 0
src/PostProcess/babylon.chromaticAberrationPostProcess.ts

@@ -0,0 +1,50 @@
+module BABYLON {
+    /**
+     * The ChromaticAberrationPostProcess separates the rgb channels in an image to produce chromatic distortion around the edges of the screen
+     */
+    export class ChromaticAberrationPostProcess extends PostProcess {
+        /**
+         * The amount of seperation of rgb channels (default: 0)
+         */
+        aberrationAmount = 0;
+
+        /**
+         * The amount the effect will increase for pixels closer to the edge of the screen. (default: 0)
+         */
+        radialIntensity = 0;
+
+        /**
+         * The normilized direction in which the rgb channels should be seperated. If set to 0,0 radial direction will be used. (default: Vector2(0.707,0.707))
+         */
+        direction = new Vector2(0.707,0.707);
+
+        /**
+         * The center position where the radialIntensity should be around. [0.5,0.5 is center of screen, 1,1 is top right corder] (default: Vector2(0.5 ,0.5))
+         */
+        centerPosition = new Vector2(0.5,0.5);
+        
+        /**
+         * Creates a new instance of @see ChromaticAberrationPostProcess
+         * @param name The name of the effect.
+         * @param screenWidth The width of the screen to apply the effect on.
+         * @param screenHeight The height of the screen to apply the effect on.
+         * @param options The required width/height ratio to downsize to before computing the render pass.
+         * @param camera The camera to apply the render pass to.
+         * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
+         * @param engine The engine which the post process will be applied. (default: current engine)
+         * @param reusable If the post process can be reused on the same frame. (default: false)
+         * @param textureType Type of textures used when performing the post process. (default: 0)
+         */
+        constructor(name: string, screenWidth:number, screenHeight:number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "chromaticAberration", ["chromatic_aberration", "screen_width", "screen_height", "direction", "radialIntensity", "centerPosition"], [], options, camera, samplingMode, engine, reusable, null, textureType);
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setFloat('chromatic_aberration', this.aberrationAmount);
+                effect.setFloat('screen_width', screenWidth);
+                effect.setFloat('screen_height', screenHeight);
+                effect.setFloat('radialIntensity', this.radialIntensity);
+                effect.setFloat2('direction', this.direction.x,this.direction.y);
+                effect.setFloat2('centerPosition', this.centerPosition.x,this.centerPosition.y);
+            })
+        }
+    }
+}

+ 0 - 0
src/PostProcess/babylon.convolutionPostProcess.ts


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