Jelajahi Sumber

Merge branch 'master' into glTFLoader-refactor

Gary Hsu 7 tahun lalu
induk
melakukan
6e30c0103c
99 mengubah file dengan 27492 tambahan dan 24906 penghapusan
  1. 10821 10533
      Playground/babylon.d.txt
  2. 53 1
      Tools/Gulp/config.json
  3. 50 23
      Viewer/src/viewer/viewer.ts
  4. 10492 10205
      dist/preview release/babylon.d.ts
  5. 47 47
      dist/preview release/babylon.js
  6. 665 267
      dist/preview release/babylon.max.js
  7. 47 47
      dist/preview release/babylon.worker.js
  8. 1798 1511
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  9. 49 49
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  10. 667 269
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  11. 667 269
      dist/preview release/customConfigurations/minimalGLTFViewer/es6.js
  12. 665 267
      dist/preview release/es6.js
  13. 2 2
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  14. 1 1
      dist/preview release/materialsLibrary/babylon.cellMaterial.min.js
  15. 2 2
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  16. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  17. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  18. 1 1
      dist/preview release/materialsLibrary/babylon.fireMaterial.min.js
  19. 2 2
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  20. 1 1
      dist/preview release/materialsLibrary/babylon.furMaterial.min.js
  21. 2 2
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  22. 1 1
      dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js
  23. 1 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.js
  24. 1 1
      dist/preview release/materialsLibrary/babylon.gridMaterial.min.js
  25. 2 2
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  26. 1 1
      dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js
  27. 2 2
      dist/preview release/materialsLibrary/babylon.normalMaterial.js
  28. 1 1
      dist/preview release/materialsLibrary/babylon.normalMaterial.min.js
  29. 2 2
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  30. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  31. 2 2
      dist/preview release/materialsLibrary/babylon.simpleMaterial.js
  32. 1 1
      dist/preview release/materialsLibrary/babylon.simpleMaterial.min.js
  33. 1 1
      dist/preview release/materialsLibrary/babylon.skyMaterial.js
  34. 1 1
      dist/preview release/materialsLibrary/babylon.skyMaterial.min.js
  35. 2 2
      dist/preview release/materialsLibrary/babylon.terrainMaterial.js
  36. 1 1
      dist/preview release/materialsLibrary/babylon.terrainMaterial.min.js
  37. 2 2
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js
  38. 1 1
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.min.js
  39. 2 2
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  40. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  41. 25 25
      dist/preview release/materialsLibrary/babylonjs.materials.js
  42. 6 6
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  43. 59 972
      dist/preview release/typedocValidationBaseline.json
  44. 61 61
      dist/preview release/viewer/babylon.viewer.js
  45. 5 0
      dist/preview release/what's new.md
  46. 2 2
      materialsLibrary/src/cell/babylon.cellMaterial.ts
  47. 2 2
      materialsLibrary/src/custom/babylon.customMaterial.ts
  48. 1 1
      materialsLibrary/src/fire/babylon.fireMaterial.ts
  49. 2 2
      materialsLibrary/src/fur/babylon.furMaterial.ts
  50. 2 2
      materialsLibrary/src/gradient/babylon.gradientMaterial.ts
  51. 1 1
      materialsLibrary/src/grid/babylon.gridmaterial.ts
  52. 2 2
      materialsLibrary/src/lava/babylon.lavaMaterial.ts
  53. 2 2
      materialsLibrary/src/normal/babylon.normalMaterial.ts
  54. 2 2
      materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts
  55. 2 2
      materialsLibrary/src/simple/babylon.simpleMaterial.ts
  56. 1 1
      materialsLibrary/src/sky/babylon.skyMaterial.ts
  57. 2 2
      materialsLibrary/src/terrain/babylon.terrainMaterial.ts
  58. 2 2
      materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts
  59. 2 2
      materialsLibrary/src/water/babylon.waterMaterial.ts
  60. 11 0
      src/Engine/babylon.engine.ts
  61. 64 3
      src/Lights/babylon.light.ts
  62. 71 2
      src/Lights/babylon.spotLight.ts
  63. 2 2
      src/Materials/Background/babylon.backgroundMaterial.ts
  64. 3 3
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  65. 4 4
      src/Materials/PBR/babylon.pbrMaterial.ts
  66. 1 1
      src/Materials/Textures/babylon.baseTexture.ts
  67. 109 108
      src/Materials/babylon.effect.ts
  68. 1 1
      src/Materials/babylon.fresnelParameters.ts
  69. 26 2
      src/Materials/babylon.material.ts
  70. 27 9
      src/Materials/babylon.materialHelper.ts
  71. 5 5
      src/Materials/babylon.standardMaterial.ts
  72. 311 100
      src/Math/babylon.math.ts
  73. 19 1
      src/Mesh/babylon.abstractMesh.ts
  74. 15 2
      src/Particles/babylon.boxParticleEmitter.ts
  75. 13 1
      src/Particles/babylon.coneParticleEmitter.ts
  76. 6 0
      src/Particles/babylon.iParticleEmitterType.ts
  77. 27 3
      src/Particles/babylon.sphereParticleEmitter.ts
  78. 31 0
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  79. 8 6
      src/PostProcess/babylon.blurPostProcess.ts
  80. 53 0
      src/PostProcess/babylon.circleOfConfusionPostProcess.ts
  81. 40 0
      src/PostProcess/babylon.depthOfFieldBlurPostProcess.ts
  82. 109 0
      src/PostProcess/babylon.depthOfFieldEffect.ts
  83. 26 0
      src/PostProcess/babylon.depthOfFieldMergePostProcess.ts
  84. 12 3
      src/Shaders/ShadersInclude/kernelBlurFragment.fx
  85. 12 3
      src/Shaders/ShadersInclude/kernelBlurFragment2.fx
  86. 3 0
      src/Shaders/ShadersInclude/lightFragment.fx
  87. 4 0
      src/Shaders/ShadersInclude/lightFragmentDeclaration.fx
  88. 4 1
      src/Shaders/ShadersInclude/lightUboDeclaration.fx
  89. 10 5
      src/Shaders/ShadersInclude/lightsFragmentFunctions.fx
  90. 25 0
      src/Shaders/circleOfConfusion.fragment.fx
  91. 15 0
      src/Shaders/depthOfFieldMerge.fragment.fx
  92. 34 5
      src/Shaders/kernelBlur.fragment.fx
  93. 62 2
      src/Tools/babylon.observable.ts
  94. 39 16
      src/Tools/babylon.promise.ts
  95. 11 0
      src/babylon.scene.ts
  96. 27 2
      tests/unit/babylon/promises/babylon.promises.tests.ts
  97. TEMPAT SAMPAH
      tests/validation/ReferenceImages/KernelBlur.png
  98. TEMPAT SAMPAH
      tests/validation/ReferenceImages/depthOfField.png
  99. 11 0
      tests/validation/config.json

File diff ditekan karena terlalu besar
+ 10821 - 10533
Playground/babylon.d.txt


+ 53 - 1
Tools/Gulp/config.json

@@ -57,7 +57,11 @@
             "geometryBufferRenderer",
             "additionalPostProcesses",
             "additionalPostProcess_blur",
+            "additionalPostProcess_depthOfFieldBlur",
             "additionalPostProcess_fxaa",
+            "additionalPostProcess_circleOfConfusion",
+            "additionalPostProcess_depthOfFieldMerge",
+            "additionalPostProcess_depthOfFieldEffect",
             "additionalPostProcess_imageProcessing",
             "bones",
             "hdr",
@@ -722,6 +726,51 @@
                 "kernelBlurVertex"
             ]
         },
+        "additionalPostProcess_depthOfFieldBlur": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldBlurPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "kernelBlur.vertex",
+                "kernelBlur.fragment"
+            ],
+            "shaderIncludes": [
+                "kernelBlurFragment",
+                "kernelBlurFragment2",
+                "kernelBlurVaryingDeclaration",
+                "kernelBlurVertex"
+            ]
+        },
+        "additionalPostProcess_circleOfConfusion": {
+            "files": [
+                "../../src/PostProcess/babylon.circleOfConfusionPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "circleOfConfusion.fragment"
+            ]
+        },
+        "additionalPostProcess_depthOfFieldMerge": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldMergePostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "depthOfFieldMerge.fragment"
+            ]
+        },
+        "additionalPostProcess_depthOfFieldEffect": {
+            "files": [
+                "../../src/PostProcess/babylon.depthOfFieldEffect.js"
+            ]
+        },
         "additionalPostProcess_fxaa": {
             "files": [
                 "../../src/PostProcess/babylon.fxaaPostProcess.js"
@@ -827,7 +876,10 @@
             ],
             "dependUpon": [
                 "renderingPipeline",
-                "additionalPostProcess_fxaa"
+                "additionalPostProcess_fxaa",
+                "additionalPostProcess_circleOfConfusion",
+                "additionalPostProcess_depthOfFieldMerge",
+                "additionalPostProcess_depthOfFieldEffect"
             ]
         },
         "bones": {

+ 50 - 23
Viewer/src/viewer/viewer.ts

@@ -1,7 +1,7 @@
 import { viewerManager } from './viewerManager';
 import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
-import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database } from 'babylonjs';
+import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight, Database, SceneLoaderProgressEvent, ISceneLoaderPlugin, ISceneLoaderPluginAsync } from 'babylonjs';
 import { ViewerConfiguration } from '../configuration/configuration';
 import { PromiseObservable } from '../util/promiseObservable';
 
@@ -13,14 +13,24 @@ export abstract class AbstractViewer {
     public scene: Scene;
     public baseId: string;
 
+    /**
+     * The last loader used to load a model. 
+     * 
+     * @type {(ISceneLoaderPlugin | ISceneLoaderPluginAsync)}
+     * @memberof AbstractViewer
+     */
+    public lastUsedLoader: ISceneLoaderPlugin | ISceneLoaderPluginAsync;
+
     protected configuration: ViewerConfiguration;
 
     // observables
     public onSceneInitObservable: PromiseObservable<Scene>;
     public onEngineInitObservable: PromiseObservable<Engine>;
     public onModelLoadedObservable: PromiseObservable<AbstractMesh[]>;
+    public onModelLoadProgressObservable: PromiseObservable<SceneLoaderProgressEvent>;
+    public onInitDoneObservable: PromiseObservable<AbstractViewer>;
 
-    private canvas: HTMLCanvasElement;
+    protected canvas: HTMLCanvasElement;
 
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
@@ -33,6 +43,8 @@ export abstract class AbstractViewer {
         this.onSceneInitObservable = new PromiseObservable();
         this.onEngineInitObservable = new PromiseObservable();
         this.onModelLoadedObservable = new PromiseObservable();
+        this.onModelLoadProgressObservable = new PromiseObservable();
+        this.onInitDoneObservable = new PromiseObservable();
 
         // add this viewer to the viewer manager
         viewerManager.addViewer(this);
@@ -68,7 +80,7 @@ export abstract class AbstractViewer {
                 if (canvas) {
                     this.canvas = canvas;
                 }
-                this.onTemplatesLoaded();
+                this._onTemplateLoaded();
             });
         });
 
