Forráskód Böngészése

Merge remote-tracking branch 'BabylonJS/master' into oimo-1.0.9

# Conflicts:
#	dist/preview release/what's new.md
Raanan Weber 7 éve
szülő
commit
2d254537d2
98 módosított fájl, 977073 hozzáadás és 32026 törlés
  1. 7839 7561
      Playground/babylon.d.txt
  2. 9162 0
      Playground/scenes/BrainStem/BrainStem.gltf
  3. BIN
      Playground/scenes/BrainStem/BrainStem0.bin
  4. BIN
      Playground/scenes/MultiPrimitive/MultiPrimitive.bin
  5. 134 0
      Playground/scenes/MultiPrimitive/MultiPrimitive.gltf
  6. 930590 0
      Playground/scenes/dummy.babylon
  7. 7834 7555
      dist/preview release/babylon.d.ts
  8. 58 56
      dist/preview release/babylon.js
  9. 860 232
      dist/preview release/babylon.max.js
  10. 59 57
      dist/preview release/babylon.worker.js
  11. 14824 14545
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  12. 58 57
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  13. 877 243
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  14. 877 243
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  15. 860 232
      dist/preview release/es6.js
  16. 1 1
      dist/preview release/gltf2Interface/package.json
  17. 3 3
      dist/preview release/gui/babylon.gui.min.js
  18. 1 1
      dist/preview release/gui/package.json
  19. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  20. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  21. 1 1
      dist/preview release/inspector/package.json
  22. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  23. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  24. 17 11
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  25. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  26. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  27. 17 11
      dist/preview release/loaders/babylon.glTFFileLoader.js
  28. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  29. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  30. 17 11
      dist/preview release/loaders/babylonjs.loaders.js
  31. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  32. 1 1
      dist/preview release/loaders/babylonjs.loaders.module.d.ts
  33. 2 2
      dist/preview release/loaders/package.json
  34. 22 13
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  35. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  36. 8 0
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  37. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js
  38. 8 0
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  39. 1 1
      dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js
  40. 8 0
      dist/preview release/materialsLibrary/babylon.normalMaterial.js
  41. 1 1
      dist/preview release/materialsLibrary/babylon.normalMaterial.min.js
  42. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  43. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  44. 46 13
      dist/preview release/materialsLibrary/babylonjs.materials.js
  45. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  46. 1 1
      dist/preview release/materialsLibrary/package.json
  47. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  48. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  49. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  50. 1 1
      dist/preview release/postProcessesLibrary/package.json
  51. 1 1
      dist/preview release/proceduralTexturesLibrary/package.json
  52. 24 0
      dist/preview release/serializers/babylon.glTF2Serializer.d.ts
  53. 88 52
      dist/preview release/serializers/babylon.glTF2Serializer.js
  54. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  55. 88 52
      dist/preview release/serializers/babylonjs.serializers.js
  56. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  57. 24 0
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  58. 2 2
      dist/preview release/serializers/package.json
  59. 2 170
      dist/preview release/typedocValidationBaseline.json
  60. 73 71
      dist/preview release/viewer/babylon.viewer.js
  61. 877 243
      dist/preview release/viewer/babylon.viewer.max.js
  62. 1 1
      dist/preview release/viewer/package.json
  63. 16 10
      dist/preview release/what's new.md
  64. 18 13
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  65. 8 0
      materialsLibrary/src/gradient/babylon.gradientMaterial.ts
  66. 8 0
      materialsLibrary/src/lava/babylon.lavaMaterial.ts
  67. 8 0
      materialsLibrary/src/normal/babylon.normalMaterial.ts
  68. 1 1
      package.json
  69. 24 2
      src/Animations/babylon.animatable.ts
  70. 111 22
      src/Animations/babylon.runtimeAnimation.ts
  71. 67 16
      src/Engine/babylon.engine.ts
  72. 266 52
      src/Lights/Shadows/babylon.shadowGenerator.ts
  73. 1 1
      src/Lights/babylon.directionalLight.ts
  74. 2 0
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  75. 2 5
      src/Materials/Textures/babylon.internalTexture.ts
  76. 22 0
      src/Materials/Textures/babylon.renderTargetTexture.ts
  77. 11 1
      src/Materials/babylon.effect.ts
  78. 14 0
      src/Materials/babylon.materialHelper.ts
  79. 229 72
      src/Math/babylon.math.ts
  80. 2 2
      src/Mesh/babylon.meshBuilder.ts
  81. 96 84
      src/Shaders/ShadersInclude/lightFragment.fx
  82. 8 1
      src/Shaders/ShadersInclude/lightFragmentDeclaration.fx
  83. 9 2
      src/Shaders/ShadersInclude/lightUboDeclaration.fx
  84. 522 214
      src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx
  85. 1 1
      src/Shaders/ShadersInclude/shadowsVertex.fx
  86. 5 1
      src/Shaders/pbr.fragment.fx
  87. 12 12
      src/Shaders/shadowMap.fragment.fx
  88. 47 8
      src/Shaders/shadowMap.vertex.fx
  89. 1 1
      src/babylon.node.ts
  90. 125 27
      src/babylon.scene.ts
  91. 36 0
      tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts
  92. BIN
      tests/validation/ReferenceImages/instances.png
  93. BIN
      tests/validation/ReferenceImages/pbrglossy.png
  94. BIN
      tests/validation/ReferenceImages/pbrrough.png
  95. BIN
      tests/validation/ReferenceImages/procedural.png
  96. BIN
      tests/validation/ReferenceImages/selfShadowing.png
  97. BIN
      tests/validation/ReferenceImages/softShadows.png
  98. 1 1
      tests/validation/config.json

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7839 - 7561
Playground/babylon.d.txt


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 9162 - 0
Playground/scenes/BrainStem/BrainStem.gltf


BIN
Playground/scenes/BrainStem/BrainStem0.bin


BIN
Playground/scenes/MultiPrimitive/MultiPrimitive.bin


+ 134 - 0
Playground/scenes/MultiPrimitive/MultiPrimitive.gltf

@@ -0,0 +1,134 @@
+{
+  "accessors": [
+    {
+      "bufferView": 0,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 1,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 2,
+      "componentType": 5125,
+      "count": 3,
+      "type": "SCALAR"
+    },
+    {
+      "bufferView": 3,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC3",
+      "max": [
+        0.5,
+        0.5,
+        0.0
+      ],
+      "min": [
+        -0.5,
+        -0.5,
+        0.0
+      ]
+    },
+    {
+      "bufferView": 4,
+      "componentType": 5126,
+      "count": 3,
+      "type": "VEC2"
+    },
+    {
+      "bufferView": 5,
+      "componentType": 5125,
+      "count": 3,
+      "type": "SCALAR"
+    }
+  ],
+  "asset": {
+    "version": "2.0"
+  },
+  "buffers": [
+    {
+      "uri": "MultiPrimitive.bin",
+      "byteLength": 144
+    }
+  ],
+  "bufferViews": [
+    {
+      "buffer": 0,
+      "byteLength": 36
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 36,
+      "byteLength": 24
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 60,
+      "byteLength": 12
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 72,
+      "byteLength": 36
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 108,
+      "byteLength": 24
+    },
+    {
+      "buffer": 0,
+      "byteOffset": 132,
+      "byteLength": 12
+    }
+  ],
+  "meshes": [
+    {
+      "primitives": [
+        {
+          "attributes": {
+            "POSITION": 0,
+            "TEXCOORD_0": 1
+          },
+          "indices": 2
+        },
+        {
+          "attributes": {
+            "POSITION": 3,
+            "TEXCOORD_0": 4
+          },
+          "indices": 5
+        }
+      ]
+    }
+  ],
+  "nodes": [
+    {
+      "name": "node",
+      "mesh": 0
+    }
+  ],
+  "scene": 0,
+  "scenes": [
+    {
+      "nodes": [
+        0
+      ]
+    }
+  ]
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 930590 - 0
Playground/scenes/dummy.babylon


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 7834 - 7555
dist/preview release/babylon.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 58 - 56
dist/preview release/babylon.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 860 - 232
dist/preview release/babylon.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 59 - 57
dist/preview release/babylon.worker.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 14824 - 14545
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 58 - 57
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 877 - 243
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 877 - 243
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 860 - 232
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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -321,7 +321,7 @@ declare module BABYLON.GLTF2 {
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
-        private _forEachNodeMesh(node, callback);
+        private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();

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

@@ -757,16 +757,16 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._forEachNodeMesh = function (node, callback) {
-                if (node._babylonMesh) {
-                    callback(node._babylonMesh);
-                }
+            GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
                 if (node._primitiveBabylonMeshes) {
                     for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
                         var babylonMesh = _a[_i];
                         callback(babylonMesh);
                     }
                 }
+                else {
+                    callback(node._babylonMesh);
+                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -776,9 +776,15 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
                         var node = nodes_2[_i];
-                        this._forEachNodeMesh(node, function (mesh) {
-                            meshes.push(mesh);
-                        });
+                        if (node._babylonMesh) {
+                            meshes.push(node._babylonMesh);
+                        }
+                        if (node._primitiveBabylonMeshes) {
+                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
+                                var babylonMesh = _b[_a];
+                                meshes.push(babylonMesh);
+                            }
+                        }
                     }
                 }
                 return meshes;
@@ -870,7 +876,7 @@ var BABYLON;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(babylonMesh);
+                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
                         this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
@@ -880,7 +886,7 @@ var BABYLON;
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
                 return Promise.all(promises).then(function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
                     });
                 });
@@ -1104,7 +1110,7 @@ var BABYLON;
             GLTFLoader.prototype._loadSkinAsync = function (context, node, mesh, skin) {
                 var _this = this;
                 var assignSkeleton = function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
                     node._babylonMesh.parent = _this._rootBabylonMesh;
@@ -1325,7 +1331,7 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            _this._forEachNodeMesh(targetNode, function (babylonMesh) {
+                            _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
                                 babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                             });

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -877,7 +877,7 @@ declare module BABYLON.GLTF2 {
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
-        private _forEachNodeMesh(node, callback);
+        private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();

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

@@ -2934,16 +2934,16 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._forEachNodeMesh = function (node, callback) {
-                if (node._babylonMesh) {
-                    callback(node._babylonMesh);
-                }
+            GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
                 if (node._primitiveBabylonMeshes) {
                     for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
                         var babylonMesh = _a[_i];
                         callback(babylonMesh);
                     }
                 }
+                else {
+                    callback(node._babylonMesh);
+                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -2953,9 +2953,15 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
                         var node = nodes_2[_i];
-                        this._forEachNodeMesh(node, function (mesh) {
-                            meshes.push(mesh);
-                        });
+                        if (node._babylonMesh) {
+                            meshes.push(node._babylonMesh);
+                        }
+                        if (node._primitiveBabylonMeshes) {
+                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
+                                var babylonMesh = _b[_a];
+                                meshes.push(babylonMesh);
+                            }
+                        }
                     }
                 }
                 return meshes;
@@ -3047,7 +3053,7 @@ var BABYLON;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(babylonMesh);
+                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
                         this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
@@ -3057,7 +3063,7 @@ var BABYLON;
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
                 return Promise.all(promises).then(function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
                     });
                 });
@@ -3281,7 +3287,7 @@ var BABYLON;
             GLTFLoader.prototype._loadSkinAsync = function (context, node, mesh, skin) {
                 var _this = this;
                 var assignSkeleton = function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
                     node._babylonMesh.parent = _this._rootBabylonMesh;
@@ -3502,7 +3508,7 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            _this._forEachNodeMesh(targetNode, function (babylonMesh) {
+                            _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
                                 babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                             });

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


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

@@ -3912,16 +3912,16 @@ var BABYLON;
                 promises.push(this._loadAnimationsAsync());
                 return Promise.all(promises).then(function () { });
             };
-            GLTFLoader.prototype._forEachNodeMesh = function (node, callback) {
-                if (node._babylonMesh) {
-                    callback(node._babylonMesh);
-                }
+            GLTFLoader.prototype._forEachPrimitive = function (node, callback) {
                 if (node._primitiveBabylonMeshes) {
                     for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
                         var babylonMesh = _a[_i];
                         callback(babylonMesh);
                     }
                 }
+                else {
+                    callback(node._babylonMesh);
+                }
             };
             GLTFLoader.prototype._getMeshes = function () {
                 var meshes = new Array();
@@ -3931,9 +3931,15 @@ var BABYLON;
                 if (nodes) {
                     for (var _i = 0, nodes_2 = nodes; _i < nodes_2.length; _i++) {
                         var node = nodes_2[_i];
-                        this._forEachNodeMesh(node, function (mesh) {
-                            meshes.push(mesh);
-                        });
+                        if (node._babylonMesh) {
+                            meshes.push(node._babylonMesh);
+                        }
+                        if (node._primitiveBabylonMeshes) {
+                            for (var _a = 0, _b = node._primitiveBabylonMeshes; _a < _b.length; _a++) {
+                                var babylonMesh = _b[_a];
+                                meshes.push(babylonMesh);
+                            }
+                        }
                     }
                 }
                 return meshes;
@@ -4025,7 +4031,7 @@ var BABYLON;
                     for (var _i = 0, primitives_1 = primitives; _i < primitives_1.length; _i++) {
                         var primitive = primitives_1[_i];
                         var primitiveBabylonMesh = new BABYLON.Mesh((mesh.name || babylonMesh.name) + "_" + primitive._index, this._babylonScene, babylonMesh);
-                        node._primitiveBabylonMeshes.push(babylonMesh);
+                        node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                         promises.push(this._loadPrimitiveAsync(context + "/primitives/" + primitive._index, node, mesh, primitive, primitiveBabylonMesh));
                         this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                     }
@@ -4035,7 +4041,7 @@ var BABYLON;
                     promises.push(this._loadSkinAsync("#/skins/" + skin._index, node, mesh, skin));
                 }
                 return Promise.all(promises).then(function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh._refreshBoundingInfo(true);
                     });
                 });
@@ -4259,7 +4265,7 @@ var BABYLON;
             GLTFLoader.prototype._loadSkinAsync = function (context, node, mesh, skin) {
                 var _this = this;
                 var assignSkeleton = function () {
-                    _this._forEachNodeMesh(node, function (babylonMesh) {
+                    _this._forEachPrimitive(node, function (babylonMesh) {
                         babylonMesh.skeleton = skin._babylonSkeleton;
                     });
                     node._babylonMesh.parent = _this._rootBabylonMesh;
@@ -4480,7 +4486,7 @@ var BABYLON;
                                 value: key.value[targetIndex],
                                 outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                             }); }));
