David Catuhe 7 years ago
parent
commit
b6794749a0
57 changed files with 43707 additions and 27568 deletions
  1. 15982 11879
      Playground/babylon.d.txt
  2. 50 2
      Tools/Gulp/config.json
  3. 25597 14218
      dist/preview release/babylon.d.ts
  4. 55 55
      dist/preview release/babylon.js
  5. 454 288
      dist/preview release/babylon.max.js
  6. 56 56
      dist/preview release/babylon.worker.js
  7. 456 290
      dist/preview release/es6.js
  8. 4 4
      dist/preview release/gui/babylon.gui.min.js
  9. 4 4
      dist/preview release/inspector/babylon.inspector.bundle.js
  10. 3 3
      dist/preview release/inspector/babylon.inspector.min.js
  11. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  12. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  13. 3 3
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  14. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  15. 3 3
      dist/preview release/loaders/babylonjs.loaders.min.js
  16. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  17. 1 1
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js
  18. 1 1
      dist/preview release/materialsLibrary/babylon.waterMaterial.min.js
  19. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  20. 1 1
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js
  21. 1 1
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js
  22. 1 1
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js
  23. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  24. 1 1
      dist/preview release/serializers/babylonjs.serializers.min.js
  25. 2 42
      dist/preview release/typedocValidationBaseline.json
  26. 62 62
      dist/preview release/viewer/babylon.viewer.js
  27. 454 288
      dist/preview release/viewer/babylon.viewer.max.js
  28. 3 1
      dist/preview release/what's new.md
  29. 0 1
      src/Materials/Background/babylon.backgroundMaterial.ts
  30. 0 1
      src/Materials/PBR/babylon.pbrBaseMaterial.ts
  31. 2 2
      src/Materials/babylon.effect.ts
  32. 1 64
      src/Materials/babylon.imageProcessingConfiguration.ts
  33. 0 1
      src/Materials/babylon.standardMaterial.ts
  34. 159 185
      src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts
  35. 2 2
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.ts
  36. 2 2
      src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.ts
  37. 117 0
      src/PostProcess/babylon.bloomEffect.ts
  38. 33 0
      src/PostProcess/babylon.bloomMergePostProcess.ts
  39. 1 0
      src/PostProcess/babylon.blurPostProcess.ts
  40. 16 18
      src/PostProcess/babylon.depthOfFieldEffect.ts
  41. 37 9
      src/PostProcess/babylon.depthOfFieldMergePostProcess.ts
  42. 30 0
      src/PostProcess/babylon.extractHighlightsPostProcess.ts
  43. 34 0
      src/PostProcess/babylon.grainPostProcess.ts
  44. 0 40
      src/PostProcess/babylon.imageProcessingPostProcess.ts
  45. 1 1
      src/PostProcess/babylon.postProcess.ts
  46. 0 5
      src/Shaders/ShadersInclude/imageProcessingDeclaration.fx
  47. 3 5
      src/Shaders/background.fragment.fx
  48. 12 0
      src/Shaders/bloomMerge.fragment.fx
  49. 1 1
      src/Shaders/chromaticAberration.fragment.fx
  50. 2 3
      src/Shaders/depthOfFieldMerge.fragment.fx
  51. 14 0
      src/Shaders/extractHighlights.fragment.fx
  52. 25 0
      src/Shaders/grain.fragment.fx
  53. 0 12
      src/Shaders/imageProcessing.fragment.fx
  54. 10 1
      src/babylon.scene.ts
  55. BIN
      tests/validation/ReferenceImages/DefaultRenderingPipeline.png
  56. BIN
      tests/validation/ReferenceImages/defaultPipeline.png
  57. 1 1
      tests/validation/config.json

File diff suppressed because it is too large
+ 15982 - 11879
Playground/babylon.d.txt


+ 50 - 2
Tools/Gulp/config.json

@@ -74,7 +74,9 @@
             "additionalPostProcess_fxaa",
             "additionalPostProcess_circleOfConfusion",
             "additionalPostProcess_depthOfFieldMerge",
+            "additionalPostProcess_bloomMerge",
             "additionalPostProcess_depthOfFieldEffect",
+            "additionalPostProcess_bloomEffect",
             "additionalPostProcess_imageProcessing",
             "bones",
             "hdr",
@@ -734,6 +736,17 @@
                 "chromaticAberration.fragment"
             ]
         },
+        "additionalPostProcess_grain": {
+            "files": [
+                "../../src/PostProcess/babylon.grainPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "grain.fragment"
+            ]
+        },
         "additionalPostProcess_depthOfFieldMerge": {
             "files": [
                 "../../src/PostProcess/babylon.depthOfFieldMergePostProcess.js"
@@ -745,6 +758,17 @@
                 "depthOfFieldMerge.fragment"
             ]
         },
+        "additionalPostProcess_bloomMerge": {
+            "files": [
+                "../../src/PostProcess/babylon.bloomMergePostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "bloomMerge.fragment"
+            ]
+        },
         "additionalPostProcess_depthOfFieldEffect": {
             "files": [
                 "../../src/PostProcess/babylon.depthOfFieldEffect.js"
@@ -755,6 +779,16 @@
                 "additionalPostProcess_circleOfConfusion"
             ]
         },
+        "additionalPostProcess_bloomEffect": {
+            "files": [
+                "../../src/PostProcess/babylon.bloomEffect.js"
+            ],
+            "dependUpon": [
+                "additionalPostProcess_blur",
+                "additionalPostProcess_bloomMerge",
+                "additionalPostProcess_extractHighlights"
+            ]
+        },
         "additionalPostProcess_fxaa": {
             "files": [
                 "../../src/PostProcess/babylon.fxaaPostProcess.js"
@@ -778,6 +812,17 @@
                 "highlights.fragment"
             ]
         },