@@ -114,16 +126,33 @@ export abstract class AbstractViewer {
      * @memberof AbstractViewer
      */
     protected onTemplatesLoaded(): Promise<AbstractViewer> {
-        let autoLoadModel = !!this.configuration.model;
-        return this.initEngine().then(() => {
-            if (autoLoadModel) {
-                return this.loadModel();
-            } else {
-                return this.scene || this.initScene();
-            }
-        }).then(() => {
-            return this;
-        });
+        return Promise.resolve(this);
+    }
+
+    /**
+     * This will force the creation of an engine and a scene.
+     * It will also load a model if preconfigured.
+     * But first - it will load the extendible onTemplateLoaded()!
+     */
+    private _onTemplateLoaded(): Promise<AbstractViewer> {
+        return this.onTemplatesLoaded().then(() => {
+            let autoLoadModel = !!this.configuration.model;
+            return this.initEngine().then((engine) => {
+                return this.onEngineInitObservable.notifyWithPromise(engine);
+            }).then(() => {
+                if (autoLoadModel) {
+                    return this.loadModel();
+                } else {
+                    return this.scene || this.initScene();
+                }
+            }).then((scene) => {
+                return this.onSceneInitObservable.notifyWithPromise(scene);
+            }).then(() => {
+                return this.onInitDoneObservable.notifyWithPromise(this);
+            }).then(() => {
+                return this;
+            });
+        })
     }
 
     /**
@@ -157,9 +186,7 @@ export abstract class AbstractViewer {
             this.engine.setHardwareScalingLevel(scale);
         }
 
-        return this.onEngineInitObservable.notifyWithPromise(this.engine).then(() => {
-            return this.engine;
-        });
+        return Promise.resolve(this.engine);
     }
 
     protected initScene(): Promise<Scene> {
@@ -176,9 +203,7 @@ export abstract class AbstractViewer {
         if (this.configuration.scene && this.configuration.scene.debug) {
             this.scene.debugLayer.show();
         }
-        return this.onSceneInitObservable.notifyWithPromise(this.scene).then(() => {
-            return this.scene!;
-        });
+        return Promise.resolve(this.scene);
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
@@ -194,12 +219,14 @@ export abstract class AbstractViewer {
             else return this.scene!;
         }).then(() => {
             return new Promise<Array<AbstractMesh>>((resolve, reject) => {
-                SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
+                this.lastUsedLoader = SceneLoader.ImportMesh(undefined, base, filename, this.scene, (meshes) => {
                     resolve(meshes);
-                }, undefined, (e, m, exception) => {
-                    console.log(m, exception);
+                }, (progressEvent) => {
+                    this.onModelLoadProgressObservable.notifyWithPromise(progressEvent);
+                }, (e, m, exception) => {
+                    // console.log(m, exception);
                     reject(m);
-                }, plugin);
+                }, plugin)!;
             });
         }).then((meshes: Array<AbstractMesh>) => {
             return this.onModelLoadedObservable.notifyWithPromise(meshes).then(() => {

File diff ditekan karena terlalu besar
+ 10492 - 10205
dist/preview release/babylon.d.ts


File diff ditekan karena terlalu besar
+ 47 - 47
dist/preview release/babylon.js


File diff ditekan karena terlalu besar
+ 665 - 267
dist/preview release/babylon.max.js


File diff ditekan karena terlalu besar
+ 47 - 47
dist/preview release/babylon.worker.js


File diff ditekan karena terlalu besar
+ 1798 - 1511
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


File diff ditekan karena terlalu besar
+ 49 - 49
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


File diff ditekan karena terlalu besar
+ 667 - 269
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


File diff ditekan karena terlalu besar
+ 667 - 269
dist/preview release/customConfigurations/minimalGLTFViewer/es6.js


File diff ditekan karena terlalu besar
+ 665 - 267
dist/preview release/es6.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.cellMaterial.js

@@ -98,11 +98,11 @@ var BABYLON;
             // High level
             defines.CELLBASIC = !this.computeHighLevel;
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.cellMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -563,11 +563,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


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

@@ -94,7 +94,7 @@ var BABYLON;
                 defines.FOG = (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled);
             }
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.fireMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.furMaterial.js

@@ -143,11 +143,11 @@ var BABYLON;
                 defines.markAsUnprocessed();
             }
             // Misc.   
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.furMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.gradientMaterial.js

@@ -118,8 +118,8 @@ var BABYLON;
                 }
             }
             var engine = scene.getEngine();
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gradientMaterial.min.js


+ 1 - 1
dist/preview release/materialsLibrary/babylon.gridMaterial.js

@@ -110,7 +110,7 @@ var BABYLON;
                 defines.PREMULTIPLYALPHA = !defines.PREMULTIPLYALPHA;
                 defines.markAsUnprocessed();
             }
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, false, defines);
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.gridMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.lavaMaterial.js

@@ -131,11 +131,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.lavaMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.normalMaterial.js

@@ -125,11 +125,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.normalMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js

@@ -86,8 +86,8 @@ var BABYLON;
                     }
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, 1);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.simpleMaterial.js

@@ -92,11 +92,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.simpleMaterial.min.js


+ 1 - 1
dist/preview release/materialsLibrary/babylon.skyMaterial.js

@@ -76,7 +76,7 @@ var BABYLON;
                     return true;
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, false, defines);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, false);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.skyMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.terrainMaterial.js

@@ -98,11 +98,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.terrainMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js

@@ -117,11 +117,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.min.js


+ 2 - 2
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -228,8 +228,8 @@ var BABYLON;
                     }
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             if (defines._areMiscDirty) {
                 if (this._fresnelSeparate) {
                     defines.FRESNELSEPARATE = true;

File diff ditekan karena terlalu besar
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


+ 25 - 25
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -96,8 +96,8 @@ var BABYLON;
                     }
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, 1);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);
@@ -326,8 +326,8 @@ var BABYLON;
                 }
             }
             var engine = scene.getEngine();
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);
@@ -611,11 +611,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -922,11 +922,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -1234,11 +1234,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -1642,8 +1642,8 @@ var BABYLON;
                     }
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             if (defines._areMiscDirty) {
                 if (this._fresnelSeparate) {
                     defines.FRESNELSEPARATE = true;
@@ -2124,7 +2124,7 @@ var BABYLON;
                 defines.FOG = (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled);
             }
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);
             // Get correct effect      
@@ -2494,11 +2494,11 @@ var BABYLON;
                 defines.markAsUnprocessed();
             }
             // Misc.   
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -2911,11 +2911,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -3317,11 +3317,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      
@@ -3658,7 +3658,7 @@ var BABYLON;
                     return true;
                 }
             }
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, false, defines);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, false);
             // Get correct effect      
@@ -3907,7 +3907,7 @@ var BABYLON;
                 defines.PREMULTIPLYALPHA = !defines.PREMULTIPLYALPHA;
                 defines.markAsUnprocessed();
             }
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, false, defines);
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -4559,11 +4559,11 @@ var BABYLON;
                 }
             }
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Get correct effect      
             if (defines.isDirty) {
                 defines.markAsProcessed();
@@ -6149,11 +6149,11 @@ var BABYLON;
             // High level
             defines.CELLBASIC = !this.computeHighLevel;
             // Misc.
-            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            BABYLON.MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
             // Lights
             defines._needNormals = BABYLON.MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
             // Values that need to be evaluated on every frame
-            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            BABYLON.MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
             // Attribs
             BABYLON.MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);
             // Get correct effect      

File diff ditekan karena terlalu besar
+ 6 - 6
dist/preview release/materialsLibrary/babylonjs.materials.min.js


File diff ditekan karena terlalu besar
+ 59 - 972
dist/preview release/typedocValidationBaseline.json


File diff ditekan karena terlalu besar
+ 61 - 61
dist/preview release/viewer/babylon.viewer.js


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

@@ -6,6 +6,8 @@
 - New [AnimationGroup class](http://doc.babylonjs.com/how_to/group) to control simultaneously multiple animations with different targets ([deltakosh](https://github.com/deltakosh))
 - `WebVRCamera` now supports GearVR ([brianzinn](https://github.com/brianzinn))
 - 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 (`spotLight.projectedLightTexture`). ([lostink](https://github.com/lostink))
 
 ## Updates
 - Tons of functions and classes received the code comments they deserved (All the community)
@@ -30,6 +32,9 @@
 - (Viewer) Models can be loaded async using JavaScript ([RaananW](https://github.com/RaananW))
 - VRHelper will notify now onSelectedMeshUnselected observable to subscribers when the applied ray selection predicate does not produce a hit and a mesh compliant with the meshSelectionPredicate was previously selected
    ([carloslanderas](https://github.com/carloslanderas))
+- (Viewer) initScene and initEngine can now be extended. onProgress during model loading is implemented as observable. ([RaananW](https://github.com/RaananW))
+- Added depth of field effect to default pipeline ([trevordev](https://github.com/trevordev))
+- The observable can now notify observers using promise-based callback chain. ([RaananW](https://github.com/RaananW))
 - Added base64 helper functions to `Tools` ([bghgary](https://github.com/bghgary))
 - Added `createDefaultCamera` and `createDefaultLight` functions to `Scene` ([bghgary](https://github.com/bghgary))
 

+ 2 - 2
materialsLibrary/src/cell/babylon.cellMaterial.ts

@@ -110,13 +110,13 @@ module BABYLON {
             defines.CELLBASIC = !this.computeHighLevel;
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/custom/babylon.customMaterial.ts

@@ -719,13 +719,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Get correct effect      
             if (defines.isDirty) {

+ 1 - 1
materialsLibrary/src/fire/babylon.fireMaterial.ts

@@ -107,7 +107,7 @@ module BABYLON {
             }
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true);

+ 2 - 2
materialsLibrary/src/fur/babylon.furMaterial.ts

@@ -181,13 +181,13 @@ module BABYLON {
             }
 
             // Misc.   
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/gradient/babylon.gradientMaterial.ts

@@ -128,9 +128,9 @@ module BABYLON {
 
             var engine = scene.getEngine();
 
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights);
 

+ 1 - 1
materialsLibrary/src/grid/babylon.gridmaterial.ts

@@ -120,7 +120,7 @@ module BABYLON {
                 defines.markAsUnprocessed();
             }
 
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, false, this.fogEnabled, false, defines);
 
             // Get correct effect      
             if (defines.isDirty) {

+ 2 - 2
materialsLibrary/src/lava/babylon.lavaMaterial.ts

@@ -153,13 +153,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/normal/babylon.normalMaterial.ts

@@ -132,13 +132,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/shadowOnly/babylon.shadowOnlyMaterial.ts

@@ -86,9 +86,9 @@ module BABYLON {
                 }
             }
 
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, 1);
 

+ 2 - 2
materialsLibrary/src/simple/babylon.simpleMaterial.ts

@@ -99,13 +99,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 1 - 1
materialsLibrary/src/sky/babylon.skyMaterial.ts

@@ -88,7 +88,7 @@ module BABYLON {
                 }
             }
 
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, false, defines);
             
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, false);

+ 2 - 2
materialsLibrary/src/terrain/babylon.terrainMaterial.ts

@@ -140,13 +140,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/triPlanar/babylon.triPlanarMaterial.ts

@@ -161,13 +161,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Lights
             defines._needNormals = MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, false, this._maxSimultaneousLights, this._disableLighting);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true);

+ 2 - 2
materialsLibrary/src/water/babylon.waterMaterial.ts

@@ -275,9 +275,9 @@ module BABYLON {
                 }
             }
 
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             if (defines._areMiscDirty) {
                 if (this._fresnelSeparate) {

+ 11 - 0
src/Engine/babylon.engine.ts

@@ -5754,6 +5754,17 @@
             return request;
         }
 
+        /** @ignore */
+        public _loadFileAsync(url: string, database?: Database, useArrayBuffer?: boolean): Promise<string | ArrayBuffer> {
+            return new Promise((resolve, reject) => {
+                this._loadFile(url, (data) => {
+                    resolve(data);
+                }, undefined, database, useArrayBuffer, (request, exception) => {
+                    reject(exception);
+                })
+            });
+        }
+
         private _partialLoadFile(url: string, index: number, loadedFiles: (string | ArrayBuffer)[], scene: Nullable<Scene>, onfinish: (files: (string | ArrayBuffer)[]) => void, onErrorCallBack: Nullable<(message?: string, exception?: any) => void> = null): void {
             var onload = (data: string | ArrayBuffer) => {
                 loadedFiles[index] = data;

+ 64 - 3
src/Lights/babylon.light.ts

@@ -1,4 +1,4 @@
-module BABYLON {
+module BABYLON {
     export class Light extends Node {
 
         //lightmapMode Consts
@@ -384,7 +384,59 @@
             }
             return b.renderPriority - a.renderPriority;
         }
+        // Projection texture, if needed
+        protected _computeTextureMatrix(): void{
+            //Leave out for different light type
+        }
+        protected _light_far  :number;
+        @serialize()
+        /**
+         * Allows reading the far clip of the Spotlight for texture projection.
+         */
+        public get light_far(): number {
+            return this._light_far;
+        }
+        /**
+         * Allows setting the far clip of the Spotlight for texture projection.
+         */
+        public set light_far(value: number) {
+            this._light_far = value;
+            this._computeTextureMatrix();
+        }
+
+        protected _light_near :number;
+        @serialize()
+        /**
+         * Allows reading the near clip of the Spotlight for texture projection.
+         */
+        public get light_near(): number {
+            return this._light_near;
+        }
+        /**
+         * Allows setting the near clip of the Spotlight for texture projection.
+         */
+        public set light_near(value: number) {
+            this._light_near = value;
+            this._computeTextureMatrix();
+        }
 
+        @serializeAsTexture("projectedLightTexture")
+        private _projectedLightTexture: Nullable<BaseTexture>;;
+        /** 
+         * Allows reading the projection texture of the light.
+        */
+        public get projectedLightTexture(): Nullable<BaseTexture> {
+            return this._projectedLightTexture;
+        }
+        /**
+        * Allows setting the projection texture of the light.
+        */
+        public set projectedLightTexture(value: Nullable<BaseTexture>) {
+            this._projectedLightTexture = value;
+            this._light_far = 1000.0;
+            this._light_near = 1e-6;
+            this._computeTextureMatrix();
+        }
         /**
          * Disposes the light.  
          */
@@ -397,8 +449,15 @@
             // Animations
             this.getScene().stopAnimation(this);
 
-            this._uniformBuffer.dispose();
+            // Remove from meshes
+            for (var mesh of this.getScene().meshes) {
+                mesh._removeLightSource(this);
+            }
 
+            this._uniformBuffer.dispose();
+            if (this._projectedLightTexture){
+                this._projectedLightTexture.dispose();
+            }
             // Remove from scene
             this.getScene().removeLight(this);
             super.dispose();
@@ -658,7 +717,6 @@
             }
             return photometricScale;
         }
-
         public _reorderLightsInScene(): void {
             var scene = this.getScene();
             if (this._renderPriority != 0) {
@@ -666,5 +724,8 @@
             }
             this.getScene().sortLightsByPriority();
         }
+
+
+
     }
 }

+ 71 - 2
src/Lights/babylon.spotLight.ts

