David Catuhe 9 vuotta sitten
vanhempi
commit
c7d2f6f390

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 26 - 26
dist/preview release/babylon.core.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 3882 - 3862
dist/preview release/babylon.d.ts


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 27 - 27
dist/preview release/babylon.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 149 - 57
dist/preview release/babylon.max.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 31 - 31
dist/preview release/babylon.noworker.js


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

@@ -1,6 +1,7 @@
 # 2.5.0:
 
 ### Major updates
+- New `StandardRenderingPipeline` effect to support screen space lens flare and depth of field. []Demo](http://www.babylonjs.com/Demos/StandardRenderingPipeline/) - ([Julien Moreau-Mathis](https://github.com/julien-moreau))
 - New `HighlightLayer` object to enable highlights rendering. [Demo](http://www.babylonjs.com/Demos/Highlights/) - ([sebavan](https://github.com/sebavan))
 - Babylon.js now supports right handed system with ```scene.useRightHandedSystem = true``` ([deltakosh](https://github.com/deltakosh))
 - Babylon.js is now compiled with [optimize-js](https://github.com/nolanlawson/optimize-js) to get faster initial load ([deltakosh](https://github.com/deltakosh))

+ 54 - 17
src/Layer/babylon.highlightlayer.js

@@ -226,12 +226,16 @@ var BABYLON;
                     return;
                 }
                 var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
-                if (_this.isReady(subMesh, hardwareInstancedRendering)) {
+                var highlightLayerMesh = _this._meshes[mesh.id];
+                var material = subMesh.getMaterial();
+                var emissiveTexture = null;
+                if (highlightLayerMesh && highlightLayerMesh.glowEmissiveOnly && material) {
+                    emissiveTexture = material.emissiveTexture;
+                }
+                if (_this.isReady(subMesh, hardwareInstancedRendering, emissiveTexture)) {
                     engine.enableEffect(_this._glowMapGenerationEffect);
                     mesh._bind(subMesh, _this._glowMapGenerationEffect, BABYLON.Material.TriangleFillMode);
-                    var material = subMesh.getMaterial();
                     _this._glowMapGenerationEffect.setMatrix("viewProjection", scene.getTransformMatrix());
-                    var highlightLayerMesh = _this._meshes[mesh.id];
                     if (highlightLayerMesh) {
                         _this._glowMapGenerationEffect.setFloat4("color", highlightLayerMesh.color.r, highlightLayerMesh.color.g, highlightLayerMesh.color.b, 1.0);
                     }
@@ -244,6 +248,11 @@ var BABYLON;
                         _this._glowMapGenerationEffect.setTexture("diffuseSampler", alphaTexture);
                         _this._glowMapGenerationEffect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
                     }
+                    // Glow emissive only
+                    if (emissiveTexture) {
+                        _this._glowMapGenerationEffect.setTexture("emissiveSampler", emissiveTexture);
+                        _this._glowMapGenerationEffect.setMatrix("emissiveMatrix", emissiveTexture.getTextureMatrix());
+                    }
                     // Bones
                     if (mesh.useBones && mesh.computeBonesUsingShaders) {
                         _this._glowMapGenerationEffect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
@@ -277,9 +286,10 @@ var BABYLON;
          * Checks for the readiness of the element composing the layer.
          * @param subMesh the mesh to check for
          * @param useInstances specify wether or not to use instances to render the mesh
+         * @param emissiveTexture the associated emissive texture used to generate the glow
          * @return true if ready otherwise, false
          */
-        HighlightLayer.prototype.isReady = function (subMesh, useInstances) {
+        HighlightLayer.prototype.isReady = function (subMesh, useInstances, emissiveTexture) {
             if (!subMesh.getMaterial().isReady()) {
                 return false;
             }
@@ -287,21 +297,45 @@ var BABYLON;
             var attribs = [BABYLON.VertexBuffer.PositionKind];
             var mesh = subMesh.getMesh();
             var material = subMesh.getMaterial();
+            var uv1 = false;
+            var uv2 = false;
             // Alpha test
             if (material && material.needAlphaTesting()) {
-                defines.push("#define ALPHATEST");
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                    attribs.push(BABYLON.VertexBuffer.UVKind);
-                    defines.push("#define UV1");
-                }
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                    var alphaTexture = material.getAlphaTestTexture();
-                    if (alphaTexture.coordinatesIndex === 1) {
-                        attribs.push(BABYLON.VertexBuffer.UV2Kind);
-                        defines.push("#define UV2");
+                var alphaTexture = material.getAlphaTestTexture();
+                if (alphaTexture) {
+                    defines.push("#define ALPHATEST");
+                    if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) &&
+                        alphaTexture.coordinatesIndex === 1) {
+                        defines.push("#define DIFFUSEUV2");
+                        uv2 = true;
+                    }
+                    else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                        defines.push("#define DIFFUSEUV1");
+                        uv1 = true;
                     }
                 }
             }
+            // Emissive
+            if (emissiveTexture) {
+                defines.push("#define EMISSIVE");
+                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind) &&
+                    emissiveTexture.coordinatesIndex === 1) {
+                    defines.push("#define EMISSIVEUV2");
+                    uv2 = true;
+                }
+                else if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                    defines.push("#define EMISSIVEUV1");
+                    uv1 = true;
+                }
+            }
+            if (uv1) {
+                attribs.push(BABYLON.VertexBuffer.UVKind);
+                defines.push("#define UV1");
+            }
+            if (uv2) {
+                attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                defines.push("#define UV2");
+            }
             // Bones
             if (mesh.useBones && mesh.computeBonesUsingShaders) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
@@ -328,7 +362,7 @@ var BABYLON;
             var join = defines.join("\n");
             if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
-                this._glowMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "color"], ["diffuseSampler"], join);
+                this._glowMapGenerationEffect = this._scene.getEngine().createEffect("glowMapGeneration", attribs, ["world", "mBones", "viewProjection", "diffuseMatrix", "color", "emissiveMatrix"], ["diffuseSampler", "emissiveSampler"], join);
             }
             return this._glowMapGenerationEffect.isReady();
         };