+        "additionalPostProcess_extractHighlights": {
+            "files": [
+                "../../src/PostProcess/babylon.extractHighlightsPostProcess.js"
+            ],
+            "dependUpon": [
+                "postProcesses"
+            ],
+            "shaders": [
+                "extractHighlights.fragment"
+            ]
+        },
         "additionalPostProcess_imageProcessing": {
             "files": [
                 "../../src/PostProcess/babylon.imageProcessingPostProcess.js"
@@ -797,6 +842,7 @@
                 "../../src/PostProcess/babylon.convolutionPostProcess.js",
                 "../../src/PostProcess/babylon.sharpenPostProcess.js",
                 "../../src/PostProcess/babylon.chromaticAberrationPostProcess.js",
+                "../../src/PostProcess/babylon.grainPostProcess.js",
                 "../../src/PostProcess/babylon.filterPostProcess.js",
                 "../../src/PostProcess/babylon.fxaaPostProcess.js",
                 "../../src/PostProcess/babylon.volumetricLightScatteringPostProcess.js",
@@ -804,6 +850,7 @@
                 "../../src/PostProcess/babylon.tonemapPostProcess.js",
                 "../../src/PostProcess/babylon.displayPassPostProcess.js",
                 "../../src/PostProcess/babylon.highlightsPostProcess.js",
+                "../../src/PostProcess/babylon.extractHighlightsPostProcess.js",
                 "../../src/PostProcess/babylon.imageProcessingPostProcess.js"
             ],
             "dependUpon": [
@@ -850,7 +897,6 @@
                 "ssao.fragment",
                 "ssao2.fragment",
                 "ssaoCombine.fragment",
-                "chromaticAberration.fragment",
                 "lensHighlights.fragment",
                 "depthOfField.fragment",
                 "standard.fragment"
@@ -864,8 +910,10 @@
                 "renderingPipeline",
                 "additionalPostProcess_fxaa",
                 "additionalPostProcess_chromaticAberration",
+                "additionalPostProcess_grain",
                 "additionalPostProcess_sharpen",
-                "additionalPostProcess_depthOfFieldEffect"
+                "additionalPostProcess_depthOfFieldEffect",
+                "additionalPostProcess_bloomEffect"
             ]
         },
         "bones": {

File diff suppressed because it is too large
+ 25597 - 14218
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 55 - 55
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 454 - 288
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 56 - 56
dist/preview release/babylon.worker.js


File diff suppressed because it is too large
+ 456 - 290
dist/preview release/es6.js


File diff suppressed because it is too large
+ 4 - 4
dist/preview release/gui/babylon.gui.min.js


File diff suppressed because it is too large
+ 4 - 4
dist/preview release/inspector/babylon.inspector.bundle.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/inspector/babylon.inspector.min.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylon.glTFFileLoader.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/loaders/babylonjs.loaders.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.waterMaterial.min.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/postProcessesLibrary/babylonjs.postProcess.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.min.js


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

@@ -1,7 +1,7 @@
 {
-  "errors": 7088,
+  "errors": 7080,
   "babylon.typedoc.json": {
-    "errors": 7088,
+    "errors": 7080,
     "AnimationKeyInterpolation": {
       "Enumeration": {
         "Comments": {
@@ -8566,55 +8566,15 @@
     },
     "DefaultRenderingPipeline": {
       "Property": {
-        "BlurXPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
-        "BlurYPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
-        "ChromaticAberrationPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
-        "CopyBackPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
-        "FinalMergePostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
         "FxaaPostProcessId": {
           "Naming": {
             "NotCamelCase": true
           }
         },
-        "HighLightsPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
         "ImageProcessingPostProcessId": {
           "Naming": {
             "NotCamelCase": true
           }
-        },
-        "PassPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
-        },
-        "SharpenPostProcessId": {
-          "Naming": {
-            "NotCamelCase": true
-          }
         }
       }
     },

File diff suppressed because it is too large
+ 62 - 62
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 454 - 288
dist/preview release/viewer/babylon.viewer.max.js


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

@@ -13,7 +13,7 @@
 - Added [VideoDome](http://doc.babylonjs.com/how_to/360videodome) class to easily support 360 videos. Demo [here](https://www.babylonjs-playground.com/frame.html#1E9JQ8#7) ([DavidHGillen](https://github.com/DavidHGillen))
 - Added [GlowLayer](https://doc.babylonjs.com/how_to/glow_layer) to easily support glow from emissive materials. Demo [here](http://www.babylonjs.com/demos/GlowLayer/) ([sebavan](https://github.com/sebavan))
 - New [AssetContainer](http://doc.babylonjs.com/how_to/how_to_use_assetcontainer) class and loading methods ([trevordev](https://github.com/trevordev))
-- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#5), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
+- Added [depth of field](https://www.babylonjs-playground.com/frame.html#8F5HYV#9), sharpening, MSAA, chromatic aberration and grain effect to the default pipeline ([trevordev](https://github.com/trevordev))
 - Added support for [animation weights](http://doc.babylonjs.com/babylon101/animations#animation-weights). Demo [here](https://www.babylonjs-playground.com/#IQN716#9) ([deltakosh](https://github.com/deltakosh))
 - Added [sub emitters for particle system](http://doc.babylonjs.com/babylon101/particles#sub-emitters) which will spawn new particle systems when particles dies. Demo [here](https://www.babylonjs-playground.com/frame.html#9NHBCC#1) ([IbraheemOsama](https://github.com/IbraheemOsama))
 - New [Babylon.js](http://doc.babylonjs.com/resources/maya) and [glTF](http://doc.babylonjs.com/resources/maya_to_gltf) exporter for Autodesk Maya ([Noalak](https://github.com/Noalak))
@@ -102,6 +102,7 @@
 - Lightmap texture in PBR material follow the gammaSpace Flag of the texture ([sebavan](https://github.com/sebavan))
 - Added setTextureFromPostProcessOutput to bind the output of a postprocess into an effect ([trevordev](https://github.com/trevordev))
 - Added support for primitive modes to glTF 2.0 loader. ([bghgary](https://github.com/bghgary)]
+- Updated bloom effect to only bloom areas of the image above a luminance threshold ([trevordev](https://github.com/trevordev))
 - Cannon and Oimo are optional dependencies ([RaananW](https://github.com/RaananW))
 - Shadows - Introduces [Normal Bias](https://doc.babylonjs.com/babylon101/shadows#normal-bias-since-32) ([sebavan](https://github.com/sebavan)))
 
@@ -130,3 +131,4 @@
 - VertexData.merge no longer supports merging of data that do not have the same set of attributes. ([bghgary](https://github.com/bghgary)]
 - glTF 2.0 loader now creates a mesh for each primitive instead of merging the primitives together into one mesh. If a mesh only has one primitive, the behavior is the same as before. This change only affects meshes that have multiple primitives. ([bghgary](https://github.com/bghgary)]
 - Engine's onCanvasPointerOutObservable will now return a PointerEvent instead of the Engine. ([trevordev](https://github.com/trevordev))
+- Removed public references to default rendering pipeline's internal post process ([trevordev](https://github.com/trevordev))

+ 0 - 1
src/Materials/Background/babylon.backgroundMaterial.ts

@@ -83,7 +83,6 @@
         public SAMPLER3DBGRMAP = false;
         public IMAGEPROCESSINGPOSTPROCESS = false;
         public EXPOSURE = false;
-        public GRAIN = false;
 
         // Reflection.
         public REFLECTION = false;

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

@@ -120,7 +120,6 @@
         public SAMPLER3DBGRMAP = false;
         public IMAGEPROCESSINGPOSTPROCESS = false;
         public EXPOSURE = false;
-        public GRAIN = false;
 
         public USEPHYSICALLIGHTFALLOFF = false;
         public TWOSIDEDLIGHTING = false;

+ 2 - 2
src/Materials/babylon.effect.ts

@@ -258,7 +258,7 @@
 
                 this._attributesNames = options.attributes;
                 this._uniformsNames = options.uniformsNames.concat(options.samplers);
-                this._samplers = options.samplers;
+                this._samplers = options.samplers.slice();
                 this.defines = options.defines;
                 this.onError = options.onError;
                 this.onCompiled = options.onCompiled;
@@ -275,7 +275,7 @@
                 this._engine = <Engine>engine;
                 this.defines = <string>defines;
                 this._uniformsNames = (<string[]>uniformsNamesOrEngine).concat(<string[]>samplers);
-                this._samplers = <string[]>samplers;
+                this._samplers = samplers ? <string[]>samplers.slice() : [];
                 this._attributesNames = (<string[]>attributesNamesOrOptions);
 
                 this.onError = onError;

+ 1 - 64
src/Materials/babylon.imageProcessingConfiguration.ts

@@ -18,10 +18,6 @@ module BABYLON {
         SAMPLER3DGREENDEPTH: boolean;
         SAMPLER3DBGRMAP: boolean;
         IMAGEPROCESSINGPOSTPROCESS: boolean;
-        /** 
-         * If the grain should be performed in the image processing shader.
-         */
-        GRAIN: boolean;
     }
 
     /**
@@ -221,57 +217,6 @@ module BABYLON {
         public vignetteCameraFov = 0.5;
 
         @serialize()
-        private _grainEnabled = false;
-
-        /**
-         * If the grain effect should be enabled.
-         */
-        public get grainEnabled(): boolean {
-            return this._grainEnabled;
-        }
-        public set grainEnabled(value: boolean) {
-            if (this._grainEnabled === value) {
-                return;
-            }
-
-            this._grainEnabled = value;
-            this._updateParameters();
-        }
-
-        @serialize()
-        private _grainIntensity = 30;
-        /**
-         * Amount of grain to be applied by the grain effect.
-         */
-        public get grainIntensity(): number {
-            return this._grainIntensity;
-        }
-        public set grainIntensity(value: number) {
-            if (this._grainIntensity === value) {
-                return;
-            }
-            this._grainIntensity = value;
-        }
-
-        @serialize()
-        private _grainAnimated = false;
-
-        /**
-         * If the grain effect should be animated.
-         */
-        public get grainAnimated(): boolean {
-            return this._grainAnimated;
-        }
-        public set grainAnimated(value: boolean) {
-            if (this._grainAnimated === value) {
-                return;
-            }
-
-            this._grainAnimated = value;
-            this._updateParameters();
-        }
-
-        @serialize()
         private _vignetteBlendMode = ImageProcessingConfiguration.VIGNETTEMODE_MULTIPLY;
         /**
          * Gets the vignette blend mode allowing different kind of effect.
@@ -391,10 +336,6 @@ module BABYLON {
             if (defines.COLORCURVES) {
                 ColorCurves.PrepareUniforms(uniforms);
             }
-            if (defines.GRAIN){
-                uniforms.push("grainVarianceAmount");
-                uniforms.push("grainAnimatedSeed");
-            }
         }
 
         /**
@@ -442,8 +383,7 @@ module BABYLON {
             defines.SAMPLER3DGREENDEPTH = this.colorGradingWithGreenDepth;
             defines.SAMPLER3DBGRMAP = this.colorGradingBGR;
             defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess;
-            defines.GRAIN = this.grainEnabled;
-            defines.IMAGEPROCESSING = defines.VIGNETTE || defines.TONEMAPPING || defines.CONTRAST || defines.EXPOSURE || defines.COLORCURVES || defines.COLORGRADING || defines.GRAIN;
+            defines.IMAGEPROCESSING = defines.VIGNETTE || defines.TONEMAPPING || defines.CONTRAST || defines.EXPOSURE || defines.COLORCURVES || defines.COLORGRADING;
         }
 
         /**
@@ -501,9 +441,6 @@ module BABYLON {
                     this.colorGradingTexture.level // weight
                 );
             }
-
-            effect.setFloat("grainVarianceAmount", this.grainIntensity);
-            effect.setFloat("grainAnimatedSeed", this.grainAnimated ? Math.random() + 1 : 1);
         }
 
         /**

+ 0 - 1
src/Materials/babylon.standardMaterial.ts

@@ -88,7 +88,6 @@ module BABYLON {
         public SAMPLER3DBGRMAP = false;
         public IMAGEPROCESSINGPOSTPROCESS = false;
         public EXPOSURE = false;
-        public GRAIN = false;
 
         constructor() {
             super();

+ 159 - 185
src/PostProcess/RenderPipeline/Pipelines/babylon.defaultRenderingPipeline.ts

@@ -9,27 +9,7 @@
         /**
 		 * ID of the sharpen post process,
 		 */
-        readonly SharpenPostProcessId: string = "SharpenPostProcessEffect";
-        /**
-		 * ID of the pass post process used for bloom,
-		 */
-        readonly PassPostProcessId: string = "PassPostProcessEffect";
-        /**
-		 * ID of the highlight post process used for bloom,
-		 */
-        readonly HighLightsPostProcessId: string = "HighLightsPostProcessEffect";
-        /**
-		 * ID of the blurX post process used for bloom,
-		 */
-        readonly BlurXPostProcessId: string = "BlurXPostProcessEffect";
-        /**
-		 * ID of the blurY post process used for bloom,
-		 */
-        readonly BlurYPostProcessId: string = "BlurYPostProcessEffect";
-        /**
-		 * ID of the copy back post process used for bloom,
-		 */
-        readonly CopyBackPostProcessId: string = "CopyBackPostProcessEffect";
+        private readonly SharpenPostProcessId: string = "SharpenPostProcessEffect";
         /**
 		 * ID of the image processing post process;
 		 */
@@ -39,13 +19,13 @@
 		 */
         readonly FxaaPostProcessId: string = "FxaaPostProcessEffect";
         /**
-		 * ID of the final merge post process;
+		 * ID of the chromatic aberration post process,
 		 */
-        readonly FinalMergePostProcessId: string = "FinalMergePostProcessEffect";
+        private readonly ChromaticAberrationPostProcessId: string = "ChromaticAberrationPostProcessEffect";
         /**
-		 * ID of the chromatic aberration post process,
+		 * ID of the grain post process
 		 */
-        readonly ChromaticAberrationPostProcessId: string = "ChromaticAberrationPostProcessEffect";
+        private readonly GrainPostProcessId: string = "GrainPostProcessEffect";
 
         // Post-processes
         /**
@@ -53,26 +33,7 @@
 		 */
         public sharpen: SharpenPostProcess;
         private _sharpenEffect: PostProcessRenderEffect;
-        /**
-		 * First pass of bloom to capture the original image texture for later use.
-		 */
-        public pass: PassPostProcess;
-        /**
-		 * Second pass of bloom used to brighten bright portions of the image.
-		 */
-        public highlights: HighlightsPostProcess;
-        /**
-		 * BlurX post process used in coordination with blurY to guassian blur the highlighted image.
-		 */
-        public blurX: BlurPostProcess;
-        /**
-		 * BlurY post process used in coordination with blurX to guassian blur the highlighted image.
-		 */
-        public blurY: BlurPostProcess;
-        /**
-		 * Final pass run for bloom to copy the resulting bloom texture back to screen.
-		 */
-        public copyBack: PassPostProcess;
+        private bloom: BloomEffect;
         /**
          * Depth of field effect, applies a blur based on how far away objects are from the focus distance.
          */
@@ -86,31 +47,33 @@
          */
         public imageProcessing: ImageProcessingPostProcess;
         /**
-         * Final post process to merge results of all previous passes
-         */
-        public finalMerge: PassPostProcess;
-        /**
 		 * Chromatic aberration post process which will shift rgb colors in the image
 		 */
         public chromaticAberration: ChromaticAberrationPostProcess;
         private _chromaticAberrationEffect: PostProcessRenderEffect;
+        /**
+		 * Grain post process which add noise to the image
+		 */
+        public grain: GrainPostProcess;
+        private _grainEffect: PostProcessRenderEffect;
 
         /**
          * Animations which can be used to tweak settings over a period of time
          */
         public animations: Animation[] = [];
 
+        private _imageProcessingConfigurationObserver:Nullable<Observer<ImageProcessingConfiguration>> = null;
         // Values   
         private _sharpenEnabled:boolean = false;    
         private _bloomEnabled: boolean = false;
         private _depthOfFieldEnabled: boolean = false;
         private _depthOfFieldBlurLevel = DepthOfFieldEffectBlurLevel.Low;
         private _fxaaEnabled: boolean = false;
-        private _msaaEnabled: boolean = false;
         private _imageProcessingEnabled: boolean = true;
         private _defaultPipelineTextureType: number;
-        private _bloomScale: number = 0.6;
+        private _bloomScale: number = 0.5;
         private _chromaticAberrationEnabled:boolean = false;  
+        private _grainEnabled:boolean = false;  
 
         private _buildAllowed = true;
 
@@ -131,18 +94,31 @@
             return this._sharpenEnabled;
         }
 
-
+        private _resizeObserver:Nullable<Observer<Engine>> = null;
+        private _hardwareScaleLevel = 1.0;
+        private _bloomKernel: number = 64;
         /**
 		 * Specifies the size of the bloom blur kernel, relative to the final output size
 		 */
         @serialize()
-        public bloomKernel: number = 64;
+        public get bloomKernel(): number{
+            return this._bloomKernel;
+        }
+        public set bloomKernel(value: number){
+            this._bloomKernel = value;
+            this.bloom.kernel = value/this._hardwareScaleLevel;
+        }
 
         /**
 		 * Specifies the weight of the bloom in the final rendering
 		 */
         @serialize()
         private _bloomWeight: number = 0.15;
+        /**
+		 * Specifies the luma threshold for the area that will be blurred by the bloom
+		 */
+        @serialize()
+        private _bloomThreshold: number = 0.9;
 
         @serialize()
         private _hdr: boolean;
@@ -154,11 +130,9 @@
             if (this._bloomWeight === value) {
                 return;
             }
+            this.bloom.weight = value;
+            
             this._bloomWeight = value;
-
-            if (this._hdr && this.copyBack) {
-                this.copyBack.alphaConstants = new Color4(value, value, value, value);
-            }
         }
 
         @serialize()
@@ -167,6 +141,22 @@
         }
 
         /**
+         * The strength of the bloom.
+         */
+        public set bloomThreshold(value: number) {
+            if (this._bloomThreshold === value) {
+                return;
+            }
+            this.bloom.threshold = value;
+            this._bloomThreshold = value;
+        }
+
+        @serialize()
+        public get bloomThreshold(): number {
+            return this._bloomThreshold;
+        }
+
+        /**
          * The scale of the bloom, lower value will provide better performance.
          */
         public set bloomScale(value: number) {
@@ -175,6 +165,9 @@
             }
             this._bloomScale = value;
 
+            // recreate bloom and dispose old as this setting is not dynamic
+            this._rebuildBloom();
+
             this._buildPipeline();
         }
 
@@ -200,6 +193,16 @@
             return this._bloomEnabled;
         }
 
+        private _rebuildBloom(){
+            // recreate bloom and dispose old as this setting is not dynamic
+            var oldBloom = this.bloom;
+            this.bloom = new BloomEffect(this._scene, this.bloomScale, this._bloomWeight, this.bloomKernel, this._defaultPipelineTextureType, false);
+            this.bloom.threshold = oldBloom.threshold;
+            for (var i = 0; i < this._cameras.length; i++) {
+                oldBloom.disposeEffects(this._cameras[i]);
+            }
+        }
+
         /**
          * If the depth of field is enabled.
          */
@@ -234,7 +237,7 @@
             // recreate dof and dispose old as this setting is not dynamic
             var oldDof = this.depthOfField;
             
-            this.depthOfField = new DepthOfFieldEffect(this._scene, null, this._depthOfFieldBlurLevel, this._defaultPipelineTextureType);
+            this.depthOfField = new DepthOfFieldEffect(this._scene, null, this._depthOfFieldBlurLevel, this._defaultPipelineTextureType, false);
             this.depthOfField.focalLength = oldDof.focalLength;
             this.depthOfField.focusDistance = oldDof.focusDistance;
             this.depthOfField.fStop = oldDof.fStop;
@@ -264,21 +267,22 @@
             return this._fxaaEnabled;
         }
 
+        private _samples = 1;
         /**
-         * If the multisample anti-aliasing is enabled.
+         * MSAA sample count, setting this to 4 will provide 4x anti aliasing. (default: 1)
          */
-        public set msaaEnabled(enabled: boolean) {
-            if (this._msaaEnabled === enabled) {
+        public set samples(sampleCount: number) {
+            if (this._samples === sampleCount) {
                 return;
             }
-            this._msaaEnabled = enabled;
+            this._samples = sampleCount;
 
             this._buildPipeline();
         }
 
         @serialize()
-        public get msaaEnabled(): boolean {
-            return this._msaaEnabled;
+        public get samples(): number {
+            return this._samples;
         }
 
         /**
@@ -314,6 +318,22 @@
         public get chromaticAberrationEnabled(): boolean {
             return this._chromaticAberrationEnabled;
         }
+        /**
+         * Enable or disable the grain process from the pipeline
+         */
+        public set grainEnabled(enabled: boolean) {
+            if (this._grainEnabled === enabled) {
+                return;
+            }
+            this._grainEnabled = enabled;
+
+            this._buildPipeline();
+        }
+
+        @serialize()
+        public get grainEnabled(): boolean {
+            return this._grainEnabled;
+        }
 
         /**
          * @constructor
@@ -358,9 +378,23 @@
 
             this.depthOfField = new DepthOfFieldEffect(this._scene, null, this._depthOfFieldBlurLevel, this._defaultPipelineTextureType, true);
             
+            this.bloom = new BloomEffect(this._scene, this._bloomScale, this._bloomWeight, this.bloomKernel, this._defaultPipelineTextureType, true);
+
             this.chromaticAberration = new ChromaticAberrationPostProcess("ChromaticAberration", engine.getRenderWidth(), engine.getRenderHeight(), 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType, true);
             this._chromaticAberrationEffect = new PostProcessRenderEffect(engine, this.ChromaticAberrationPostProcessId, () => { return this.chromaticAberration; }, true);
-            
+
+            this.grain = new GrainPostProcess("Grain", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType, true);
+            this._grainEffect = new PostProcessRenderEffect(engine, this.GrainPostProcessId, () => { return this.grain; }, true);
+
+            this._resizeObserver = engine.onResizeObservable.add(()=>{
+                this._hardwareScaleLevel = engine.getHardwareScalingLevel();
+                this.bloomKernel = this.bloomKernel
+            })
+
+            this._imageProcessingConfigurationObserver = this._scene.imageProcessingConfiguration.onUpdateParameters.add(()=>{
+                this.bloom._downscale._exposure = this._scene.imageProcessingConfiguration.exposure;
+            })
+
             this._buildPipeline();
         }
 
@@ -374,14 +408,17 @@
             this._buildAllowed = previousState;
         }
 
+        private _hasCleared = false;
         private _prevPostProcess:Nullable<PostProcess> = null;
         private _prevPrevPostProcess:Nullable<PostProcess> = null;
 
         private _setAutoClearAndTextureSharing(postProcess:PostProcess, skipTextureSharing = false){
-            if(this._prevPostProcess && this._prevPostProcess.autoClear){
+            if(this._hasCleared){
                 postProcess.autoClear = false;
             }else{
                 postProcess.autoClear = true;
+                this._scene.autoClear = false;
+                this._hasCleared = true;
             }
 
             if(!skipTextureSharing){
@@ -402,7 +439,8 @@
             if (!this._buildAllowed) {
                 return;
             }
-
+            this._scene.autoClear = true;
+            
             var engine = this._scene.getEngine();
 
             this._disposePostProcesses();
@@ -414,14 +452,7 @@
             this._reset();
             this._prevPostProcess = null;
             this._prevPrevPostProcess = null;
-
-            if (this.sharpenEnabled) {
-                if(!this.sharpen.isReady()){
-                    this.sharpen.updateEffect();
-                }
-                this.addEffect(this._sharpenEffect);
-                this._setAutoClearAndTextureSharing(this.sharpen);
-            }
+            this._hasCleared = false;            
 
             if (this.depthOfFieldEnabled) {
                 var depthTexture = this._scene.enableDepthRenderer(this._cameras[0]).getDepthMap();
@@ -430,90 +461,41 @@
                     this.depthOfField._updateEffects();
                 }
                 this.addEffect(this.depthOfField);
-                this._setAutoClearAndTextureSharing(this.depthOfField._depthOfFieldMerge);
+                this._setAutoClearAndTextureSharing(this.depthOfField._effects[0], true);
             }
 
             if (this.bloomEnabled) {
-                this.pass = new PassPostProcess("sceneRenderTarget", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this._setAutoClearAndTextureSharing(this.pass, true);
-                this.addEffect(new PostProcessRenderEffect(engine, this.PassPostProcessId, () => { return this.pass; }, true));
-
-                if (!this._hdr) { // Need to enhance highlights if not using float rendering
-                    this.highlights = new HighlightsPostProcess("highlights", this.bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                    this.addEffect(new PostProcessRenderEffect(engine, this.HighLightsPostProcessId, () => { return this.highlights; }, true));
-                    this.highlights.autoClear = false;
-                    this.highlights.alwaysForcePOT = true;
-                }
-
-                this.blurX = new BlurPostProcess("horizontal blur", new Vector2(1.0, 0), 10.0, this.bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this.addEffect(new PostProcessRenderEffect(engine, this.BlurXPostProcessId, () => { return this.blurX; }, true));
-                this.blurX.alwaysForcePOT = true;
-                this.blurX.autoClear = false;
-                this.blurX.onActivateObservable.add(() => {
-                    let dw = this.blurX.width / engine.getRenderWidth(true);
-                    this.blurX.kernel = this.bloomKernel * dw;
-                });
-
-                this.blurY = new BlurPostProcess("vertical blur", new Vector2(0, 1.0), 10.0, this.bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this.addEffect(new PostProcessRenderEffect(engine, this.BlurYPostProcessId, () => { return this.blurY; }, true));
-                this.blurY.alwaysForcePOT = true;
-                this.blurY.autoClear = false;
-                this.blurY.onActivateObservable.add(() => {
-                    let dh = this.blurY.height / engine.getRenderHeight(true);
-                    this.blurY.kernel = this.bloomKernel * dh;
-                });
-
-                this.copyBack = new PassPostProcess("bloomBlendBlit", this.bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this.addEffect(new PostProcessRenderEffect(engine, this.CopyBackPostProcessId, () => { return this.copyBack; }, true));
-                this.copyBack.alwaysForcePOT = true;
-                if (this._hdr) {
-                    this.copyBack.alphaMode = Engine.ALPHA_INTERPOLATE;
-                    let w = this.bloomWeight;
-                    this.copyBack.alphaConstants = new Color4(w, w, w, w);
-                } else {
-                    this.copyBack.alphaMode = Engine.ALPHA_SCREENMODE;
-                }
-                this.copyBack.autoClear = false;
-            }
-
-            if (this._imageProcessingEnabled) {
-                this.imageProcessing = new ImageProcessingPostProcess("imageProcessing", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                if (this._hdr) {
-                    this.addEffect(new PostProcessRenderEffect(engine, this.ImageProcessingPostProcessId, () => { return this.imageProcessing; }, true));
-                } else {
-                    this._scene.imageProcessingConfiguration.applyByPostProcess = false;
+                if(!this.bloom._isReady()){
+                    this.bloom._updateEffects();
                 }
+                this.addEffect(this.bloom);
+                this._setAutoClearAndTextureSharing(this.bloom._effects[0], true);
             }
 
-            if (this._hdr && this.imageProcessing) {
-                this.finalMerge = this.imageProcessing;
-            }
-            else {
-                this.finalMerge = new PassPostProcess("finalMerge", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this.addEffect(new PostProcessRenderEffect(engine, this.FinalMergePostProcessId, () => { return this.finalMerge; }, true));
-                this._setAutoClearAndTextureSharing(this.finalMerge, true);
-                
-                this.finalMerge.autoClear = !this.bloomEnabled && (!this._hdr || !this.imageProcessing);
+            if (this._imageProcessingEnabled) {	
+                this.imageProcessing = new ImageProcessingPostProcess("imageProcessing", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);	
+                if (this._hdr) {	
+                    this.addEffect(new PostProcessRenderEffect(engine, this.ImageProcessingPostProcessId, () => { return this.imageProcessing; }, true));	
+                    this._setAutoClearAndTextureSharing(this.imageProcessing);	
+                } else {		
+                    this._scene.imageProcessingConfiguration.applyByPostProcess = false;		
+                }		
             }
 
-            if (this.bloomEnabled) {
-                if (this._hdr) { // Share render targets to save memory
-                    this.copyBack.shareOutputWith(this.blurX);
-                    if (this.imageProcessing) {
-                        this.imageProcessing.shareOutputWith(this.pass);
-                        this.imageProcessing.autoClear = false;
-                    } else {
-                        this.finalMerge.shareOutputWith(this.pass);
-                    }
-                } else {
-                    this.finalMerge.shareOutputWith(this.pass);
+            if (this.sharpenEnabled) {
+                if(!this.sharpen.isReady()){
+                    this.sharpen.updateEffect();
                 }
+                this.addEffect(this._sharpenEffect);
+                this._setAutoClearAndTextureSharing(this.sharpen);
             }
 
-            if (this.fxaaEnabled) {
-                this.fxaa = new FxaaPostProcess("fxaa", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
-                this.addEffect(new PostProcessRenderEffect(engine, this.FxaaPostProcessId, () => { return this.fxaa; }, true));
-                this._setAutoClearAndTextureSharing(this.fxaa);
+            if (this.grainEnabled) {
+                if(!this.grain.isReady()){
+                    this.grain.updateEffect();
+                }
+                this.addEffect(this._grainEffect);
+                this._setAutoClearAndTextureSharing(this.grain);
             }
 
             if (this.chromaticAberrationEnabled) {
@@ -524,14 +506,19 @@
                 this._setAutoClearAndTextureSharing(this.chromaticAberration);
             }
 
+            if (this.fxaaEnabled) {
+                this.fxaa = new FxaaPostProcess("fxaa", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._defaultPipelineTextureType);
+                this.addEffect(new PostProcessRenderEffect(engine, this.FxaaPostProcessId, () => { return this.fxaa; }, true));
+                this._setAutoClearAndTextureSharing(this.fxaa, true);
+            }
+
             if (this._cameras !== null) {
                 this._scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(this._name, this._cameras);
             }
 
-            if(this.msaaEnabled){
-                if(!this._enableMSAAOnFirstPostProcess()){
-                    BABYLON.Tools.Warn("MSAA failed to enable, MSAA is only supported in browsers that support webGL >= 2.0");
-                }
+            
+            if(!this._enableMSAAOnFirstPostProcess(this.samples) && this.samples > 1){
+                BABYLON.Tools.Warn("MSAA failed to enable, MSAA is only supported in browsers that support webGL >= 2.0");
             }
         }
 
@@ -539,26 +526,6 @@
             for (var i = 0; i < this._cameras.length; i++) {
                 var camera = this._cameras[i];
 
-                if (this.pass) {
-                    this.pass.dispose(camera);
-                }
-
-                if (this.highlights) {
-                    this.highlights.dispose(camera);
-                }
-
-                if (this.blurX) {
-                    this.blurX.dispose(camera);
-                }
-
-                if (this.blurY) {
-                    this.blurY.dispose(camera);
-                }
-
-                if (this.copyBack) {
-                    this.copyBack.dispose(camera);
-                }
-
                 if (this.imageProcessing) {
                     this.imageProcessing.dispose(camera);
                 }
@@ -567,10 +534,6 @@
                     this.fxaa.dispose(camera);
                 }
 
-                if (this.finalMerge) {
-                    this.finalMerge.dispose(camera);
-                }
-
                 // These are created in the constructor and should not be disposed on every pipeline change
                 if(disposeNonRecreated){
                     if (this.sharpen) {
@@ -580,26 +543,33 @@
                     if(this.depthOfField){
                         this.depthOfField.disposeEffects(camera);
                     }
+
+                    if(this.bloom){
+                        this.bloom.disposeEffects(camera);
+                    }
     
                     if(this.chromaticAberration){
                         this.chromaticAberration.dispose(camera);
                     }
+
+                    if(this.grain){
+                        this.grain.dispose(camera);
+                    }
                 }
             }
-
-            (<any>this.pass) = null;
-            (<any>this.highlights) = null;
-            (<any>this.blurX) = null;
-            (<any>this.blurY) = null;
-            (<any>this.copyBack) = null;
+            
             (<any>this.imageProcessing) = null;
             (<any>this.fxaa) = null;
-            (<any>this.finalMerge) = null;
 
             if(disposeNonRecreated){
                 (<any>this.sharpen) = null;
+                (<any>this._sharpenEffect) = null;
                 (<any>this.depthOfField) = null;
+                (<any>this.bloom) = null;
                 (<any>this.chromaticAberration) = null;
+                (<any>this._chromaticAberrationEffect) = null;
+                (<any>this.grain) = null;
+                (<any>this._grainEffect) = null;
             } 
         }
 
@@ -608,9 +578,13 @@
          */
         public dispose(): void {
             this._disposePostProcesses(true);
-
             this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._cameras);
-
+            this._scene.autoClear = true;
+            if(this._resizeObserver){
+                this._scene.getEngine().onResizeObservable.remove(this._resizeObserver);
+                this._resizeObserver = null;
+            }
+            this._scene.imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingConfigurationObserver)
             super.dispose();
         }
 

+ 2 - 2
src/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.ts

@@ -143,13 +143,13 @@ module BABYLON {
             this._renderEffectsForIsolatedPass = new Array<PostProcessRenderEffect>();
         }
 
-        protected _enableMSAAOnFirstPostProcess():boolean{
+        protected _enableMSAAOnFirstPostProcess(sampleCount: number):boolean{
             // Set samples of the very first post process to 4 to enable native anti-aliasing in browsers that support webGL 2.0 (See: https://github.com/BabylonJS/Babylon.js/issues/3754)
             var effectKeys = Object.keys(this._renderEffects);
             if(this.engine.webGLVersion >= 2 && effectKeys.length > 0){
                 var postProcesses = this._renderEffects[effectKeys[0]].getPostProcesses();
                 if(postProcesses){
-                    postProcesses[0].samples = 4;
+                    postProcesses[0].samples = sampleCount;
                     return true;
                 }
             }

+ 2 - 2
src/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.ts

@@ -1,7 +1,7 @@
 module BABYLON {
     export class PostProcessRenderPipelineManager {
-        private _renderPipelines: any;
-
+        private _renderPipelines: {[Key:string]:PostProcessRenderPipeline};
+        
         constructor() {
             this._renderPipelines = {};
         }

+ 117 - 0
src/PostProcess/babylon.bloomEffect.ts

@@ -0,0 +1,117 @@
+module BABYLON {
+    /**
+     * The bloom effect spreads bright areas of an image to simulate artifacts seen in cameras
+     */
+    export class BloomEffect extends PostProcessRenderEffect{
+        /**
+         * Internal
+         */
+        public _effects: Array<PostProcess> = [];
+
+        /**
+         * Internal
+         */
+        public _downscale:ExtractHighlightsPostProcess;
+        private _blurX:BlurPostProcess;
+        private _blurY:BlurPostProcess;
+        private _upscale:PassPostProcess;
+        private _merge:BloomMergePostProcess;
+        
+        /**
+         * The luminance threshold to find bright areas of the image to bloom. 
+         */
+        public get threshold():number{
+            return this._downscale.threshold;
+        }
+        public set threshold(value: number){
+            this._downscale.threshold = value;
+        }
+
+        /**
+         * The strength of the bloom.
+         */
+        public get weight():number{
+            return this._merge.weight;
+        }
+        public set weight(value: number){
+            this._merge.weight = value;
+        }
+
+        /**
+         * Specifies the size of the bloom blur kernel, relative to the final output size
+         */
+        public get kernel():number{
+            return this._blurX.kernel / this.bloomScale;
+        }
+        public set kernel(value: number){
+            this._blurX.kernel = value * this.bloomScale;
+            this._blurY.kernel = value * this.bloomScale;
+        }
+        
+        /**
+         * Creates a new instance of @see BloomEffect
+         * @param scene The scene the effect belongs to.
+         * @param bloomScale The ratio of the blur texture to the input texture that should be used to compute the bloom.
+         * @param bloomKernel The size of the kernel to be used when applying the blur.
+         * @param bloomWeight The the strength of bloom.
+         * @param pipelineTextureType The type of texture to be used when performing the post processing.
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+         */
+        constructor(scene: Scene, private bloomScale:number, bloomWeight:number, bloomKernel:number, pipelineTextureType = 0, blockCompilation = false) {
+            super(scene.getEngine(), "bloom", ()=>{
+                return this._effects;
+            }, true);
+            this._downscale = new ExtractHighlightsPostProcess("highlights", 1.0, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+
+            this._blurX = new BlurPostProcess("horizontal blur", new Vector2(1.0, 0), 10.0, bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, undefined, blockCompilation);
+            this._blurX.alwaysForcePOT = true;
+            this._blurX.autoClear = false;
+
+            this._blurY = new BlurPostProcess("vertical blur", new Vector2(0, 1.0), 10.0, bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, undefined, blockCompilation);
+            this._blurY.alwaysForcePOT = true;
+            this._blurY.autoClear = false;
+
+            this.kernel = bloomKernel;
+
+            this._upscale = new PassPostProcess("upscale", bloomScale, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+            this._upscale.autoClear = false;
+            this._effects = [this._downscale, this._blurX, this._blurY, this._upscale];
+
+            this._merge = new BloomMergePostProcess("bloomMerge", this._downscale, this._blurY, bloomWeight, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+            this._merge.autoClear = false;
+            this._effects.push(this._merge);
+        }
+
+        /**
+         * Disposes each of the internal effects for a given camera.
+         * @param camera The camera to dispose the effect on.
+         */
+        public disposeEffects(camera:Camera){
+            for(var effect in this._effects){
+                this._effects[effect].dispose(camera);
+            }
+        }
+        
+        /**
+         * Internal
+         */
+        public _updateEffects(){
+            for(var effect in this._effects){
+                this._effects[effect].updateEffect();
+            }
+        }
+
+        /**
+         * Internal
+         * @returns if all the contained post processes are ready.
+         */
+        public _isReady(){
+            for(var effect in this._effects){
+                if(!this._effects[effect].isReady()){
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+}

+ 33 - 0
src/PostProcess/babylon.bloomMergePostProcess.ts

@@ -0,0 +1,33 @@
+module BABYLON {
+    /**
+     * The BloomMergePostProcess merges blurred images with the original based on the values of the circle of confusion.
+     */
+    export class BloomMergePostProcess extends PostProcess {
+        /**
+         * Creates a new instance of @see BloomMergePostProcess
+         * @param name The name of the effect.
+         * @param originalFromInput Post process which's input will be used for the merge.
+         * @param blurred Blurred highlights post process which's output will be used.
+         * @param weight Weight of the bloom to be added to the original input.
+         * @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)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+         */
+        constructor(name: string, originalFromInput:PostProcess, blurred:PostProcess, /** Weight of the bloom to be added to the original input. */ public weight:number, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+            super(name, "bloomMerge", ["bloomWeight"], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2", "bloomBlur"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setTextureFromPostProcess("textureSampler", originalFromInput);
+                effect.setTextureFromPostProcessOutput("bloomBlur", blurred);
+                effect.setFloat("bloomWeight", this.weight);   
+            });
+
+            if(!blockCompilation){
+                this.updateEffect();
+            }
+        }
+    }
+}

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

@@ -174,6 +174,7 @@
 				defines += `#define PACKEDFLOAT 1`;
 			}
 
+			this.blockCompilation = false;
             super.updateEffect(defines, null, null, {
 				varyingCount: varyingCount,
 				depCount: depCount

+ 16 - 18
src/PostProcess/babylon.depthOfFieldEffect.ts

@@ -21,14 +21,17 @@ module BABYLON {
      */
     export class DepthOfFieldEffect extends PostProcessRenderEffect{
         private _circleOfConfusion: CircleOfConfusionPostProcess;
-        private _depthOfFieldBlurX: Array<DepthOfFieldBlurPostProcess>;
-        private _depthOfFieldBlurY: Array<DepthOfFieldBlurPostProcess>;
         /**
-         * Private, last post process of dof
+         * Internal, blurs from high to low
          */
-        public _depthOfFieldMerge: DepthOfFieldMergePostProcess;
+        public _depthOfFieldBlurX: Array<DepthOfFieldBlurPostProcess>;
+        private _depthOfFieldBlurY: Array<DepthOfFieldBlurPostProcess>;
+        private _dofMerge: Nullable<DepthOfFieldMergePostProcess>;
 
-        private _effects: Array<PostProcess> = [];
+        /**
+         * Internal post processes in depth of field effect
+         */
+        public _effects: Array<PostProcess> = [];
 
         /**
          * The focal the length of the camera used in the effect
@@ -114,10 +117,6 @@ module BABYLON {
                 this._depthOfFieldBlurY.push(blurY);
                 this._depthOfFieldBlurX.push(blurX);
             }
-
-            // Merge blurred images with original image based on circleOfConfusion
-            this._depthOfFieldMerge = new DepthOfFieldMergePostProcess("depthOfFieldMerge", this._circleOfConfusion, this._circleOfConfusion, this._depthOfFieldBlurX, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
-            this._depthOfFieldMerge.autoClear = false;
             
             // Set all post processes on the effect.
             this._effects= [this._circleOfConfusion];
@@ -125,7 +124,11 @@ module BABYLON {
                 this._effects.push(this._depthOfFieldBlurY[i]);
                 this._effects.push(this._depthOfFieldBlurX[i]);
             }
-            this._effects.push(this._depthOfFieldMerge);
+
+            // Merge blurred images with original image based on circleOfConfusion
+            this._dofMerge = new DepthOfFieldMergePostProcess("dofMerge", this._circleOfConfusion, this._circleOfConfusion, this._depthOfFieldBlurX, 1, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, pipelineTextureType, blockCompilation);
+            this._dofMerge.autoClear = false;
+            this._effects.push(this._dofMerge);
         }
 
         /**
@@ -140,14 +143,9 @@ module BABYLON {
          * @param camera The camera to dispose the effect on.
          */
         public disposeEffects(camera:Camera){
-            this._circleOfConfusion.dispose(camera);
-            this._depthOfFieldBlurX.forEach(element => {
-                element.dispose(camera);
-            });
-            this._depthOfFieldBlurY.forEach(element => {
-                element.dispose(camera);
-            });
-            this._depthOfFieldMerge.dispose(camera);
+            for(var effect in this._effects){
+                this._effects[effect].dispose(camera);
+            }            
         }
 
         /**

+ 37 - 9
src/PostProcess/babylon.depthOfFieldMergePostProcess.ts

@@ -1,14 +1,38 @@
 module BABYLON {
     /**
+     * Options to be set when merging outputs from the default pipeline.
+     */
+	export class DepthOfFieldMergePostProcessOptions {
+        /**
+         * The original image to merge on top of
+         */
+        public originalFromInput: PostProcess;
+        /**
+         * Parameters to perform the merge of the depth of field effect
+         */
+        public depthOfField?: {
+            circleOfConfusion: PostProcess;
+            blurSteps: Array<PostProcess>;
+        };
+        /**
+         * Parameters to perform the merge of bloom effect
+         */
+        public bloom?: {
+            blurred: PostProcess;
+            weight: number;
+        };
+    }
+
+    /**
      * 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 CircleOfConfusionPostProcess
+         * Creates a new instance of DepthOfFieldMergePostProcess
          * @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 blurSteps Incrimental bluring post processes.
+         * @param originalFromInput Post process which's input will be used for the merge.
+         * @param circleOfConfusion Circle of confusion post process which's output will be used to blur each pixel.
+         * @param blurSteps Blur post processes from low to high which will be mixed with the original image.
          * @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)
@@ -17,14 +41,14 @@ module BABYLON {
          * @param textureType Type of textures used when performing the post process. (default: 0)
          * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
          */
-        constructor(name: string, original: PostProcess, circleOfConfusion: PostProcess, private blurSteps: Array<PostProcess>, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
-            super(name, "depthOfFieldMerge", [], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
+        constructor(name: string, originalFromInput:PostProcess, circleOfConfusion:PostProcess, private blurSteps:Array<PostProcess>, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+            super(name, "depthOfFieldMerge", ["bloomWeight"], ["circleOfConfusionSampler", "blurStep0", "blurStep1", "blurStep2", "bloomBlur"], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, true);
             this.onApplyObservable.add((effect: Effect) => {
+                effect.setTextureFromPostProcess("textureSampler", originalFromInput);
                 effect.setTextureFromPostProcessOutput("circleOfConfusionSampler", circleOfConfusion);
-                effect.setTextureFromPostProcess("textureSampler", original);
                 blurSteps.forEach((step,index)=>{
                     effect.setTextureFromPostProcessOutput("blurStep"+(blurSteps.length-index-1), step);
-                });
+                });    
             });
 
             if(!blockCompilation){
@@ -43,7 +67,11 @@ module BABYLON {
          */
         public updateEffect(defines: Nullable<string> = null, uniforms: Nullable<string[]> = null, samplers: Nullable<string[]> = null, indexParameters?: any,
             onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void) {
-            super.updateEffect(defines ? defines : "#define BLUR_LEVEL "+(this.blurSteps.length-1)+"\n", uniforms, samplers, indexParameters, onCompiled, onError);
+            if(!defines){
+                defines = "";
+                defines += "#define BLUR_LEVEL "+(this.blurSteps.length-1)+"\n";
+            }
+            super.updateEffect(defines, uniforms, samplers, indexParameters, onCompiled, onError);
         }
     }
 }

+ 30 - 0
src/PostProcess/babylon.extractHighlightsPostProcess.ts

@@ -0,0 +1,30 @@
+module BABYLON {
+    /**
+     * The extract highlights post process sets all pixels to black except pixels above the specified luminance threshold. Used as the first step for a bloom effect.
+     */
+    export class ExtractHighlightsPostProcess extends PostProcess {
+        /**
+         * The luminance threshold, pixels below this value will be set to black.
+         */
+        public threshold = 0.9;
+
+        /**
+         * Internal
+         */
+        public _exposure = 1;
+        /**
+         * Post process which has the input texture to be used when performing highlight extraction
+         */
+        public _inputPostProcess:Nullable<PostProcess> = null;
+        constructor(name: string, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+            super(name, "extractHighlights", ["threshold", "exposure"], null, options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation);
+            this.onApplyObservable.add((effect: Effect) => {
+                if(this._inputPostProcess){
+                    effect.setTextureFromPostProcess("textureSampler", this._inputPostProcess);
+                }
+                effect.setFloat('threshold', Math.pow(this.threshold, BABYLON.ToGammaSpace));
+                effect.setFloat('exposure', this._exposure);
+            })
+        }
+    }
+} 

+ 34 - 0
src/PostProcess/babylon.grainPostProcess.ts

@@ -0,0 +1,34 @@
+module BABYLON {
+    /**
+     * The GrainPostProcess adds noise to the image at mid luminance levels
+     */
+    export class GrainPostProcess extends PostProcess {
+        /**
+         * The intensity of the grain added (default: 30)
+         */
+        public intensity:number = 30;
+        /**
+         * If the grain should be randomized on every frame
+         */
+        public animated:boolean = false;
+        
+        /**
+         * Creates a new instance of @see GrainPostProcess
+         * @param name The name of the effect.
+         * @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)
+         * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
+         */
+        constructor(name: string, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false) {
+            super(name, "grain", ["intensity", "animatedSeed"], [], options, camera, samplingMode, engine, reusable, null, textureType, undefined, null, blockCompilation);
+            this.onApplyObservable.add((effect: Effect) => {
+                effect.setFloat('intensity', this.intensity);
+                effect.setFloat('animatedSeed', this.animated ? Math.random() + 1 : 1);
+            })
+        }
+    }
+}

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

@@ -272,45 +272,6 @@
             this.imageProcessingConfiguration.vignetteEnabled = value;
         }
 
-        /**
-         * Gets wether the grain effect is enabled.
-         */
-        public get grainEnabled(): boolean {
-            return this.imageProcessingConfiguration.grainEnabled;
-        }
-        /**
-         * Sets wether the grain effect is enabled.
-         */
-        public set grainEnabled(value: boolean) {
-            this.imageProcessingConfiguration.grainEnabled = value;
-        }
-
-        /**
-         * Gets the grain effect's intensity.
-         */
-        public get grainIntensity(): number {
-            return this.imageProcessingConfiguration.grainIntensity;
-        }
-        /**
-         * Sets the grain effect's intensity.
-         */
-        public set grainIntensity(value: number) {
-            this.imageProcessingConfiguration.grainIntensity = value;
-        }
-
-        /**
-         * Gets wether the grain effect is animated.
-         */
-        public get grainAnimated(): boolean {
-            return this.imageProcessingConfiguration.grainAnimated;
-        }
-        /**
-         * Sets wether the grain effect is animated.
-         */
-        public set grainAnimated(value: boolean) {
-            this.imageProcessingConfiguration.grainAnimated = value;
-        }
-
         @serialize()
         private _fromLinearSpace = true;
         /**
@@ -349,7 +310,6 @@
             SAMPLER3DBGRMAP: false,
             IMAGEPROCESSINGPOSTPROCESS: false,
             EXPOSURE: false,
-            GRAIN: false,
         }
 
         constructor(name: string, options: number | PostProcessOptions, camera: Nullable<Camera> = null, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Engine.TEXTURETYPE_UNSIGNED_INT, imageProcessingConfiguration?: ImageProcessingConfiguration) {

+ 1 - 1
src/PostProcess/babylon.postProcess.ts

@@ -19,7 +19,6 @@
         * Internal, reference to the location where this postprocess was output to. (Typically the texture on the next postprocess in the chain)
         */
         public _outputTexture: Nullable<InternalTexture> = null;
-
         /**
         * Sampling mode used by the shader
         * See https://doc.babylonjs.com/classes/3.1/texture
@@ -73,6 +72,7 @@
         private _camera: Camera;
         private _scene: Scene;
         private _engine: Engine;
+        
         private _options: number | PostProcessOptions;
         private _reusable = false;
         private _textureType: number;

+ 0 - 5
src/Shaders/ShadersInclude/imageProcessingDeclaration.fx

@@ -25,9 +25,4 @@
 		uniform sampler2D txColorTransform;
 	#endif
 	uniform vec4 colorTransformSettings;
-#endif
-
-#ifdef GRAIN
-	uniform float grainVarianceAmount;
-	uniform float grainAnimatedSeed;
 #endif

+ 3 - 5
src/Shaders/background.fragment.fx

@@ -287,11 +287,9 @@ vec4 color = vec4(finalColor, finalAlpha);
     color.rgb *= color.a;
 #endif
 
-#ifndef GRAIN // Do not apply noise multiple times
-    #ifdef NOISE
-        color.rgb += dither(vPositionW.xy, 0.5);
-        color = max(color, 0.0);
-    #endif
+#ifdef NOISE
+    color.rgb += dither(vPositionW.xy, 0.5);
+    color = max(color, 0.0);
 #endif
 
     gl_FragColor = color;

+ 12 - 0
src/Shaders/bloomMerge.fragment.fx

@@ -0,0 +1,12 @@
+uniform sampler2D textureSampler;
+uniform sampler2D bloomBlur;
+
+varying vec2 vUV;
+uniform float bloomWeight;
+
+void main(void)
+{
+    gl_FragColor = texture2D(textureSampler, vUV);
+    vec3 blurred = texture2D(bloomBlur, vUV).rgb;
+    gl_FragColor.rgb = gl_FragColor.rgb + (blurred.rgb * bloomWeight); 
+}

+ 1 - 1
src/Shaders/chromaticAberration.fragment.fx

@@ -39,6 +39,6 @@ void main(void)
 	original.r = texture2D(textureSampler, ref_coords_r).r;
 	original.g = texture2D(textureSampler, ref_coords_g).g;
 	original.b = texture2D(textureSampler, ref_coords_b).b;
-
+	original.a = clamp(texture2D(textureSampler, ref_coords_r).a + texture2D(textureSampler, ref_coords_g).a + texture2D(textureSampler, ref_coords_b).a, 0., 1.);
 	gl_FragColor = original;
 }

+ 2 - 3
src/Shaders/depthOfFieldMerge.fragment.fx

@@ -1,5 +1,6 @@
-// samplers
 uniform sampler2D textureSampler;
+varying vec2 vUV;
+
 uniform sampler2D circleOfConfusionSampler;
 uniform sampler2D blurStep0;
 
@@ -9,8 +10,6 @@ uniform sampler2D blurStep1;
 #if BLUR_LEVEL > 1
 uniform sampler2D blurStep2;
 #endif
-// varyings
-varying vec2 vUV;
 
 void main(void)
 {

+ 14 - 0
src/Shaders/extractHighlights.fragment.fx

@@ -0,0 +1,14 @@
+#include<helperFunctions>
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+uniform float threshold;
+uniform float exposure;
+
+void main(void) 
+{
+	gl_FragColor = texture2D(textureSampler, vUV);
+	float luma = getLuminance(gl_FragColor.rgb * exposure);
+	gl_FragColor.rgb = step(threshold, luma) * gl_FragColor.rgb;
+}

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

@@ -0,0 +1,25 @@
+#include<helperFunctions>
+
+// samplers
+uniform sampler2D textureSampler;	// original color
+
+// uniforms
+uniform float intensity;
+uniform float animatedSeed;
+
+// varyings
+varying vec2 vUV;
+
+void main(void)
+{
+    gl_FragColor = texture2D(textureSampler, vUV);
+	vec2 seed = vUV*(animatedSeed);
+    float grain = dither(seed, intensity);
+
+    // Add less grain when luminance is high or low
+    float lum = getLuminance(gl_FragColor.rgb);
+    float grainAmount = (cos(-PI + (lum*PI*2.))+1.)/2.;
+    gl_FragColor.rgb += grain * grainAmount;
+
+    gl_FragColor.rgb = max(gl_FragColor.rgb, 0.0);
+}

+ 0 - 12
src/Shaders/imageProcessing.fragment.fx

@@ -18,18 +18,6 @@ void main(void)
 		result.rgb = toLinearSpace(result.rgb);
 	#endif
 
-	#ifdef GRAIN
-		vec2 seed = vUV*(grainAnimatedSeed);
-		float grain = dither(seed, grainVarianceAmount);
-
-		// Add less grain when luminance is high or low
-		float lum = getLuminance(result.rgb);
-		float grainAmount = (cos(-PI + (lum*PI*2.))+1.)/2.;
-		result.rgb += grain * grainAmount;
-
-		result.rgb = max(result.rgb, 0.0);
-	#endif
-
 	result = applyImageProcessing(result);
 #else
 	// In case where the input is in linear space we at least need to put it back in gamma.

+ 10 - 1
src/babylon.scene.ts

@@ -4186,7 +4186,16 @@
                 throw "No camera available to enable depth renderer";
             }
             if (!this._depthRenderer[camera.id]) {
-                this._depthRenderer[camera.id] = new DepthRenderer(this, Engine.TEXTURETYPE_FLOAT, camera);
+                var textureType = 0;
+                if (this._engine.getCaps().textureHalfFloatRender) {
+                    textureType = Engine.TEXTURETYPE_HALF_FLOAT;
+                }
+                else if (this._engine.getCaps().textureFloatRender) {
+                    textureType = Engine.TEXTURETYPE_FLOAT;
+                } else {
+                    throw "Depth renderer does not support int texture type";
+                }
+                this._depthRenderer[camera.id] = new DepthRenderer(this, textureType, camera);
             }
 
             return this._depthRenderer[camera.id];

BIN
tests/validation/ReferenceImages/DefaultRenderingPipeline.png


BIN
tests/validation/ReferenceImages/defaultPipeline.png


+ 1 - 1
tests/validation/config.json

@@ -286,7 +286,7 @@
     },
     {
       "title": "Default pipeline",
-      "playgroundId": "#NAW8EA#3",
+      "playgroundId": "#NAW8EA#6",
       "renderCount": 20,
       "referenceImage": "defaultPipeline.png"
     },