@@ -1,5 +1,55 @@
 module BABYLON {
     export class SpotLight extends ShadowLight {
+        /**
+            upVector , rightVector and direction will form the coordinate system for this spot light. 
+            These three vectors will be used as projection matrix when doing texture projection.
+            
+            Also we have the following rules always holds:
+            direction cross up   = right
+            right cross dirction = up
+            up cross right       = forward
+
+            light_near and light_far will control the range of the texture projection. If a plane is 
+            out of the range in spot light space, there is no texture projection.
+
+            Warning:
+            Change the angle of the Spotlight, direction of the SpotLight will not re-compute the 
+            projection matrix. Need to call computeTextureMatrix() to recompute manually. Add inheritance
+            to the setting function of the 2 attributes will solve the problem.
+        */
+        /**
+         * Main function for light texture projection matrix computing.
+         */
+        protected _computeTextureMatrix(): void{    
+
+            var viewLightMatrix = Matrix.Zero();
+            Matrix.LookAtLHToRef(this.position, this.position.add(this.direction), Vector3.Up(), viewLightMatrix);
+
+            var light_far = this.light_far;
+            var light_near = this.light_near;
+
+            var P = light_far / (light_far - light_near);
+            var Q = - P * light_near;
+            var S = 1.0 / Math.tan(this._angle / 2.0);
+            var A = 1.0;
+            
+            var projectionLightMatrix = Matrix.Zero();
+            Matrix.FromValuesToRef(S/A, 0.0, 0.0, 0.0,
+                0.0, S, 0.0, 0.0,
+                0.0, 0.0, P, 1.0,
+                0.0, 0.0, Q, 0.0, projectionLightMatrix);
+
+            var scaleMatrix = Matrix.Zero();
+            Matrix.FromValuesToRef(0.5, 0.0, 0.0, 0.0,
+                0.0, 0.5, 0.0, 0.0,
+                0.0, 0.0, 0.5, 0.0,
+                0.5, 0.5, 0.5, 1.0, scaleMatrix);
+                
+            this._textureProjectionMatrix.copyFrom(viewLightMatrix);
+            this._textureProjectionMatrix.multiplyToRef(projectionLightMatrix, this._textureProjectionMatrix);
+            this._textureProjectionMatrix.multiplyToRef(scaleMatrix, this._textureProjectionMatrix);
+        }
+
         private _angle: number;
         @serialize()
         public get angle(): number {
@@ -25,10 +75,24 @@
             this._shadowAngleScale = value;
             this.forceProjectionMatrixCompute();
         }
-
         @serialize()
         public exponent: number;
-        
+
+        private _textureProjectionMatrix = Matrix.Zero();
+        @serialize()
+        /**
+        * Allows reading the projecton texture
+        */
+        public get textureMatrix(): Matrix{
+            return this._textureProjectionMatrix;
+        }
+        /**
+        * Allows setting the value of projection texture
+        */
+        public set textureMatrix(value: Matrix) {
+            this._textureProjectionMatrix = value;
+        }
+
         /**
          * Creates a SpotLight object in the scene with the passed parameters :   
          * - `position` (Vector3) is the initial SpotLight position,  
@@ -123,6 +187,11 @@
                 normalizeDirection.z,
                 Math.cos(this.angle * 0.5),
                 lightIndex);
+
+            effect.setMatrix("textureProjectionMatrix" + lightIndex, this._textureProjectionMatrix);
+            if (this.projectedLightTexture){
+                effect.setTexture("projectionLightSampler" + lightIndex, this.projectedLightTexture);
+            }
             return this;
         }
     }

+ 2 - 2
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -696,10 +696,10 @@
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, false, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
 
             // Attribs
             if (MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false)) {

+ 3 - 3
src/Materials/PBR/babylon.pbrBaseMaterial.ts

@@ -537,7 +537,7 @@
 
             this._forceAlphaTest = (value === PBRMaterial.PBRMATERIAL_ALPHATESTANDBLEND);
 
-            this._markAllSubMeshesAsTexturesDirty();
+            this._markAllSubMeshesAsTexturesAndMiscDirty();
         }
 
         /**
@@ -901,10 +901,10 @@
             defines.HORIZONOCCLUSION = this._useHorizonOcclusion;
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest, defines);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false, this._shouldTurnAlphaTestOn(mesh) || this._forceAlphaTest);
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances ? true : false);
 
             // Attribs
             if (MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true, this._transparencyMode !== PBRMaterial.PBRMATERIAL_OPAQUE) && mesh) {

+ 4 - 4
src/Materials/PBR/babylon.pbrMaterial.ts

@@ -101,7 +101,7 @@
         public ambientTextureStrength: number = 1.0;
 
         @serializeAsTexture()
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public opacityTexture: BaseTexture;
 
         @serializeAsTexture()
@@ -225,21 +225,21 @@
          * Specifies that the alpha is coming form the albedo channel alpha channel for alpha blending.
          */
         @serialize()
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public useAlphaFromAlbedoTexture = false;
 
         /**
          * Enforces alpha test in opaque or blend mode in order to improve the performances of some situations.
          */
         @serialize()
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public forceAlphaTest = false;
 
         /**
          * Defines the alpha limits in alpha test mode.
          */
         @serialize()
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public alphaCutOff = 0.4;
 
         /**

+ 1 - 1
src/Materials/Textures/babylon.baseTexture.ts

@@ -13,7 +13,7 @@
             }
             this._hasAlpha = value;
             if (this._scene) {
-                this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag);
+                this._scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag | Material.MiscDirtyFlag);
             }
         }
         public get hasAlpha(): boolean {

+ 109 - 108
src/Materials/babylon.effect.ts

@@ -183,28 +183,32 @@
                 fragmentSource = baseName.fragment || baseName;
             }
 
-            this._loadVertexShader(vertexSource, vertexCode => {
-                this._processIncludes(vertexCode, vertexCodeWithIncludes => {
-                    this._processShaderConversion(vertexCodeWithIncludes, false, migratedVertexCode => {
-                        this._loadFragmentShader(fragmentSource, (fragmentCode) => {
-                            this._processIncludes(fragmentCode, fragmentCodeWithIncludes => {
-                                this._processShaderConversion(fragmentCodeWithIncludes, true, migratedFragmentCode => {
-                                    if (baseName) {
-                                        var vertex = baseName.vertexElement || baseName.vertex || baseName;
-                                        var fragment = baseName.fragmentElement || baseName.fragment || baseName;
-
-                                        this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + migratedVertexCode;
-                                        this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
-                                    } else {
-                                        this._vertexSourceCode = migratedVertexCode;
-                                        this._fragmentSourceCode = migratedFragmentCode;
-                                    }
-                                    this._prepareEffect();
-                                });
-                            });
-                        });
-                    });
-                });
+            let finalVertexCode: string;
+
+            this._loadVertexShaderAsync(vertexSource)
+            .then((vertexCode) => {
+                return this._processIncludesAsync(vertexCode);
+            })
+            .then((vertexCodeWithIncludes) => {
+                finalVertexCode = this._processShaderConversion(vertexCodeWithIncludes, false);
+                return this._loadFragmentShaderAsync(fragmentSource);
+            })
+            .then((fragmentCode) => {
+                return this._processIncludesAsync(fragmentCode);
+            })
+            .then((fragmentCodeWithIncludes) => {
+                let migratedFragmentCode = this._processShaderConversion(fragmentCodeWithIncludes, true);
+                if (baseName) {
+                    var vertex = baseName.vertexElement || baseName.vertex || baseName;
+                    var fragment = baseName.fragmentElement || baseName.fragment || baseName;
+
+                    this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + finalVertexCode;
+                    this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
+                } else {
+                    this._vertexSourceCode = finalVertexCode;
+                    this._fragmentSourceCode = migratedFragmentCode;
+                }
+                this._prepareEffect(); 
             });
         }
 
@@ -271,27 +275,25 @@
             });
         }
 
-        public _loadVertexShader(vertex: any, callback: (data: any) => void): void {
+        /** @ignore */
+        public _loadVertexShaderAsync(vertex: any): Promise<any> {
             if (Tools.IsWindowObjectExist()) {
                 // DOM element ?
                 if (vertex instanceof HTMLElement) {
                     var vertexCode = Tools.GetDOMTextContent(vertex);
-                    callback(vertexCode);
-                    return;
+                    return Promise.resolve(vertexCode);
                 }
             }
 
             // Base64 encoded ?
             if (vertex.substr(0, 7) === "base64:") {
                 var vertexBinary = window.atob(vertex.substr(7));
-                callback(vertexBinary);
-                return;
+                return Promise.resolve(vertexBinary);
             }
 
             // Is in local store ?
             if (Effect.ShadersStore[vertex + "VertexShader"]) {
-                callback(Effect.ShadersStore[vertex + "VertexShader"]);
-                return;
+                return Promise.resolve(Effect.ShadersStore[vertex + "VertexShader"]);
             }
 
             var vertexShaderUrl;
@@ -303,35 +305,32 @@
             }
 
             // Vertex shader
-            this._engine._loadFile(vertexShaderUrl + ".vertex.fx", callback);
+            return this._engine._loadFileAsync(vertexShaderUrl + ".vertex.fx");
         }
 
-        public _loadFragmentShader(fragment: any, callback: (data: any) => void): void {
+        /** @ignore */
+        public _loadFragmentShaderAsync(fragment: any): Promise<any>  {
             if (Tools.IsWindowObjectExist()) {
                 // DOM element ?
                 if (fragment instanceof HTMLElement) {
                     var fragmentCode = Tools.GetDOMTextContent(fragment);
-                    callback(fragmentCode);
-                    return;
+                    return Promise.resolve(fragmentCode);
                 }
             }
 
             // Base64 encoded ?
             if (fragment.substr(0, 7) === "base64:") {
                 var fragmentBinary = window.atob(fragment.substr(7));
-                callback(fragmentBinary);
-                return;
+                return Promise.resolve(fragmentBinary);
             }
 
             // Is in local store ?
             if (Effect.ShadersStore[fragment + "PixelShader"]) {
-                callback(Effect.ShadersStore[fragment + "PixelShader"]);
-                return;
+                return Promise.resolve(Effect.ShadersStore[fragment + "PixelShader"]);
             }
 
             if (Effect.ShadersStore[fragment + "FragmentShader"]) {
-                callback(Effect.ShadersStore[fragment + "FragmentShader"]);
-                return;
+                return Promise.resolve(Effect.ShadersStore[fragment + "FragmentShader"]);
             }
 
             var fragmentShaderUrl;
@@ -343,7 +342,7 @@
             }
 
             // Fragment shader
-            this._engine._loadFile(fragmentShaderUrl + ".fragment.fx", callback);
+            return this._engine._loadFileAsync(fragmentShaderUrl + ".fragment.fx");
         }
 
         private _dumpShadersSource(vertexCode: string, fragmentCode: string, defines: string): void {
@@ -375,19 +374,16 @@
             }
         };
 
-        private _processShaderConversion(sourceCode: string, isFragment: boolean, callback: (data: any) => void): void {
-
+        private _processShaderConversion(sourceCode: string, isFragment: boolean): any {
             var preparedSourceCode = this._processPrecision(sourceCode);
 
             if (this._engine.webGLVersion == 1) {
-                callback(preparedSourceCode);
-                return;
+                return preparedSourceCode;
             }
 
             // Already converted
             if (preparedSourceCode.indexOf("#version 3") !== -1) {
-                callback(preparedSourceCode.replace("#version 300 es", ""));
-                return;
+                return preparedSourceCode.replace("#version 300 es", "");
             }
 
             var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
@@ -416,92 +412,97 @@
                 result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
             }
 
-            callback(result);
+            return result;
         }
 
-        private _processIncludes(sourceCode: string, callback: (data: any) => void): void {
-            var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
-            var match = regex.exec(sourceCode);
+        private _processIncludesAsync(sourceCode: string): Promise<any> {
+            return new Promise((resolve, reject) => {
+                var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
+                var match = regex.exec(sourceCode);
 
-            var returnValue = new String(sourceCode);
+                var returnValue = sourceCode;
 
-            while (match != null) {
-                var includeFile = match[1];
+                while (match != null) {
+                    var includeFile = match[1];
 
-                // Uniform declaration
-                if (includeFile.indexOf("__decl__") !== -1) {
-                    includeFile = includeFile.replace(/__decl__/, "");
-                    if (this._engine.supportsUniformBuffers) {
-                        includeFile = includeFile.replace(/Vertex/, "Ubo");
-                        includeFile = includeFile.replace(/Fragment/, "Ubo");
+                    // Uniform declaration
+                    if (includeFile.indexOf("__decl__") !== -1) {
+                        includeFile = includeFile.replace(/__decl__/, "");
+                        if (this._engine.supportsUniformBuffers) {
+                            includeFile = includeFile.replace(/Vertex/, "Ubo");
+                            includeFile = includeFile.replace(/Fragment/, "Ubo");
+                        }
+                        includeFile = includeFile + "Declaration";
                     }
-                    includeFile = includeFile + "Declaration";
-                }
 
-                if (Effect.IncludesShadersStore[includeFile]) {
-                    // Substitution
-                    var includeContent = Effect.IncludesShadersStore[includeFile];
-                    if (match[2]) {
-                        var splits = match[3].split(",");
+                    if (Effect.IncludesShadersStore[includeFile]) {
+                        // Substitution
+                        var includeContent = Effect.IncludesShadersStore[includeFile];
+                        if (match[2]) {
+                            var splits = match[3].split(",");
 
-                        for (var index = 0; index < splits.length; index += 2) {
-                            var source = new RegExp(splits[index], "g");
-                            var dest = splits[index + 1];
+                            for (var index = 0; index < splits.length; index += 2) {
+                                var source = new RegExp(splits[index], "g");
+                                var dest = splits[index + 1];
 
-                            includeContent = includeContent.replace(source, dest);
+                                includeContent = includeContent.replace(source, dest);
+                            }
                         }
-                    }
 
-                    if (match[4]) {
-                        var indexString = match[5];
+                        if (match[4]) {
+                            var indexString = match[5];
 
-                        if (indexString.indexOf("..") !== -1) {
-                            var indexSplits = indexString.split("..");
-                            var minIndex = parseInt(indexSplits[0]);
-                            var maxIndex = parseInt(indexSplits[1]);
-                            var sourceIncludeContent = includeContent.slice(0);
-                            includeContent = "";
+                            if (indexString.indexOf("..") !== -1) {
+                                var indexSplits = indexString.split("..");
+                                var minIndex = parseInt(indexSplits[0]);
+                                var maxIndex = parseInt(indexSplits[1]);
+                                var sourceIncludeContent = includeContent.slice(0);
+                                includeContent = "";
 
-                            if (isNaN(maxIndex)) {
-                                maxIndex = this._indexParameters[indexSplits[1]];
-                            }
+                                if (isNaN(maxIndex)) {
+                                    maxIndex = this._indexParameters[indexSplits[1]];
+                                }
 
-                            for (var i = minIndex; i < maxIndex; i++) {
+                                for (var i = minIndex; i < maxIndex; i++) {
+                                    if (!this._engine.supportsUniformBuffers) {
+                                        // Ubo replacement
+                                        sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
+                                            return p1 + "{X}";
+                                        });
+                                    }
+                                    includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
+                                }
+                            } else {
                                 if (!this._engine.supportsUniformBuffers) {
                                     // Ubo replacement
-                                    sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
+                                    includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
                                         return p1 + "{X}";
                                     });
                                 }
-                                includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
-                            }
-                        } else {
-                            if (!this._engine.supportsUniformBuffers) {
-                                // Ubo replacement
-                                includeContent = includeContent.replace(/light\{X\}.(\w*)/g, (str: string, p1: string) => {
-                                    return p1 + "{X}";
-                                });
+                                includeContent = includeContent.replace(/\{X\}/g, indexString);
                             }
-                            includeContent = includeContent.replace(/\{X\}/g, indexString);
                         }
-                    }
 
-                    // Replace
-                    returnValue = returnValue.replace(match[0], includeContent);
-                } else {
-                    var includeShaderUrl = Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
+                        // Replace
+                        returnValue = returnValue.replace(match[0], includeContent);
+                    } else {
+                        var includeShaderUrl = Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
+
+                        this._engine._loadFileAsync(includeShaderUrl)
+                            .then((fileContent) => {
+                                Effect.IncludesShadersStore[includeFile] = fileContent as string;
+                                return this._processIncludesAsync(returnValue);
+                            })
+                            .then((returnValue) => {
+                                resolve(returnValue);
+                            });
+                        return;
+                    }
 
-                    this._engine._loadFile(includeShaderUrl, (fileContent) => {
-                        Effect.IncludesShadersStore[includeFile] = fileContent as string;
-                        this._processIncludes(<string>returnValue, callback);
-                    });
-                    return;
+                    match = regex.exec(sourceCode);
                 }
-
-                match = regex.exec(sourceCode);
-            }
-
-            callback(returnValue);
+                resolve(returnValue);
+            });            
         }
 
         private _processPrecision(source: string): string {

+ 1 - 1
src/Materials/babylon.fresnelParameters.ts

@@ -10,7 +10,7 @@
             }
 
             this._isEnabled = value;
-            Engine.MarkAllMaterialsAsDirty(Material.FresnelDirtyFlag);
+            Engine.MarkAllMaterialsAsDirty(Material.FresnelDirtyFlag | Material.MiscDirtyFlag);
         }   
 
         public leftColor = Color3.White();

+ 26 - 2
src/Materials/babylon.material.ts

@@ -251,8 +251,18 @@
         @serialize()
         public state = "";
 
-        @serialize()
-        public alpha = 1.0;
+        @serialize("alpha")
+        protected _alpha = 1.0;
+        public set alpha(value: number) {
+            if (this._alpha === value) {
+                return;
+            }
+            this._alpha = value;
+            this.markAsDirty(Material.MiscDirtyFlag);
+        }
+        public get alpha(): number {
+            return this._alpha;
+        }        
 
         @serialize("backFaceCulling")
         protected _backFaceCulling = true;
@@ -708,6 +718,13 @@
             this._markAllSubMeshesAsDirty(defines => defines.markAsFresnelDirty());
         }
 