-                            _this._forEachNodeMesh(targetNode, function (babylonMesh) {
+                            _this._forEachPrimitive(targetNode, function (babylonMesh) {
                                 var morphTarget = babylonMesh.morphTargetManager.getTarget(targetIndex);
                                 babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                             });

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -979,7 +979,7 @@ declare module BABYLON.GLTF2 {
         private _createRootNode();
         private _loadNodesAsync(nodes);
         _loadSceneAsync(context: string, scene: ILoaderScene): Promise<void>;
-        private _forEachNodeMesh(node, callback);
+        private _forEachPrimitive(node, callback);
         private _getMeshes();
         private _getSkeletons();
         private _startAnimations();

+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "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-alphaB"
+        "babylonjs-gltf2interface": "3.2.0-alphaC"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

+ 22 - 13
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -11,7 +11,6 @@ var __extends = (this && this.__extends) || (function () {
 })();
 var BABYLON;
 (function (BABYLON) {
-    // old version of standard material updated every 3 months
     var CustomShaderStructure = /** @class */ (function () {
         function CustomShaderStructure() {
         }
@@ -37,40 +36,51 @@ var BABYLON;
         CustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
             for (var el in this._newUniformInstances) {
                 var ea = el.toString().split('-');
-                if (ea[0] == 'vec2')
+                if (ea[0] == 'vec2') {
                     effect.setVector2(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'vec3')
+                }
+                else if (ea[0] == 'vec3') {
                     effect.setVector3(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'vec4')
+                }
+                else if (ea[0] == 'vec4') {
                     effect.setVector4(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'mat4')
+                }
+                else if (ea[0] == 'mat4') {
                     effect.setMatrix(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'float')
+                }
+                else if (ea[0] == 'float') {
                     effect.setFloat(ea[1], this._newUniformInstances[el]);
+                }
             }
             for (var el in this._newSamplerInstances) {
                 var ea = el.toString().split('-');
-                if (ea[0] == 'sampler2D' && this._newSamplerInstances[el].isReady && this._newSamplerInstances[el].isReady())
+                if (ea[0] == 'sampler2D' && this._newSamplerInstances[el].isReady && this._newSamplerInstances[el].isReady()) {
                     effect.setTexture(ea[1], this._newSamplerInstances[el]);
+                }
             }
         };
         CustomMaterial.prototype.ReviewUniform = function (name, arr) {
             if (name == "uniform") {
-                for (var ind in this._newUniforms)
-                    if (this._customUniform[ind].indexOf('sampler') == -1)
+                for (var ind in this._newUniforms) {
+                    if (this._customUniform[ind].indexOf('sampler') == -1) {
                         arr.push(this._newUniforms[ind]);
+                    }
+                }
             }
             if (name == "sampler") {
-                for (var ind in this._newUniforms)
-                    if (this._customUniform[ind].indexOf('sampler') != -1)
+                for (var ind in this._newUniforms) {
+                    if (this._customUniform[ind].indexOf('sampler') != -1) {
                         arr.push(this._newUniforms[ind]);
+                    }
+                }
             }
             return arr;
         };
         CustomMaterial.prototype.Builder = function (shaderName, uniforms, uniformBuffers, samplers, defines) {
             var _this = this;
-            if (this._isCreatedShader)
+            if (this._isCreatedShader) {
                 return this._createdShaderName;
+            }
             this._isCreatedShader = false;
             CustomMaterial.ShaderIndexer++;
             var name = "custom_" + CustomMaterial.ShaderIndexer;
@@ -86,7 +96,6 @@ var BABYLON;
                     fn_afterBind(m, e);
                 }
                 catch (e) { }
-                ;
             };
             BABYLON.Effect.ShadersStore[name + "VertexShader"] = this.VertexShader
                 .replace('#define CUSTOM_VERTEX_BEGIN', (this.CustomParts.Vertex_Begin ? this.CustomParts.Vertex_Begin : ""))

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 8 - 0
dist/preview release/materialsLibrary/babylon.gradientMaterial.js

@@ -56,10 +56,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js


+ 8 - 0
dist/preview release/materialsLibrary/babylon.lavaMaterial.js

@@ -56,10 +56,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js


+ 8 - 0
dist/preview release/materialsLibrary/babylon.normalMaterial.js

@@ -56,10 +56,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.normalMaterial.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


+ 46 - 13
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -274,10 +274,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;
@@ -552,10 +560,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;
@@ -857,10 +873,18 @@ var BABYLON;
             _this.SHADOWESM1 = false;
             _this.SHADOWESM2 = false;
             _this.SHADOWESM3 = false;
+            _this.SHADOWPOISSON0 = false;
+            _this.SHADOWPOISSON1 = false;
+            _this.SHADOWPOISSON2 = false;
+            _this.SHADOWPOISSON3 = false;
             _this.SHADOWPCF0 = false;
             _this.SHADOWPCF1 = false;
             _this.SHADOWPCF2 = false;
             _this.SHADOWPCF3 = false;
+            _this.SHADOWPCSS0 = false;
+            _this.SHADOWPCSS1 = false;
+            _this.SHADOWPCSS2 = false;
+            _this.SHADOWPCSS3 = false;
             _this.NORMAL = false;
             _this.UV1 = false;
             _this.UV2 = false;
@@ -4023,7 +4047,6 @@ BABYLON.Effect.ShadersStore['gridPixelShader'] = "#extension GL_OES_standard_der
 
 var BABYLON;
 (function (BABYLON) {
-    // old version of standard material updated every 3 months
     var CustomShaderStructure = /** @class */ (function () {
         function CustomShaderStructure() {
         }
@@ -4049,40 +4072,51 @@ var BABYLON;
         CustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
             for (var el in this._newUniformInstances) {
                 var ea = el.toString().split('-');
-                if (ea[0] == 'vec2')
+                if (ea[0] == 'vec2') {
                     effect.setVector2(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'vec3')
+                }
+                else if (ea[0] == 'vec3') {
                     effect.setVector3(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'vec4')
+                }
+                else if (ea[0] == 'vec4') {
                     effect.setVector4(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'mat4')
+                }
+                else if (ea[0] == 'mat4') {
                     effect.setMatrix(ea[1], this._newUniformInstances[el]);
-                else if (ea[0] == 'float')
+                }
+                else if (ea[0] == 'float') {
                     effect.setFloat(ea[1], this._newUniformInstances[el]);
+                }
             }
             for (var el in this._newSamplerInstances) {
                 var ea = el.toString().split('-');
-                if (ea[0] == 'sampler2D' && this._newSamplerInstances[el].isReady && this._newSamplerInstances[el].isReady())
+                if (ea[0] == 'sampler2D' && this._newSamplerInstances[el].isReady && this._newSamplerInstances[el].isReady()) {
                     effect.setTexture(ea[1], this._newSamplerInstances[el]);
+                }
             }
         };
         CustomMaterial.prototype.ReviewUniform = function (name, arr) {
             if (name == "uniform") {
-                for (var ind in this._newUniforms)
-                    if (this._customUniform[ind].indexOf('sampler') == -1)
+                for (var ind in this._newUniforms) {
+                    if (this._customUniform[ind].indexOf('sampler') == -1) {
                         arr.push(this._newUniforms[ind]);
+                    }
+                }
             }
             if (name == "sampler") {
-                for (var ind in this._newUniforms)
-                    if (this._customUniform[ind].indexOf('sampler') != -1)
+                for (var ind in this._newUniforms) {
+                    if (this._customUniform[ind].indexOf('sampler') != -1) {
                         arr.push(this._newUniforms[ind]);
+                    }
+                }
             }
             return arr;
         };
         CustomMaterial.prototype.Builder = function (shaderName, uniforms, uniformBuffers, samplers, defines) {
             var _this = this;
-            if (this._isCreatedShader)
+            if (this._isCreatedShader) {
                 return this._createdShaderName;
+            }
             this._isCreatedShader = false;
             CustomMaterial.ShaderIndexer++;
             var name = "custom_" + CustomMaterial.ShaderIndexer;
@@ -4098,7 +4132,6 @@ var BABYLON;
                     fn_afterBind(m, e);
                 }
                 catch (e) { }
-                ;
             };
             BABYLON.Effect.ShadersStore[name + "VertexShader"] = this.VertexShader
                 .replace('#define CUSTOM_VERTEX_BEGIN', (this.CustomParts.Vertex_Begin ? this.CustomParts.Vertex_Begin : ""))

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 3 - 3
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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 24 - 0
dist/preview release/serializers/babylon.glTF2Serializer.d.ts

@@ -441,6 +441,30 @@ declare module BABYLON.GLTF2 {
          */
         private static _GetMaxComponent(color);
         /**
+         * Convert a PBRMaterial (Metallic/Roughness) to Metallic Roughness factors.
+         * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+         * @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.
+         * @returns - glTF PBR Metallic Roughness factors.
+         */
+        private static _ConvertMetalRoughFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
+        /**
+         * Convert a PBRMaterial (Specular/Glossiness) to Metallic Roughness factors.
+         * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+         * @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.
+         * @returns - glTF PBR Metallic Roughness factors.
+         */
+        private static _ConvertSpecGlossFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
+        /**
          * 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.

+ 88 - 52
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -1271,8 +1271,8 @@ var BABYLON;
                 for (var h = 0; h < height; ++h) {
                     for (var w = 0; w < width; ++w) {
                         var offset = (width * h + w) * strideSize;
-                        var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).multiply(factors.diffuseColor);
-                        var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).multiply(factors.specularColor);
+                        var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                        var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
                         var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
                         var specularGlossiness = {
                             diffuseColor: diffuseColor,
@@ -1289,7 +1289,7 @@ var BABYLON;
                         baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
                         baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
                         baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                        metallicRoughnessBuffer[offset] = 255;
+                        metallicRoughnessBuffer[offset] = 0;
                         metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
                         metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
                         metallicRoughnessBuffer[offset + 3] = 255;
@@ -1309,13 +1309,17 @@ var BABYLON;
                         baseColorBuffer[destinationOffset] /= metallicRoughnessFactors.baseColor.r > this._epsilon ? metallicRoughnessFactors.baseColor.r : 1;
                         baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors.baseColor.g > this._epsilon ? metallicRoughnessFactors.baseColor.g : 1;
                         baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors.baseColor.b > this._epsilon ? metallicRoughnessFactors.baseColor.b : 1;
-                        var baseColorPixel = new BABYLON.Color3(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                        if (!this.FuzzyEquals(baseColorPixel, BABYLON.Color3.White(), this._epsilon)) {
+                        var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                        var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                        baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                        baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                        baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                        if (!this.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), this._epsilon)) {
                             writeOutBaseColorTexture = true;
                         }
                         metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors.roughness > this._epsilon ? metallicRoughnessFactors.roughness : 1;
                         metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors.metallic > this._epsilon ? metallicRoughnessFactors.metallic : 1;
-                        var metallicRoughnessPixel = new BABYLON.Color3(metallicRoughnessBuffer[destinationOffset], metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                        var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
                         if (!this.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), this._epsilon)) {
                             writeOutMetallicRoughnessTexture = true;
                         }
@@ -1375,6 +1379,81 @@ var BABYLON;
                 return 0;
             };
             /**
+             * Convert a PBRMaterial (Metallic/Roughness) to Metallic Roughness factors.
+             * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+             * @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.
+             * @returns - glTF PBR Metallic Roughness factors.
+             */
+            _GLTFMaterial._ConvertMetalRoughFactorsToMetallicRoughness = function (babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords) {
+                var metallicRoughness = {
+                    baseColor: babylonPBRMaterial.albedoColor,
+                    metallic: babylonPBRMaterial.metallic,
+                    roughness: babylonPBRMaterial.roughness
+                };
+                if (hasTextureCoords) {
+                    if (babylonPBRMaterial.albedoTexture) {
+                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMaterial.metallicTexture) {
+                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
+                        }
+                    }
+                }
+                return metallicRoughness;
+            };
+            /**
+             * Convert a PBRMaterial (Specular/Glossiness) to Metallic Roughness factors.
+             * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+             * @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.
+             * @returns - glTF PBR Metallic Roughness factors.
+             */
+            _GLTFMaterial._ConvertSpecGlossFactorsToMetallicRoughness = function (babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords) {
+                var specGloss = {
+                    diffuseColor: babylonPBRMaterial.albedoColor || BABYLON.Color3.White(),
+                    specularColor: babylonPBRMaterial.reflectivityColor || BABYLON.Color3.White(),
+                    glossiness: babylonPBRMaterial.microSurface || 1,
+                };
+                if (babylonPBRMaterial.reflectivityTexture && !babylonPBRMaterial.useMicroSurfaceFromReflectivityMapAlpha) {
+                    throw new Error("_ConvertPBRMaterial: Glossiness values not included in the reflectivity texture currently not supported");
+                }
+                var metallicRoughnessFactors = this._ConvertSpecularGlossinessTexturesToMetallicRoughness(babylonPBRMaterial.albedoTexture, babylonPBRMaterial.reflectivityTexture, specGloss, mimeType);
+                if (!metallicRoughnessFactors) {
+                    metallicRoughnessFactors = this._ConvertSpecularGlossinessToMetallicRoughness(specGloss);
+                }
+                else {
+                    if (hasTextureCoords) {
+                        if (metallicRoughnessFactors.baseColorTextureBase64) {
+                            var glTFBaseColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughnessFactors.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
+                            if (glTFBaseColorTexture != null) {
+                                glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
+                            }
+                        }
+                        if (metallicRoughnessFactors.metallicRoughnessTextureBase64) {
+                            var glTFMRColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughnessFactors.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
+                            if (glTFMRColorTexture != null) {
+                                glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
+                            }
+                        }
+                    }
+                }
+                return metallicRoughnessFactors;
+            };
+            /**
              * 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.
@@ -1391,42 +1470,11 @@ var BABYLON;
                     name: babylonPBRMaterial.name
                 };
                 var useMetallicRoughness = babylonPBRMaterial.isMetallicWorkflow();
-                if (!useMetallicRoughness) {
-                    var specGloss = {
-                        diffuseColor: babylonPBRMaterial.albedoColor || BABYLON.Color3.White(),
-                        specularColor: babylonPBRMaterial.reflectivityColor || BABYLON.Color3.White(),
-                        glossiness: babylonPBRMaterial.microSurface || 1,
-                    };
-                    if (babylonPBRMaterial.reflectivityTexture && !babylonPBRMaterial.useMicroSurfaceFromReflectivityMapAlpha) {
-                        throw new Error("_ConvertPBRMaterial: Glossiness values not included in the reflectivity texture currently not supported");
-                    }
-                    metallicRoughness = this._ConvertSpecularGlossinessTexturesToMetallicRoughness(babylonPBRMaterial.albedoTexture, babylonPBRMaterial.reflectivityTexture, specGloss, mimeType);
-                    if (!metallicRoughness) {
-                        metallicRoughness = this._ConvertSpecularGlossinessToMetallicRoughness(specGloss);
-                    }
-                    else {
-                        if (hasTextureCoords) {
-                            if (metallicRoughness.baseColorTextureBase64) {
-                                var glTFBaseColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughness.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
-                                if (glTFBaseColorTexture != null) {
-                                    glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
-                                }
-                            }
-                            if (metallicRoughness.metallicRoughnessTextureBase64) {
-                                var glTFMRColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughness.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
-                                if (glTFMRColorTexture != null) {
-                                    glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
-                                }
-                            }
-                        }
-                    }
+                if (useMetallicRoughness) {
+                    metallicRoughness = this._ConvertMetalRoughFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
                 }
                 else {
-                    metallicRoughness = {
-                        baseColor: babylonPBRMaterial.albedoColor,
-                        metallic: babylonPBRMaterial.metallic,
-                        roughness: babylonPBRMaterial.roughness
-                    };
+                    metallicRoughness = this._ConvertSpecGlossFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
                 }
                 if (!(this.FuzzyEquals(metallicRoughness.baseColor, BABYLON.Color3.White(), this._epsilon) && babylonPBRMaterial.alpha >= this._epsilon)) {
                     glTFPbrMetallicRoughness.baseColorFactor = [
@@ -1449,12 +1497,6 @@ var BABYLON;
                     glTFMaterial.doubleSided = true;
                 }
                 if (hasTextureCoords) {
-                    if (useMetallicRoughness && babylonPBRMaterial.albedoTexture) {
-                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
-                        if (glTFTexture) {
-                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                        }
-                    }
                     if (babylonPBRMaterial.bumpTexture) {
                         var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.bumpTexture, mimeType, images, textures, imageData);
                         if (glTFTexture) {
@@ -1479,12 +1521,6 @@ var BABYLON;
                             glTFMaterial.emissiveTexture = glTFTexture;
                         }
                     }
-                    if (babylonPBRMaterial.metallicTexture) {
-                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
-                        if (glTFTexture != null) {
-                            glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
-                        }
-                    }
                 }
                 if (!this.FuzzyEquals(babylonPBRMaterial.emissiveColor, BABYLON.Color3.Black(), this._epsilon)) {
                     glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


+ 88 - 52
dist/preview release/serializers/babylonjs.serializers.js

@@ -1425,8 +1425,8 @@ var BABYLON;
                 for (var h = 0; h < height; ++h) {
                     for (var w = 0; w < width; ++w) {
                         var offset = (width * h + w) * strideSize;
-                        var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).multiply(factors.diffuseColor);
-                        var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).multiply(factors.specularColor);
+                        var diffuseColor = BABYLON.Color3.FromInts(diffuseBuffer[offset], diffuseBuffer[offset + 1], diffuseBuffer[offset + 2]).toLinearSpace().multiply(factors.diffuseColor);
+                        var specularColor = BABYLON.Color3.FromInts(specularGlossinessBuffer[offset], specularGlossinessBuffer[offset + 1], specularGlossinessBuffer[offset + 2]).toLinearSpace().multiply(factors.specularColor);
                         var glossiness = (specularGlossinessBuffer[offset + 3] / 255) * factors.glossiness;
                         var specularGlossiness = {
                             diffuseColor: diffuseColor,
@@ -1443,7 +1443,7 @@ var BABYLON;
                         baseColorBuffer[offset + 1] = metallicRoughness.baseColor.g * 255;
                         baseColorBuffer[offset + 2] = metallicRoughness.baseColor.b * 255;
                         baseColorBuffer[offset + 3] = resizedTextures.texture1.hasAlpha ? diffuseBuffer[offset + 3] : 255;
-                        metallicRoughnessBuffer[offset] = 255;
+                        metallicRoughnessBuffer[offset] = 0;
                         metallicRoughnessBuffer[offset + 1] = metallicRoughness.roughness * 255;
                         metallicRoughnessBuffer[offset + 2] = metallicRoughness.metallic * 255;
                         metallicRoughnessBuffer[offset + 3] = 255;
@@ -1463,13 +1463,17 @@ var BABYLON;
                         baseColorBuffer[destinationOffset] /= metallicRoughnessFactors.baseColor.r > this._epsilon ? metallicRoughnessFactors.baseColor.r : 1;
                         baseColorBuffer[destinationOffset + 1] /= metallicRoughnessFactors.baseColor.g > this._epsilon ? metallicRoughnessFactors.baseColor.g : 1;
                         baseColorBuffer[destinationOffset + 2] /= metallicRoughnessFactors.baseColor.b > this._epsilon ? metallicRoughnessFactors.baseColor.b : 1;
-                        var baseColorPixel = new BABYLON.Color3(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
-                        if (!this.FuzzyEquals(baseColorPixel, BABYLON.Color3.White(), this._epsilon)) {
+                        var linearBaseColorPixel = BABYLON.Color3.FromInts(baseColorBuffer[destinationOffset], baseColorBuffer[destinationOffset + 1], baseColorBuffer[destinationOffset + 2]);
+                        var sRGBBaseColorPixel = linearBaseColorPixel.toGammaSpace();
+                        baseColorBuffer[destinationOffset] = sRGBBaseColorPixel.r * 255;
+                        baseColorBuffer[destinationOffset + 1] = sRGBBaseColorPixel.g * 255;
+                        baseColorBuffer[destinationOffset + 2] = sRGBBaseColorPixel.b * 255;
+                        if (!this.FuzzyEquals(sRGBBaseColorPixel, BABYLON.Color3.White(), this._epsilon)) {
                             writeOutBaseColorTexture = true;
                         }
                         metallicRoughnessBuffer[destinationOffset + 1] /= metallicRoughnessFactors.roughness > this._epsilon ? metallicRoughnessFactors.roughness : 1;
                         metallicRoughnessBuffer[destinationOffset + 2] /= metallicRoughnessFactors.metallic > this._epsilon ? metallicRoughnessFactors.metallic : 1;
-                        var metallicRoughnessPixel = new BABYLON.Color3(metallicRoughnessBuffer[destinationOffset], metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
+                        var metallicRoughnessPixel = BABYLON.Color3.FromInts(255, metallicRoughnessBuffer[destinationOffset + 1], metallicRoughnessBuffer[destinationOffset + 2]);
                         if (!this.FuzzyEquals(metallicRoughnessPixel, BABYLON.Color3.White(), this._epsilon)) {
                             writeOutMetallicRoughnessTexture = true;
                         }
@@ -1529,6 +1533,81 @@ var BABYLON;
                 return 0;
             };
             /**
+             * Convert a PBRMaterial (Metallic/Roughness) to Metallic Roughness factors.
+             * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+             * @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.
+             * @returns - glTF PBR Metallic Roughness factors.
+             */
+            _GLTFMaterial._ConvertMetalRoughFactorsToMetallicRoughness = function (babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords) {
+                var metallicRoughness = {
+                    baseColor: babylonPBRMaterial.albedoColor,
+                    metallic: babylonPBRMaterial.metallic,
+                    roughness: babylonPBRMaterial.roughness
+                };
+                if (hasTextureCoords) {
+                    if (babylonPBRMaterial.albedoTexture) {
+                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture) {
+                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
+                        }
+                    }
+                    if (babylonPBRMaterial.metallicTexture) {
+                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
+                        if (glTFTexture != null) {
+                            glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
+                        }
+                    }
+                }
+                return metallicRoughness;
+            };
+            /**
+             * Convert a PBRMaterial (Specular/Glossiness) to Metallic Roughness factors.
+             * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+             * @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.
+             * @returns - glTF PBR Metallic Roughness factors.
+             */
+            _GLTFMaterial._ConvertSpecGlossFactorsToMetallicRoughness = function (babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords) {
+                var specGloss = {
+                    diffuseColor: babylonPBRMaterial.albedoColor || BABYLON.Color3.White(),
+                    specularColor: babylonPBRMaterial.reflectivityColor || BABYLON.Color3.White(),
+                    glossiness: babylonPBRMaterial.microSurface || 1,
+                };
+                if (babylonPBRMaterial.reflectivityTexture && !babylonPBRMaterial.useMicroSurfaceFromReflectivityMapAlpha) {
+                    throw new Error("_ConvertPBRMaterial: Glossiness values not included in the reflectivity texture currently not supported");
+                }
+                var metallicRoughnessFactors = this._ConvertSpecularGlossinessTexturesToMetallicRoughness(babylonPBRMaterial.albedoTexture, babylonPBRMaterial.reflectivityTexture, specGloss, mimeType);
+                if (!metallicRoughnessFactors) {
+                    metallicRoughnessFactors = this._ConvertSpecularGlossinessToMetallicRoughness(specGloss);
+                }
+                else {
+                    if (hasTextureCoords) {
+                        if (metallicRoughnessFactors.baseColorTextureBase64) {
+                            var glTFBaseColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughnessFactors.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
+                            if (glTFBaseColorTexture != null) {
+                                glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
+                            }
+                        }
+                        if (metallicRoughnessFactors.metallicRoughnessTextureBase64) {
+                            var glTFMRColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughnessFactors.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
+                            if (glTFMRColorTexture != null) {
+                                glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
+                            }
+                        }
+                    }
+                }
+                return metallicRoughnessFactors;
+            };
+            /**
              * 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.
@@ -1545,42 +1624,11 @@ var BABYLON;
                     name: babylonPBRMaterial.name
                 };
                 var useMetallicRoughness = babylonPBRMaterial.isMetallicWorkflow();
-                if (!useMetallicRoughness) {
-                    var specGloss = {
-                        diffuseColor: babylonPBRMaterial.albedoColor || BABYLON.Color3.White(),
-                        specularColor: babylonPBRMaterial.reflectivityColor || BABYLON.Color3.White(),
-                        glossiness: babylonPBRMaterial.microSurface || 1,
-                    };
-                    if (babylonPBRMaterial.reflectivityTexture && !babylonPBRMaterial.useMicroSurfaceFromReflectivityMapAlpha) {
-                        throw new Error("_ConvertPBRMaterial: Glossiness values not included in the reflectivity texture currently not supported");
-                    }
-                    metallicRoughness = this._ConvertSpecularGlossinessTexturesToMetallicRoughness(babylonPBRMaterial.albedoTexture, babylonPBRMaterial.reflectivityTexture, specGloss, mimeType);
-                    if (!metallicRoughness) {
-                        metallicRoughness = this._ConvertSpecularGlossinessToMetallicRoughness(specGloss);
-                    }
-                    else {
-                        if (hasTextureCoords) {
-                            if (metallicRoughness.baseColorTextureBase64) {
-                                var glTFBaseColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughness.baseColorTextureBase64, "bjsBaseColorTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
-                                if (glTFBaseColorTexture != null) {
-                                    glTFPbrMetallicRoughness.baseColorTexture = glTFBaseColorTexture;
-                                }
-                            }
-                            if (metallicRoughness.metallicRoughnessTextureBase64) {
-                                var glTFMRColorTexture = _GLTFMaterial._GetTextureInfoFromBase64(metallicRoughness.metallicRoughnessTextureBase64, "bjsMetallicRoughnessTexture_" + (textures.length) + ".png", mimeType, images, textures, imageData);
-                                if (glTFMRColorTexture != null) {
-                                    glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFMRColorTexture;
-                                }
-                            }
-                        }
-                    }
+                if (useMetallicRoughness) {
+                    metallicRoughness = this._ConvertMetalRoughFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
                 }
                 else {
-                    metallicRoughness = {
-                        baseColor: babylonPBRMaterial.albedoColor,
-                        metallic: babylonPBRMaterial.metallic,
-                        roughness: babylonPBRMaterial.roughness
-                    };
+                    metallicRoughness = this._ConvertSpecGlossFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
                 }
                 if (!(this.FuzzyEquals(metallicRoughness.baseColor, BABYLON.Color3.White(), this._epsilon) && babylonPBRMaterial.alpha >= this._epsilon)) {
                     glTFPbrMetallicRoughness.baseColorFactor = [
@@ -1603,12 +1651,6 @@ var BABYLON;
                     glTFMaterial.doubleSided = true;
                 }
                 if (hasTextureCoords) {
-                    if (useMetallicRoughness && babylonPBRMaterial.albedoTexture) {
-                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.albedoTexture, mimeType, images, textures, imageData);
-                        if (glTFTexture) {
-                            glTFPbrMetallicRoughness.baseColorTexture = glTFTexture;
-                        }
-                    }
                     if (babylonPBRMaterial.bumpTexture) {
                         var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.bumpTexture, mimeType, images, textures, imageData);
                         if (glTFTexture) {
@@ -1633,12 +1675,6 @@ var BABYLON;
                             glTFMaterial.emissiveTexture = glTFTexture;
                         }
                     }
-                    if (babylonPBRMaterial.metallicTexture) {
-                        var glTFTexture = _GLTFMaterial._ExportTexture(babylonPBRMaterial.metallicTexture, mimeType, images, textures, imageData);
-                        if (glTFTexture != null) {
-                            glTFPbrMetallicRoughness.metallicRoughnessTexture = glTFTexture;
-                        }
-                    }
                 }
                 if (!this.FuzzyEquals(babylonPBRMaterial.emissiveColor, BABYLON.Color3.Black(), this._epsilon)) {
                     glTFMaterial.emissiveFactor = babylonPBRMaterial.emissiveColor.asArray();

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


+ 24 - 0
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -456,6 +456,30 @@ declare module BABYLON.GLTF2 {
          */
         private static _GetMaxComponent(color);
         /**
+         * Convert a PBRMaterial (Metallic/Roughness) to Metallic Roughness factors.
+         * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+         * @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.
+         * @returns - glTF PBR Metallic Roughness factors.
+         */
+        private static _ConvertMetalRoughFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
+        /**
+         * Convert a PBRMaterial (Specular/Glossiness) to Metallic Roughness factors.
+         * @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 glTFPbrMetallicRoughness - glTF PBR Metallic Roughness interface.
+         * @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.
+         * @returns - glTF PBR Metallic Roughness factors.
+         */
+        private static _ConvertSpecGlossFactorsToMetallicRoughness(babylonPBRMaterial, mimeType, images, textures, glTFPbrMetallicRoughness, imageData, hasTextureCoords);
+        /**
          * 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.

+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "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-alphaB"
+        "babylonjs-gltf2interface": "3.2.0-alphaC"
     },
     "peerDependencies": {
         "babylonjs": ">=3.2.0-alpha"

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

@@ -1,7 +1,7 @@
 {
-  "errors": 7184,
+  "errors": 7154,
   "babylon.typedoc.json": {
-    "errors": 7184,
+    "errors": 7154,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -2205,11 +2205,6 @@
             "MissingText": true
           }
         },
-        "speedRatio": {
-          "Comments": {
-            "MissingText": true
-          }
-        },
         "target": {
           "Comments": {
             "MissingText": true
@@ -12135,28 +12130,6 @@
             }
           }
         },
-        "setTexture": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "channel": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "uniform": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "texture": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "setTextureArray": {
           "Comments": {
             "MissingText": true
@@ -24108,35 +24081,6 @@
             }
           }
         },
-        "toEulerAngles": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "order": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
-        "toEulerAnglesToRef": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "result": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "order": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "toRotationMatrix": {
           "Comments": {
             "MissingReturn": true
@@ -25782,25 +25726,6 @@
           "MissingText": true
         }
       },
-      "Constructor": {
-        "new RuntimeAnimation": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "target": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "animation": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        }
-      },
       "Property": {
         "animation": {
           "Comments": {
@@ -25826,60 +25751,11 @@
             }
           }
         },
-        "animate": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "delay": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "from": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "to": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "loop": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "speedRatio": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "blend": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "dispose": {
           "Comments": {
             "MissingText": true
           }
         },
-        "goToFrame": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "frame": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "isStopped": {
           "Comments": {
             "MissingText": true
@@ -25889,23 +25765,6 @@
           "Comments": {
             "MissingText": true
           }
-        },
-        "setValue": {
-          "Comments": {
-            "MissingText": true
-          },
-          "Parameter": {
-            "currentValue": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "blend": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
         }
       }
     },
@@ -27212,33 +27071,6 @@
             }
           }
         },
-        "beginAnimation": {
-          "Comments": {
-            "MissingReturn": true
-          },
-          "Parameter": {
-            "loop": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "speedRatio": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "onAnimationEnd": {
-              "Comments": {
-                "MissingText": true
-              }
-            },
-            "animatable": {
-              "Comments": {
-                "MissingText": true
-              }
-            }
-          }
-        },
         "beginDirectAnimation": {
           "Parameter": {
             "target": {

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 73 - 71
dist/preview release/viewer/babylon.viewer.js


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 877 - 243
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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

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

@@ -2,25 +2,29 @@
 
 ## Major updates
 
-- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles) ([deltakosh](https://github.com/deltakosh))
+- Support for [GPU particles](https://doc.babylonjs.com/babylon101/particles#gpu-particles). Demo [here](https://www.babylonjs-playground.com/frame.html#PU4WYI#2) ([deltakosh](https://github.com/deltakosh))
 - 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))
+- 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 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` add basic support for Daydream and Gear VR ([brianzinn](https://github.com/brianzinn))
+- `WebVRCamera`: added basic support for Daydream and Gear VR ([brianzinn](https://github.com/brianzinn))
+- Introduced [Projection Texture on SpotLight](http://doc.babylonjs.com/babylon101/lights#projection-texture). Demo [here](https://www.babylonjs-playground.com/frame.html#CQNGRK) ([lostink](https://github.com/lostink))
+- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode). Demo [here](https://www.babylonjs-playground.com/frame.html#RNASML#4) ([deltakosh](https://github.com/deltakosh))
+- Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos. Demo [here](https://www.babylonjs-playground.com/frame.html#1E9JQ8#7) ([DavidHGillen](https://github.com/DavidHGillen))
+- Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([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](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#3) ([deltakosh](https://github.com/deltakosh))
+- Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
+- New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
 - 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))
-- Introduced support for [local cubemaps](http://doc.babylonjs.com/how_to/reflect#using-local-cubemap-mode) ([deltakosh](https://github.com/deltakosh))
-- 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, sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
-- Particle System SubEmitters- Spawn new Sub emitter when particles dies. Cone/Sphere shapes emitters ([IbraheemOsama](https://github.com/IbraheemOsama))
+- New [glTF exporter](http://doc.babylonjs.com/resources/3dsmax_to_gltf) for Autodesk 3dsmax ([Noalak](https://github.com/Noalak))
 - Physics - Latest production version of Oimo.js is being used - 1.0.9 ([RaananW](https://github.com/RaananW))
 
 ## Updates
 
 - Tons of functions and classes received the code comments they deserved (All the community)
+- New [particle system emitter shapes](http://doc.babylonjs.com/babylon101/particles#particles-shapes): cone and sphere ([IbraheemOsama](https://github.com/IbraheemOsama))
 - Added support for 16bits TGA ([deltakosh](https://github.com/deltakosh))
 - 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))
@@ -90,6 +94,8 @@
 - EnvironmentHelper has no an onError observable to handle errors when loading the textures ([RaananW](https://github.com/RaananW))
 - (Viewer) Viewer supports model animations ([RaananW](https://github.com/RaananW))
 - Tests for sharpen, chromatic aberration, default pipeline and enable/disable post processes ([trevordev](https://github.com/trevordev))
+- onPointer* callbacks have now the event type as a 3rd variable ([RaananW](https://github.com/RaananW))
+- Lightmap texture in PBR material follow the gammaSpace Flag of the texture ([sebavan](https://github.com/sebavan))
 
 ## Bug fixes
 

+ 18 - 13
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -307,16 +307,15 @@ module BABYLON.GLTF2 {
             return Promise.all(promises).then(() => {});
         }
 
-        private _forEachNodeMesh(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
-            if (node._babylonMesh) {
-                callback(node._babylonMesh);
-            }
-
+        private _forEachPrimitive(node: ILoaderNode, callback: (babylonMesh: Mesh) => void): void {
             if (node._primitiveBabylonMeshes) {
                 for (const babylonMesh of node._primitiveBabylonMeshes) {
                     callback(babylonMesh);
                 }
             }
+            else {
+                callback(node._babylonMesh!);
+        }
         }
 
         private _getMeshes(): Mesh[] {
@@ -328,9 +327,15 @@ module BABYLON.GLTF2 {
             const nodes = this._gltf.nodes;
             if (nodes) {
                 for (const node of nodes) {
-                    this._forEachNodeMesh(node, mesh => {
-                        meshes.push(mesh);
-                    });
+                    if (node._babylonMesh) {
+                        meshes.push(node._babylonMesh);
+                }
+
+                    if (node._primitiveBabylonMeshes) {
+                        for (const babylonMesh of node._primitiveBabylonMeshes) {
+                            meshes.push(babylonMesh);
+            }
+                    }
                 }
             }
 
@@ -437,7 +442,7 @@ module BABYLON.GLTF2 {
                 node._primitiveBabylonMeshes = [];
                 for (const primitive of primitives) {
                     const primitiveBabylonMesh = new Mesh(`${mesh.name || babylonMesh.name}_${primitive._index}`, this._babylonScene, babylonMesh);
-                    node._primitiveBabylonMeshes.push(babylonMesh);
+                    node._primitiveBabylonMeshes.push(primitiveBabylonMesh);
                     promises.push(this._loadPrimitiveAsync(`${context}/primitives/${primitive._index}`, node, mesh, primitive, primitiveBabylonMesh));
                     this.onMeshLoadedObservable.notifyObservers(babylonMesh);
                 }
@@ -449,7 +454,7 @@ module BABYLON.GLTF2 {
             }
 
             return Promise.all(promises).then(() => {
-                this._forEachNodeMesh(node, babylonMesh => {
+                this._forEachPrimitive(node, babylonMesh => {
                     babylonMesh._refreshBoundingInfo(true);
                 });
             });
@@ -711,8 +716,8 @@ module BABYLON.GLTF2 {
 
         private _loadSkinAsync(context: string, node: ILoaderNode, mesh: ILoaderMesh, skin: ILoaderSkin): Promise<void> {
             const assignSkeleton = () => {
-                this._forEachNodeMesh(node, babylonMesh => {
-                    babylonMesh.skeleton = skin._babylonSkeleton;
+                this._forEachPrimitive(node, babylonMesh => {
+                    babylonMesh.skeleton = skin._babylonSkeleton!;
                 });
 
                 node._babylonMesh!.parent = this._rootBabylonMesh;
@@ -965,7 +970,7 @@ module BABYLON.GLTF2 {
                             outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
                         })));
 
-                        this._forEachNodeMesh(targetNode, babylonMesh => {
+                        this._forEachPrimitive(targetNode, babylonMesh => {
                             const morphTarget = babylonMesh.morphTargetManager!.getTarget(targetIndex);
                             babylonAnimationGroup.addTargetedAnimation(babylonAnimation, morphTarget);
                         });

+ 8 - 0
materialsLibrary/src/gradient/babylon.gradientMaterial.ts

@@ -37,10 +37,18 @@ module BABYLON {
         public SHADOWESM1 = false;
         public SHADOWESM2 = false;
         public SHADOWESM3 = false;
+        public SHADOWPOISSON0 = false;
+        public SHADOWPOISSON1 = false;
+        public SHADOWPOISSON2 = false;
+        public SHADOWPOISSON3 = false;
         public SHADOWPCF0 = false;
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 8 - 0
materialsLibrary/src/lava/babylon.lavaMaterial.ts

@@ -37,10 +37,18 @@ module BABYLON {
         public SHADOWESM1 = false;
         public SHADOWESM2 = false;
         public SHADOWESM3 = false;
+        public SHADOWPOISSON0 = false;
+        public SHADOWPOISSON1 = false;
+        public SHADOWPOISSON2 = false;
+        public SHADOWPOISSON3 = false;
         public SHADOWPCF0 = false;
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 8 - 0
materialsLibrary/src/normal/babylon.normalMaterial.ts

@@ -37,10 +37,18 @@ module BABYLON {
         public SHADOWESM1 = false;
         public SHADOWESM2 = false;
         public SHADOWESM3 = false;
+        public SHADOWPOISSON0 = false;
+        public SHADOWPOISSON1 = false;
+        public SHADOWPOISSON2 = false;
+        public SHADOWPOISSON3 = false;
         public SHADOWPCF0 = false;
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 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-alphaB",
+    "version": "3.2.0-alphaC",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 24 - 2
src/Animations/babylon.animatable.ts

@@ -6,9 +6,30 @@
         private _paused = false;
         private _scene: Scene;
         private _speedRatio = 1;
+        private _weight = -1.0;
 
         public animationStarted = false;
 
+        /**
+         * Gets or sets the animatable weight (-1.0 by default meaning not weighted)
+         */
+        public get weight(): number {
+            return this._weight;
+        }
+
+        public set weight(value: number) {
+            if (value === -1) { // -1 is ok and means no weight
+                this._weight = -1;
+                return;
+            }
+
+            // Else weight must be in [0, 1] range
+            this._weight = Math.min(Math.max(value, 0), 1.0);
+        }
+
+        /**
+         * Gets or sets the speed ratio to apply to the animatable (1.0 by default)
+         */
         public get speedRatio(): number {
             return this._speedRatio;
         }
@@ -22,6 +43,7 @@
             this._speedRatio = value;
         }
 
+
         constructor(scene: Scene, public target: any, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, speedRatio: number = 1.0, public onAnimationEnd?: Nullable<() => void>, animations?: any) {
             if (animations) {
                 this.appendAnimations(target, animations);
@@ -41,7 +63,7 @@
             for (var index = 0; index < animations.length; index++) {
                 var animation = animations[index];
 
-                this._runtimeAnimations.push(new RuntimeAnimation(target, animation));
+                this._runtimeAnimations.push(new RuntimeAnimation(target, animation, this._scene));
             }
         }
 
@@ -205,7 +227,7 @@
 
             for (index = 0; index < runtimeAnimations.length; index++) {
                 var animation = runtimeAnimations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio);
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this._speedRatio, this._weight);
                 running = running || isRunning;
             }
 

+ 111 - 22
src/Animations/babylon.runtimeAnimation.ts

@@ -5,15 +5,63 @@
         private _animation: Animation;
         private _target: any;
 
-        private _originalBlendValue: any;
+        private _originalValue: any;
         private _offsetsCache: {[key: string]: any} = {};
         private _highLimitsCache: {[key: string]: any} = {};
         private _stopped = false;
         private _blendingFactor = 0;
-        
-        public constructor(target: any, animation: Animation) {
+        private _scene: Scene;
+
+        private _currentValue: any;
+        private _activeTarget: any;
+        private _targetPath: string;
+        private _weight = 1.0
+
+        /**
+         * Gets the weight of the runtime animation
+         */
+        public get weight(): number {
+            return this._weight;
+        }           
+
+        /**
+         * Gets the original value of the runtime animation
+         */
+        public get originalValue(): any {
+            return this._originalValue;
+        }        
+
+        /**
+         * Gets the current value of the runtime animation
+         */
+        public get currentValue(): any {
+            return this._currentValue;
+        }
+
+        /**
+         * Gets the path where to store the animated value in the target
+         */
+        public get targetPath(): string {
+            return this._targetPath;
+        }
+
+        /**
+         * Gets the actual target of the runtime animation
+         */
+        public get target(): any {
+            return this._activeTarget;
+        }
+
+        /**
+         * Create a new RuntimeAnimation object
+         * @param target defines the target of the animation
+         * @param animation defines the source {BABYLON.Animation} object
+         * @param scene defines the hosting scene
+         */
+        public constructor(target: any, animation: Animation, scene: Scene) {
             this._animation = animation;
             this._target = target;
+            this._scene = scene;
 
             animation._runtimeAnimations.push(this);
         }
@@ -27,7 +75,7 @@
             this._highLimitsCache = {};
             this.currentFrame = 0;
             this._blendingFactor = 0;
-            this._originalBlendValue = null;
+            this._originalValue = null;
         }
 
         public isStopped(): boolean {
@@ -175,7 +223,12 @@
             return this._getKeyValue(keys[keys.length - 1].value);
         }
 
-        public setValue(currentValue: any, blend: boolean = false): void {
+        /**
+         * Affect the interpolated value to the target
+         * @param currentValue defines the value computed by the animation
+         * @param weight defines the weight to apply to this value
+         */
+        public setValue(currentValue: any, weight = 1.0): void {
             // Set value
             var path: any;
             var destination: any;
@@ -189,42 +242,63 @@
                     property = property[targetPropertyPath[index]];
                 }
 
-                path = targetPropertyPath[targetPropertyPath.length - 1];
+                path =  [targetPropertyPath.length - 1];
                 destination = property;
             } else {
                 path = targetPropertyPath[0];
                 destination = this._target;
             }
 
+            this._targetPath = path;
+            this._activeTarget = destination;
+            this._weight = weight;
+
             // Blending
             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();
+            if (enableBlending && this._blendingFactor <= 1.0 || weight !== -1.0) {
+                if (!this._originalValue) {
+                    let originalValue: any;
+
+                    if (destination.getRestPose) { // For bones
+                        originalValue = destination.getRestPose();
+                    } else {
+                        originalValue = destination[path]
+                    }
+
+                    if (originalValue.clone) {
+                        this._originalValue = originalValue.clone();
                     } else {
-                        this._originalBlendValue = destination[path];
+                        this._originalValue = originalValue;
                     }
                 }
+            }
 
-                if (this._originalBlendValue.prototype) { // Complex value
+            if (enableBlending && this._blendingFactor <= 1.0) {
+                if (this._originalValue.prototype) { // Complex value
                     
-                    if (this._originalBlendValue.prototype.Lerp) { // Lerp supported
-                        destination[path] = this._originalBlendValue.construtor.prototype.Lerp(currentValue, this._originalBlendValue, this._blendingFactor);
+                    if (this._originalValue.prototype.Lerp) { // Lerp supported
+                        this._currentValue = this._originalValue.construtor.prototype.Lerp(currentValue, this._originalValue, this._blendingFactor);
                     } else { // Blending not supported
-                        destination[path] = currentValue;
+                        this._currentValue = currentValue;
                     }
 
-                } else if (this._originalBlendValue.m) { // Matrix
-                    destination[path] = Matrix.Lerp(this._originalBlendValue, currentValue, this._blendingFactor);
+                } else if (this._originalValue.m) { // Matrix
+                    this._currentValue = Matrix.Lerp(this._originalValue, currentValue, this._blendingFactor);
                 } else { // Direct value
-                    destination[path] = this._originalBlendValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
+                    this._currentValue = this._originalValue * (1.0 - this._blendingFactor) + this._blendingFactor * currentValue;
                 }
                 this._blendingFactor += blendingSpeed;
+                
+                destination[path] = this._currentValue;
             } else {
-                destination[path] = currentValue;
+                this._currentValue = currentValue;
+                if (weight !== -1.0) {
+                    this._scene._registerTargetForLateAnimationBinding(this);
+                } else {
+                    destination[path] = this._currentValue;
+                }
             }
 
             if (this._target.markAsDirty) {
@@ -240,6 +314,10 @@
             return this._animation.loopMode;
         }
 
+        /**
+         * Move the current animation to a given frame
+         * @param frame defines the frame to move to
+         */
         public goToFrame(frame: number): void {
             let keys = this._animation.getKeys();
 
@@ -251,7 +329,7 @@
 
             var currentValue = this._interpolate(frame, 0, this._getCorrectLoopMode());
 
-            this.setValue(currentValue);
+            this.setValue(currentValue, -1);
         }
 
         public _prepareForSpeedRatioChange(newSpeedRatio: number): void {
@@ -264,7 +342,17 @@
         private _previousDelay: number;
         private _previousRatio: number;
 
-        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, blend: boolean = false): boolean {
+        /**
+         * Execute the current animation
+         * @param delay defines the delay to add to the current frame
+         * @param from defines the lower bound of the animation range
+         * @param to defines the upper bound of the animation range
+         * @param loop defines if the current animation must loop
+         * @param speedRatio defines the current speed ratio
+         * @param weight defines the weight of the animation (default is -1 so no weight)
+         * @returns a boolean indicating if the animation has ended
+         */
+        public animate(delay: number, from: number, to: number, loop: boolean, speedRatio: number, weight = -1.0): boolean {
             let targetPropertyPath = this._animation.targetPropertyPath
             if (!targetPropertyPath || targetPropertyPath.length < 1) {
                 this._stopped = true;
@@ -385,7 +473,8 @@
             var currentValue = this._interpolate(currentFrame, repeatCount, this._getCorrectLoopMode(), offsetValue, highLimitValue);
 
             // Set value
-            this.setValue(currentValue);
+            this.setValue(currentValue, weight);
+
             // Check events
             let events = this._animation.getEvents();
             for (var index = 0; index < events.length; index++) {

+ 67 - 16
src/Engine/babylon.engine.ts

@@ -235,6 +235,8 @@
         bilinearFiltering?: boolean;
         /** Specifies the comparison function to set on the texture. If 0 or undefined, the texture is not in comparison mode */
         comparisonFunction?: number;
+        /** Specifies if the created texture is a cube texture */
+        isCube?: boolean;
     }
 
     /**
@@ -595,7 +597,7 @@
         }
 
         public static get Version(): string {
-            return "3.2.0-alphaB";
+            return "3.2.0-alphaC";
         }
 
         // Updatable statics so stick with vars here
@@ -1973,10 +1975,10 @@
 
                 if (depthStencilTexture) {
                     if (depthStencilTexture._generateStencilBuffer) {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
                     }
                     else {
-                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture, 0);
+                        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, depthStencilTexture._webGLTexture, 0);
                     }
                 }
             }
@@ -2632,7 +2634,7 @@
             this._drawCalls.addCount(1, false);
             // Render
 
-            const drawMode = this.DrawMode(fillMode);
+            const drawMode = this._drawMode(fillMode);
             var indexFormat = this._uintIndicesCurrentlySet ? this._gl.UNSIGNED_INT : this._gl.UNSIGNED_SHORT;
             var mult = this._uintIndicesCurrentlySet ? 4 : 2;
             if (instancesCount) {
@@ -2647,7 +2649,7 @@
             this.applyStates();
             this._drawCalls.addCount(1, false);
 
-            const drawMode = this.DrawMode(fillMode);
+            const drawMode = this._drawMode(fillMode);
             if (instancesCount) {
                 this._gl.drawArraysInstanced(drawMode, verticesStart, verticesCount, instancesCount);
             } else {
@@ -2655,7 +2657,7 @@
             }
         }
 
-        private DrawMode(fillMode: number): number {
+        private _drawMode(fillMode: number): number {
             switch (fillMode) {
                 // Triangle views
                 case Material.TriangleFillMode:
@@ -2757,7 +2759,7 @@
 
             this.onBeforeShaderCompilationObservable.notifyObservers(this);
 
-            var shaderVersion = (this._webGLVersion > 1) ? "#version 300 es\n" : "";
+            var shaderVersion = (this._webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
             var vertexShader = compileShader(context, vertexCode, "vertex", defines, shaderVersion);
             var fragmentShader = compileShader(context, fragmentCode, "fragment", defines, shaderVersion);
 
@@ -3704,10 +3706,10 @@
             internalTexture.generateMipMaps = false;
             internalTexture._generateDepthBuffer = true;
             internalTexture._generateStencilBuffer = generateStencil;
-            internalTexture.samplingMode = bilinearFiltering ? Texture.NEAREST_SAMPLINGMODE : Texture.BILINEAR_SAMPLINGMODE;
+            internalTexture.samplingMode = bilinearFiltering ? Texture.BILINEAR_SAMPLINGMODE : Texture.NEAREST_SAMPLINGMODE;
             internalTexture.type = Engine.TEXTURETYPE_UNSIGNED_INT;
             internalTexture._comparisonFunction = comparisonFunction;
-
+            
             var gl = this._gl;
             var target = internalTexture.isCube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
             var samplingParameters = getSamplingParameters(internalTexture.samplingMode, false, gl);
@@ -3734,6 +3736,23 @@
          * @returns The texture
          */
         public createDepthStencilTexture(size: number | { width: number, height: number }, options: DepthTextureCreationOptions) : InternalTexture {
+            if (options.isCube) {
+                let width = (<{ width: number, height: number }>size).width || <number>size;
+                return this._createDepthStencilCubeTexture(width, options);
+            }
+            else {
+                return this._createDepthStencilTexture(size, options);
+            }
+        }
+
+        /**
+         * Creates a depth stencil texture.
+         * This is only available in WebGL 2 or with the depth texture extension available.
+         * @param size The size of face edge in the texture.
+         * @param options The options defining the texture.
+         * @returns The texture
+         */
+        private _createDepthStencilTexture(size: number | { width: number, height: number }, options: DepthTextureCreationOptions) : InternalTexture {
             var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_DEPTHTEXTURE);
 
             if (!this._caps.depthTextureExtension) {
@@ -3782,7 +3801,7 @@
          * @param options The options defining the cube texture.
          * @returns The cube texture
          */
-        public createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions) : InternalTexture {
+        private _createDepthStencilCubeTexture(size: number, options: DepthTextureCreationOptions) : InternalTexture {
             var internalTexture = new InternalTexture(this, InternalTexture.DATASOURCE_UNKNOWN);
             internalTexture.isCube = true;
 
@@ -3835,18 +3854,18 @@
             this.bindUnboundFramebuffer(internalTexture._framebuffer);
             if (depthStencilTexture.isCube) {
                 if (depthStencilTexture._generateStencilBuffer) {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
                 }
                 else {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_CUBE_MAP_POSITIVE_X, depthStencilTexture._webGLTexture, 0);
                 }
             }
             else {
                 if (depthStencilTexture._generateStencilBuffer) {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
                 }
                 else {
-                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
+                    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture._webGLTexture, 0);
                 }
             }
             this.bindUnboundFramebuffer(null);
@@ -5196,6 +5215,12 @@
             }
         }
 
+        /**
+         * Sets a texture to the according uniform.
+         * @param channel The texture channel
+         * @param uniform The uniform to set
+         * @param texture The texture to apply
+         */
         public setTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<BaseTexture>): void {
             if (channel < 0) {
                 return;
@@ -5208,6 +5233,29 @@
             this._setTexture(channel, texture);
         }
 
+        /**
+         * Sets a depth stencil texture from a render target to the according uniform.
+         * @param channel The texture channel
+         * @param uniform The uniform to set
+         * @param texture The render target texture containing the depth stencil texture to apply
+         */
+        public setDepthStencilTexture(channel: number, uniform: Nullable<WebGLUniformLocation>, texture: Nullable<RenderTargetTexture>): void {
+            if (channel < 0) {
+                return;
+            }
+
+            if (uniform) {
+                this._boundUniforms[channel] = uniform;
+            }
+
+            if (!texture || !texture.depthStencilTexture) {
+                this._setTexture(channel, null);
+            }
+            else {
+                this._setTexture(channel, texture, false, true);
+            }
+        }
+
         private _bindSamplerUniformToChannel(sourceSlot: number, destination: number) {
             let uniform = this._boundUniforms[sourceSlot];
             if (uniform._currentState === destination) {
@@ -5217,7 +5265,7 @@
             uniform._currentState = destination;
         }
 
-        private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false): boolean {
+        private _setTexture(channel: number, texture: Nullable<BaseTexture>, isPartOfTextureArray = false, depthStencilTexture = false): boolean {
             // Not ready?
             if (!texture) {
                 if (this._boundTexturesCache[channel] != null) {
@@ -5241,7 +5289,10 @@
             }
 
             let internalTexture: InternalTexture;
-            if (texture.isReady()) {
+            if (depthStencilTexture) {
+                internalTexture = (<RenderTargetTexture>texture).depthStencilTexture!;
+            }
+            else if (texture.isReady()) {
                 internalTexture = <InternalTexture>texture.getInternalTexture();
             }
             else if (texture.isCube) {

+ 266 - 52
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -81,76 +81,106 @@
      * Documentation: https://doc.babylonjs.com/babylon101/shadows
      */
     export class ShadowGenerator implements IShadowGenerator {
-        private static _FILTER_NONE = 0;
-        private static _FILTER_EXPONENTIALSHADOWMAP = 1;
-        private static _FILTER_POISSONSAMPLING = 2;
-        private static _FILTER_BLUREXPONENTIALSHADOWMAP = 3;
-        private static _FILTER_CLOSEEXPONENTIALSHADOWMAP = 4;
-        private static _FILTER_BLURCLOSEEXPONENTIALSHADOWMAP = 5;
-
         /**
          * Shadow generator mode None: no filtering applied.
          */
-        public static get FILTER_NONE(): number {
-            return ShadowGenerator._FILTER_NONE;
-        }
-
-        /**
-         * Shadow generator mode Poisson Sampling: Percentage Closer Filtering.
-         * (Multiple Tap around evenly distributed around the pixel are used to evaluate the shadow strength)
-         */
-        public static get FILTER_POISSONSAMPLING(): number {
-            return ShadowGenerator._FILTER_POISSONSAMPLING;
-        }
-
+        public static readonly FILTER_NONE = 0;
         /**
          * Shadow generator mode ESM: Exponential Shadow Mapping.
          * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
          */
-        public static get FILTER_EXPONENTIALSHADOWMAP(): number {
-            return ShadowGenerator._FILTER_EXPONENTIALSHADOWMAP;
-        }
-
+        public static readonly FILTER_EXPONENTIALSHADOWMAP = 1;
+        /**
+         * Shadow generator mode Poisson Sampling: Percentage Closer Filtering.
+         * (Multiple Tap around evenly distributed around the pixel are used to evaluate the shadow strength)
+         */
+        public static readonly FILTER_POISSONSAMPLING = 2;
         /**
          * Shadow generator mode ESM: Blurred Exponential Shadow Mapping.
          * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
          */
-        public static get FILTER_BLUREXPONENTIALSHADOWMAP(): number {
-            return ShadowGenerator._FILTER_BLUREXPONENTIALSHADOWMAP;
-        }
-
+        public static readonly FILTER_BLUREXPONENTIALSHADOWMAP = 3;
         /**
          * Shadow generator mode ESM: Exponential Shadow Mapping using the inverse of the exponential preventing 
          * edge artifacts on steep falloff.
          * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
          */
-        public static get FILTER_CLOSEEXPONENTIALSHADOWMAP(): number {
-            return ShadowGenerator._FILTER_CLOSEEXPONENTIALSHADOWMAP;
-        }
-
+        public static readonly FILTER_CLOSEEXPONENTIALSHADOWMAP = 4;
         /**
          * Shadow generator mode ESM: Blurred Exponential Shadow Mapping using the inverse of the exponential preventing 
          * edge artifacts on steep falloff.
          * (http://developer.download.nvidia.com/presentations/2008/GDC/GDC08_SoftShadowMapping.pdf)
          */
-        public static get FILTER_BLURCLOSEEXPONENTIALSHADOWMAP(): number {
-            return ShadowGenerator._FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
-        }
+        public static readonly FILTER_BLURCLOSEEXPONENTIALSHADOWMAP = 5;
+        /**
+         * Shadow generator mode PCF: Percentage Closer Filtering 
+         * benefits from Webgl 2 shadow samplers. Fallback to Poisson Sampling in Webgl 1
+         * (https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch11.html)
+         */
+        public static readonly FILTER_PCF = 6;
+        /**
+         * Shadow generator mode PCSS: Percentage Closering Soft Shadow. 
+         * benefits from Webgl 2 shadow samplers. Fallback to Poisson Sampling in Webgl 1
+         * Contact Hardening
+         */
+        public static readonly FILTER_PCSS = 7;
+
+        /**
+         * Reserved for PCF and PCSS
+         * Highest Quality.
+         * 
+         * Execute PCF on a 5*5 kernel improving a lot the shadow aliasing artifacts.
+         * 
+         * Execute PCSS with 32 taps blocker search and 64 taps PCF.
+         */
+        public static readonly QUALITY_HIGH = 0;
+        /**
+         * Reserved for PCF and PCSS
+         * Good tradeoff for quality/perf cross devices
+         * 
+         * Execute PCF on a 3*3 kernel.
+         * 
+         * Execute PCSS with 16 taps blocker search and 32 taps PCF.
+         */
+        public static readonly QUALITY_MEDIUM = 1;
+        /**
+         * Reserved for PCF and PCSS
+         * The lowest quality but the fastest.
+         * 
+         * Execute PCF on a 1*1 kernel.
+         * 
+         * Execute PCSS with 16 taps blocker search and 16 taps PCF.
+         */
+        public static readonly QUALITY_LOW = 2;
 
         private _bias = 0.00005;
         /**
-         * Gets the bias: offset applied on the depth preventing acnea.
+         * Gets the bias: offset applied on the depth preventing acnea (in light direction).
          */
         public get bias(): number {
             return this._bias;
         }
         /**
-         * Sets the bias: offset applied on the depth preventing acnea.
+         * Sets the bias: offset applied on the depth preventing acnea (in light direction).
          */
         public set bias(bias: number) {
             this._bias = bias;
         }
 
+        private _normalBias = 0;
+        /**
+         * Gets the normalBias: offset applied on the depth preventing acnea (along side the normal direction and proportinal to the light/normal angle).
+         */
+        public get normalBias(): number {
+            return this._normalBias;
+        }
+        /**
+         * Sets the normalBias: offset applied on the depth preventing acnea (along side the normal direction and proportinal to the light/normal angle).
+         */
+        public set normalBias(normalBias: number) {
+            this._normalBias = normalBias;
+        }
+
         private _blurBoxOffset = 1;
         /**
          * Gets the blur box offset: offset applied during the blur pass.
@@ -273,6 +303,19 @@
                     this.useCloseExponentialShadowMap = true;
                     return;
                 }
+                // PCF on cubemap would also be expensive
+                else if (value === ShadowGenerator.FILTER_PCF || value === ShadowGenerator.FILTER_PCSS) {
+                    this.usePoissonSampling = true;
+                    return;
+                }
+            }
+
+            // Weblg1 fallback for PCF.
+            if (value === ShadowGenerator.FILTER_PCF || value === ShadowGenerator.FILTER_PCSS) {
+                if (this._scene.getEngine().webGLVersion === 1) {
+                    this.usePoissonSampling = true;
+                    return;
+                }
             }
 
             if (this._filter === value) {
@@ -286,13 +329,13 @@
         }
 
         /**
-         * Gets if the current filter is set to Poisson Sampling aka PCF.
+         * Gets if the current filter is set to Poisson Sampling.
          */
         public get usePoissonSampling(): boolean {
             return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
         }
         /**
-         * Sets the current filter to Poisson Sampling aka PCF.
+         * Sets the current filter to Poisson Sampling.
          */
         public set usePoissonSampling(value: boolean) {
             if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
@@ -394,7 +437,7 @@
             return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
         }
         /**
-         * Sets the current filter to fileterd "close ESM" (using the inverse of the 
+         * Sets the current filter to filtered "close ESM" (using the inverse of the 
          * exponential to prevent steep falloff artifacts).
          */
         public set useBlurCloseExponentialShadowMap(value: boolean) {
@@ -404,6 +447,80 @@
             this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to "PCF" (percentage closer filtering).
+         */
+        public get usePercentageCloserFiltering(): boolean {
+            return this.filter === ShadowGenerator.FILTER_PCF;
+        }
+        /**
+         * Sets the current filter to "PCF" (percentage closer filtering).
+         */
+        public set usePercentageCloserFiltering(value: boolean) {
+            if (!value && this.filter !== ShadowGenerator.FILTER_PCF) {
+                return;
+            }
+            this.filter = (value ? ShadowGenerator.FILTER_PCF : ShadowGenerator.FILTER_NONE);
+        }
+
+        private _filteringQuality = ShadowGenerator.QUALITY_HIGH;
+        /**
+         * Gets the PCF or PCSS Quality.
+         * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
+         */
+        public get filteringQuality(): number {
+            return this._filteringQuality;
+        }
+        /**
+         * Sets the PCF or PCSS Quality.
+         * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
+         */
+        public set filteringQuality(filteringQuality: number) {
+            this._filteringQuality = filteringQuality;
+        }
+
+        /**
+         * Gets if the current filter is set to "PCSS" (contact hardening).
+         */
+        public get useContactHardeningShadow(): boolean {
+            return this.filter === ShadowGenerator.FILTER_PCSS;
+        }
+        /**
+         * Sets the current filter to "PCSS" (contact hardening).
+         */
+        public set useContactHardeningShadow(value: boolean) {
+            if (!value && this.filter !== ShadowGenerator.FILTER_PCSS) {
+                return;
+            }
+            this.filter = (value ? ShadowGenerator.FILTER_PCSS : ShadowGenerator.FILTER_NONE);
+        }
+
+        private _contactHardeningLightSizeUVRatio = 0.1;
+        /**
+         * Gets the Light Size (in shadow map uv unit) used in PCSS to determine the blocker search area and the penumbra size.
+         * Using a ratio helps keeping shape stability independently of the map size.
+         *
+         * It does not account for the light projection as it was having too much 
+         * instability during the light setup or during light position changes.
+         * 
+         * Only valid if useContactHardeningShadow is true.
+         */
+        public get contactHardeningLightSizeUVRatio(): number {
+            return this._contactHardeningLightSizeUVRatio;
+        }
+        /**
+         * Sets the Light Size (in shadow map uv unit) used in PCSS to determine the blocker search area and the penumbra size.
+         * Using a ratio helps keeping shape stability independently of the map size.
+         * 
+         * It does not account for the light projection as it was having too much 
+         * instability during the light setup or during light position changes.
+         * 
+         * Only valid if useContactHardeningShadow is true.
+         */
+        public set contactHardeningLightSizeUVRatio(contactHardeningLightSizeUVRatio: number) {
+            this._contactHardeningLightSizeUVRatio = contactHardeningLightSizeUVRatio;
+        }
+
         private _darkness = 0;
         /**
          * Returns the darkness value (float). This can only decrease the actual darkness of a shadow.
@@ -595,6 +712,7 @@
             }
 
             this._initializeGenerator();
+            this._applyFilterValues();
         }
 
         private _initializeGenerator(): void {
@@ -604,7 +722,14 @@
 
         private _initializeShadowMap(): void {
             // Render target
-            this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
+            let engine = this._scene.getEngine();
+            if (engine.webGLVersion > 1) {
+                this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube(), undefined, false, false);
+                this._shadowMap.createDepthStencilTexture(Engine.LESS, true);
+            }
+            else {
+                this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
+            }
             this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.anisotropicFilteringLevel = 1;
@@ -615,6 +740,9 @@
             // Record Face Index before render.
             this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
                 this._currentFaceIndex = faceIndex;
+                if (this._filter === ShadowGenerator.FILTER_PCF) {
+                    engine.setColorWrite(false);
+                }
             });
 
             // Custom render function.
@@ -622,6 +750,9 @@
 
             // Blur if required afer render.
             this._shadowMap.onAfterUnbindObservable.add(() => {
+                if (this._filter === ShadowGenerator.FILTER_PCF) {
+                    engine.setColorWrite(true);
+                }
                 if (!this.useBlurExponentialShadowMap && !this.useBlurCloseExponentialShadowMap) {
                     return;
                 }
@@ -633,14 +764,17 @@
             });
 
             // Clear according to the chosen filter.
-            let zero = new Color4(0, 0, 0, 0);
-            let one = new Color4(1.0, 1.0, 1.0, 1.0);
+            var clearZero = new Color4(0, 0, 0, 0);
+            var clearOne = new Color4(1.0, 1.0, 1.0, 1.0);
             this._shadowMap.onClearObservable.add((engine: Engine) => {
-                if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
-                    engine.clear(zero, true, true, true);
+                if (this._filter === ShadowGenerator.FILTER_PCF) {
+                    engine.clear(clearOne, false, true, false);
+                }
+                else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
+                    engine.clear(clearZero, true, true, false);
                 }
                 else {
-                    engine.clear(one, true, true, true);
+                    engine.clear(clearOne, true, true, false);
                 }
             });
         }
@@ -740,10 +874,15 @@
                 engine.enableEffect(this._effect);
                 mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
 
-                this._effect.setFloat2("biasAndScale", this.bias, this.depthScale);
+                this._effect.setFloat3("biasAndScale", this.bias, this.normalBias, this.depthScale);
 
                 this._effect.setMatrix("viewProjection", this.getTransformMatrix());
-                this._effect.setVector3("lightPosition", this.getLight().position);
+                if (this.getLight().getTypeID() === Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
+                    this._effect.setVector3("lightData", this._cachedDirection);
+                }
+                else {
+                    this._effect.setVector3("lightData", this._cachedPosition);
+                }
 
                 if (scene.activeCamera) {
                     this._effect.setFloat2("depthValues", this.getLight().getDepthMinZ(scene.activeCamera), this.getLight().getDepthMinZ(scene.activeCamera) + this.getLight().getDepthMaxZ(scene.activeCamera));
@@ -787,7 +926,7 @@
                 return;
             }
 
-            if (this.filter === ShadowGenerator.FILTER_NONE) {
+            if (this.filter === ShadowGenerator.FILTER_NONE || this.filter === ShadowGenerator.FILTER_PCSS) {
                 this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
             } else {
                 this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
@@ -883,12 +1022,27 @@
             if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
                 defines.push("#define ESM");
             }
+            else if (this.usePercentageCloserFiltering || this.useContactHardeningShadow) {
+                defines.push("#define DEPTHTEXTURE");
+            }
 
             var attribs = [VertexBuffer.PositionKind];
 
             var mesh = subMesh.getMesh();
             var material = subMesh.getMaterial();
 
+            // Normal bias.
+            if (this.normalBias && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                attribs.push(VertexBuffer.NormalKind);
+                defines.push("#define NORMAL");
+                if (mesh.nonUniformScaling) {
+                    defines.push("#define NONUNIFORMSCALING");
+                }
+                if (this.getLight().getTypeID() === Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
+                    defines.push("#define DIRECTIONINLIGHTDATA");
+                }
+            }
+
             // Alpha test
             if (material && material.needAlphaTesting()) {
                 var alphaTexture = material.getAlphaTestTexture();
@@ -936,7 +1090,7 @@
                 this._cachedDefines = join;
                 this._effect = this._scene.getEngine().createEffect("shadowMap",
                     attribs,
-                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues", "biasAndScale"],
+                    ["world", "mBones", "viewProjection", "diffuseMatrix", "lightData", "depthValues", "biasAndScale"],
                     ["diffuseSampler"], join);
             }
 
@@ -978,8 +1132,28 @@
 
             defines["SHADOW" + lightIndex] = true;
 
-            if (this.usePoissonSampling) {
+            if (this.useContactHardeningShadow) {
+                defines["SHADOWPCSS" + lightIndex] = true;
+                if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
+                    defines["SHADOWLOWQUALITY" + lightIndex] = true;
+                }
+                else if (this._filteringQuality === ShadowGenerator.QUALITY_MEDIUM) {
+                    defines["SHADOWMEDIUMQUALITY" + lightIndex] = true;
+                }
+                // else default to high.
+            }
+            if (this.usePercentageCloserFiltering) {
                 defines["SHADOWPCF" + lightIndex] = true;
+                if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
+                    defines["SHADOWLOWQUALITY" + lightIndex] = true;
+                }
+                else if (this._filteringQuality === ShadowGenerator.QUALITY_MEDIUM) {
+                    defines["SHADOWMEDIUMQUALITY" + lightIndex] = true;
+                }
+                // else default to high.
+            }
+            else if (this.usePoissonSampling) {
+                defines["SHADOWPOISSON" + lightIndex] = true;
             }
             else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
                 defines["SHADOWESM" + lightIndex] = true;
@@ -1021,8 +1195,22 @@
             if (!light.needCube()) {
                 effect.setMatrix("lightMatrix" + lightIndex, this.getTransformMatrix());
             }
-            effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
-            light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
+
+            // Only PCF uses depth stencil texture.
+            if (this._filter === ShadowGenerator.FILTER_PCF) {
+                effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+                light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), shadowMap.getSize().width, 1 / shadowMap.getSize().width, this.frustumEdgeFalloff, lightIndex);
+            }
+            else if (this._filter === ShadowGenerator.FILTER_PCSS) {
+                effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+                effect.setTexture("depthSampler" + lightIndex, this.getShadowMapForRendering());
+                light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), 1 / shadowMap.getSize().width, this._contactHardeningLightSizeUVRatio * shadowMap.getSize().width, this.frustumEdgeFalloff, lightIndex);
+            }
+            else {
+                effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+                light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
+            }
+
             light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(camera), this.getLight().getDepthMinZ(camera) + this.getLight().getDepthMaxZ(camera), lightIndex);
         }
 
@@ -1171,6 +1359,14 @@
             serializationObject.useKernelBlur = this.useKernelBlur;
             serializationObject.transparencyShadow = this._transparencyShadow;
 
+            serializationObject.bias = this.bias;
+            serializationObject.normalBias = this.normalBias;
+
+            serializationObject.usePercentageCloserFiltering = this.usePercentageCloserFiltering;
+            serializationObject.useContactHardeningShadow = this.useContactHardeningShadow;
+            serializationObject.filteringQuality = this.filteringQuality;
+            serializationObject.contactHardeningLightSizeUVRatio = this.contactHardeningLightSizeUVRatio;
+
             serializationObject.renderList = [];
             if (shadowMap.renderList) {
                 for (var meshIndex = 0; meshIndex < shadowMap.renderList.length; meshIndex++) {
@@ -1223,6 +1419,20 @@
             else if (parsedShadowGenerator.useBlurCloseExponentialShadowMap) {
                 shadowGenerator.useBlurCloseExponentialShadowMap = true;
             }
+            else if (parsedShadowGenerator.usePercentageCloserFiltering) {
+                shadowGenerator.usePercentageCloserFiltering = true;
+            }
+            else if (parsedShadowGenerator.useContactHardeningShadow) {
+                shadowGenerator.useContactHardeningShadow = true;
+            }
+
+            if (parsedShadowGenerator.filteringQuality) {
+                shadowGenerator.filteringQuality = parsedShadowGenerator.filteringQuality;
+            }
+
+            if (parsedShadowGenerator.contactHardeningLightSizeUVRatio) {
+                shadowGenerator.contactHardeningLightSizeUVRatio = parsedShadowGenerator.contactHardeningLightSizeUVRatio;
+            }
 
             // Backward compat
             else if (parsedShadowGenerator.useVarianceShadowMap) {
@@ -1256,6 +1466,10 @@
                 shadowGenerator.bias = parsedShadowGenerator.bias;
             }
 
+            if (parsedShadowGenerator.normalBias !== undefined) {
+                shadowGenerator.normalBias = parsedShadowGenerator.normalBias;
+            }
+
             if (parsedShadowGenerator.darkness) {
                 shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
             }

+ 1 - 1
src/Lights/babylon.directionalLight.ts

@@ -23,7 +23,7 @@
             this.forceProjectionMatrixCompute();
         }
 
-        private _shadowOrthoScale = 0.5;
+        private _shadowOrthoScale = 0.1;
         /**
          * Gets the shadow projection scale against the optimal computed one.
          * 0.1 by default which means that the projection window is increase by 10% from the optimal size.

+ 2 - 0
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -65,6 +65,7 @@
         public LIGHTMAP = false;
         public LIGHTMAPDIRECTUV = 0;
         public USELIGHTMAPASSHADOWMAP = false;
+        public GAMMALIGHTMAP = false;
 
         public REFLECTION = false;
         public REFLECTIONMAP_3D = false;
@@ -1105,6 +1106,7 @@
                     if (this._lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
                         MaterialHelper.PrepareDefinesForMergedUV(this._lightmapTexture, defines, "LIGHTMAP");
                         defines.USELIGHTMAPASSHADOWMAP = this._useLightmapAsShadowmap;
+                        defines.GAMMALIGHTMAP = this._lightmapTexture.gammaSpace;
                     } else {
                         defines.LIGHTMAP = false;
                     }

+ 2 - 5
src/Materials/Textures/babylon.internalTexture.ts

@@ -322,13 +322,10 @@ module BABYLON {
                         bilinearFiltering: this.samplingMode !== Texture.BILINEAR_SAMPLINGMODE,
                         comparisonFunction: this._comparisonFunction,
                         generateStencil: this._generateStencilBuffer,
+                        isCube: this.isCube
                     };
 
-                    if (this.isCube) {
-                        proxy = this._engine.createDepthStencilTexture({ width: this.width, height: this.height }, depthTextureOptions);
-                    } else {
-                        proxy = this._engine.createDepthStencilCubeTexture(this.width, depthTextureOptions);
-                    }
+                    proxy = this._engine.createDepthStencilTexture({ width: this.width, height: this.height }, depthTextureOptions);
                     proxy._swapAndDie(this);
 
                     this.isReady = true;

+ 22 - 0
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -229,6 +229,28 @@
 
         }
 
+        /**
+         * Creates a depth stencil texture.
+         * This is only available in WebGL 2 or with the depth texture extension available.
+         * @param comparisonFunction Specifies the comparison function to set on the texture. If 0 or undefined, the texture is not in comparison mode
+         * @param bilinearFiltering Specifies whether or not bilinear filtering is enable on the texture
+         * @param generateStencil Specifies whether or not a stencil should be allocated in the texture
+         */
+        public createDepthStencilTexture(comparisonFunction: number = 0, bilinearFiltering: boolean = true, generateStencil: boolean = false) : void {
+            if (!this.getScene()) {
+                return;
+            }
+
+            var engine = this.getScene()!.getEngine();
+            this.depthStencilTexture = engine.createDepthStencilTexture(this._size, {
+                bilinearFiltering,
+                comparisonFunction,
+                generateStencil,
+                isCube: this.isCube
+            });
+            engine.setFrameBufferDepthStencilTexture(this);
+        }
+
         private _processSizeParameter(size: number | {width: number, height: number} | {ratio: number}): void {
             if ((<{ratio: number}>size).ratio) {
                 this._sizeRatio = (<{ratio: number}>size).ratio;

+ 11 - 1
src/Materials/babylon.effect.ts

@@ -580,7 +580,7 @@
 
         private _dumpShadersSource(vertexCode: string, fragmentCode: string, defines: string): void {
             // Rebuild shaders source code
-            var shaderVersion = (this._engine.webGLVersion > 1) ? "#version 300 es\n" : "";
+            var shaderVersion = (this._engine.webGLVersion > 1) ? "#version 300 es\n#define WEBGL2 \n" : "";
             var prefix = shaderVersion + (defines ? defines + "\n" : "");
             vertexCode = prefix + vertexCode;
             fragmentCode = prefix + fragmentCode;
@@ -920,6 +920,16 @@
         public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
             this._engine.setTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
         }
+
+        /**
+         * Sets a depth stencil texture from a render target on the engine to be used in the shader.
+         * @param channel Name of the sampler variable.
+         * @param texture Texture to set.
+         */
+        public setDepthStencilTexture(channel: string, texture: Nullable<RenderTargetTexture>): void {
+            this._engine.setDepthStencilTexture(this._samplers.indexOf(channel), this.getUniform(channel), texture);
+        }
+
         /**
          * Sets an array of textures on the engine to be used in the shader.
          * @param channel Name of the variable.

+ 14 - 0
src/Materials/babylon.materialHelper.ts

@@ -239,8 +239,12 @@ module BABYLON {
                     // Shadows
                     defines["SHADOW" + lightIndex] = false;
                     defines["SHADOWPCF" + lightIndex] = false;
+                    defines["SHADOWPCSS" + lightIndex] = false;
+                    defines["SHADOWPOISSON" + lightIndex] = false;
                     defines["SHADOWESM" + lightIndex] = false;
                     defines["SHADOWCUBE" + lightIndex] = false;
+                    defines["SHADOWLOWQUALITY" + lightIndex] = false;
+                    defines["SHADOWMEDIUMQUALITY" + lightIndex] = false;
 
                     if (mesh && mesh.receiveShadows && scene.shadowsEnabled && light.shadowEnabled) {
                         var shadowGenerator = light.getShadowGenerator();
@@ -345,6 +349,8 @@ module BABYLON {
                 }
 
                 samplersList.push("shadowSampler" + lightIndex);
+                samplersList.push("depthSampler" + lightIndex);
+
                 if (defines["PROJECTEDLIGHTTEXTURE" + lightIndex]){
                     samplersList.push("projectionLightSampler" + lightIndex,);
                     uniformsList.push(
@@ -387,6 +393,14 @@ module BABYLON {
                         fallbacks.addFallback(rank, "SHADOWPCF" + lightIndex);
                     }
 
+                    if (defines["SHADOWPCSS" + lightIndex]) {
+                        fallbacks.addFallback(rank, "SHADOWPCSS" + lightIndex);
+                    }
+
+                    if (defines["SHADOWPOISSON" + lightIndex]) {
+                        fallbacks.addFallback(rank, "SHADOWPOISSON" + lightIndex);
+                    }
+
                     if (defines["SHADOWESM" + lightIndex]) {
                         fallbacks.addFallback(rank, "SHADOWESM" + lightIndex);
                     }

+ 229 - 72
src/Math/babylon.math.ts

@@ -148,7 +148,7 @@
         /**
          * Multiplies in place each rgb value by scale 
          * @param scale defines the scaling factor
-         * @returns the updated Color3.  
+         * @returns the updated Color3 
          */
         public scale(scale: number): Color3 {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
@@ -158,7 +158,7 @@
          * Multiplies the rgb values by scale and stores the result into "result"
          * @param scale defines the scaling factor 
          * @param result defines the Color3 object where to store the result
-         * @returns the unmodified current Color3.  
+         * @returns the unmodified current Color3 
          */
         public scaleToRef(scale: number, result: Color3): Color3 {
             result.r = this.r * scale;
@@ -168,6 +168,19 @@
         }
 
         /**
+         * Scale the current Color3 values by a factor and add the result to a given Color3  
+         * @param scale defines the scale factor
+         * @param result defines color to store the result into
+         * @returns the unmodified current Color3 
+         */
+        public scaleAndAddToRef(scale: number, result: Color3): Color3 {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            return this;
+        }          
+
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -553,7 +566,7 @@
          * Multiplies the current Color4 values by scale and stores the result in "result"
          * @param scale defines the scaling factor to apply
          * @param result defines the Color4 object where to store the result
-         * @returns the current Color4.  
+         * @returns the current unmodified Color4
          */
         public scaleToRef(scale: number, result: Color4): Color4 {
             result.r = this.r * scale;
@@ -564,6 +577,20 @@
         }
 
         /**
+         * Scale the current Color4 values by a factor and add the result to a given Color4  
+         * @param scale defines the scale factor
+         * @param result defines the Color4 object where to store the result
+         * @returns the unmodified current Color4 
+         */
+        public scaleAndAddToRef(scale: number, result: Color4): Color4 {
+            result.r += this.r * scale;
+            result.g += this.g * scale;
+            result.b += this.b * scale;
+            result.a += this.a * scale;
+            return this;
+        }          
+
+        /**
          * Clamps the rgb values by the min and max values and stores the result into "result"
          * @param min defines minimum clamping value (default is 0)
          * @param max defines maximum clamping value (default is 1)
@@ -1026,12 +1053,40 @@
             this.y *= scale;
             return this;
         }
+
         /**
          * Returns a new Vector2 scaled by "scale" from the current Vector2.  
          */
         public scale(scale: number): Vector2 {
-            return new Vector2(this.x * scale, this.y * scale);
+            let result = new Vector2(0, 0);
+            this.scaleToRef(scale, result);
+            return result;
         }
+
+        /**
+         * Scale the current Vector2 values by a factor to a given Vector2  
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2 
+         */
+        public scaleToRef(scale: number, result: Vector2): Vector2 {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            return this;
+        }         
+
+        /**
+         * Scale the current Vector2 values by a factor and add the result to a given Vector2  
+         * @param scale defines the scale factor
+         * @param result defines the Vector2 object where to store the result
+         * @returns the unmodified current Vector2 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector2): Vector2 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            return this;
+        } 
+
         /**
          * Boolean : True if the passed vector coordinates strictly equal the current Vector2 ones.  
          */
@@ -1515,6 +1570,19 @@
         }
 
         /**
+         * Scale the current Vector3 values by a factor and add the result to a given Vector3  
+         * @param scale defines the scale factor
+         * @param result defines the Vector3 object where to store the result
+         * @returns the unmodified current Vector3 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector3): Vector3 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            return this;
+        }         
+
+        /**
          * Returns true if the current Vector3 and the passed vector coordinates are strictly equal
          * @param otherVector defines the second operand
          * @returns true if both vectors are equals
@@ -2554,6 +2622,20 @@
         }
 
         /**
+         * Scale the current Vector4 values by a factor and add the result to a given Vector4  
+         * @param scale defines the scale factor
+         * @param result defines the Vector4 object where to store the result
+         * @returns the unmodified current Vector4 
+         */
+        public scaleAndAddToRef(scale: number, result: Vector4): Vector4 {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        }         
+
+        /**
          * Boolean : True if the current Vector4 coordinates are stricly equal to the passed ones.  
          */
         public equals(otherVector: Vector4): boolean {
@@ -3088,6 +3170,35 @@
         public scale(value: number): Quaternion {
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         }
+
+        /**
+         * Scale the current Quaternion values by a factor to a given Quaternion  
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion 
+         */
+        public scaleToRef(scale: number, result: Quaternion): Quaternion {
+            result.x = this.x * scale;
+            result.y = this.y * scale;
+            result.z = this.z * scale;
+            result.w = this.w * scale;
+            return this;
+        }         
+
+        /**
+         * Scale the current Quaternion values by a factor and add the result to a given Quaternion  
+         * @param scale defines the scale factor
+         * @param result defines the Quaternion object where to store the result
+         * @returns the unmodified current Quaternion 
+         */
+        public scaleAndAddToRef(scale: number, result: Quaternion): Quaternion {
+            result.x += this.x * scale;
+            result.y += this.y * scale;
+            result.z += this.z * scale;
+            result.w += this.w * scale;
+            return this;
+        }            
+
         /**
          * Returns a new Quaternion set as the quaternion mulplication result of the current one with the passed one "q1".  
          */
@@ -3159,8 +3270,11 @@
             this.w *= length;
             return this;
         }
+
         /**
-         * Returns a new Vector3 set with the Euler angles translated from the current Quaternion.  
+         * Returns a new Vector3 set with the Euler angles translated from the current Quaternion
+         * @param order is a reserved parameter and is ignore for now
+         * @returns the new Vector3
          */
         public toEulerAngles(order = "YZX"): Vector3 {
             var result = Vector3.Zero();
@@ -3169,8 +3283,10 @@
         }
 
         /**
-         * Sets the passed vector3 "result" with the Euler angles translated from the current Quaternion.  
-         * Returns the current Quaternion.  
+         * Sets the passed vector3 "result" with the Euler angles translated from the current Quaternion
+         * @param result defines the vector which will be filled with the Euler angles
+         * @param order is a reserved parameter and is ignore for now
+         * @returns the current Quaternion
          */
         public toEulerAnglesToRef(result: Vector3, order = "YZX"): Quaternion {
 
@@ -3894,6 +4010,111 @@
         }
 
         /**
+         * Returns the index-th row of the current matrix as a new Vector4.  
+         */
+        public getRow(index: number): Nullable<Vector4> {
+            if (index < 0 || index > 3) {
+                return null;
+            }
+            var i = index * 4;
+            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
+        }
+
+        /**
+         * Sets the index-th row of the current matrix with the passed Vector4 values.
+         * Returns the updated Matrix.    
+         */
+        public setRow(index: number, row: Vector4): Matrix {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = row.x;
+            this.m[i + 1] = row.y;
+            this.m[i + 2] = row.z;
+            this.m[i + 3] = row.w;
+
+            this._markAsUpdated();
+
+            return this;
+        }
+
+        /**
+         * Compute the transpose of the matrix.  
+         * Returns a new Matrix.  
+         */
+        public transpose(): Matrix {
+            return Matrix.Transpose(this);
+        }
+
+        /**
+         * Compute the transpose of the matrix.  
+         * Returns the current matrix.  
+         */
+        public transposeToRef(result: Matrix): Matrix {
+            Matrix.TransposeToRef(this, result);
+
+            return this;
+        }
+
+        /**
+         * Sets the index-th row of the current matrix with the passed 4 x float values.
+         * Returns the updated Matrix.    
+         */
+        public setRowFromFloats(index: number, x: number, y: number, z: number, w: number): Matrix {
+            if (index < 0 || index > 3) {
+                return this;
+            }
+            var i = index * 4;
+            this.m[i + 0] = x;
+            this.m[i + 1] = y;
+            this.m[i + 2] = z;
+            this.m[i + 3] = w;
+
+            this._markAsUpdated();
+            return this;
+        }
+
+        /**
+         * Compute a new Matrix set with the current Matrix values multiplied by scale (float)
+         * @param scale defines the scale factor
+         * @returns a new Matrix
+         */
+        public scale(scale: number): Matrix {
+            var result = new Matrix();
+            this.scaleToRef(scale, result);
+            return result;
+        }
+
+        /**
+         * Scale the current Matrix values by a factor to a given result Matrix  
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix  
+         */
+        public scaleToRef(scale: number, result: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] = this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        }          
+        
+        /**
+         * Scale the current Matrix values by a factor and add the result to a given Matrix  
+         * @param scale defines the scale factor
+         * @param result defines the Matrix to store the result
+         * @returns the current Matrix  
+         */
+        public scaleAndAddToRef(scale: number, result: Matrix): Matrix {
+            for (var index = 0; index < 16; index++) {
+                result.m[index] += this.m[index] * scale;
+            }
+            result._markAsUpdated();
+            return this;
+        }          
+
+        /**
          * Writes to the given matrix a normal matrix, computed from this one (using values from identity matrix for fourth row and column).  
          * @param ref matrix to store the result
          */
@@ -3999,71 +4220,7 @@
             result.m[15] = initialM44;
 
             result._markAsUpdated();
-        }
-        /**
-         * Returns the index-th row of the current matrix as a new Vector4.  
-         */
-        public getRow(index: number): Nullable<Vector4> {
-            if (index < 0 || index > 3) {
-                return null;
-            }
-            var i = index * 4;
-            return new Vector4(this.m[i + 0], this.m[i + 1], this.m[i + 2], this.m[i + 3]);
-        }
-        /**
-         * Sets the index-th row of the current matrix with the passed Vector4 values.
-         * Returns the updated Matrix.    
-         */
-        public setRow(index: number, row: Vector4): Matrix {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = row.x;
-            this.m[i + 1] = row.y;
-            this.m[i + 2] = row.z;
-            this.m[i + 3] = row.w;
-
-            this._markAsUpdated();
-
-            return this;
-        }
-
-        /**
-         * Compute the transpose of the matrix.  
-         * Returns a new Matrix.  
-         */
-        public transpose(): Matrix {
-            return Matrix.Transpose(this);
-        }
-
-        /**
-         * Compute the transpose of the matrix.  
-         * Returns the current matrix.  
-         */
-        public transposeToRef(result: Matrix): Matrix {
-            Matrix.TransposeToRef(this, result);
-
-            return this;
-        }
-
-        /**
-         * Sets the index-th row of the current matrix with the passed 4 x float values.
-         * Returns the updated Matrix.    
-         */
-        public setRowFromFloats(index: number, x: number, y: number, z: number, w: number): Matrix {
-            if (index < 0 || index > 3) {
-                return this;
-            }
-            var i = index * 4;
-            this.m[i + 0] = x;
-            this.m[i + 1] = y;
-            this.m[i + 2] = z;
-            this.m[i + 3] = w;
-
-            this._markAsUpdated();
-            return this;
-        }
+        }    
 
         /**
          * Static identity matrix to be used as readonly matrix

+ 2 - 2
src/Mesh/babylon.meshBuilder.ts

@@ -798,12 +798,12 @@
 
                 vertexData.applyToMesh(ground, updatable);
 
-                ground._setReady(true);
-
                 //execute ready callback, if set
                 if (onReady) {
                     onReady(ground);
                 }
+
+                ground._setReady(true);
             };
 
             Tools.LoadImage(url, onload, () => { }, scene.database);

+ 96 - 84
src/Shaders/ShadersInclude/lightFragment.fx

@@ -2,91 +2,103 @@
     #if defined(SHADOWONLY) || (defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X}) && defined(LIGHTMAPNOSPECULAR{X}))
         //No light calculation
     #else
-		#ifdef PBR
-			#ifdef SPOTLIGHT{X}
-				info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
-			#endif
-			#ifdef HEMILIGHT{X}
-				info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightGround, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
-			#endif
-			#if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
-				info = computeLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
-			#endif
-		#else
-			#ifdef SPOTLIGHT{X}
-				info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, glossiness);
-			#endif
-			#ifdef HEMILIGHT{X}
-				info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightGround, glossiness);
-			#endif
-			#if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
-				info = computeLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, glossiness);
-			#endif
-		#endif
-		#ifdef PROJECTEDLIGHTTEXTURE{X}
-			info.diffuse *= computeProjectionTextureDiffuseLighting(projectionLightSampler{X}, textureProjectionMatrix{X});
-		#endif
+        #ifdef PBR
+            #ifdef SPOTLIGHT{X}
+                info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
+            #endif
+            #ifdef HEMILIGHT{X}
+                info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightGround, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
+            #endif
+            #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
+                info = computeLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, roughness, NdotV, specularEnvironmentR0, specularEnvironmentR90, NdotL);
+            #endif
+        #else
+            #ifdef SPOTLIGHT{X}
+                info = computeSpotLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDirection, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, glossiness);
+            #endif
+            #ifdef HEMILIGHT{X}
+                info = computeHemisphericLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightGround, glossiness);
+            #endif
+            #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
+                info = computeLighting(viewDirectionW, normalW, light{X}.vLightData, light{X}.vLightDiffuse.rgb, light{X}.vLightSpecular, light{X}.vLightDiffuse.a, glossiness);
+            #endif
+        #endif
+        #ifdef PROJECTEDLIGHTTEXTURE{X}
+            info.diffuse *= computeProjectionTextureDiffuseLighting(projectionLightSampler{X}, textureProjectionMatrix{X});
+        #endif
     #endif
-	#ifdef SHADOW{X}
-		#ifdef SHADOWCLOSEESM{X}
-			#if defined(SHADOWCUBE{X})
-				shadow = computeShadowWithCloseESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
-			#else
-				shadow = computeShadowWithCloseESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
-			#endif
-		#else
-			#ifdef SHADOWESM{X}
-				#if defined(SHADOWCUBE{X})
-					shadow = computeShadowWithESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
-				#else
-					shadow = computeShadowWithESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
-				#endif
-			#else	
-				#ifdef SHADOWPCF{X}
-					#if defined(SHADOWCUBE{X})
-						shadow = computeShadowWithPCFCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.depthValues);
-					#else
-						shadow = computeShadowWithPCF(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-					#endif
-				#else
-					#if defined(SHADOWCUBE{X})
-						shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
-					#else
-						shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-					#endif
-				#endif
-			#endif
-		#endif
+    #ifdef SHADOW{X}
+        #ifdef SHADOWCLOSEESM{X}
+            #if defined(SHADOWCUBE{X})
+                shadow = computeShadowWithCloseESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
+            #else
+                shadow = computeShadowWithCloseESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
+            #endif
+        #elif defined(SHADOWESM{X})
+            #if defined(SHADOWCUBE{X})
+                shadow = computeShadowWithESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
+            #else
+                shadow = computeShadowWithESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
+            #endif
+        #elif defined(SHADOWPOISSON{X})
+            #if defined(SHADOWCUBE{X})
+                shadow = computeShadowWithPoissonSamplingCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.depthValues);
+            #else
+                shadow = computeShadowWithPoissonSampling(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #endif
+        #elif defined(SHADOWPCF{X})
+            #if defined(SHADOWLOWQUALITY{X})
+                shadow = computeShadowWithPCF1(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #elif defined(SHADOWMEDIUMQUALITY{X})
+                shadow = computeShadowWithPCF3(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #else
+                shadow = computeShadowWithPCF5(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #endif
+        #elif defined(SHADOWPCSS{X})
+            #if defined(SHADOWLOWQUALITY{X})
+                shadow = computeShadowWithPCSS16(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #elif defined(SHADOWMEDIUMQUALITY{X})
+                shadow = computeShadowWithPCSS32(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #else
+                shadow = computeShadowWithPCSS64(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #endif
+        #else
+            #if defined(SHADOWCUBE{X})
+                shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
+            #else
+                shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #endif
+        #endif
 
-		#ifdef SHADOWONLY
-			#ifndef SHADOWINUSE
-				#define SHADOWINUSE
-			#endif
-			globalShadow += shadow;
-			shadowLightCount += 1.0;
-		#endif
-	#else
-		shadow = 1.;
-	#endif
+        #ifdef SHADOWONLY
+            #ifndef SHADOWINUSE
+                #define SHADOWINUSE
+            #endif
+            globalShadow += shadow;
+            shadowLightCount += 1.0;
+        #endif
+    #else
+        shadow = 1.;
+    #endif
 
-	#ifndef SHADOWONLY
-		#ifdef CUSTOMUSERLIGHTING
-			diffuseBase += computeCustomDiffuseLighting(info, diffuseBase, shadow);
-			#ifdef SPECULARTERM
-				specularBase += computeCustomSpecularLighting(info, specularBase, shadow);
-			#endif
-		#elif defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})
-			diffuseBase += lightmapColor * shadow;
-			#ifdef SPECULARTERM
-				#ifndef LIGHTMAPNOSPECULAR{X}
-					specularBase += info.specular * shadow * lightmapColor;
-				#endif
-			#endif
-		#else
-			diffuseBase += info.diffuse * shadow;
-			#ifdef SPECULARTERM
-				specularBase += info.specular * shadow;
-			#endif
-		#endif
-	#endif
+    #ifndef SHADOWONLY
+        #ifdef CUSTOMUSERLIGHTING
+            diffuseBase += computeCustomDiffuseLighting(info, diffuseBase, shadow);
+            #ifdef SPECULARTERM
+                specularBase += computeCustomSpecularLighting(info, specularBase, shadow);
+            #endif
+        #elif defined(LIGHTMAP) && defined(LIGHTMAPEXCLUDED{X})
+            diffuseBase += lightmapColor * shadow;
+            #ifdef SPECULARTERM
+                #ifndef LIGHTMAPNOSPECULAR{X}
+                    specularBase += info.specular * shadow * lightmapColor;
+                #endif
+            #endif
+        #else
+            diffuseBase += info.diffuse * shadow;
+            #ifdef SPECULARTERM
+                specularBase += info.specular * shadow;
+            #endif
+        #endif
+    #endif
 #endif

+ 8 - 1
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -13,7 +13,14 @@
 			varying vec4 vPositionFromLight{X};
 			varying float vDepthMetric{X};
 
-			uniform sampler2D shadowSampler{X};
+			#if defined(SHADOWPCSS{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+				uniform highp sampler2D depthSampler{X};
+			#elif defined(SHADOWPCF{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+			#else
+				uniform sampler2D shadowSampler{X};
+			#endif
 			uniform mat4 lightMatrix{X};
 		#endif
 		uniform vec4 shadowsInfo{X};

+ 9 - 2
src/Shaders/ShadersInclude/lightUboDeclaration.fx

@@ -19,12 +19,19 @@
 #endif
 #ifdef SHADOW{X}
 	#if defined(SHADOWCUBE{X})
-		uniform samplerCube shadowSampler{X};
+		uniform samplerCube shadowSampler{X};		
 	#else
 		varying vec4 vPositionFromLight{X};
 		varying float vDepthMetric{X};
 
-		uniform sampler2D shadowSampler{X};
+		#if defined(SHADOWPCSS{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+				uniform highp sampler2D depthSampler{X};
+		#elif defined(SHADOWPCF{X})
+			uniform highp sampler2DShadow shadowSampler{X};
+		#else
+			uniform sampler2D shadowSampler{X};
+		#endif
 		uniform mat4 lightMatrix{X};
 	#endif
 #endif

+ 522 - 214
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -1,216 +1,524 @@
 #ifdef SHADOWS
-	#ifndef SHADOWFLOAT
-		float unpack(vec4 color)
-		{
-			const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
-			return dot(color, bit_shift);
-		}
-	#endif
-
-	float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, vec2 depthValues)
-	{
-		vec3 directionToLight = vPositionW - lightPosition;
-		float depth = length(directionToLight);
-		depth = (depth + depthValues.x) / (depthValues.y);
-		depth = clamp(depth, 0., 1.0);
-
-		directionToLight = normalize(directionToLight);
-		directionToLight.y = -directionToLight.y;
-		
-		#ifndef SHADOWFLOAT
-			float shadow = unpack(textureCube(shadowSampler, directionToLight));
-		#else
-			float shadow = textureCube(shadowSampler, directionToLight).x;
-		#endif
-
-		if (depth > shadow)
-		{
-			return darkness;
-		}
-		return 1.0;
-	}
-
-	float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness, vec2 depthValues)
-	{
-		vec3 directionToLight = vPositionW - lightPosition;
-		float depth = length(directionToLight);
-		depth = (depth + depthValues.x) / (depthValues.y);
-		depth = clamp(depth, 0., 1.0);
-
-		directionToLight = normalize(directionToLight);
-		directionToLight.y = -directionToLight.y;
-
-		float visibility = 1.;
-
-		vec3 poissonDisk[4];
-		poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
-		poissonDisk[1] = vec3(1.0, -1.0, -1.0);
-		poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
-		poissonDisk[3] = vec3(1.0, -1.0, 1.0);
-
-		// Poisson Sampling
-
-		#ifndef SHADOWFLOAT
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
-			if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
-		#else
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
-			if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
-		#endif
-
-		return  min(1.0, visibility + darkness);
-	}
-
-	float computeShadowWithESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
-	{
-		vec3 directionToLight = vPositionW - lightPosition;
-		float depth = length(directionToLight);
-		depth = (depth + depthValues.x) / (depthValues.y);
-		float shadowPixelDepth = clamp(depth, 0., 1.0);
-
-		directionToLight = normalize(directionToLight);
-		directionToLight.y = -directionToLight.y;
-		
-		#ifndef SHADOWFLOAT
-			float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
-		#else
-			float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
-		#endif
-
-		float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);	
-		return esm;
-	}
-
-	float computeShadowWithCloseESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
-	{
-		vec3 directionToLight = vPositionW - lightPosition;
-		float depth = length(directionToLight);
-		depth = (depth + depthValues.x) / (depthValues.y);
-		float shadowPixelDepth = clamp(depth, 0., 1.0);
-
-		directionToLight = normalize(directionToLight);
-		directionToLight.y = -directionToLight.y;
-		
-		#ifndef SHADOWFLOAT
-			float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
-		#else
-			float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
-		#endif
-
-		float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
-
-		return esm;
-	}
-
-	float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
-	{
-		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
-		vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
-
-		if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-		{
-			return 1.0;
-		}
-
-		float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
-
-		#ifndef SHADOWFLOAT
-			float shadow = unpack(texture2D(shadowSampler, uv));
-		#else
-			float shadow = texture2D(shadowSampler, uv).x;
-		#endif
-
-		if (shadowPixelDepth > shadow)
-		{
-			return computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff);
-		}
-		return 1.;
-	}
-
-	float computeShadowWithPCF(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float mapSize, float darkness, float frustumEdgeFalloff)
-	{
-		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
-		vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
-
-		if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-		{
-			return 1.0;
-		}
-
-		float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
-
-		float visibility = 1.;
-
-		vec2 poissonDisk[4];
-		poissonDisk[0] = vec2(-0.94201624, -0.39906216);
-		poissonDisk[1] = vec2(0.94558609, -0.76890725);
-		poissonDisk[2] = vec2(-0.094184101, -0.92938870);
-		poissonDisk[3] = vec2(0.34495938, 0.29387760);
-
-		// Poisson Sampling
-
-		#ifndef SHADOWFLOAT
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
-			if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
-		#else
-			if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
-			if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
-		#endif
-
-		return computeFallOff(min(1.0, visibility + darkness), clipSpace.xy, frustumEdgeFalloff);
-	}
-
-	float computeShadowWithESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
-	{
-		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
-		vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
-
-		if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-		{
-			return 1.0;
-		}
-
-		float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
-
-		#ifndef SHADOWFLOAT
-			float shadowMapSample = unpack(texture2D(shadowSampler, uv));
-		#else
-			float shadowMapSample = texture2D(shadowSampler, uv).x;
-		#endif
-		
-		float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
-
-		return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
-	}
-
-	float computeShadowWithCloseESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
-	{
-		vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
-		vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
-
-		if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
-		{
-			return 1.0;
-		}
-
-		float shadowPixelDepth = clamp(depthMetric, 0., 1.0);		
-		
-		#ifndef SHADOWFLOAT
-			float shadowMapSample = unpack(texture2D(shadowSampler, uv));
-		#else
-			float shadowMapSample = texture2D(shadowSampler, uv).x;
-		#endif
-		
-		float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
-
-		return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
-	}
+    #ifndef SHADOWFLOAT
+        float unpack(vec4 color)
+        {
+            const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+            return dot(color, bit_shift);
+        }
+    #endif
+
+    float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, vec2 depthValues)
+    {
+        vec3 directionToLight = vPositionW - lightPosition;
+        float depth = length(directionToLight);
+        depth = (depth + depthValues.x) / (depthValues.y);
+        depth = clamp(depth, 0., 1.0);
+
+        directionToLight = normalize(directionToLight);
+        directionToLight.y = -directionToLight.y;
+        
+        #ifndef SHADOWFLOAT
+            float shadow = unpack(textureCube(shadowSampler, directionToLight));
+        #else
+            float shadow = textureCube(shadowSampler, directionToLight).x;
+        #endif
+
+        if (depth > shadow)
+        {
+            return darkness;
+        }
+        return 1.0;
+    }
+
+    float computeShadowWithPoissonSamplingCube(vec3 lightPosition, samplerCube shadowSampler, float mapSize, float darkness, vec2 depthValues)
+    {
+        vec3 directionToLight = vPositionW - lightPosition;
+        float depth = length(directionToLight);
+        depth = (depth + depthValues.x) / (depthValues.y);
+        depth = clamp(depth, 0., 1.0);
+
+        directionToLight = normalize(directionToLight);
+        directionToLight.y = -directionToLight.y;
+
+        float visibility = 1.;
+
+        vec3 poissonDisk[4];
+        poissonDisk[0] = vec3(-1.0, 1.0, -1.0);
+        poissonDisk[1] = vec3(1.0, -1.0, -1.0);
+        poissonDisk[2] = vec3(-1.0, -1.0, -1.0);
+        poissonDisk[3] = vec3(1.0, -1.0, 1.0);
+
+        // Poisson Sampling
+
+        #ifndef SHADOWFLOAT
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize)) < depth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize)) < depth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize)) < depth) visibility -= 0.25;
+            if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize)) < depth) visibility -= 0.25;
+        #else
+            if (textureCube(shadowSampler, directionToLight + poissonDisk[0] * mapSize).x < depth) visibility -= 0.25;
+            if (textureCube(shadowSampler, directionToLight + poissonDisk[1] * mapSize).x < depth) visibility -= 0.25;
+            if (textureCube(shadowSampler, directionToLight + poissonDisk[2] * mapSize).x < depth) visibility -= 0.25;
+            if (textureCube(shadowSampler, directionToLight + poissonDisk[3] * mapSize).x < depth) visibility -= 0.25;
+        #endif
+
+        return  min(1.0, visibility + darkness);
+    }
+
+    float computeShadowWithESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
+    {
+        vec3 directionToLight = vPositionW - lightPosition;
+        float depth = length(directionToLight);
+        depth = (depth + depthValues.x) / (depthValues.y);
+        float shadowPixelDepth = clamp(depth, 0., 1.0);
+
+        directionToLight = normalize(directionToLight);
+        directionToLight.y = -directionToLight.y;
+        
+        #ifndef SHADOWFLOAT
+            float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
+        #else
+            float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
+        #endif
+
+        float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);	
+        return esm;
+    }
+
+    float computeShadowWithCloseESMCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float depthScale, vec2 depthValues)
+    {
+        vec3 directionToLight = vPositionW - lightPosition;
+        float depth = length(directionToLight);
+        depth = (depth + depthValues.x) / (depthValues.y);
+        float shadowPixelDepth = clamp(depth, 0., 1.0);
+
+        directionToLight = normalize(directionToLight);
+        directionToLight.y = -directionToLight.y;
+        
+        #ifndef SHADOWFLOAT
+            float shadowMapSample = unpack(textureCube(shadowSampler, directionToLight));
+        #else
+            float shadowMapSample = textureCube(shadowSampler, directionToLight).x;
+        #endif
+
+        float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
+
+        return esm;
+    }
+
+    float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
+    {
+        vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+        vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
+
+        if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+        {
+            return 1.0;
+        }
+
+        float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
+
+        #ifndef SHADOWFLOAT
+            float shadow = unpack(texture2D(shadowSampler, uv));
+        #else
+            float shadow = texture2D(shadowSampler, uv).x;
+        #endif
+
+        if (shadowPixelDepth > shadow)
+        {
+            return computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff);
+        }
+        return 1.;
+    }
+
+    float computeShadowWithPoissonSampling(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float mapSize, float darkness, float frustumEdgeFalloff)
+    {
+        vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+        vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
+
+        if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+        {
+            return 1.0;
+        }
+
+        float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
+
+        float visibility = 1.;
+
+        vec2 poissonDisk[4];
+        poissonDisk[0] = vec2(-0.94201624, -0.39906216);
+        poissonDisk[1] = vec2(0.94558609, -0.76890725);
+        poissonDisk[2] = vec2(-0.094184101, -0.92938870);
+        poissonDisk[3] = vec2(0.34495938, 0.29387760);
+
+        // Poisson Sampling
+
+        #ifndef SHADOWFLOAT
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
+            if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] * mapSize)) < shadowPixelDepth) visibility -= 0.25;
+        #else
+            if (texture2D(shadowSampler, uv + poissonDisk[0] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
+            if (texture2D(shadowSampler, uv + poissonDisk[1] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
+            if (texture2D(shadowSampler, uv + poissonDisk[2] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
+            if (texture2D(shadowSampler, uv + poissonDisk[3] * mapSize).x < shadowPixelDepth) visibility -= 0.25;
+        #endif
+
+        return computeFallOff(min(1.0, visibility + darkness), clipSpace.xy, frustumEdgeFalloff);
+    }
+
+    float computeShadowWithESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
+    {
+        vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+        vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
+
+        if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+        {
+            return 1.0;
+        }
+
+        float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
+
+        #ifndef SHADOWFLOAT
+            float shadowMapSample = unpack(texture2D(shadowSampler, uv));
+        #else
+            float shadowMapSample = texture2D(shadowSampler, uv).x;
+        #endif
+        
+        float esm = 1.0 - clamp(exp(min(87., depthScale * shadowPixelDepth)) * shadowMapSample, 0., 1. - darkness);
+
+        return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
+    }
+
+    float computeShadowWithCloseESM(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float depthScale, float frustumEdgeFalloff)
+    {
+        vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+        vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
+
+        if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+        {
+            return 1.0;
+        }
+
+        float shadowPixelDepth = clamp(depthMetric, 0., 1.0);		
+        
+        #ifndef SHADOWFLOAT
+            float shadowMapSample = unpack(texture2D(shadowSampler, uv));
+        #else
+            float shadowMapSample = texture2D(shadowSampler, uv).x;
+        #endif
+        
+        float esm = clamp(exp(min(87., -depthScale * (shadowPixelDepth - shadowMapSample))), darkness, 1.);
+
+        return computeFallOff(esm, clipSpace.xy, frustumEdgeFalloff);
+    }
+
+    #ifdef WEBGL2
+        // Shadow PCF kernel size 1 with a single tap (lowest quality)
+        float computeShadowWithPCF1(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
+        {
+            if (depthMetric > 1.0 || depthMetric < 0.0) {
+                return 1.0;
+            }
+
+            vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+            vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+
+            float shadow = texture2D(shadowSampler, uvDepth);
+            shadow = mix(darkness, 1., shadow);
+            return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
+        }
+
+        // Shadow PCF kernel 3*3 in only 4 taps (medium quality)
+        // This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
+        // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
+        float computeShadowWithPCF3(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
+        {
+            if (depthMetric > 1.0 || depthMetric < 0.0) {
+                return 1.0;
+            }
+
+            vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+            vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+
+            vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x;	// uv in texel units
+            uv += 0.5;											// offset of half to be in the center of the texel
+            vec2 st = fract(uv);								// how far from the center
+            vec2 base_uv = floor(uv) - 0.5;						// texel coord
+            base_uv *= shadowMapSizeAndInverse.y;				// move back to uv coords
+
+            // Equation resolved to fit in a 3*3 distribution like 
+            // 1 2 1
+            // 2 4 2 
+            // 1 2 1
+            vec2 uvw0 = 3. - 2. * st;
+            vec2 uvw1 = 1. + 2. * st;
+            vec2 u = vec2((2. - st.x) / uvw0.x - 1., st.x / uvw1.x + 1.) * shadowMapSizeAndInverse.y;
+            vec2 v = vec2((2. - st.y) / uvw0.y - 1., st.y / uvw1.y + 1.) * shadowMapSizeAndInverse.y;
+
+            float shadow = 0.;
+            shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
+            shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
+            shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
+            shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
+            shadow = shadow / 16.;
+
+            shadow = mix(darkness, 1., shadow);
+            return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
+        }
+        
+        // Shadow PCF kernel 5*5 in only 9 taps (high quality)
+        // This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
+        // https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
+        float computeShadowWithPCF5(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
+        {
+            if (depthMetric > 1.0 || depthMetric < 0.0) {
+                return 1.0;
+            }
+
+            vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+            vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+
+            vec2 uv = uvDepth.xy * shadowMapSizeAndInverse.x;	// uv in texel units
+            uv += 0.5;											// offset of half to be in the center of the texel
+            vec2 st = fract(uv);								// how far from the center
+            vec2 base_uv = floor(uv) - 0.5;						// texel coord
+            base_uv *= shadowMapSizeAndInverse.y;				// move back to uv coords
+
+            // Equation resolved to fit in a 5*5 distribution like 
+            // 1 2 4 2 1
+            vec2 uvw0 = 4. - 3. * st;
+            vec2 uvw1 = vec2(7.);
+            vec2 uvw2 = 1. + 3. * st;
+
+            vec3 u = vec3((3. - 2. * st.x) / uvw0.x - 2., (3. + st.x) / uvw1.x, st.x / uvw2.x + 2.) * shadowMapSizeAndInverse.y;
+            vec3 v = vec3((3. - 2. * st.y) / uvw0.y - 2., (3. + st.y) / uvw1.y, st.y / uvw2.y + 2.) * shadowMapSizeAndInverse.y;
+
+            float shadow = 0.;
+            shadow += uvw0.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[0]), uvDepth.z));
+            shadow += uvw1.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[0]), uvDepth.z));
+            shadow += uvw2.x * uvw0.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[0]), uvDepth.z));
+            shadow += uvw0.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[1]), uvDepth.z));
+            shadow += uvw1.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[1]), uvDepth.z));
+            shadow += uvw2.x * uvw1.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[1]), uvDepth.z));
+            shadow += uvw0.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[0], v[2]), uvDepth.z));
+            shadow += uvw1.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[1], v[2]), uvDepth.z));
+            shadow += uvw2.x * uvw2.y * texture2D(shadowSampler, vec3(base_uv.xy + vec2(u[2], v[2]), uvDepth.z));
+            shadow = shadow / 144.;
+
+            shadow = mix(darkness, 1., shadow);
+            return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
+        }
+
+        const vec3 PoissonSamplers32[64] = vec3[64](
+            vec3(0.06407013, 0.05409927, 0.),
+            vec3(0.7366577, 0.5789394, 0.),
+            vec3(-0.6270542, -0.5320278, 0.),
+            vec3(-0.4096107, 0.8411095, 0.),
+            vec3(0.6849564, -0.4990818, 0.),
+            vec3(-0.874181, -0.04579735, 0.),
+            vec3(0.9989998, 0.0009880066, 0.),
+            vec3(-0.004920578, -0.9151649, 0.),
+            vec3(0.1805763, 0.9747483, 0.),
+            vec3(-0.2138451, 0.2635818, 0.),
+            vec3(0.109845, 0.3884785, 0.),
+            vec3(0.06876755, -0.3581074, 0.),
+            vec3(0.374073, -0.7661266, 0.),
+            vec3(0.3079132, -0.1216763, 0.),
+            vec3(-0.3794335, -0.8271583, 0.),
+            vec3(-0.203878, -0.07715034, 0.),
+            vec3(0.5912697, 0.1469799, 0.),
+            vec3(-0.88069, 0.3031784, 0.),
+            vec3(0.5040108, 0.8283722, 0.),
+            vec3(-0.5844124, 0.5494877, 0.),
+            vec3(0.6017799, -0.1726654, 0.),
+            vec3(-0.5554981, 0.1559997, 0.),
+            vec3(-0.3016369, -0.3900928, 0.),
+            vec3(-0.5550632, -0.1723762, 0.),
+            vec3(0.925029, 0.2995041, 0.),
+            vec3(-0.2473137, 0.5538505, 0.),
+            vec3(0.9183037, -0.2862392, 0.),
+            vec3(0.2469421, 0.6718712, 0.),
+            vec3(0.3916397, -0.4328209, 0.),
+            vec3(-0.03576927, -0.6220032, 0.),
+            vec3(-0.04661255, 0.7995201, 0.),
+            vec3(0.4402924, 0.3640312, 0.),
+
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.),
+            vec3(0., 0., 0.)
+        );
+
+        const vec3 PoissonSamplers64[64] = vec3[64](
+            vec3(-0.613392, 0.617481, 0.),
+            vec3(0.170019, -0.040254, 0.),
+            vec3(-0.299417, 0.791925, 0.),
+            vec3(0.645680, 0.493210, 0.),
+            vec3(-0.651784, 0.717887, 0.),
+            vec3(0.421003, 0.027070, 0.),
+            vec3(-0.817194, -0.271096, 0.),
+            vec3(-0.705374, -0.668203, 0.),
+            vec3(0.977050, -0.108615, 0.),
+            vec3(0.063326, 0.142369, 0.),
+            vec3(0.203528, 0.214331, 0.),
+            vec3(-0.667531, 0.326090, 0.),
+            vec3(-0.098422, -0.295755, 0.),
+            vec3(-0.885922, 0.215369, 0.),
+            vec3(0.566637, 0.605213, 0.),
+            vec3(0.039766, -0.396100, 0.),
+            vec3(0.751946, 0.453352, 0.),
+            vec3(0.078707, -0.715323, 0.),
+            vec3(-0.075838, -0.529344, 0.),
+            vec3(0.724479, -0.580798, 0.),
+            vec3(0.222999, -0.215125, 0.),
+            vec3(-0.467574, -0.405438, 0.),
+            vec3(-0.248268, -0.814753, 0.),
+            vec3(0.354411, -0.887570, 0.),
+            vec3(0.175817, 0.382366, 0.),
+            vec3(0.487472, -0.063082, 0.),
+            vec3(-0.084078, 0.898312, 0.),
+            vec3(0.488876, -0.783441, 0.),
+            vec3(0.470016, 0.217933, 0.),
+            vec3(-0.696890, -0.549791, 0.),
+            vec3(-0.149693, 0.605762, 0.),
+            vec3(0.034211, 0.979980, 0.),
+            vec3(0.503098, -0.308878, 0.),
+            vec3(-0.016205, -0.872921, 0.),
+            vec3(0.385784, -0.393902, 0.),
+            vec3(-0.146886, -0.859249, 0.),
+            vec3(0.643361, 0.164098, 0.),
+            vec3(0.634388, -0.049471, 0.),
+            vec3(-0.688894, 0.007843, 0.),
+            vec3(0.464034, -0.188818, 0.),
+            vec3(-0.440840, 0.137486, 0.),
+            vec3(0.364483, 0.511704, 0.),
+            vec3(0.034028, 0.325968, 0.),
+            vec3(0.099094, -0.308023, 0.),
+            vec3(0.693960, -0.366253, 0.),
+            vec3(0.678884, -0.204688, 0.),
+            vec3(0.001801, 0.780328, 0.),
+            vec3(0.145177, -0.898984, 0.),
+            vec3(0.062655, -0.611866, 0.),
+            vec3(0.315226, -0.604297, 0.),
+            vec3(-0.780145, 0.486251, 0.),
+            vec3(-0.371868, 0.882138, 0.),
+            vec3(0.200476, 0.494430, 0.),
+            vec3(-0.494552, -0.711051, 0.),
+            vec3(0.612476, 0.705252, 0.),
+            vec3(-0.578845, -0.768792, 0.),
+            vec3(-0.772454, -0.090976, 0.),
+            vec3(0.504440, 0.372295, 0.),
+            vec3(0.155736, 0.065157, 0.),
+            vec3(0.391522, 0.849605, 0.),
+            vec3(-0.620106, -0.328104, 0.),
+            vec3(0.789239, -0.419965, 0.),
+            vec3(-0.545396, 0.538133, 0.),
+            vec3(-0.178564, -0.596057, 0.)
+        );
+
+        // PCSS
+        // This helps to achieve a contact hardening effect on the shadow
+        // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
+        // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
+        // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
+        float computeShadowWithPCSS(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers)
+        {
+            if (depthMetric > 1.0 || depthMetric < 0.0) {
+                return 1.0;
+            }
+
+            vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+            vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+
+            float blockerDepth = 0.0;
+            float sumBlockerDepth = 0.0;
+            float numBlocker = 0.0;
+            for (int i = 0; i < searchTapCount; i ++) {
+                blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy)).r;
+                if (blockerDepth < depthMetric) {
+                    sumBlockerDepth += blockerDepth;
+                    numBlocker++;
+                }
+            }
+
+            if (numBlocker < 1.0) {
+                return 1.0;
+            }
+            float avgBlockerDepth = sumBlockerDepth / numBlocker;
+
+            // Offset preventing aliasing on contact.
+            float AAOffset = shadowMapSizeInverse * 10.;
+            // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
+            // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
+            float penumbraRatio = ((depthMetric - avgBlockerDepth) + AAOffset);
+            float filterRadius = penumbraRatio * lightSizeUV * shadowMapSizeInverse;
+
+            float random = getRand(vPositionFromLight.xy);
+            float rotationAngle = random * 3.1415926;
+            vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
+
+            float shadow = 0.;
+            for (int i = 0; i < pcfTapCount; i++) {
+                vec3 offset = poissonSamplers[i];
+                // Rotated offset.
+                offset = vec3(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0.);
+                shadow += texture2D(shadowSampler, uvDepth + offset * filterRadius);
+            }
+            shadow /= float(pcfTapCount);
+
+            // Blocker distance falloff
+            shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
+
+            // Apply darkness
+            shadow = mix(darkness, 1., shadow);
+
+            // Apply light frustrum fallof
+            return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
+        }
+
+        float computeShadowWithPCSS16(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
+        }
+
+        float computeShadowWithPCSS32(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
+        }
+
+        float computeShadowWithPCSS64(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
+        }
+    #endif
 #endif

+ 1 - 1
src/Shaders/ShadersInclude/shadowsVertex.fx

@@ -1,6 +1,6 @@
 #ifdef SHADOWS
 	#if defined(SHADOW{X}) && !defined(SHADOWCUBE{X})
 		vPositionFromLight{X} = lightMatrix{X} * worldPos;
-		vDepthMetric{X} =  ((vPositionFromLight{X}.z + light{X}.depthValues.x) / (light{X}.depthValues.y));
+		vDepthMetric{X} = ((vPositionFromLight{X}.z + light{X}.depthValues.x) / (light{X}.depthValues.y));
 	#endif
 #endif

+ 5 - 1
src/Shaders/pbr.fragment.fx

@@ -602,7 +602,11 @@ void main(void) {
 #endif
 
 #ifdef LIGHTMAP
-	vec3 lightmapColor = toLinearSpace(texture2D(lightmapSampler, vLightmapUV + uvOffset).rgb) * vLightmapInfos.y;
+	vec3 lightmapColor = texture2D(lightmapSampler, vLightmapUV + uvOffset).rgb);
+	#ifdef GAMMALIGHTMAP
+		lightmapColor = toLinearSpace(lightmapColor);
+	#endif
+	lightmapColor *= vLightmapInfos.y
 #endif
 
 	lightingInfo info;

+ 12 - 12
src/Shaders/shadowMap.fragment.fx

@@ -1,13 +1,13 @@
 #ifndef FLOAT
 vec4 pack(float depth)
 {
-	const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
-	const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
+    const vec4 bit_shift = vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0);
+    const vec4 bit_mask = vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0);
 
-	vec4 res = fract(depth * bit_shift);
-	res -= res.xxyz * bit_mask;
+    vec4 res = fract(depth * bit_shift);
+    res -= res.xxyz * bit_mask;
 
-	return res;
+    return res;
 }
 #endif
 
@@ -18,25 +18,25 @@ varying vec2 vUV;
 uniform sampler2D diffuseSampler;
 #endif
 
-uniform vec2 biasAndScale;
+uniform vec3 biasAndScale;
 uniform vec2 depthValues;
 
 void main(void)
 {
 #ifdef ALPHATEST
-	if (texture2D(diffuseSampler, vUV).a < 0.4)
-		discard;
+    if (texture2D(diffuseSampler, vUV).a < 0.4)
+        discard;
 #endif
 
-	float depth = vDepthMetric;
+    float depth = vDepthMetric;
 
 #ifdef ESM
-	depth = clamp(exp(-min(87., biasAndScale.y * depth)), 0., 1.);
+    depth = clamp(exp(-min(87., biasAndScale.z * depth)), 0., 1.);
 #endif
 
 #ifdef FLOAT
-	gl_FragColor = vec4(depth, 1.0, 1.0, 1.0);
+    gl_FragColor = vec4(depth, 1.0, 1.0, 1.0);
 #else
-	gl_FragColor = pack(depth);
+    gl_FragColor = pack(depth);
 #endif
 }

+ 47 - 8
src/Shaders/shadowMap.vertex.fx

@@ -1,13 +1,19 @@
 // Attribute
 attribute vec3 position;
 
+#ifdef NORMAL
+    attribute vec3 normal;
+    uniform vec3 lightData;
+#endif
+
 #include<bonesDeclaration>
 
 // Uniforms
 #include<instancesDeclaration>
+#include<helperFunctions>
 
 uniform mat4 viewProjection;
-uniform vec2 biasAndScale;
+uniform vec3 biasAndScale;
 uniform vec2 depthValues;
 
 varying float vDepthMetric;
@@ -29,15 +35,48 @@ void main(void)
 #include<bonesVertex>
 
 vec4 worldPos = finalWorld * vec4(position, 1.0);
+
+// Normal inset Bias.
+#ifdef NORMAL
+    mat3 normalWorld = mat3(finalWorld);
+
+    #ifdef NONUNIFORMSCALING
+        normalWorld = transposeMat3(inverseMat3(normalWorld));
+    #endif
+
+    vec3 worldNor = normalize(normalWorld * normal);
+
+    #ifdef DIRECTIONINLIGHTDATA
+        vec3 worldLightDir = normalize(-lightData.xyz);
+    #else
+        vec3 directionToLight = lightData.xyz - worldPos.xyz;
+        vec3 worldLightDir = normalize(directionToLight);
+    #endif
+
+    float ndl = dot(worldNor, worldLightDir);
+    float sinNL = sqrt(1.0 - ndl * ndl);
+    float normalBias = biasAndScale.y * sinNL;
+
+    worldPos.xyz -= worldNor * normalBias;
+#endif
+
+// Projection.
 gl_Position = viewProjection * worldPos;
-vDepthMetric = ((gl_Position.z + depthValues.x) / (depthValues.y)) + biasAndScale.x;
+
+#ifdef DEPTHTEXTURE
+    // Depth texture Linear bias.
+    gl_Position.z += biasAndScale.x * gl_Position.w;
+#endif
+
+    // Color Texture Linear bias.
+    vDepthMetric = ((gl_Position.z + depthValues.x) / (depthValues.y)) + biasAndScale.x;
 
 #ifdef ALPHATEST
-	#ifdef UV1
-		vUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
-	#endif
-	#ifdef UV2
-		vUV = vec2(diffuseMatrix * vec4(uv2, 1.0, 0.0));
-	#endif
+    #ifdef UV1
+        vUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
+    #endif
+    #ifdef UV2
+        vUV = vec2(diffuseMatrix * vec4(uv2, 1.0, 0.0));
+    #endif
 #endif
 }

+ 1 - 1
src/babylon.node.ts

@@ -477,10 +477,10 @@
                 return;
             }
 
-            this._isReady = true;
             if (this.onReady) {
                 this.onReady(this);
             }
+            this._isReady = true;
         }
 
         /**

+ 125 - 27
src/babylon.scene.ts

@@ -467,6 +467,7 @@
 
         // Animations
         public animations: Animation[] = [];
+        private _registeredForLateAnimationBindings = new SmartArrayNoDuplicate<any>(256);
 
         // Pointers
         public pointerDownPredicate: (Mesh: AbstractMesh) => boolean;
@@ -477,11 +478,11 @@
         private _onPointerUp: (evt: PointerEvent) => void;
 
         /** Deprecated. Use onPointerObservable instead */
-        public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo) => void;
+        public onPointerMove: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
         /** Deprecated. Use onPointerObservable instead */
-        public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
+        public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo, type: PointerEventTypes) => void;
         /** Deprecated. Use onPointerObservable instead */
-        public onPointerUp: (evt: PointerEvent, pickInfo: Nullable<PickingInfo>) => void;
+        public onPointerUp: (evt: PointerEvent, pickInfo: Nullable<PickingInfo>, type: PointerEventTypes) => void;
         /** Deprecated. Use onPointerObservable instead */
         public onPointerPick: (evt: PointerEvent, pickInfo: PickingInfo) => void;
 
@@ -1278,12 +1279,13 @@
             }
 
             if (pickResult) {
+                let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
+
                 if (this.onPointerMove) {
-                    this.onPointerMove(evt, pickResult);
+                    this.onPointerMove(evt, pickResult, type);
                 }
 
                 if (this.onPointerObservable.hasObservers()) {
-                    let type = evt.type === "mousewheel" || evt.type === "DOMMouseScroll" ? PointerEventTypes.POINTERWHEEL : PointerEventTypes.POINTERMOVE;
                     let pi = new PointerInfo(type, evt, pickResult);
                     this.onPointerObservable.notifyObservers(pi, type);
                 }
@@ -1345,12 +1347,13 @@
             }
 
             if (pickResult) {
+                let type = PointerEventTypes.POINTERDOWN;
+
                 if (this.onPointerDown) {
-                    this.onPointerDown(evt, pickResult);
+                    this.onPointerDown(evt, pickResult, type);
                 }
 
                 if (this.onPointerObservable.hasObservers()) {
-                    let type = PointerEventTypes.POINTERDOWN;
                     let pi = new PointerInfo(type, evt, pickResult);
                     this.onPointerObservable.notifyObservers(pi, type);
                 }
@@ -1406,10 +1409,7 @@
                 this._pickedDownMesh.actionManager.processTrigger(ActionManager.OnPickOutTrigger, ActionEvent.CreateNew(this._pickedDownMesh, evt));
             }
 
-            if (this.onPointerUp) {
-                this.onPointerUp(evt, pickResult);
-            }
-
+            let type = PointerEventTypes.POINTERUP;
             if (this.onPointerObservable.hasObservers()) {
                 if (!clickInfo.ignore) {
                     if (!clickInfo.hasSwiped) {
@@ -1426,12 +1426,15 @@
                     }
                 }
                 else {
-                    let type = PointerEventTypes.POINTERUP;
                     let pi = new PointerInfo(type, evt, pickResult);
                     this.onPointerObservable.notifyObservers(pi, type);
                 }
             }
 
+            if (this.onPointerUp) {
+                this.onPointerUp(evt, pickResult, type);
+            }
+
             return this;
         }
 
@@ -2064,25 +2067,49 @@
         }
 
         // Animations
+
         /**
          * Will start the animation sequence of a given target
-         * @param target - the target
-         * @param {number} from - from which frame should animation start
-         * @param {number} to - till which frame should animation run.
-         * @param {boolean} [loop] - should the animation loop
-         * @param {number} [speedRatio] - the speed in which to run the animation
-         * @param {Function} [onAnimationEnd] function to be executed when the animation ended.
-         * @param {BABYLON.Animatable} [animatable] an animatable object. If not provided a new one will be created from the given params.
-         * Returns {BABYLON.Animatable} the animatable object created for this animation
-         * See BABYLON.Animatable
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param weight defines the weight to apply to the animation (1.0 by default)
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
+         */
+        public beginWeightedAnimation(target: any, from: number, to: number, weight = 1.0, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
+            let returnedAnimatable = this.beginAnimation(target, from, to, loop, speedRatio, onAnimationEnd, animatable, false);
+            returnedAnimatable.weight = weight;
+
+            return returnedAnimatable;
+        }
+
+        /**
+         * Will start the animation sequence of a given target
+         * @param target defines the target
+         * @param from defines from which frame should animation start
+         * @param to defines until which frame should animation run.
+         * @param loop defines if the animation loops
+         * @param speedRatio defines the speed in which to run the animation (1.0 by default)
+         * @param onAnimationEnd defines the function to be executed when the animation ends
+         * @param animatable defines an animatable object. If not provided a new one will be created from the given params
+         * @param stopCurrent defines if the current animations must be stopped first (true by default)
+         * @returns the animatable object created for this animation
+         * @see BABYLON.Animatable
          */
-        public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable): Animatable {
+        public beginAnimation(target: any, from: number, to: number, loop?: boolean, speedRatio: number = 1.0, onAnimationEnd?: () => void, animatable?: Animatable, stopCurrent = true): Animatable {
 
             if (from > to && speedRatio > 0) {
                 speedRatio *= -1;
             }
 
-            this.stopAnimation(target);
+            if (stopCurrent) {
+                this.stopAnimation(target);
+            }
 
             if (!animatable) {
                 animatable = new Animatable(this, target, from, to, loop, speedRatio, onAnimationEnd);
@@ -2097,11 +2124,13 @@
             if (target.getAnimatables) {
                 var animatables = target.getAnimatables();
                 for (var index = 0; index < animatables.length; index++) {
-                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable);
+                    this.beginAnimation(animatables[index], from, to, loop, speedRatio, onAnimationEnd, animatable, stopCurrent);
                 }
             }
 
-            animatable.reset();
+            if (stopCurrent) {
+                animatable.reset();
+            }
 
             return animatable;
         }
@@ -2193,7 +2222,7 @@
             if (!this.animationsEnabled || this._activeAnimatables.length === 0) {
                 return;
             }
-
+           
             // Getting time
             var now = Tools.Now;
             if (!this._animationTimeLast) {
@@ -2208,6 +2237,74 @@
             for (var index = 0; index < this._activeAnimatables.length; index++) {
                 this._activeAnimatables[index]._animate(this._animationTime);
             }
+
+            // Late animation bindings
+            this._processLateAnimationBindings();
+        }
+
+        /** @ignore */
+        public _registerTargetForLateAnimationBinding(runtimeAnimation: RuntimeAnimation): void {
+            let target = runtimeAnimation.target;
+            this._registeredForLateAnimationBindings.pushNoDuplicate(target);
+
+            if (!target._lateAnimationHolders) {
+                target._lateAnimationHolders = {};               
+            }
+
+            if (!target._lateAnimationHolders[runtimeAnimation.targetPath]) {
+                target._lateAnimationHolders[runtimeAnimation.targetPath] = {
+                    totalWeight: 0,
+                    animations: []
+                }
+            }
+
+            target._lateAnimationHolders[runtimeAnimation.targetPath].animations.push(runtimeAnimation);
+            target._lateAnimationHolders[runtimeAnimation.targetPath].totalWeight += runtimeAnimation.weight;
+        }
+
+        private _processLateAnimationBindings(): void {
+            if (!this._registeredForLateAnimationBindings.length) {
+                return;
+            }
+            for (var index = 0; index < this._registeredForLateAnimationBindings.length; index++) {
+                var target = this._registeredForLateAnimationBindings.data[index];
+
+                for (var path in target._lateAnimationHolders) {
+                    var holder = target._lateAnimationHolders[path];       
+                    
+                    // Sanity check
+                    if (!holder.animations[0].originalValue.scaleAndAddToRef) {
+                        continue;
+                    }
+
+                    let normalizer = 1.0;
+                    let finalValue: any;
+
+                    if (holder.totalWeight < 1.0) {
+                        // We need to mix the original value in
+                        let originalValue = holder.animations[0].originalValue;                       
+
+                        finalValue = originalValue.scale(1.0 - holder.totalWeight)
+                    } else {
+                        // We need to normalize the weights
+                        normalizer = holder.totalWeight;
+                    }
+
+                    for (var animIndex = 0; animIndex < holder.animations.length; animIndex++) {
+                        var runtimeAnimation = holder.animations[animIndex];    
+                        if (finalValue) {
+                            runtimeAnimation.currentValue.scaleAndAddToRef(runtimeAnimation.weight / normalizer, finalValue);
+                        } else {
+                            finalValue = runtimeAnimation.currentValue.scale(runtimeAnimation.weight / normalizer);
+                        }
+                    }
+
+                    runtimeAnimation.target[path] = finalValue;
+                }
+
+                target._lateAnimationHolders = {};
+            }
+            this._registeredForLateAnimationBindings.reset();
         }
 
         // Matrix
@@ -3240,7 +3337,7 @@
             if (!this.activeCamera) {
                 return this;
             }
-            
+
             if (!this._frustumPlanes) {
                 this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix());
             }
@@ -4147,6 +4244,7 @@
             this._activeSkeletons.dispose();
             this._softwareSkinnedMeshes.dispose();
             this._renderTargets.dispose();
+            this._registeredForLateAnimationBindings.dispose();
 
             if (this._boundingBoxRenderer) {
                 this._boundingBoxRenderer.dispose();

+ 36 - 0
tests/unit/babylon/src/Loading/babylon.sceneLoader.tests.ts

@@ -286,6 +286,42 @@ describe('Babylon Scene Loader', function () {
             return Promise.all(promises);
         });
 
+        it('Load MultiPrimitive', () => {
+            const scene = new BABYLON.Scene(subject);
+            return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/MultiPrimitive/", "MultiPrimitive.gltf", scene).then(result => {
+                expect(result.meshes, "meshes").to.have.lengthOf(4);
+
+                const node = scene.getMeshByName("node");
+                expect(node, "node").to.exist;
+                expect(node, "node").to.be.an.instanceof(BABYLON.Mesh);
+
+                const mesh = node as BABYLON.Mesh;
+                expect(mesh.geometry).to.not.exist;
+                expect(mesh.material).to.not.exist;
+
+                expect(mesh.getChildren(), "mesh children").to.have.lengthOf(2);
+                for (const childNode of mesh.getChildren()) {
+                    expect(childNode, "child node").to.be.an.instanceof(BABYLON.Mesh);
+                    const childMesh = childNode as BABYLON.Mesh;
+                    expect(childMesh.geometry).to.exist;
+                    expect(childMesh.material).to.exist;
+                }
+            });
+        });
+
+        it('Load BrainStem', () => {
+            const scene = new BABYLON.Scene(subject);
+            return BABYLON.SceneLoader.ImportMeshAsync(null, "/Playground/scenes/BrainStem/", "BrainStem.gltf", scene).then(result => {
+                expect(result.skeletons, "skeletons").to.have.lengthOf(1);
+
+                const node1 = scene.getMeshByName("node1");
+                for (const childMesh of node1.getChildMeshes()) {
+                    expect(childMesh.skeleton, "mesh skeleton").to.exist;
+                    expect(childMesh.skeleton.name, "mesh skeleton name").to.equal(result.skeletons[0].name);
+                }
+            });
+        });
+
         // TODO: test animation group callback
         // TODO: test material instancing
         // TODO: test ImportMesh with specific node name

BIN
tests/validation/ReferenceImages/instances.png


BIN
tests/validation/ReferenceImages/pbrglossy.png


BIN
tests/validation/ReferenceImages/pbrrough.png


BIN
tests/validation/ReferenceImages/procedural.png


BIN
tests/validation/ReferenceImages/selfShadowing.png


BIN
tests/validation/ReferenceImages/softShadows.png


+ 1 - 1
tests/validation/config.json

@@ -386,7 +386,7 @@
     },
     {
       "title": "Instances",
-      "renderCount": 2,
+      "renderCount": 50,
       "scriptToRun": "/Demos/Instances/instances.js",
       "functionToCall": "CreateInstancesTestScene",
       "referenceImage": "instances.png",