@@ -389,9 +423,11 @@ var BABYLON;
          * Add a mesh in the highlight layer in order to make it glow with the chosen color.
          * @param mesh The mesh to highlight
          * @param color The color of the highlight
+         * @param glowEmissiveOnly Extract the glow from the emissive texture
          */
-        HighlightLayer.prototype.pushMesh = function (mesh, color) {
+        HighlightLayer.prototype.addMesh = function (mesh, color, glowEmissiveOnly) {
             var _this = this;
+            if (glowEmissiveOnly === void 0) { glowEmissiveOnly = false; }
             var meshHighlight = this._meshes[mesh.id];
             if (meshHighlight) {
                 meshHighlight.color = color;
@@ -404,7 +440,8 @@ var BABYLON;
                     observerHighlight: mesh.onBeforeRenderObservable.add(function (mesh) {
                         mesh.getScene().getEngine().setStencilFunctionReference(_this._instanceGlowingMeshStencilReference);
                     }),
-                    observerDefault: mesh.onAfterRenderObservable.add(this.defaultStencilReference)
+                    observerDefault: mesh.onAfterRenderObservable.add(this.defaultStencilReference),
+                    glowEmissiveOnly: glowEmissiveOnly
                 };
             }
             this._shouldRender = true;

+ 94 - 39
src/PostProcess/babylon.standardRenderingPipeline.js

@@ -24,19 +24,31 @@ var BABYLON;
             this.gaussianBlurHPostProcesses = [];
             this.gaussianBlurVPostProcesses = [];
             this.textureAdderPostProcess = null;
-            this.depthOfFieldSourcePostProcess = null;
+            this.textureAdderFinalPostProcess = null;
+            this.lensFlarePostProcess = null;
+            this.lensFlareShiftPostProcess = null;
+            this.lensFlareComposePostProcess = null;
             this.depthOfFieldPostProcess = null;
+            this.motionBlurPostProcess = null;
+            // Values
             this.brightThreshold = 1.0;
             this.gaussianCoefficient = 0.25;
             this.gaussianMean = 1.0;
             this.gaussianStandardDeviation = 1.0;
             this.exposure = 1.0;
             this.lensTexture = null;
+            this.lensColorTexture = null;
+            this.lensFlareStrength = 1.0;
+            this.lensFlareGhostDispersal = 1.0;
+            this.lensFlareHaloWidth = 0.4;
+            this.lensFlareDistortionStrength = 4.0;
+            this.lensStarTexture = null;
+            this.lensFlareDirtTexture = null;
             this.depthOfFieldDistance = 10.0;
             this._depthRenderer = null;
             // Getters and setters
-            this._blurEnabled = true;
-            this._depthOfFieldEnabled = false;
+            this._depthOfFieldEnabled = true;
+            this._lensFlareEnabled = true;
             // Initialize
             this._scene = scene;
             // Create pass post-processe
@@ -59,10 +71,12 @@ var BABYLON;
             // Create texture adder post-process
             this._createTextureAdderPostProcess(scene, ratio);
             // Create depth-of-field source post-process
-            this.depthOfFieldSourcePostProcess = new BABYLON.PostProcess("HDRDepthOfFieldSource", "standard", [], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
-            this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", function () { return _this.depthOfFieldSourcePostProcess; }, true));
+            this.textureAdderFinalPostProcess = new BABYLON.PostProcess("HDRTextureAdderPostProcess", "standard", [], [], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", function () { return _this.textureAdderFinalPostProcess; }, true));
+            // Create lens flare post-process
+            this._createLensFlarePostProcess(scene, ratio);
             // Create gaussian blur used by depth-of-field
-            this._createGaussianBlurPostProcesses(scene, ratio / 2, 4);
+            this._createGaussianBlurPostProcesses(scene, ratio / 2, 5);
             // Create depth-of-field post-process
             this._createDepthOfFieldPostProcess(scene, ratio);
             // Finish
@@ -70,52 +84,54 @@ var BABYLON;
             if (cameras !== null) {
                 scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
             }
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", cameras);
+            // Deactivate
+            this.LensFlareEnabled = false;
+            this.DepthOfFieldEnabled = false;
         }
-        Object.defineProperty(StandardRenderingPipeline.prototype, "BlurEnabled", {
+        Object.defineProperty(StandardRenderingPipeline.prototype, "DepthOfFieldEnabled", {
             get: function () {
-                return this._blurEnabled;
+                return this._depthOfFieldEnabled;
             },
             set: function (enabled) {
-                if (enabled && !this._blurEnabled || !enabled && this._blurEnabled) {
-                    for (var i = 0; i < this.gaussianBlurHPostProcesses.length - 1; i++) {
-                        if (enabled) {
-                            this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
-                            this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
-                        }
-                        else {
-                            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
-                            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
-                        }
-                    }
+                var blurIndex = this.gaussianBlurHPostProcesses.length - 1;
+                if (enabled && !this._depthOfFieldEnabled) {
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
+                    this._depthRenderer = this._scene.enableDepthRenderer();
                 }
-                this._blurEnabled = enabled;
+                else if (!enabled && this._depthOfFieldEnabled) {
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
+                }
+                this._depthOfFieldEnabled = enabled;
             },
             enumerable: true,
             configurable: true
         });
-        Object.defineProperty(StandardRenderingPipeline.prototype, "DepthOfFieldEnabled", {
+        Object.defineProperty(StandardRenderingPipeline.prototype, "LensFlareEnabled", {
             get: function () {
-                return this._depthOfFieldEnabled;
+                return this._lensFlareEnabled;
             },
             set: function (enabled) {
-                if (enabled && !this._depthOfFieldEnabled) {
-                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
+                var blurIndex = this.gaussianBlurHPostProcesses.length - 2;
+                if (enabled && !this._lensFlareEnabled) {
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlare", this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlareShift", this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
                     this._depthRenderer = this._scene.enableDepthRenderer();
                 }
-                else if (!enabled && this._depthOfFieldEnabled) {
-                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
-                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
+                else if (!enabled && this._lensFlareEnabled) {
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlare", this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlareShift", this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                    this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
                 }
-                this._depthOfFieldEnabled = enabled;
+                this._lensFlareEnabled = enabled;
             },
             enumerable: true,
             configurable: true
@@ -207,7 +223,7 @@ var BABYLON;
         StandardRenderingPipeline.prototype._createTextureAdderPostProcess = function (scene, ratio) {
             var _this = this;
             var lastGaussianBlurPostProcess = this.gaussianBlurVPostProcesses[3];
-            this.textureAdderPostProcess = new BABYLON.PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define TEXTURE_ADDER", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.textureAdderPostProcess = new BABYLON.PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define TEXTURE_ADDER", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
             this.textureAdderPostProcess.onApply = function (effect) {
                 effect.setTextureFromPostProcess("otherSampler", _this.originalPostProcess);
                 effect.setTexture("lensSampler", _this.lensTexture);
@@ -216,12 +232,51 @@ var BABYLON;
             // Add to pipeline
             this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRTextureAdder", function () { return _this.textureAdderPostProcess; }, true));
         };
+        // Create lens flare post-process
+        StandardRenderingPipeline.prototype._createLensFlarePostProcess = function (scene, ratio) {
+            var _this = this;
+            this.lensFlarePostProcess = new BABYLON.PostProcess("HDRLensFlare", "standard", ["strength", "ghostDispersal", "haloWidth"], ["lensColorSampler"], ratio / 8, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define LENS_FLARE", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.lensFlareShiftPostProcess = new BABYLON.PostProcess("HDRLensFlareShift", "standard", ["resolution", "distortionStrength"], [], ratio / 8, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE_SHIFT", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._createGaussianBlurPostProcesses(scene, ratio / 8, 4);
+            this.lensFlareComposePostProcess = new BABYLON.PostProcess("HDRLensFlareCompose", "standard", ["viewMatrix", "scaleBias1", "scaleBias2"], ["otherSampler", "lensDirtSampler", "lensStarSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE_COMPOSE", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
+            var resolution = new BABYLON.Vector2(0, 0);
+            // Lens flare
+            this.lensFlarePostProcess.onApply = function (effect) {
+                effect.setTextureFromPostProcess("textureSampler", _this.textureAdderPostProcess);
+                effect.setTexture("lensColorSampler", _this.lensColorTexture);
+                effect.setFloat("strength", _this.lensFlareStrength);
+                effect.setFloat("ghostDispersal", _this.lensFlareGhostDispersal);
+                effect.setFloat("haloWidth", _this.lensFlareHaloWidth);
+            };
+            // Shift
+            this.lensFlareShiftPostProcess.onApply = function (effect) {
+                resolution.x = _this.lensFlareShiftPostProcess.width;
+                resolution.y = _this.lensFlareShiftPostProcess.height;
+                effect.setVector2("resolution", resolution);
+                effect.setFloat("distortionStrength", _this.lensFlareDistortionStrength);
+            };
+            // Compose
+            var scaleBias1 = BABYLON.Matrix.GetAsMatrix3x3(BABYLON.Matrix.FromValues(2.0, 0.0, -1.0, 0.0, 0.0, 2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+            var scaleBias2 = BABYLON.Matrix.GetAsMatrix3x3(BABYLON.Matrix.FromValues(0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0));
+            this.lensFlareComposePostProcess.onApply = function (effect) {
+                effect.setTextureFromPostProcess("otherSampler", _this.textureAdderFinalPostProcess);
+                effect.setTexture("lensDirtSampler", _this.lensFlareDirtTexture);
+                effect.setTexture("lensStarSampler", _this.lensStarTexture);
+                effect.setMatrix("viewMatrix", _this._scene.activeCamera.getViewMatrix());
+                effect.setMatrix3x3("scaleBias1", scaleBias1);
+                effect.setMatrix3x3("scaleBias2", scaleBias2);
+            };
+            // Add to pipeline
+            this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRLensFlare", function () { return _this.lensFlarePostProcess; }, false));
+            this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareShift", function () { return _this.lensFlareShiftPostProcess; }, false));
+            this.addEffect(new BABYLON.PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareCompose", function () { return _this.lensFlareComposePostProcess; }, false));
+        };
         // Create depth-of-field post-process
         StandardRenderingPipeline.prototype._createDepthOfFieldPostProcess = function (scene, ratio) {
             var _this = this;
             this.depthOfFieldPostProcess = new BABYLON.PostProcess("HDRDepthOfField", "standard", ["distance"], ["otherSampler", "depthSampler"], ratio, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DEPTH_OF_FIELD", BABYLON.Engine.TEXTURETYPE_UNSIGNED_INT);
             this.depthOfFieldPostProcess.onApply = function (effect) {
-                effect.setTextureFromPostProcess("otherSampler", _this.depthOfFieldSourcePostProcess);
+                effect.setTextureFromPostProcess("otherSampler", _this.textureAdderFinalPostProcess);
                 effect.setTexture("depthSampler", _this._depthRenderer.getDepthMap());
                 effect.setFloat("distance", _this.depthOfFieldDistance);
             };

+ 132 - 45
src/PostProcess/babylon.standardRenderingPipeline.ts

@@ -1,17 +1,29 @@
 module BABYLON {
     export class StandardRenderingPipeline extends PostProcessRenderPipeline implements IDisposable {
-        // Public members
+        /**
+        * Public members
+        */
+        // Post-processes
         public originalPostProcess: PostProcess;
         public downSampleX4PostProcess: PostProcess = null;
         public brightPassPostProcess: PostProcess = null;
         public gaussianBlurHPostProcesses: PostProcess[] = [];
         public gaussianBlurVPostProcesses: PostProcess[] = [];
         public textureAdderPostProcess: PostProcess = null;
-        public depthOfFieldSourcePostProcess: PostProcess = null;
+
+        public textureAdderFinalPostProcess: PostProcess = null;
+
+        public lensFlarePostProcess: PostProcess = null;
+        public lensFlareShiftPostProcess: PostProcess = null;
+        public lensFlareComposePostProcess: PostProcess = null;
+
         public depthOfFieldPostProcess: PostProcess = null;
 
+        public motionBlurPostProcess: PostProcess = null;
+
+        // Values
         public brightThreshold: number = 1.0;
-        
+
         public gaussianCoefficient: number = 0.25;
         public gaussianMean: number = 1.0;
         public gaussianStandardDeviation: number = 1.0;
@@ -19,50 +31,39 @@
         public exposure: number = 1.0;
         public lensTexture: Texture = null;
 
+        public lensColorTexture: Texture = null;
+        public lensFlareStrength: number = 1.0;
+        public lensFlareGhostDispersal: number = 1.0;
+        public lensFlareHaloWidth: number = 0.4;
+        public lensFlareDistortionStrength: number = 4.0;
+        public lensStarTexture: Texture = null;
+        public lensFlareDirtTexture: Texture = null;
+
         public depthOfFieldDistance: number = 10.0;
 
-        // Private members
+        /**
+        * Private members
+        */
         private _scene: Scene;
-        
+
         private _depthRenderer: DepthRenderer = null;
 
         // Getters and setters
-        private _blurEnabled: boolean = true;
-        private _depthOfFieldEnabled: boolean = false;
-
-        public set BlurEnabled(enabled: boolean) {
-            if (enabled && !this._blurEnabled || !enabled && this._blurEnabled) {
-                for (var i = 0; i < this.gaussianBlurHPostProcesses.length - 1; i++) {
-                    if (enabled) {
-                        this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
-                        this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
-                    }
-                    else {
-                        this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + i, this._scene.cameras);
-                        this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + i, this._scene.cameras);
-                    }
-                }
-            }
-
-            this._blurEnabled = enabled;
-        }
-
-        public get BlurEnabled(): boolean {
-            return this._blurEnabled;
-        }
+        private _depthOfFieldEnabled: boolean = true;
+        private _lensFlareEnabled: boolean = true;
 
         public set DepthOfFieldEnabled(enabled: boolean) {
+            var blurIndex = this.gaussianBlurHPostProcesses.length - 1;
+
             if (enabled && !this._depthOfFieldEnabled) {
-                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
-                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
-                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
                 this._depthRenderer = this._scene.enableDepthRenderer();
             }
             else if (!enabled && this._depthOfFieldEnabled) {
-                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", this._scene.cameras);
-                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", this._scene.cameras);
-                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
                 this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", this._scene.cameras);
             }
 
@@ -73,6 +74,32 @@
             return this._depthOfFieldEnabled;
         }
 
+        public set LensFlareEnabled(enabled: boolean) {
+            var blurIndex = this.gaussianBlurHPostProcesses.length - 2;
+
+            if (enabled && !this._lensFlareEnabled) {
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlare", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlareShift", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.enableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
+                this._depthRenderer = this._scene.enableDepthRenderer();
+            }
+            else if (!enabled && this._lensFlareEnabled) {
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlare", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlareShift", this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV" + blurIndex, this._scene.cameras);
+                this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRLensFlareCompose", this._scene.cameras);
+            }
+
+            this._lensFlareEnabled = enabled;
+        }
+
+        public get LensFlareEnabled(): boolean {
+            return this._lensFlareEnabled;
+        }
+
         /**
          * @constructor
          * @param {string} name - The rendering pipeline name
@@ -113,11 +140,14 @@
             this._createTextureAdderPostProcess(scene, ratio);
 
             // Create depth-of-field source post-process
-            this.depthOfFieldSourcePostProcess = new PostProcess("HDRDepthOfFieldSource", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_UNSIGNED_INT);
-            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", () => { return this.depthOfFieldSourcePostProcess; }, true));
+            this.textureAdderFinalPostProcess = new PostProcess("HDRTextureAdderPostProcess", "standard", [], [], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define PASS_POST_PROCESS", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRDepthOfFieldSource", () => { return this.textureAdderFinalPostProcess; }, true));
+
+            // Create lens flare post-process
+            this._createLensFlarePostProcess(scene, ratio);
 
             // Create gaussian blur used by depth-of-field
-            this._createGaussianBlurPostProcesses(scene, ratio / 2, 4);
+            this._createGaussianBlurPostProcesses(scene, ratio / 2, 5);
 
             // Create depth-of-field post-process
             this._createDepthOfFieldPostProcess(scene, ratio);
@@ -129,10 +159,9 @@
                 scene.postProcessRenderPipelineManager.attachCamerasToRenderPipeline(name, cameras);
             }
 
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfFieldSource", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurH4", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRGaussianBlurV4", cameras);
-            this._scene.postProcessRenderPipelineManager.disableEffectInPipeline(this._name, "HDRDepthOfField", cameras);
+            // Deactivate
+            this.LensFlareEnabled = false;
+            this.DepthOfFieldEnabled = false;
         }
 
         // Down Sample X4 Post-Processs
@@ -174,7 +203,7 @@
                 brightOffsets[5] = -0.5 * sV;
                 brightOffsets[6] = 0.5 * sU;
                 brightOffsets[7] = -0.5 * sV;
-                
+
                 effect.setArray2("dsOffsets", brightOffsets);
                 effect.setFloat("brightThreshold", this.brightThreshold);
             }
@@ -201,7 +230,7 @@
                             * (1.0 / Math.sqrt(2.0 * Math.PI * this.gaussianStandardDeviation))
                             * Math.exp((-((x - this.gaussianMean) * (x - this.gaussianMean))) / (2.0 * this.gaussianStandardDeviation * this.gaussianStandardDeviation));
                     }
-                    
+
                     var lastOutputDimensions: any = {
                         width: scene.getEngine().getRenderWidth(),
                         height: scene.getEngine().getRenderHeight()
@@ -238,7 +267,7 @@
         private _createTextureAdderPostProcess(scene: Scene, ratio: number): void {
             var lastGaussianBlurPostProcess = this.gaussianBlurVPostProcesses[3];
 
-            this.textureAdderPostProcess = new PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define TEXTURE_ADDER", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.textureAdderPostProcess = new PostProcess("HDRTextureAdder", "standard", ["exposure"], ["otherSampler", "lensSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define TEXTURE_ADDER", Engine.TEXTURETYPE_UNSIGNED_INT);
             this.textureAdderPostProcess.onApply = (effect: Effect) => {
                 effect.setTextureFromPostProcess("otherSampler", this.originalPostProcess);
                 effect.setTexture("lensSampler", this.lensTexture);
@@ -250,11 +279,69 @@
             this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRTextureAdder", () => { return this.textureAdderPostProcess; }, true));
         }
 
+        // Create lens flare post-process
+        private _createLensFlarePostProcess(scene: Scene, ratio: number): void {
+            this.lensFlarePostProcess = new PostProcess("HDRLensFlare", "standard", ["strength", "ghostDispersal", "haloWidth"], ["lensColorSampler"], ratio / 8, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), true, "#define LENS_FLARE", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this.lensFlareShiftPostProcess = new PostProcess("HDRLensFlareShift", "standard", ["resolution", "distortionStrength"], [], ratio / 8, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE_SHIFT", Engine.TEXTURETYPE_UNSIGNED_INT);
+            this._createGaussianBlurPostProcesses(scene, ratio / 8, 4);
+            this.lensFlareComposePostProcess = new PostProcess("HDRLensFlareCompose", "standard", ["viewMatrix", "scaleBias1", "scaleBias2"], ["otherSampler", "lensDirtSampler", "lensStarSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define LENS_FLARE_COMPOSE", Engine.TEXTURETYPE_UNSIGNED_INT);
+
+            var resolution = new Vector2(0, 0);
+
+            // Lens flare
+            this.lensFlarePostProcess.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("textureSampler", this.textureAdderPostProcess);
+                effect.setTexture("lensColorSampler", this.lensColorTexture);
+                effect.setFloat("strength", this.lensFlareStrength);
+                effect.setFloat("ghostDispersal", this.lensFlareGhostDispersal);
+                effect.setFloat("haloWidth", this.lensFlareHaloWidth);
+            };
+
+            // Shift
+            this.lensFlareShiftPostProcess.onApply = (effect: Effect) => {
+                resolution.x = this.lensFlareShiftPostProcess.width;
+                resolution.y = this.lensFlareShiftPostProcess.height;
+                effect.setVector2("resolution", resolution);
+
+                effect.setFloat("distortionStrength", this.lensFlareDistortionStrength);
+            };
+
+            // Compose
+            var scaleBias1 = Matrix.GetAsMatrix3x3(Matrix.FromValues(
+                2.0, 0.0, -1.0, 0.0,
+                0.0, 2.0, -1.0, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 0.0
+            ));
+
+            var scaleBias2 = Matrix.GetAsMatrix3x3(Matrix.FromValues(
+                0.5, 0.0, 0.5, 0.0,
+                0.0, 0.5, 0.5, 0.0,
+                0.0, 0.0, 1.0, 0.0,
+                0.0, 0.0, 0.0, 0.0
+            ));
+
+            this.lensFlareComposePostProcess.onApply = (effect: Effect) => {
+                effect.setTextureFromPostProcess("otherSampler", this.textureAdderFinalPostProcess);
+                effect.setTexture("lensDirtSampler", this.lensFlareDirtTexture);
+                effect.setTexture("lensStarSampler", this.lensStarTexture);
+
+                effect.setMatrix("viewMatrix", this._scene.activeCamera.getViewMatrix());
+                effect.setMatrix3x3("scaleBias1", scaleBias1);
+                effect.setMatrix3x3("scaleBias2", scaleBias2);
+            };
+
+            // Add to pipeline
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlare", () => { return this.lensFlarePostProcess; }, false));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareShift", () => { return this.lensFlareShiftPostProcess; }, false));
+            this.addEffect(new PostProcessRenderEffect(scene.getEngine(), "HDRLensFlareCompose", () => { return this.lensFlareComposePostProcess; }, false));
+        }
+
         // Create depth-of-field post-process
         private _createDepthOfFieldPostProcess(scene: Scene, ratio: number): void {
             this.depthOfFieldPostProcess = new PostProcess("HDRDepthOfField", "standard", ["distance"], ["otherSampler", "depthSampler"], ratio, null, Texture.BILINEAR_SAMPLINGMODE, scene.getEngine(), false, "#define DEPTH_OF_FIELD", Engine.TEXTURETYPE_UNSIGNED_INT);
             this.depthOfFieldPostProcess.onApply = (effect: Effect) => {
-                effect.setTextureFromPostProcess("otherSampler", this.depthOfFieldSourcePostProcess);
+                effect.setTextureFromPostProcess("otherSampler", this.textureAdderFinalPostProcess);
                 effect.setTexture("depthSampler", this._depthRenderer.getDepthMap());
 
                 effect.setFloat("distance", this.depthOfFieldDistance);

+ 152 - 14
src/Shaders/standard.fragment.fx

@@ -73,13 +73,13 @@ void main(void)
 	vec4 color = vec4(0.0, 0.0, 0.0, 0.0);
 
 	for (int i = 0; i < 9; i++) {
-		#ifdef GAUSSIAN_BLUR_H
+#ifdef GAUSSIAN_BLUR_H
 		color += (texture2D(textureSampler, vUV + vec2(blurOffsets[i] * 2.0, 0.0)) * blurWeights[i]);
 		color += (texture2D(textureSampler, vUV - vec2(blurOffsets[i] * 2.0, 0.0)) * blurWeights[i]);
-		#else
+#else
 		color += (texture2D(textureSampler, vUV + vec2(0.0, blurOffsets[i] * 2.0)) * blurWeights[i]);
 		color += (texture2D(textureSampler, vUV - vec2(0.0, blurOffsets[i] * 2.0)) * blurWeights[i]);
-		#endif
+#endif
 	}
 
 	color.a = 1.0;
@@ -96,7 +96,7 @@ uniform float exposure;
 void main(void)
 {
 	vec3 colour = texture2D(textureSampler, vUV).rgb;
-	
+
 	colour *= exposure;
 
 	vec3 X = max(vec3(0.0, 0.0, 0.0), colour - 0.004);
@@ -109,6 +109,144 @@ void main(void)
 }
 #endif
 
+#if defined(LENS_FLARE)
+#define GHOSTS 3
+
+uniform sampler2D lensColorSampler;
+
+uniform float strength;
+uniform float ghostDispersal;
+uniform float haloWidth;
+
+float hash(vec2 p) {
+	float h = dot(p, vec2(127.1, 311.7));
+	return -1.0 + 2.0*fract(sin(h)*43758.5453123);
+}
+
+float noise(in vec2 p) {
+	vec2 i = floor(p);
+	vec2 f = fract(p);
+	vec2 u = f*f*(3.0 - 2.0*f);
+
+	return mix(mix(hash(i + vec2(0.0, 0.0)),
+		hash(i + vec2(1.0, 0.0)), u.x),
+		mix(hash(i + vec2(0.0, 1.0)),
+			hash(i + vec2(1.0, 1.0)), u.x), u.y);
+}
+
+float fbm(vec2 p) {
+	float f = 0.0;
+	f += 0.5000 * noise(p); p *= 2.02;
+	f += 0.2500 * noise(p); p *= 2.03;
+	f += 0.1250 * noise(p); p *= 2.01;
+	f += 0.0625 * noise(p); p *= 2.04;
+	f /= 0.9375;
+	return f;
+}
+
+vec3 pattern(vec2 uv)
+{
+	vec2 p = -1.0 + 2.0 * uv;
+	float p2 = dot(p, p);
+	float f = fbm(vec2(15.0*p2)) / 2.0;
+	float r = 0.2 + 0.6 * sin(12.5*length(uv - vec2(0.5)));
+	float g = 0.2 + 0.6 * sin(20.5*length(uv - vec2(0.5)));
+	float b = 0.2 + 0.6 * sin(17.2*length(uv - vec2(0.5)));
+	return (1.0 - f) * vec3(r, g, b);
+}
+
+float luminance(vec3 color)
+{
+	return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
+}
+
+void main(void)
+{
+	vec2 uv = -vUV + vec2(1.0);
+	vec2 ghostDir = (vec2(0.5) - uv) * ghostDispersal;
+
+	vec4 result = vec4(0.0);
+	for (int i = 0; i < GHOSTS; ++i)
+	{
+		vec2 offset = fract(uv + ghostDir * float(i));
+		float weight = length(vec2(0.5) - offset) / length(vec2(0.5));
+		weight = pow(1.0 - weight, 10.0);
+		result += texture2D(textureSampler, offset) * weight;
+	}
+
+	float patternWeight = 0.4 * length(vec2(0.5) - uv);
+	result = mix(result, result * vec4(pattern(uv), 1.0), 0.6);
+
+	result *= texture2D(lensColorSampler, vec2(length(vec2(0.5) - vUV) / length(vec2(0.5))));
+
+	vec2 haloVec = normalize(ghostDir) * haloWidth;
+	float weight = length(vec2(0.5) - fract(uv + haloVec)) / length(vec2(0.5));
+	weight = pow(1.0 - weight, 5.0);
+	vec4 halo = texture2D(textureSampler, uv + haloVec) * weight;
+
+	gl_FragColor = (result + halo) * strength;
+}
+#endif
+
+#if defined(LENS_FLARE_SHIFT)
+uniform vec2 resolution;
+uniform float distortionStrength;
+
+void main(void)
+{
+	const float dispersion = 0.15;
+
+	vec2 uv = -vUV + vec2(1.0);
+	vec2 ghostDir = (vec2(0.5) - vUV);
+
+	vec2 texelSize = 1.0 / resolution;
+	vec3 distortion = vec3(-texelSize.x * distortionStrength, 0.0, texelSize.x * distortionStrength);
+	vec2 direction = vec2(normalize(ghostDir));
+
+	vec4 rgbShift = vec4(
+		texture2D(textureSampler, vUV + direction * distortion.r).r,
+		texture2D(textureSampler, vUV + direction * distortion.g).g,
+		texture2D(textureSampler, vUV + direction * distortion.b).b,
+		1.0
+	);
+
+	gl_FragColor = rgbShift;
+}
+#endif
+
+#if defined(LENS_FLARE_COMPOSE)
+uniform sampler2D otherSampler;
+uniform sampler2D lensDirtSampler;
+uniform sampler2D lensStarSampler;
+
+uniform mat4 viewMatrix;
+uniform mat3 scaleBias1;
+uniform mat3 scaleBias2;
+
+void main(void)
+{
+	vec3 camerax = viewMatrix[0].xyz;
+	vec3 cameraz = viewMatrix[1].xyz;
+	float camRot = dot(camerax, vec3(0.0, 0.0, 1.0)) + dot(cameraz, vec3(0.0, 1.0, 0.0));
+
+	mat3 rotation = mat3(
+		cos(camRot), -sin(camRot), 0.0,
+		sin(camRot), cos(camRot), 0.0,
+		0.0, 0.0, 1.0
+	);
+
+	mat3 lensMatrix = scaleBias2 * rotation * scaleBias1;
+	vec2 lensFlareCoords = (lensMatrix * vec3(vUV, 1.0)).xy;
+
+	vec4 lensMod = texture2D(lensDirtSampler, vUV);
+	lensMod += texture2D(lensStarSampler, lensFlareCoords);
+
+	vec4 result = texture2D(textureSampler, vUV) * lensMod;
+
+	gl_FragColor = texture2D(otherSampler, vUV) + result;
+}
+#endif
+
 #if defined(DEPTH_OF_FIELD)
 uniform sampler2D otherSampler;
 uniform sampler2D depthSampler;
@@ -123,16 +261,16 @@ void main(void)
 	float factor = 0.0;
 
 	if (dist < 0.05)
-        factor = 1.0;
-    else if (dist < 0.1)
-        factor = 20.0 * (0.1 - dist);
-    else if (dist < 0.5)
-        factor=0.0;
-    else
-        factor = 2.0 * (dist - 0.5);
-
-    factor = clamp(factor, 0.0, 0.90);
-    gl_FragColor = mix(sharp, blur, factor);
+		factor = 1.0;
+	else if (dist < 0.1)
+		factor = 20.0 * (0.1 - dist);
+	else if (dist < 0.5)
+		factor = 0.0;
+	else
+		factor = 2.0 * (dist - 0.5);
+
+	factor = clamp(factor, 0.0, 0.90);
+	gl_FragColor = mix(sharp, blur, factor);
 }
 
 #endif