+        protected _markAllSubMeshesAsFresnelAndMiscDirty() {
+            this._markAllSubMeshesAsDirty(defines => {
+                defines.markAsFresnelDirty();
+                defines.markAsMiscDirty();
+            });
+        }        
+
         protected _markAllSubMeshesAsLightsDirty() {
             this._markAllSubMeshesAsDirty(defines => defines.markAsLightDirty());
         }
@@ -720,6 +737,13 @@
             this._markAllSubMeshesAsDirty(defines => defines.markAsMiscDirty());
         }
 
+        protected _markAllSubMeshesAsTexturesAndMiscDirty() {
+            this._markAllSubMeshesAsDirty(defines => {
+                defines.markAsTexturesDirty();
+                defines.markAsMiscDirty();
+            });
+        }        
+
         public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
             // Animations
             this.getScene().stopAnimation(this);

+ 27 - 9
src/Materials/babylon.materialHelper.ts

@@ -1,4 +1,4 @@
-module BABYLON {
+module BABYLON {
     export class MaterialHelper {
 
         public static BindEyePosition(effect: Effect, scene: Scene): void {
@@ -32,24 +32,35 @@
             }
         }
 
-        public static PrepareDefinesForMisc(mesh: AbstractMesh, scene: Scene, useLogarithmicDepth: boolean, pointsCloud: boolean, fogEnabled: boolean, defines: any): void {
+        /**
+         * Helper used to prepare the list of defines associated with misc. values for shader compilation
+         * @param mesh defines the current mesh
+         * @param scene defines the current scene
+         * @param useLogarithmicDepth defines if logarithmic depth has to be turned on
+         * @param pointsCloud defines if point cloud rendering has to be turned on
+         * @param fogEnabled defines if fog has to be turned on
+         * @param alphaTest defines if alpha testing has to be turned on
+         * @param defines defines the current list of defines
+         */
+        public static PrepareDefinesForMisc(mesh: AbstractMesh, scene: Scene, useLogarithmicDepth: boolean, pointsCloud: boolean, fogEnabled: boolean, alphaTest: boolean, defines: any): void {
             if (defines._areMiscDirty) {
                 defines["LOGARITHMICDEPTH"] = useLogarithmicDepth;
                 defines["POINTSIZE"] = (pointsCloud || scene.forcePointsCloud);
                 defines["FOG"] = (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && fogEnabled);
                 defines["NONUNIFORMSCALING"] = mesh.nonUniformScaling;
+                defines["ALPHATEST"] = alphaTest;
             }
         }
 
         /**
-         * Helper used to prepare the list of defines for shader compilation
+         * Helper used to prepare the list of defines associated with frame values for shader compilation
          * @param scene defines the current scene
          * @param engine defines the current engine
          * @param defines specifies the list of active defines
          * @param useInstances defines if instances have to be turned on
          * @param alphaTest defines if alpha testing has to be turned on
          */
-        public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean, alphaTest: boolean): void {
+        public static PrepareDefinesForFrameBoundValues(scene: Scene, engine: Engine, defines: any, useInstances: boolean): void {
             var changed = false;
 
             if (defines["CLIPPLANE"] !== (scene.clipPlane !== undefined && scene.clipPlane !== null)) {
@@ -57,11 +68,6 @@
                 changed = true;
             }
 
-            if (defines["ALPHATEST"] !== alphaTest) {
-                defines["ALPHATEST"] = !defines["ALPHATEST"];
-                changed = true;
-            }
-
             if (defines["DEPTHPREPASS"] !== !engine.getColorWrite()) {
                 defines["DEPTHPREPASS"] = !defines["DEPTHPREPASS"];
                 changed = true;
@@ -201,6 +207,12 @@
                         defines["LIGHTMAPNOSPECULAR" + lightIndex] = false;
                     }
 
+                    //Projection texture
+                    if (light.projectedLightTexture){
+                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = true;
+                    }else{
+                        defines["PROJECTEDLIGHTTEXTURE" + lightIndex] = false;                        
+                    }
                     lightIndex++;
                     if (lightIndex === maxSimultaneousLights)
                         break;
@@ -279,6 +291,12 @@
                 }
 
                 samplersList.push("shadowSampler" + lightIndex);
+                if (defines["PROJECTEDLIGHTTEXTURE" + lightIndex]){
+                    samplersList.push("projectionLightSampler" + lightIndex,);
+                    uniformsList.push(
+                        "textureProjectionMatrix" + lightIndex,
+                    );
+                }
             }
 
             if (defines["NUM_MORPH_INFLUENCERS"]) {

+ 5 - 5
src/Materials/babylon.standardMaterial.ts

@@ -108,7 +108,7 @@ module BABYLON {
     export class StandardMaterial extends PushMaterial {
         @serializeAsTexture("diffuseTexture")
         private _diffuseTexture: Nullable<BaseTexture>;;
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public diffuseTexture: Nullable<BaseTexture>;;
 
         @serializeAsTexture("ambientTexture")
@@ -118,7 +118,7 @@ module BABYLON {
 
         @serializeAsTexture("opacityTexture")
         private _opacityTexture: Nullable<BaseTexture>;;
-        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        @expandToProperty("_markAllSubMeshesAsTexturesAndMiscDirty")
         public opacityTexture: Nullable<BaseTexture>;;
 
         @serializeAsTexture("reflectionTexture")
@@ -233,7 +233,7 @@ module BABYLON {
 
         @serializeAsFresnelParameters("opacityFresnelParameters")
         private _opacityFresnelParameters: FresnelParameters;
-        @expandToProperty("_markAllSubMeshesAsFresnelDirty")
+        @expandToProperty("_markAllSubMeshesAsFresnelAndMiscDirty")
         public opacityFresnelParameters: FresnelParameters;
 
 
@@ -739,13 +739,13 @@ module BABYLON {
             }
 
             // Misc.
-            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, defines);
+            MaterialHelper.PrepareDefinesForMisc(mesh, scene, this._useLogarithmicDepth, this.pointsCloud, this.fogEnabled, this._shouldTurnAlphaTestOn(mesh), defines);
 
             // Attribs
             MaterialHelper.PrepareDefinesForAttributes(mesh, defines, true, true, true);
 
             // Values that need to be evaluated on every frame
-            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances, this._shouldTurnAlphaTestOn(mesh));
+            MaterialHelper.PrepareDefinesForFrameBoundValues(scene, engine, defines, useInstances);
 
             // Get correct effect      
             if (defines.isDirty) {

+ 311 - 100
src/Math/babylon.math.ts

@@ -3,28 +3,51 @@
     export const ToLinearSpace = 2.2;
     export const Epsilon = 0.001;
 
+    /**
+     * Class used to hold a RBG color
+     */
     export class Color3 {
+
         /**
-         * Creates a new Color3 object from red, green, blue values, all between 0 and 1.  
+         * Creates a new Color3 object from red, green, blue values, all between 0 and 1
+         * @param r defines the red component (between 0 and 1, default is 0)
+         * @param g defines the green component (between 0 and 1, default is 0) 
+         * @param b defines the blue component (between 0 and 1, default is 0)
          */
-        constructor(public r: number = 0, public g: number = 0, public b: number = 0) {
+        constructor(
+            /**
+             * Defines the red component (between 0 and 1, default is 0)
+             */
+            public r: number = 0, 
+            /**
+             * Defines the green component (between 0 and 1, default is 0) 
+             */
+            public g: number = 0, 
+            /**
+             * Defines the blue component (between 0 and 1, default is 0)
+             */
+            public b: number = 0) {
         }
 
         /**
-         * Returns a string with the Color3 current values.  
+         * Creates a string with the Color3 current values
+         * @returns the string representation of the Color3 object
          */
         public toString(): string {
             return "{R: " + this.r + " G:" + this.g + " B:" + this.b + "}";
         }
 
         /**
-         * Returns the string "Color3".
+         * Returns the string "Color3"
+         * @returns "Color3"
          */
         public getClassName(): string {
             return "Color3";
         }
+
         /**
-         * Returns the Color3 hash code.  
+         * Compute the Color3 hash code
+         * @returns an unique number that can be used to hash Color3 objects
          */
         public getHashCode(): number {
             let hash = this.r || 0;
@@ -34,9 +57,12 @@
         }
 
         // Operators
+
         /**
-         * Stores in the passed array from the passed starting index the red, green, blue values as successive elements.  
-         * Returns the Color3.  
+         * Stores in the passed array from the passed starting index the red, green, blue values as successive elements  
+         * @param array defines the array where to store the r,g,b components
+         * @param index defines an optional index in the target array to define where to start storing values
+         * @returns the current Color3 object
          */
         public toArray(array: FloatArray, index?: number): Color3 {
             if (index === undefined) {
@@ -51,14 +77,17 @@
         }
 
         /**
-         * Returns a new Color4 object from the current Color3 and the passed alpha.  
+         * Returns a new {BABYLON.Color4} object from the current Color3 and the passed alpha 
+         * @param alpha defines the alpha component on the new {BABYLON.Color4} object (default is 1)
+         * @returns a new {BABYLON.Color4} object
          */
         public toColor4(alpha = 1): Color4 {
             return new Color4(this.r, this.g, this.b, alpha);
         }
 
         /**
-         * Returns a new array populated with 3 numeric elements : red, green and blue values.  
+         * Returns a new array populated with 3 numeric elements : red, green and blue values  
+         * @returns the new array
          */
         public asArray(): number[] {
             var result = new Array<number>();
@@ -67,23 +96,27 @@
         }
 
         /**
-         * Returns the luminance value (float).  
+         * Returns the luminance value
+         * @returns a float value
          */
         public toLuminance(): number {
             return this.r * 0.3 + this.g * 0.59 + this.b * 0.11;
         }
 
         /**
-         * Multiply each Color3 rgb values by the passed Color3 rgb values in a new Color3 object.  
-         * Returns this new object.  
+         * Multiply each Color3 rgb values by the passed Color3 rgb values in a new Color3 object 
+         * @param otherColor defines the second operand
+         * @returns the new Color3 object
          */
         public multiply(otherColor: Color3): Color3 {
             return new Color3(this.r * otherColor.r, this.g * otherColor.g, this.b * otherColor.b);
         }
 
         /**
-         * Multiply the rgb values of the Color3 and the passed Color3 and stores the result in the object "result".  
-         * Returns the current Color3.  
+         * Multiply the rgb values of the Color3 and the passed Color3 and stores the result in the object "result"
+         * @param otherColor defines the second operand
+         * @param result defines the Color3 object where to store the result
+         * @returns the current Color3
          */
         public multiplyToRef(otherColor: Color3, result: Color3): Color3 {
             result.r = this.r * otherColor.r;
@@ -93,30 +126,39 @@
         }
 
         /**
-         * Boolean : True if the rgb values are equal to the passed ones.  
+         * Determines equality between Color3 objects
+         * @param otherColor defines the second operand
+         * @returns true if the rgb values are equal to the passed ones 
          */
         public equals(otherColor: Color3): boolean {
             return otherColor && this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b;
         }
 
         /**
-         * Boolean : True if the rgb values are equal to the passed ones.  
+         * Determines equality between the current Color3 object and a set of r,b,g values
+         * @param r defines the red component to check
+         * @param g defines the green component to check
+         * @param b defines the blue component to check
+         * @returns true if the rgb values are equal to the passed ones 
          */
         public equalsFloats(r: number, g: number, b: number): boolean {
             return this.r === r && this.g === g && this.b === b;
         }
 
         /**
-         * Multiplies in place each rgb value by scale.  
-         * Returns the updated Color3.  
+         * Multiplies in place each rgb value by scale 
+         * @param scale defines the scaling factor
+         * @returns the updated Color3.  
          */
         public scale(scale: number): Color3 {
             return new Color3(this.r * scale, this.g * scale, this.b * scale);
         }
 
         /**
-         * Multiplies the rgb values by scale and stores the result into "result".  
-         * Returns the unmodified current Color3.  
+         * 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.  
          */
         public scaleToRef(scale: number, result: Color3): Color3 {
             result.r = this.r * scale;
@@ -126,12 +168,11 @@
         }
 
         /**
-         * Clamps the rgb values by the min and max values and stores the result into "result".
-         * Returns the unmodified current Color3.
-         * @param min - minimum clamping value.  Defaults to 0
-         * @param max - maximum clamping value.  Defaults to 1
-         * @param result - color to store the result into.
-         * @returns - the original Color3
+         * 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)
+         * @param result defines color to store the result into
+         * @returns the original Color3
          */
         public clampToRef(min: number = 0, max: number = 1, result: Color3): Color3 {
             result.r = BABYLON.Scalar.Clamp(this.r, min, max);
@@ -141,15 +182,19 @@
         }
 
         /**
-         * Returns a new Color3 set with the added values of the current Color3 and of the passed one.  
+         * Creates a new Color3 set with the added values of the current Color3 and of the passed one
+         * @param otherColor defines the second operand
+         * @returns the new Color3
          */
         public add(otherColor: Color3): Color3 {
             return new Color3(this.r + otherColor.r, this.g + otherColor.g, this.b + otherColor.b);
         }
 
         /**
-         * Stores the result of the addition of the current Color3 and passed one rgb values into "result".  
-         * Returns the unmodified current Color3.  
+         * Stores the result of the addition of the current Color3 and passed one rgb values into "result"
+         * @param otherColor defines the second operand
+         * @param result defines Color3 object to store the result into
+         * @returns the unmodified current Color3
          */
         public addToRef(otherColor: Color3, result: Color3): Color3 {
             result.r = this.r + otherColor.r;
@@ -159,15 +204,19 @@
         }
 
         /**
-         * Returns a new Color3 set with the subtracted values of the passed one from the current Color3 .  
+         * Returns a new Color3 set with the subtracted values of the passed one from the current Color3
+         * @param otherColor defines the second operand
+         * @returns the new Color3
          */
         public subtract(otherColor: Color3): Color3 {
             return new Color3(this.r - otherColor.r, this.g - otherColor.g, this.b - otherColor.b);
         }
 
         /**
-         * Stores the result of the subtraction of passed one from the current Color3 rgb values into "result".  
-         * Returns the unmodified current Color3.  
+         * Stores the result of the subtraction of passed one from the current Color3 rgb values into "result"  
+         * @param otherColor defines the second operand
+         * @param result defines Color3 object to store the result into
+         * @returns the unmodified current Color3
          */
         public subtractToRef(otherColor: Color3, result: Color3): Color3 {
             result.r = this.r - otherColor.r;
@@ -177,15 +226,17 @@
         }
 
         /**
-         * Returns a new Color3 copied the current one.  
+         * Copy the current object
+         * @returns a new Color3 copied the current one
          */
         public clone(): Color3 {
             return new Color3(this.r, this.g, this.b);
         }
 
         /**
-         * Copies the rgb values from the source in the current Color3.  
-         * Returns the updated Color3.  
+         * Copies the rgb values from the source in the current Color3
+         * @param source defines the source Color3 object
+         * @returns the updated Color3 object
          */
         public copyFrom(source: Color3): Color3 {
             this.r = source.r;
@@ -193,9 +244,13 @@
             this.b = source.b;
             return this;
         }
+
         /**
-         * Updates the Color3 rgb values from the passed floats.  
-         * Returns the Color3.  
+         * Updates the Color3 rgb values from the passed floats
+         * @param r defines the red component to read from
+         * @param g defines the green component to read from
+         * @param b defines the blue component to read from
+         * @returns the current Color3 object
          */
         public copyFromFloats(r: number, g: number, b: number): Color3 {
             this.r = r;
@@ -205,15 +260,19 @@
         }
 
         /**
-         * Updates the Color3 rgb values from the passed floats.  
-         * Returns the Color3.  
+         * Updates the Color3 rgb values from the passed floats
+         * @param r defines the red component to read from
+         * @param g defines the green component to read from
+         * @param b defines the blue component to read from
+         * @returns the current Color3 object
          */
         public set(r: number, g: number, b: number): Color3 {
             return this.copyFromFloats(r, g, b);
         }
 
         /**
-         * Returns the Color3 hexadecimal code as a string.  
+         * Compute the Color3 hexadecimal code as a string  
+         * @returns a string containing the hexadecimal representation of the Color3 object
          */
         public toHexString(): string {
             var intR = (this.r * 255) | 0;
@@ -223,7 +282,8 @@
         }
 
         /**
-         * Returns a new Color3 converted to linear space.  
+         * Computes a new Color3 converted from the current one to linear space
+         * @returns a new Color3 object
          */
         public toLinearSpace(): Color3 {
             var convertedColor = new Color3();
@@ -232,8 +292,9 @@
         }
 
         /**
-         * Converts the Color3 values to linear space and stores the result in "convertedColor".  
-         * Returns the unmodified Color3.  
+         * Converts the Color3 values to linear space and stores the result in "convertedColor"
+         * @param convertedColor defines the Color3 object where to store the linear space version 
+         * @returns the unmodified Color3
          */
         public toLinearSpaceToRef(convertedColor: Color3): Color3 {
             convertedColor.r = Math.pow(this.r, ToLinearSpace);
@@ -243,7 +304,8 @@
         }
 
         /**
-         * Returns a new Color3 converted to gamma space.  
+         * Computes a new Color3 converted from the current one to gamma space
+         * @returns a new Color3 object
          */
         public toGammaSpace(): Color3 {
             var convertedColor = new Color3();
@@ -252,8 +314,9 @@
         }
 
         /**
-         * Converts the Color3 values to gamma space and stores the result in "convertedColor".  
-         * Returns the unmodified Color3.  
+         * Converts the Color3 values to gamma space and stores the result in "convertedColor"
+         * @param convertedColor defines the Color3 object where to store the gamma space version 
+         * @returns the unmodified Color3
          */
         public toGammaSpaceToRef(convertedColor: Color3): Color3 {
             convertedColor.r = Math.pow(this.r, ToGammaSpace);
@@ -263,8 +326,11 @@
         }
 
         // Statics
+
         /**
-         * Creates a new Color3 from the string containing valid hexadecimal values.  
+         * Creates a new Color3 from the string containing valid hexadecimal values
+         * @param hex defines a string containing valid hexadecimal values
+         * @returns a new Color3 object 
          */
         public static FromHexString(hex: string): Color3 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 7) {
@@ -280,21 +346,32 @@
         }
 
         /**
-         * Creates a new Vector3 from the startind index of the passed array.
+         * Creates a new Vector3 from the starting index of the passed array
+         * @param array defines the source array
+         * @param offset defines an offset in the source array
+         * @returns a new Color3 object
          */
         public static FromArray(array: ArrayLike<number>, offset: number = 0): Color3 {
             return new Color3(array[offset], array[offset + 1], array[offset + 2]);
         }
 
         /**
-         * Creates a new Color3 from integer values ( < 256).  
+         * Creates a new Color3 from integer values (< 256)
+         * @param r defines the red component to read from (value between 0 and 255)
+         * @param g defines the green component to read from (value between 0 and 255)
+         * @param b defines the blue component to read from (value between 0 and 255)
+         * @returns a new Color3 object
          */
         public static FromInts(r: number, g: number, b: number): Color3 {
             return new Color3(r / 255.0, g / 255.0, b / 255.0);
         }
 
         /**
-         * Creates a new Color3 with values linearly interpolated of "amount" between the start Color3 and the end Color3.  
+         * Creates a new Color3 with values linearly interpolated of "amount" between the start Color3 and the end Color3
+         * @param start defines the start Color3 value
+         * @param end defines the end Color3 value
+         * @param amount defines the gradient value between start and end
+         * @returns a new Color3 object
          */
         public static Lerp(start: Color3, end: Color3, amount: number): Color3 {
             var r = start.r + ((end.r - start.r) * amount);
@@ -303,30 +380,99 @@
             return new Color3(r, g, b);
         }
 
+        /**
+         * Returns a Color3 value containing a red color
+         * @returns a new Color3 object
+         */
         public static Red(): Color3 { return new Color3(1, 0, 0); }
+        /**
+         * Returns a Color3 value containing a green color
+         * @returns a new Color3 object
+         */        
         public static Green(): Color3 { return new Color3(0, 1, 0); }
+        /**
+         * Returns a Color3 value containing a blue color
+         * @returns a new Color3 object
+         */        
         public static Blue(): Color3 { return new Color3(0, 0, 1); }
+        /**
+         * Returns a Color3 value containing a black color
+         * @returns a new Color3 object
+         */        
         public static Black(): Color3 { return new Color3(0, 0, 0); }
+        /**
+         * Returns a Color3 value containing a white color
+         * @returns a new Color3 object
+         */        
         public static White(): Color3 { return new Color3(1, 1, 1); }
+        /**
+         * Returns a Color3 value containing a purple color
+         * @returns a new Color3 object
+         */        
         public static Purple(): Color3 { return new Color3(0.5, 0, 0.5); }
+        /**
+         * Returns a Color3 value containing a magenta color
+         * @returns a new Color3 object
+         */        
         public static Magenta(): Color3 { return new Color3(1, 0, 1); }
+        /**
+         * Returns a Color3 value containing a yellow color
+         * @returns a new Color3 object
+         */        
         public static Yellow(): Color3 { return new Color3(1, 1, 0); }
+        /**
+         * Returns a Color3 value containing a gray color
+         * @returns a new Color3 object
+         */        
         public static Gray(): Color3 { return new Color3(0.5, 0.5, 0.5); }
+        /**
+         * Returns a Color3 value containing a teal color
+         * @returns a new Color3 object
+         */        
         public static Teal(): Color3 { return new Color3(0, 1.0, 1.0); }
+        /**
+         * Returns a Color3 value containing a random color
+         * @returns a new Color3 object
+         */     
         public static Random(): Color3 { return new Color3(Math.random(), Math.random(), Math.random()); }
     }
 
+    /**
+     * Class used to hold a RBGA color
+     */    
     export class Color4 {
         /**
-         * Creates a new Color4 object from the passed float values ( < 1) : red, green, blue, alpha.  
-         */
-        constructor(public r: number = 0, public g: number = 0, public b: number = 0, public a: number = 1) {
+         * Creates a new Color4 object from red, green, blue values, all between 0 and 1
+         * @param r defines the red component (between 0 and 1, default is 0)
+         * @param g defines the green component (between 0 and 1, default is 0) 
+         * @param b defines the blue component (between 0 and 1, default is 0)
+         * @param a defines the alpha component (between 0 and 1, default is 1)
+         */
+        constructor(
+            /**
+             * Defines the red component (between 0 and 1, default is 0)
+             */
+            public r: number = 0, 
+            /**
+             * Defines the green component (between 0 and 1, default is 0) 
+             */
+            public g: number = 0, 
+            /**
+             * Defines the blue component (between 0 and 1, default is 0)
+             */
+            public b: number = 0, 
+            /**
+             * Defines the alpha component (between 0 and 1, default is 1)
+             */
+            public a: number = 1) {
         }
 
         // Operators
+
         /**
-         * Adds in place the passed Color4 values to the current Color4.  
-         * Returns the updated Color4.  
+         * Adds in place the passed Color4 values to the current Color4 object
+         * @param right defines the second operand
+         * @returns the current updated Color4 object
          */
         public addInPlace(right: Color4): Color4 {
             this.r += right.r;
@@ -337,7 +483,8 @@
         }
 
         /**
-         * Returns a new array populated with 4 numeric elements : red, green, blue, alpha values.  
+         * Creates a new array populated with 4 numeric elements : red, green, blue, alpha values
+         * @returns the new array
          */
         public asArray(): number[] {
             var result = new Array<number>();
@@ -346,8 +493,10 @@
         }
 
         /**
-         * Stores from the starting index in the passed array the Color4 successive values.  
-         * Returns the Color4.  
+         * Stores from the starting index in the passed array the Color4 successive values 
+         * @param array defines the array where to store the r,g,b components
+         * @param index defines an optional index in the target array to define where to start storing values
+         * @returns the current Color4 object
          */
         public toArray(array: number[], index?: number): Color4 {
             if (index === undefined) {
@@ -361,21 +510,28 @@
         }
 
         /**
-         * Returns a new Color4 set with the added values of the current Color4 and of the passed one.  
+         * Creates a new Color4 set with the added values of the current Color4 and of the passed one 
+         * @param right defines the second operand
+         * @returns a new Color4 object
          */
         public add(right: Color4): Color4 {
             return new Color4(this.r + right.r, this.g + right.g, this.b + right.b, this.a + right.a);
         }
+
         /**
-         * Returns a new Color4 set with the subtracted values of the passed one from the current Color4.    
+         * Creates a new Color4 set with the subtracted values of the passed one from the current Color4   
+         * @param right defines the second operand
+         * @returns a new Color4 object
          */
         public subtract(right: Color4): Color4 {
             return new Color4(this.r - right.r, this.g - right.g, this.b - right.b, this.a - right.a);
         }
 
         /**
-         * Subtracts the passed ones from the current Color4 values and stores the results in "result".  
-         * Returns the Color4.  
+         * Subtracts the passed ones from the current Color4 values and stores the results in "result"
+         * @param right defines the second operand
+         * @param result defines the Color4 object where to store the result
+         * @returns the current Color4 object 
          */
         public subtractToRef(right: Color4, result: Color4): Color4 {
             result.r = this.r - right.r;
@@ -384,16 +540,21 @@
             result.a = this.a - right.a;
             return this;
         }
+
         /**
-         * Creates a new Color4 with the current Color4 values multiplied by scale.  
+         * Creates a new Color4 with the current Color4 values multiplied by scale
+         * @param scale defines the scaling factor to apply
+         * @returns a new Color4 object  
          */
         public scale(scale: number): Color4 {
             return new Color4(this.r * scale, this.g * scale, this.b * scale, this.a * scale);
         }
 
         /**
-         * Multiplies the current Color4 values by scale and stores the result in "result".  
-         * Returns the Color4.  
+         * 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.  
          */
         public scaleToRef(scale: number, result: Color4): Color4 {
             result.r = this.r * scale;
@@ -404,12 +565,11 @@
         }
 
         /**
-         * Clamps the rgb values by the min and max values and stores the result into "result".
-         * Returns the unmodified current Color4.
-         * @param min - minimum clamping value.  Defaults to 0
-         * @param max - maximum clamping value.  Defaults to 1
-         * @param result - color to store the result into.
-         * @returns - the original Color4
+         * 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)
+         * @param result defines color to store the result into.
+         * @returns the cuurent Color4
          */
         public clampToRef(min: number = 0, max: number = 1, result: Color4): Color4 {
             result.r = BABYLON.Scalar.Clamp(this.r, min, max);
@@ -420,19 +580,19 @@
         }
 
         /**
-          * Multipy an RGBA Color4 value by another and return a new Color4 object
-          * @param color The Color4 (RGBA) value to multiply by
-          * @returns A new Color4.
+          * Multipy an Color4 value by another and return a new Color4 object
+          * @param color defines the Color4 value to multiply by
+          * @returns a new Color4 object
           */
         public multiply(color: Color4): Color4 {
             return new Color4(this.r * color.r, this.g * color.g, this.b * color.b, this.a * color.a);
         }
 
         /**
-         * Multipy an RGBA Color4 value by another and push the result in a reference value
-         * @param color The Color4 (RGBA) value to multiply by
-         * @param result The Color4 (RGBA) to fill the result in 
-         * @returns the result Color4.
+         * Multipy a Color4 value by another and push the result in a reference value
+         * @param color defines the Color4 value to multiply by
+         * @param result defines the Color4 to fill the result in 
+         * @returns the result Color4
          */
         public multiplyToRef(color: Color4, result: Color4): Color4 {
             result.r = this.r * color.r;
@@ -441,20 +601,26 @@
             result.a = this.a * color.a;
             return result;
         }
+
         /**
-         * Returns a string with the Color4 values.  
+         * Creates a string with the Color4 current values
+         * @returns the string representation of the Color4 object
          */
         public toString(): string {
             return "{R: " + this.r + " G:" + this.g + " B:" + this.b + " A:" + this.a + "}";
         }
+
         /**
          * Returns the string "Color4"
+         * @returns "Color4"
          */
         public getClassName(): string {
             return "Color4";
         }
+
         /**
-         * Return the Color4 hash code as a number.  
+         * Compute the Color4 hash code
+         * @returns an unique number that can be used to hash Color4 objects
          */
         public getHashCode(): number {
             let hash = this.r || 0;
@@ -463,15 +629,19 @@
             hash = (hash * 397) ^ (this.a || 0);
             return hash;
         }
+
         /**
-         * Creates a new Color4 copied from the current one.  
+         * Creates a new Color4 copied from the current one
+         * @returns a new Color4 object
          */
         public clone(): Color4 {
             return new Color4(this.r, this.g, this.b, this.a);
         }
+
         /**
-         * Copies the passed Color4 values into the current one.  
-         * Returns the updated Color4.  
+         * Copies the passed Color4 values into the current one
+         * @param source defines the source Color4 object
+         * @returns the current updated Color4 object
          */
         public copyFrom(source: Color4): Color4 {
             this.r = source.r;
@@ -482,8 +652,12 @@
         }
 
         /**
-         * Copies the passed float values into the current one.  
-         * Returns the updated Color4.  
+         * Copies the passed float values into the current one
+         * @param r defines the red component to read from
+         * @param g defines the green component to read from
+         * @param b defines the blue component to read from
+         * @param a defines the alpha component to read from
+         * @returns the current updated Color4 object 
          */
         public copyFromFloats(r: number, g: number, b: number, a: number): Color4 {
             this.r = r;
@@ -494,14 +668,20 @@
         }
 
         /**
-         * Copies the passed float values into the current one.  
-         * Returns the updated Color4.  
+         * Copies the passed float values into the current one
+         * @param r defines the red component to read from
+         * @param g defines the green component to read from
+         * @param b defines the blue component to read from
+         * @param a defines the alpha component to read from
+         * @returns the current updated Color4 object 
          */
         public set(r: number, g: number, b: number, a: number): Color4 {
             return this.copyFromFloats(r, g, b, a);
         }
+
         /**
-         * Returns a string containing the hexadecimal Color4 code.  
+         * Compute the Color4 hexadecimal code as a string  
+         * @returns a string containing the hexadecimal representation of the Color4 object
          */
         public toHexString(): string {
             var intR = (this.r * 255) | 0;
@@ -512,7 +692,8 @@
         }
 
         /**
-         * Returns a new Color4 converted to linear space.  
+         * Computes a new Color4 converted from the current one to linear space
+         * @returns a new Color4 object
          */
         public toLinearSpace(): Color4 {
             var convertedColor = new Color4();
@@ -521,8 +702,9 @@
         }
 
         /**
-         * Converts the Color4 values to linear space and stores the result in "convertedColor".  
-         * Returns the unmodified Color4.  
+         * Converts the Color4 values to linear space and stores the result in "convertedColor"
+         * @param convertedColor defines the Color4 object where to store the linear space version 
+         * @returns the unmodified Color4
          */
         public toLinearSpaceToRef(convertedColor: Color4): Color4 {
             convertedColor.r = Math.pow(this.r, ToLinearSpace);
@@ -533,7 +715,8 @@
         }
 
         /**
-         * Returns a new Color4 converted to gamma space.  
+         * Computes a new Color4 converted from the current one to gamma space
+         * @returns a new Color4 object
          */
         public toGammaSpace(): Color4 {
             var convertedColor = new Color4();
@@ -542,8 +725,9 @@
         }
 
         /**
-         * Converts the Color4 values to gamma space and stores the result in "convertedColor".  
-         * Returns the unmodified Color4.  
+         * Converts the Color4 values to gamma space and stores the result in "convertedColor"
+         * @param convertedColor defines the Color4 object where to store the gamma space version 
+         * @returns the unmodified Color4
          */
         public toGammaSpaceToRef(convertedColor: Color4): Color4 {
             convertedColor.r = Math.pow(this.r, ToGammaSpace);
@@ -554,8 +738,11 @@
         }
 
         // Statics
+
         /**
-         * Creates a new Color4 from the valid hexadecimal value contained in the passed string.  
+         * Creates a new Color4 from the string containing valid hexadecimal values
+         * @param hex defines a string containing valid hexadecimal values
+         * @returns a new Color4 object 
          */
         public static FromHexString(hex: string): Color4 {
             if (hex.substring(0, 1) !== "#" || hex.length !== 9) {
@@ -572,15 +759,24 @@
         }
 
         /**
-         * Creates a new Color4 object set with the linearly interpolated values of "amount" between the left Color4 and the right Color4.  
+         * Creates a new Color4 object set with the linearly interpolated values of "amount" between the left Color4 object and the right Color4 object
+         * @param left defines the start value
+         * @param right defines the end value
+         * @param amount defines the gradient factor
+         * @returns a new Color4 object
          */
         public static Lerp(left: Color4, right: Color4, amount: number): Color4 {
             var result = new Color4(0.0, 0.0, 0.0, 0.0);
             Color4.LerpToRef(left, right, amount, result);
             return result;
         }
+
         /**
-         * Set the passed "result" with the linearly interpolated values of "amount" between the left Color4 and the right Color4.
+         * Set the passed "result" with the linearly interpolated values of "amount" between the left Color4 object and the right Color4 object
+         * @param left defines the start value
+         * @param right defines the end value
+         * @param amount defines the gradient factor
+         * @param result defines the Color4 object where to store data
          */
         public static LerpToRef(left: Color4, right: Color4, amount: number, result: Color4): void {
             result.r = left.r + (right.r - left.r) * amount;
@@ -590,19 +786,34 @@
         }
 
         /**
-         * Creates a new Color4 from the starting index element of the passed array.
+         * Creates a new Color4 from the starting index element of the passed array
+         * @param array defines the source array to read from
+         * @param offset defines the offset in the source array
+         * @returns a new Color4 object
          */
         public static FromArray(array: ArrayLike<number>, offset: number = 0): Color4 {
             return new Color4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
         }
 
         /**
-         * Creates a new Color4 from the passed integers ( < 256 ).
+         * Creates a new Color3 from integer values (< 256)
+         * @param r defines the red component to read from (value between 0 and 255)
+         * @param g defines the green component to read from (value between 0 and 255)
+         * @param b defines the blue component to read from (value between 0 and 255)
+         * @param a defines the alpha component to read from (value between 0 and 255)
+         * @returns a new Color3 object
          */
         public static FromInts(r: number, g: number, b: number, a: number): Color4 {
             return new Color4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
         }
 
+        /**
+         * Check the content of a given array and convert it to an array containing RGBA data
+         * If the original array was already containing count * 4 values then it is returned directly
+         * @param colors defines the array to check
+         * @param count defines the number of RGBA data to expect
+         * @returns an array containing count * 4 values (RGBA)
+         */
         public static CheckColors4(colors: number[], count: number): number[] {
             // Check if color3 was used
             if (colors.length === count * 3) {
@@ -3393,7 +3604,7 @@
          * - a scale vector3 passed as a reference to update, 
          * - a rotation quaternion passed as a reference to update,
          * - a translation vector3 passed as a reference to update.  
-         * Returns the boolean `true`.  
+         * Returns the true if operation was successful.  
          */
         public decompose(scale: Vector3, rotation: Quaternion, translation: Vector3): boolean {
             translation.x = this.m[12];

+ 19 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -205,7 +205,24 @@
 
         private _occlusionQuery: Nullable<WebGLQuery>;
 
-        public visibility = 1.0;
+        private _visibility = 1.0;
+        /**
+         * Gets or sets mesh visibility between 0 and 1 (defult is 1)
+         */
+        public get visibility(): number {
+            return this._visibility;
+        }
+        /**
+         * Gets or sets mesh visibility between 0 and 1 (defult is 1)
+         */        
+        public set visibility(value: number) {
+            if (this._visibility === value) {
+                return;
+            }
+
+            this._visibility = value;
+            this._markSubMeshesAsMiscDirty();
+        }        
         public alphaIndex = Number.MAX_VALUE;
         public isVisible = true;
         public isPickable = true;
@@ -269,6 +286,7 @@
 
             this._hasVertexAlpha = value;
             this._markSubMeshesAsAttributesDirty();
+            this._markSubMeshesAsMiscDirty();
         }
 
         private _useVertexColors = true;

+ 15 - 2
src/Particles/babylon.boxParticleEmitter.ts

@@ -74,7 +74,7 @@ module BABYLON {
          * @param directionToUpdate is the direction vector to update with the result
          * @param particle is the particle we are computed the direction for
          */
-        startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+        public startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
             var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
             var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
@@ -88,12 +88,25 @@ module BABYLON {
          * @param positionToUpdate is the position vector to update with the result
          * @param particle is the particle we are computed the position for
          */
-        startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+        public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
             var randX = Scalar.RandomRange(this.minEmitBox.x, this.maxEmitBox.x);
             var randY = Scalar.RandomRange(this.minEmitBox.y, this.maxEmitBox.y);
             var randZ = Scalar.RandomRange(this.minEmitBox.z, this.maxEmitBox.z);
 
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): BoxParticleEmitter
+        {
+            let newOne = new BoxParticleEmitter(this._particleSystem);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }
     }
 }

+ 13 - 1
src/Particles/babylon.coneParticleEmitter.ts

@@ -53,7 +53,7 @@ module BABYLON {
          * @param directionToUpdate is the direction vector to update with the result
          * @param particle is the particle we are computed the direction for
          */
-        startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+        public startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             if (this.angle === 0) {
                 Vector3.TransformNormalFromFloatsToRef(0, emitPower, 0, worldMatrix, directionToUpdate);
             }
@@ -92,5 +92,17 @@ module BABYLON {
 
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): ConeParticleEmitter {
+            let newOne = new ConeParticleEmitter(this.radius, this.angle, this.directionRandomizer);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }          
     }
 }

+ 6 - 0
src/Particles/babylon.iParticleEmitterType.ts

@@ -20,5 +20,11 @@ module BABYLON {
          * @param particle is the particle we are computed the position for
          */
         startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void;
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        clone(): IParticleEmitterType;
     }
 }

+ 27 - 3
src/Particles/babylon.sphereParticleEmitter.ts

@@ -29,7 +29,7 @@ module BABYLON {
          * @param directionToUpdate is the direction vector to update with the result
          * @param particle is the particle we are computed the direction for
          */
-        startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+        public startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             var direction = particle.position.subtract(worldMatrix.getTranslation()).normalize();
             var randX = Scalar.RandomRange(0, this.directionRandomizer);
             var randY = Scalar.RandomRange(0, this.directionRandomizer);
@@ -48,7 +48,7 @@ module BABYLON {
          * @param positionToUpdate is the position vector to update with the result
          * @param particle is the particle we are computed the position for
          */
-        startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+        public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
             var phi = Scalar.RandomRange(0, 2 * Math.PI);
             var theta = Scalar.RandomRange(0, Math.PI);
             var randX = this.radius * Math.cos(phi) * Math.sin(theta);
@@ -56,6 +56,18 @@ module BABYLON {
             var randZ = this.radius * Math.sin(phi) * Math.sin(theta);
             Vector3.TransformCoordinatesFromFloatsToRef(randX, randY, randZ, worldMatrix, positionToUpdate);
         }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): SphereParticleEmitter {
+            let newOne = new SphereParticleEmitter(this.radius, this.directionRandomizer);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }        
     }
 
     /**
@@ -89,11 +101,23 @@ module BABYLON {
          * @param directionToUpdate is the direction vector to update with the result
          * @param particle is the particle we are computed the direction for
          */
-        startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+        public startDirectionFunction(emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
             var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
             var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
             var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
             Vector3.TransformNormalFromFloatsToRef(randX * emitPower, randY * emitPower, randZ * emitPower, worldMatrix, directionToUpdate);
         }
+
+        /**
+         * Clones the current emitter and returns a copy of it
+         * @returns the new emitter
+         */
+        public clone(): SphereDirectedParticleEmitter {
+            let newOne = new SphereDirectedParticleEmitter(this.radius, this.direction1, this.direction2);
+
+            Tools.DeepCopy(this, newOne);
+
+            return newOne;
+        }          
     }
 }

+ 31 - 0
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -17,6 +17,10 @@
         public blurX: BlurPostProcess;
         public blurY: BlurPostProcess;
         public copyBack: PassPostProcess;
+        /**
+         * Depth of field effect, applies a blur based on how far away objects are from the focus distance.
+         */
+        public depthOfField: DepthOfFieldEffect;
         public fxaa: FxaaPostProcess;
         public imageProcessing: ImageProcessingPostProcess;
         public finalMerge: PassPostProcess;
@@ -26,6 +30,7 @@
 
         // Values       
         private _bloomEnabled: boolean = false;
+        private _depthOfFieldEnabled: boolean = false;
         private _fxaaEnabled: boolean = false;
         private _imageProcessingEnabled: boolean = true;
         private _defaultPipelineTextureType: number;
@@ -92,6 +97,23 @@
             return this._bloomEnabled;
         }
 
+        /**
+         * If the depth of field is enabled.
+         */
+        @serialize()
+        public get depthOfFieldEnabled(): boolean {
+            return this._depthOfFieldEnabled;
+        }   
+        
+        public set depthOfFieldEnabled(enabled: boolean) {
+            if (this._depthOfFieldEnabled === enabled) {
+                return;
+            }
+            this._depthOfFieldEnabled = enabled;
+            
+            this._buildPipeline();
+        }
+
         public set fxaaEnabled(enabled: boolean) {
             if (this._fxaaEnabled === enabled) {
                 return;
@@ -219,6 +241,10 @@
                 this.copyBack.autoClear = false;
             }
 
+            if(this.depthOfFieldEnabled){
+                this.depthOfField = new DepthOfFieldEffect(this, this._scene, this._cameras[0], this._defaultPipelineTextureType);
+            }
+
             if (this._imageProcessingEnabled) {
                 this.imageProcessing = new ImageProcessingPostProcess("imageProcessing", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
                 if (this._hdr) {
@@ -303,6 +329,10 @@
                 if (this.finalMerge) {
                     this.finalMerge.dispose(camera);
                 }
+
+                if(this.depthOfField){
+                    this.depthOfField.disposeEffects(camera);
+                }
             }
 
             (<any>this.pass) = null;
@@ -313,6 +343,7 @@
             (<any>this.imageProcessing) = null;
             (<any>this.fxaa) = null;
             (<any>this.finalMerge) = null;
+            (<any>this.depthOfField) = null;
         }
 
         // Dispose

+ 8 - 6
src/PostProcess/babylon.blurPostProcess.ts

@@ -3,7 +3,7 @@
 		protected _kernel: number;
 		protected _idealKernel: number;
 		protected _packedFloat: boolean	= false;
-
+		protected _staticDefines:string = ""
 		/**
 		 * Sets the length in pixels of the blur sample region
 		 */
@@ -44,10 +44,11 @@
 		}
 
         constructor(name: string, public direction: Vector2, kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
-            super(name, "kernelBlur", ["delta", "direction"], null, options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", {varyingCount: 0, depCount: 0}, true);
-            this.onApplyObservable.add((effect: Effect) => {
-                effect.setFloat2('delta', (1 / this.width) * this.direction.x, (1 / this.height) * this.direction.y);
-            });
+            super(name, "kernelBlur", ["delta", "direction", "cameraMinMaxZ"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType, "kernelBlur", {varyingCount: 0, depCount: 0}, true);
+			
+			this.onApplyObservable.add((effect: Effect) => {
+				effect.setFloat2('delta', (1 / this.width) * this.direction.x, (1 / this.height) * this.direction.y);
+			});
 
             this.kernel = kernel;
         }
@@ -120,7 +121,8 @@
 
             let varyingCount = Math.min(offsets.length, freeVaryingVec2);
         
-            let defines = "";
+			let defines = "";
+			defines+=this._staticDefines;
             for (let i = 0; i < varyingCount; i++) {
                 defines += `#define KERNEL_OFFSET${i} ${this._glslFloat(offsets[i])}\r\n`;
                 defines += `#define KERNEL_WEIGHT${i} ${this._glslFloat(weights[i])}\r\n`;

+ 53 - 0
src/PostProcess/babylon.circleOfConfusionPostProcess.ts

@@ -0,0 +1,53 @@
+module BABYLON {
+    /**
+     * The CircleOfConfusionPostProcess computes the circle of confusion value for each pixel given required lens parameters. See https://en.wikipedia.org/wiki/Circle_of_confusion
+     */
+    export class CircleOfConfusionPostProcess extends PostProcess {
+        /**
+         * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
+         */
+        lensSize = 50
+        /**
+         * F-Stop of the effect's camera. The diamater of the resulting aperture can be computed by lensSize/fStop. (default: 1.4)
+         */
+        fStop = 1.4;
+        /**
+         * Distance away from the camera to focus on in scene units/1000 (eg. millimeter). (default: 2000)
+         */
+        focusDistance = 2000;
+        /**
+         * Focal length of the effect's camera in scene units/1000 (eg. millimeter). (default: 50)
+         */
+        focalLength = 50;
+        
+        /**
+         * Creates a new instance of @see CircleOfConfusionPostProcess
+         * @param name The name of the effect.
+         * @param scene The scene the effect belongs to.
+         * @param depthTexture The depth texture of the scene to compute the circle of confusion.
+         * @param options The required width/height ratio to downsize to before computing the render pass.
+         * @param camera The camera to apply the render pass to.
+         * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
+         * @param engine The engine which the post process will be applied. (default: current engine)
+         * @param reusable If the post process can be reused on the same frame. (default: false)
+         * @param textureType Type of textures used when performing the post process. (default: 0)
+         */
+        constructor(name: string, scene: Scene, depthTexture: RenderTargetTexture, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "circleOfConfusion", ["cameraMinMaxZ", "focusDistance", "cocPrecalculation"], ["depthSampler"], options, camera, samplingMode, engine, reusable, null, textureType);
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setTexture("depthSampler", depthTexture);
+                
+                // Circle of confusion calculation, See https://developer.nvidia.com/gpugems/GPUGems/gpugems_ch23.html
+                var aperture = this.lensSize/this.fStop;
+                var cocPrecalculation = ((aperture * this.focalLength)/((this.focusDistance - this.focalLength)));// * ((this.focusDistance - pixelDistance)/pixelDistance) [This part is done in shader]
+                
+                effect.setFloat('focusDistance', this.focusDistance);
+                effect.setFloat('cocPrecalculation', cocPrecalculation);
+                
+                if(scene.activeCamera){
+                    effect.setFloat2('cameraMinMaxZ', scene.activeCamera.minZ, scene.activeCamera.maxZ);
+                }
+            })
+        }
+    }
+}

+ 40 - 0
src/PostProcess/babylon.depthOfFieldBlurPostProcess.ts

@@ -0,0 +1,40 @@
+module BABYLON {    
+    /**
+     * The DepthOfFieldBlurPostProcess applied a blur in a give direction.
+     * This blur differs from the standard BlurPostProcess as it attempts to avoid blurring pixels 
+     * based on samples that have a large difference in distance than the center pixel.
+     * See section 2.6.2 http://fileadmin.cs.lth.se/cs/education/edan35/lectures/12dof.pdf
+     */
+    export class DepthOfFieldBlurPostProcess extends BlurPostProcess {
+        /**
+         * Creates a new instance of @see CircleOfConfusionPostProcess
+         * @param name The name of the effect.
+         * @param scene The scene the effect belongs to.
+         * @param direction The direction the blur should be applied.
+         * @param kernel The size of the kernel used to blur.
+         * @param options The required width/height ratio to downsize to before computing the render pass.
+         * @param camera The camera to apply the render pass to.
+         * @param depthMap The depth map to be used to avoid blurring accross edges
+         * @param imageToBlur The image to apply the blur to (default: Current rendered frame)
+         * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
+         * @param engine The engine which the post process will be applied. (default: current engine)
+         * @param reusable If the post process can be reused on the same frame. (default: false)
+         * @param textureType Type of textures used when performing the post process. (default: 0)
+         */
+        constructor(name: string, scene: Scene, public direction: Vector2, kernel: number, options: number | PostProcessOptions, camera: Nullable<Camera>, depthMap:RenderTargetTexture, imageToBlur:Nullable<PostProcess> = null, samplingMode: number = Texture.BILINEAR_SAMPLINGMODE, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, direction, kernel, options, camera, samplingMode = Texture.BILINEAR_SAMPLINGMODE, engine, reusable, textureType = Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._staticDefines += `#define DOF 1\r\n`;
+			
+			this.onApplyObservable.add((effect: Effect) => {
+                // TODO: setTextureFromPostProcess seems to be setting the input texture instead of output of the post process passed in 
+                if(imageToBlur != null){
+                    effect.setTextureFromPostProcess("textureSampler", imageToBlur);
+                }
+                effect.setTexture("depthSampler", depthMap);
+                if(scene.activeCamera){
+                    effect.setFloat2('cameraMinMaxZ', scene.activeCamera.minZ, scene.activeCamera.maxZ);
+                }
+			});
+        }
+    }
+}

+ 109 - 0
src/PostProcess/babylon.depthOfFieldEffect.ts

@@ -0,0 +1,109 @@
+module BABYLON {
+    
+    /**
+     * The depth of field effect applies a blur to objects that are closer or further from where the camera is focusing.
+     */
+    export class DepthOfFieldEffect extends PostProcessRenderEffect{
+        private readonly DepthOfFieldPassPostProcessId: string = "DepthOfFieldPassPostProcessId";
+        private readonly CircleOfConfusionPostProcessId: string = "CircleOfConfusionPostProcessEffect"; 
+        private readonly DepthOfFieldBlurXPostProcessId: string = "DepthOfFieldBlurXPostProcessEffect";
+        private readonly DepthOfFieldBlurYPostProcessId: string = "DepthOfFieldBlurYPostProcessEffect";
+        private readonly DepthOfFieldMergePostProcessId: string = "DepthOfFieldMergePostProcessEffect";
+
+        private depthOfFieldPass: PassPostProcess;
+        private circleOfConfusion: CircleOfConfusionPostProcess;
+        private depthOfFieldBlurX: DepthOfFieldBlurPostProcess;
+        private depthOfFieldBlurY: DepthOfFieldBlurPostProcess;
+        private depthOfFieldMerge: DepthOfFieldMergePostProcess;
+
+        /**
+         * The size of the kernel to be used for the blur
+         */
+        public set kernelSize(value: number){
+            this.depthOfFieldBlurX.kernel = value;
+            this.depthOfFieldBlurY.kernel = value;
+        }
+        public get kernelSize(){
+            return this.depthOfFieldBlurX.kernel;
+        }
+        /**
+         * The focal the length of the camera used in the effect
+         */
+        public set focalLength(value: number){
+            this.circleOfConfusion.focalLength = value;
+        }
+        public get focalLength(){
+            return this.circleOfConfusion.focalLength;
+        }
+        /**
+         * F-Stop of the effect's camera. The diamater of the resulting aperture can be computed by lensSize/fStop. (default: 1.4)
+         */
+        public set fStop(value: number){
+            this.circleOfConfusion.fStop = value;
+        }
+        public get fStop(){
+            return this.circleOfConfusion.fStop;
+        }
+        /**
+         * Distance away from the camera to focus on in scene units/1000 (eg. millimeter). (default: 2000)
+         */
+        public set focusDistance(value: number){
+            this.circleOfConfusion.focusDistance = value;
+        }
+        public get focusDistance(){
+            return this.circleOfConfusion.focusDistance;
+        }
+        /**
+         * Max lens size in scene units/1000 (eg. millimeter). Standard cameras are 50mm. (default: 50) The diamater of the resulting aperture can be computed by lensSize/fStop.
+         */
+        public set lensSize(value: number){
+            this.circleOfConfusion.lensSize = value;
+        }
+        public get lensSize(){
+            return this.circleOfConfusion.lensSize;
+        }
+
+        /**
+         * Creates a new instance of @see DepthOfFieldEffect
+         * @param pipeline The pipeline to add the depth of field effect to.
+         * @param scene The scene the effect belongs to.
+         * @param camera The camera to apply the depth of field on.
+         * @param pipelineTextureType The type of texture to be used when performing the post processing.
+         */
+        constructor(pipeline: PostProcessRenderPipeline, scene: Scene, camera:Camera, pipelineTextureType = 0) {
+            super(scene.getEngine(), "depth of field", ()=>{return this.circleOfConfusion}, true);
+            // Enable and get current depth map
+            var depthMap = scene.enableDepthRenderer().getDepthMap();
+            // Circle of confusion value for each pixel is used to determine how much to blur that pixel
+            this.circleOfConfusion = new BABYLON.CircleOfConfusionPostProcess("circleOfConfusion", scene, depthMap, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            pipeline.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.CircleOfConfusionPostProcessId, () => { return this.circleOfConfusion; }, true));  
+         
+            // Capture circle of confusion texture
+            this.depthOfFieldPass = new PassPostProcess("depthOfFieldPass", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            pipeline.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.DepthOfFieldPassPostProcessId, () => { return this.depthOfFieldPass; }, true));
+
+            // Blur the image but do not blur on sharp far to near distance changes to avoid bleeding artifacts 
+            // See section 2.6.2 http://fileadmin.cs.lth.se/cs/education/edan35/lectures/12dof.pdf
+            this.depthOfFieldBlurY = new DepthOfFieldBlurPostProcess("verticle blur", scene, new Vector2(0, 1.0), 15, 1.0, null, depthMap, this.circleOfConfusion, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            pipeline.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.DepthOfFieldBlurYPostProcessId, () => { return this.depthOfFieldBlurY; }, true));
+            this.depthOfFieldBlurX = new DepthOfFieldBlurPostProcess("horizontal blur", scene, new Vector2(1.0, 0), 15, 1.0, null,  depthMap, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            pipeline.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.DepthOfFieldBlurXPostProcessId, () => { return this.depthOfFieldBlurX; }, true));
+
+            // Merge blurred images with original image based on circleOfConfusion
+            this.depthOfFieldMerge = new DepthOfFieldMergePostProcess("depthOfFieldMerge", this.circleOfConfusion, this.depthOfFieldPass, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType);
+            pipeline.addEffect(new PostProcessRenderEffect(scene.getEngine(), this.DepthOfFieldMergePostProcessId, () => { return this.depthOfFieldMerge; }, true));
+        }
+
+        /**
+         * Disposes each of the internal effects for a given camera.
+         * @param camera The camera to dispose the effect on.
+         */
+        public disposeEffects(camera:Camera){
+            this.depthOfFieldPass.dispose(camera);
+            this.circleOfConfusion.dispose(camera);
+            this.depthOfFieldBlurX.dispose(camera);
+            this.depthOfFieldBlurY.dispose(camera);
+            this.depthOfFieldMerge.dispose(camera);
+        }
+    }
+}

+ 26 - 0
src/PostProcess/babylon.depthOfFieldMergePostProcess.ts

@@ -0,0 +1,26 @@
+module BABYLON {
+    /**
+     * The DepthOfFieldMergePostProcess merges blurred images with the original based on the values of the circle of confusion.
+     */
+    export class DepthOfFieldMergePostProcess extends PostProcess {
+        /**
+         * Creates a new instance of @see CircleOfConfusionPostProcess
+         * @param name The name of the effect.
+         * @param original The non-blurred image to be modified
+         * @param circleOfConfusion The circle of confusion post process that will determine how blurred each pixel should become.
+         * @param options The required width/height ratio to downsize to before computing the render pass.
+         * @param camera The camera to apply the render pass to.
+         * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
+         * @param engine The engine which the post process will be applied. (default: current engine)
+         * @param reusable If the post process can be reused on the same frame. (default: false)
+         * @param textureType Type of textures used when performing the post process. (default: 0)
+         */
+        constructor(name: string, original: PostProcess, circleOfConfusion: PostProcess, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT) {
+            super(name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "originalSampler"], options, camera, samplingMode, engine, reusable, null, textureType);
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setTextureFromPostProcess("circleOfConfusionSampler", circleOfConfusion);
+                effect.setTextureFromPostProcess("originalSampler", original);
+            })
+        }
+    }
+}

+ 12 - 3
src/Shaders/ShadersInclude/kernelBlurFragment.fx

@@ -1,5 +1,14 @@
-#ifdef PACKEDFLOAT
-    blend += unpack(texture2D(textureSampler, sampleCoord{X})) * KERNEL_WEIGHT{X};
+#ifdef DOF
+    sampleDepth = sampleDistance(sampleCoord{X});
+    factor = clamp(1.0-((centerSampleDepth - sampleDepth)/centerSampleDepth),0.0,1.0);
+    computedWeight = KERNEL_WEIGHT{X} * factor;
+    sumOfWeights += computedWeight;
 #else
-    blend += texture2D(textureSampler, sampleCoord{X}) * KERNEL_WEIGHT{X};
+    computedWeight = KERNEL_WEIGHT{X};
+#endif
+
+#ifdef PACKEDFLOAT
+    blend += unpack(texture2D(textureSampler, sampleCoord{X})) * computedWeight;
+#else
+    blend += texture2D(textureSampler, sampleCoord{X}) * computedWeight;
 #endif

+ 12 - 3
src/Shaders/ShadersInclude/kernelBlurFragment2.fx

@@ -1,5 +1,14 @@
-#ifdef PACKEDFLOAT
-    blend += unpack(texture2D(textureSampler, sampleCenter + delta * KERNEL_DEP_OFFSET{X})) * KERNEL_DEP_WEIGHT{X};
+#ifdef DOF
+    sampleDepth = sampleDistance(sampleCoord{X});
+    factor = clamp(1.0-((centerSampleDepth - sampleDepth)/centerSampleDepth),0.0,1.0);
+    computedWeight = KERNEL_DEP_WEIGHT{X} * factor;
+    sumOfWeights += computedWeight;
 #else
-    blend += texture2D(textureSampler, sampleCenter + delta * KERNEL_DEP_OFFSET{X}) * KERNEL_DEP_WEIGHT{X};
+    computedWeight = KERNEL_DEP_WEIGHT{X};
+#endif
+
+#ifdef PACKEDFLOAT
+    blend += unpack(texture2D(textureSampler, sampleCenter + delta * KERNEL_DEP_OFFSET{X})) * computedWeight;
+#else
+    blend += texture2D(textureSampler, sampleCenter + delta * KERNEL_DEP_OFFSET{X}) * computedWeight;
 #endif

+ 3 - 0
src/Shaders/ShadersInclude/lightFragment.fx

@@ -23,6 +23,9 @@
 				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 = computeProjectionTexture(info,projectionLightSampler{X},textureProjectionMatrix{X});
+		#endif
     #endif
 	#ifdef SHADOW{X}
 		#ifdef SHADOWCLOSEESM{X}

+ 4 - 0
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -25,4 +25,8 @@
 	#ifdef HEMILIGHT{X}
 		uniform vec3 vLightGround{X};
 	#endif
+	#ifdef PROJECTEDLIGHTTEXTURE{X}
+		uniform mat4 textureProjectionMatrix{X};
+		uniform sampler2D projectionLightSampler{X};
+	#endif
 #endif

+ 4 - 1
src/Shaders/ShadersInclude/lightUboDeclaration.fx

@@ -13,7 +13,10 @@
 		vec4 shadowsInfo;
 		vec2 depthValues;
 	} light{X};
-
+#ifdef PROJECTEDLIGHTTEXTURE{X}
+	uniform mat4 textureProjectionMatrix{X};
+	uniform sampler2D projectionLightSampler{X};
+#endif
 #ifdef SHADOW{X}
 	#if defined(SHADOWCUBE{X})
 		uniform samplerCube shadowSampler{X};

+ 10 - 5
src/Shaders/ShadersInclude/lightsFragmentFunctions.fx

@@ -1,4 +1,4 @@
-// Light Computing
+// Light Computing
 struct lightingInfo
 {
 	vec3 diffuse;
@@ -32,9 +32,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
 #ifdef NDOTL
 	result.ndl = ndl;
 #endif
-
 	result.diffuse = ndl * diffuseColor * attenuation;
-
 #ifdef SPECULARTERM
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightVectorW);
@@ -67,7 +65,6 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
 		result.ndl = ndl;
 #endif
 		result.diffuse = ndl * diffuseColor * attenuation;
-
 #ifdef SPECULARTERM
 		// Specular
 		vec3 angleW = normalize(viewDirectionW + lightVectorW);
@@ -109,6 +106,14 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
 
 	result.specular = specComp * specularColor;
 #endif
+		return result;
+}
 
+lightingInfo computeProjectionTexture(lightingInfo origin,sampler2D projectionLightSampler, mat4 textureProjectionMatrix){
+	lightingInfo result = origin;
+	vec4 strq = textureProjectionMatrix * vec4(vPositionW, 1.0);
+	strq /= strq.w;
+	vec4 textureColor = texture2D(projectionLightSampler, strq.xy);
+	result.diffuse *= vec3(textureColor);
 	return result;
-}
+}

+ 25 - 0
src/Shaders/circleOfConfusion.fragment.fx

@@ -0,0 +1,25 @@
+// samplers
+uniform sampler2D depthSampler;
+
+// varyings
+varying vec2 vUV;
+
+// preconputed uniforms (not effect parameters)
+uniform vec2 cameraMinMaxZ;
+
+// uniforms
+uniform float focusDistance;
+uniform float cocPrecalculation;
+
+float sampleDistance(const in vec2 offset) {
+    float depth = texture2D(depthSampler, offset).r;	// depth value from DepthRenderer: 0 to 1
+	return (cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth)*1000.0;		            // actual distance from the lens in scene units/1000 (eg. millimeter)
+}
+
+void main(void)
+{
+    float pixelDistance = sampleDistance(vUV);
+    float coc = abs(cocPrecalculation* ((focusDistance - pixelDistance)/pixelDistance));
+    coc = clamp(coc, 0.0, 1.0);
+    gl_FragColor = vec4(coc, coc, coc, 1.0);
+}

+ 15 - 0
src/Shaders/depthOfFieldMerge.fragment.fx

@@ -0,0 +1,15 @@
+// samplers
+uniform sampler2D textureSampler;
+uniform sampler2D originalSampler;
+uniform sampler2D circleOfConfusionSampler;
+
+// varyings
+varying vec2 vUV;
+
+void main(void)
+{
+    vec4 blurred = texture2D(textureSampler, vUV);
+    vec4 original = texture2D(originalSampler, vUV);
+    float coc = texture2D(circleOfConfusionSampler, vUV).r;
+    gl_FragColor = mix(original, blurred, coc);
+}

+ 34 - 5
src/Shaders/kernelBlur.fragment.fx

@@ -4,6 +4,18 @@ uniform vec2 delta;
 
 // Varying
 varying vec2 sampleCenter;
+
+#ifdef DOF
+	uniform sampler2D depthSampler;
+
+	uniform vec2 cameraMinMaxZ;
+
+	float sampleDistance(const in vec2 offset) {
+		float depth = texture2D(depthSampler, offset).r; // depth value from DepthRenderer: 0 to 1 
+		return cameraMinMaxZ.x + (cameraMinMaxZ.y - cameraMinMaxZ.x)*depth; // actual distance from the lens 
+	}
+#endif
+
 #include<kernelBlurVaryingDeclaration>[0..varyingCount]
 
 #ifdef PACKEDFLOAT
@@ -27,11 +39,20 @@ varying vec2 sampleCenter;
 
 void main(void)
 {
-#ifdef PACKEDFLOAT	
-	float blend = 0.;
-#else
-	vec4 blend = vec4(0.);
-#endif
+	#ifdef DOF
+		float sumOfWeights = 0.0; // Since not all values are blended, keep track of sum to devide result by at the end to get an average
+		float sampleDepth = 0.0;
+    	float factor = 0.0;
+		float centerSampleDepth = sampleDistance(sampleCenter);
+	#endif
+
+	float computedWeight = 0.0;
+
+	#ifdef PACKEDFLOAT	
+		float blend = 0.;
+	#else
+		vec4 blend = vec4(0.);
+	#endif
 
 	#include<kernelBlurFragment>[0..varyingCount]
 	#include<kernelBlurFragment2>[0..depCount]
@@ -41,4 +62,12 @@ void main(void)
 	#else
 		gl_FragColor = blend;
 	#endif
+
+	#ifdef DOF
+		// If there are no samples to blend, make pixel black.
+		if(sumOfWeights == 0.0){
+			gl_FragColor = vec4(0.0,0.0,0.0,1.0);
+		}
+		gl_FragColor /= sumOfWeights;
+	#endif
 }

+ 62 - 2
src/Tools/babylon.observable.ts

@@ -39,6 +39,12 @@
          * The current object in the bubbling phase
          */
         public currentTarget?: any;
+
+        /**
+         * This will be populated with the return value of the last function that was executed.
+         * If it is the first function in the callback chain it will be the event data.
+         */
+        public lastReturnValue?: any;
     }
 
     /**
@@ -187,13 +193,14 @@
             state.target = target;
             state.currentTarget = currentTarget;
             state.skipNextObservers = false;
+            state.lastReturnValue = eventData;
 
             for (var obs of this._observers) {
                 if (obs.mask & mask) {
                     if (obs.scope) {
-                        obs.callback.apply(obs.scope, [eventData, state])
+                        state.lastReturnValue = obs.callback.apply(obs.scope, [eventData, state])
                     } else {
-                        obs.callback(eventData, state);
+                        state.lastReturnValue = obs.callback(eventData, state);
                     }
                 }
                 if (state.skipNextObservers) {
@@ -204,6 +211,59 @@
         }
 
         /**
+         * Calling this will execute each callback, expecting it to be a promise or return a value.
+         * If at any point in the chain one function fails, the promise will fail and the execution will not continue.
+         * This is useful when a chain of events (sometimes async events) is needed to initialize a certain object
+         * and it is crucial that all callbacks will be executed.
+         * The order of the callbacks is kept, callbacks are not executed parallel.
+         * 
+         * @param eventData The data to be sent to each callback
+         * @param mask is used to filter observers defaults to -1
+         * @param target the callback target (see EventState)
+         * @param currentTarget The current object in the bubbling phase
+         * @returns {Promise<T>} will return a Promise than resolves when all callbacks executed successfully.
+         */
+        public notifyObserversWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<T> {
+
+            // create an empty promise
+            let p: Promise<any> = Promise.resolve(eventData);
+
+            // no observers? return this promise.
+            if (!this._observers.length) {
+                return p;
+            }
+
+            let state = this._eventState;
+            state.mask = mask;
+            state.target = target;
+            state.currentTarget = currentTarget;
+            state.skipNextObservers = false;
+
+            // execute one callback after another (not using Promise.all, the order is important)
+            this._observers.forEach(obs => {
+                if (state.skipNextObservers) {
+                    return;
+                }
+                if (obs.mask & mask) {
+                    if (obs.scope) {
+                        p = p.then((lastReturnedValue) => {
+                            state.lastReturnValue = lastReturnedValue;
+                            return obs.callback.apply(obs.scope, [eventData, state]);
+                        });
+                    } else {
+                        p = p.then((lastReturnedValue) => {
+                            state.lastReturnValue = lastReturnedValue;
+                            return obs.callback(eventData, state);
+                        });
+                    }
+                }
+            });
+
+            // return the eventData
+            return p.then(() => { return eventData; });
+        }
+
+        /**
          * Notify a specific observer
          * @param eventData
          * @param mask

+ 39 - 16
src/Tools/babylon.promise.ts

@@ -17,7 +17,7 @@ module BABYLON {
         private _state = PromiseStates.Pending;
         private _result?: Nullable<T>;
         private _reason: any;
-        private _child: InternalPromise<T>;
+        private _children = new Array<InternalPromise<T>>();
         private _onFulfilled?: (fulfillment?: Nullable<T>) => Nullable<InternalPromise<T>> | T;
         private _onRejected?: (reason: any) => void;
         private _rejectWasConsumed = false;
@@ -26,27 +26,27 @@ module BABYLON {
             return this._state;
         }
 
-        public isFulfilled(): boolean {
+        public get isFulfilled(): boolean {
             return this._state === PromiseStates.Fulfilled;
         }            
 
-        public isRejected(): boolean {
+        public get isRejected(): boolean {
             return this._state === PromiseStates.Rejected;
         }
     
-        public isPending(): boolean {
+        public get isPending(): boolean {
             return this._state === PromiseStates.Pending;
         }
     
         public value(): Nullable<T> | undefined {
-            if (!this.isFulfilled()) {
+            if (!this.isFulfilled) {
                 throw new Error("Promise is not fulfilled");
             }
             return this._result;
         }     
         
         public reason(): any {
-            if (!this.isRejected()) {
+            if (!this.isRejected) {
                 throw new Error("Promise is not rejected");
             }
             return this._reason;
@@ -82,7 +82,7 @@ module BABYLON {
             newPromise._onRejected = onRejected;
 
             // Composition
-            this._child = newPromise;
+            this._children.push(newPromise);
 
             if (this._state !== PromiseStates.Pending) {
                 if (this._state === PromiseStates.Fulfilled || this._rejectWasConsumed) {
@@ -91,7 +91,7 @@ module BABYLON {
                     if (returnedValue !== undefined && returnedValue !== null) {
                         if ((<InternalPromise<T>>returnedValue)._state !== undefined) {
                             let returnedPromise = returnedValue as InternalPromise<T>;
-                            newPromise._child = returnedPromise;
+                            newPromise._children.push(returnedPromise);
                             newPromise = returnedPromise;
                         } else {
                             newPromise._result = (<T>returnedValue);
@@ -104,22 +104,45 @@ module BABYLON {
 
             return newPromise;
         }       
+
+        private _moveChildren(children: InternalPromise<T>[]): void {
+            this._children = children.splice(0, children.length);
+
+            if (this.isFulfilled) {
+                for (var child of this._children) {
+                    child._resolve(this._result);
+                } 
+            } else if (this.isRejected) {
+                for (var child of this._children) {
+                    child._reject(this._reason);
+                }                 
+            }
+        }
         
         private _resolve(value?: Nullable<T>): Nullable<InternalPromise<T>> | T {
             try {
                 this._state = PromiseStates.Fulfilled;
                 this._result = value;
-                let returnedPromise: Nullable<InternalPromise<T>> | T = null;
+                let returnedValue: Nullable<InternalPromise<T>> | T = null;
 
                 if (this._onFulfilled) {
-                    returnedPromise = this._onFulfilled(value);
+                    returnedValue = this._onFulfilled(value);
+                }
+
+                if (returnedValue !== undefined && returnedValue !== null) {
+                    if ((<InternalPromise<T>>returnedValue)._state !== undefined) {
+                        // Transmit children
+                        let returnedPromise = returnedValue as InternalPromise<T>;
+                        
+                        returnedPromise._moveChildren(this._children);
+                    }
                 }
 
-                if (this._child) {
-                    this._child._resolve(value);
+                for (var child of this._children) {
+                    child._resolve(value);
                 }                
 
-                return returnedPromise;
+                return returnedValue;
             } catch(e) {
                 this._reject((<Error>e).message);
             }
@@ -136,11 +159,11 @@ module BABYLON {
                 this._rejectWasConsumed = true;
             }
 
-            if (this._child) {
+            for (var child of this._children) {
                 if (this._rejectWasConsumed) {
-                    this._child._resolve(null);
+                    child._resolve(null);
                 } else {
-                    this._child._reject(reason);
+                    child._reject(reason);
                 }
             }                
         }

+ 11 - 0
src/babylon.scene.ts

@@ -4834,5 +4834,16 @@
             });
             return request;
         }
+
+        /** @ignore */
+        public _loadFileAsync(url: string, useDatabase?: boolean, useArrayBuffer?: boolean): Promise<string | ArrayBuffer> {
+            return new Promise((resolve, reject) => {
+                this._loadFile(url, (data) => {
+                    resolve(data);
+                }, undefined, useDatabase, useArrayBuffer, (request, exception) => {
+                    reject(exception);
+                })
+            });
+        }
     }
 }

+ 27 - 2
tests/unit/babylon/promises/babylon.promises.tests.ts

@@ -147,7 +147,32 @@ describe('Babylon.Promise', () => {
             .then(number => { 
                 number.should.be.equal(3);
                 done();
-             })
+             });
         });
-    });      
+    });     
+    
+    describe('#Multiple children', () => {
+        it('should correctly handle multiple independant "then"', (done) => {
+            mocha.timeout(10000);
+            var promise1 = new Promise(function(resolve, reject) {
+                setTimeout(function() {
+                    resolve('Success!');
+                }, 500);
+            });
+            var sum = 0;
+            promise1.then(function(value) {
+                sum++;
+                if (sum === 2) {
+                    done();
+                }
+            });
+            
+            promise1.then(function(value) {
+                sum++;
+                if (sum === 2) {
+                    done();
+                }
+            });
+        });
+    });     
 });

TEMPAT SAMPAH
tests/validation/ReferenceImages/KernelBlur.png


TEMPAT SAMPAH
tests/validation/ReferenceImages/depthOfField.png


+ 11 - 0
tests/validation/config.json

@@ -237,6 +237,17 @@
       "referenceImage": "assetContainer.png"
     },
     {
+      "title": "Depth of field",
+      "playgroundId": "#IDSQK2#16",
+      "renderCount": 20,
+      "referenceImage": "depthOfField.png"
+    },
+    {
+      "title": "Kernel Blur",
+      "playgroundId": "#Y0WKT0",
+      "referenceImage": "KernelBlur.png"
+    },
+    {
       "title": "GLTF Mesh Primitive Attribute Test",
       "scriptToRun": "/Demos/GLTFMeshPrimitiveAttributeTest/index.js",
       "functionToCall": "createScene",